def publish_network_messages(net): """ Push messages to network, ``net``. """ from x84.bbs import DBProxy from x84.bbs.msgbase import format_origin_line, MSGDB log = logging.getLogger(__name__) log.debug(u'[{net[name]}] publishing new messages.'.format(net=net)) queuedb = DBProxy('{0}queues'.format(net['name']), use_session=False) transdb = DBProxy('{0}trans'.format(net['name']), use_session=False) msgdb = DBProxy(MSGDB, use_session=False) # publish each message for msg_id in sorted(queuedb.keys(), cmp=lambda x, y: cmp(int(x), int(y))): if msg_id not in msgdb: log.warn('[{net[name]}] No such message (msg_id={msg_id})' .format(net=net, msg_id=msg_id)) del queuedb[msg_id] continue msg = msgdb[msg_id] trans_parent = None if msg.parent is not None: matches = [key for key, data in transdb.items() if int(data) == msg.parent] if len(matches) > 0: trans_parent = matches[0] else: log.warn('[{net[name]}] Parent ID {msg.parent} ' 'not in translation-DB (msg_id={msg_id})' .format(net=net, msg=msg, msg_id=msg_id)) trans_id = push_rest(net=net, msg=msg, parent=trans_parent) if trans_id is False: log.error('[{net[name]}] Message not posted (msg_id={msg_id})' .format(net=net, msg_id=msg_id)) continue if trans_id in transdb.keys(): log.error('[{net[name]}] trans_id={trans_id} conflicts with ' '(msg_id={msg_id})' .format(net=net, trans_id=trans_id, msg_id=msg_id)) with queuedb: del queuedb[msg_id] continue # transform, and possibly duplicate(?) message .. with transdb, msgdb, queuedb: transdb[trans_id] = msg_id msg.body = u''.join((msg.body, format_origin_line())) msgdb[msg_id] = msg del queuedb[msg_id] log.info('[{net[name]}] Published (msg_id={msg_id}) => {trans_id}' .format(net=net, msg_id=msg_id, trans_id=trans_id))
def publish_network_messages(net): " Push messages to network. " from x84.bbs import DBProxy from x84.bbs.msgbase import format_origin_line, MSGDB log = logging.getLogger(__name__) log.debug(u'[{net[name]}] publishing new messages.'.format(net=net)) queuedb = DBProxy('{0}queues'.format(net['name']), use_session=False) transdb = DBProxy('{0}trans'.format(net['name']), use_session=False) msgdb = DBProxy(MSGDB, use_session=False) # publish each message for msg_id in sorted(queuedb.keys(), cmp=lambda x, y: cmp(int(x), int(y))): if msg_id not in msgdb: log.warn('{net[name]} No such message (msg_id={msg_id})' .format(net=net, msg_id=msg_id)) del queuedb[msg_id] continue msg = msgdb[msg_id] trans_parent = None if msg.parent is not None: matches = [key for key, data in transdb.items() if int(data) == msg.parent] if len(matches) > 0: trans_parent = matches[0] else: log.warn('{net[name]} Parent ID {msg.parent} ' 'not in translation-DB (msg_id={msg_id})' .format(net=net, msg=msg, msg_id=msg_id)) trans_id = push_rest(net=net, msg=msg, parent=trans_parent) if trans_id is False: log.error('{net[name]} Message not posted (msg_id={msg_id})' .format(net=net['name'], msg_id=msg_id)) continue if trans_id in transdb.keys(): log.error('{net[name]} trans_id={trans_id} conflicts with ' '(msg_id={msg_id})' .format(net=net, trans_id=trans_id, msg_id=msg_id)) with queuedb: del queuedb[msg_id] continue # transform, and possibly duplicate(?) message .. with transdb, msgdb, queuedb: transdb[trans_id] = msg_id msg.body = u''.join((msg.body, format_origin_line())) msgdb[msg_id] = msg del queuedb[msg_id] log.info('{net[name]} Published (msg_id={msg_id}) => {trans_id}' .format(net=net, msg_id=msg_id, trans_id=trans_id))
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))
def add_oneline(msg): """ Add a oneliner to the local database. """ import time from x84.bbs import getsession, DBProxy, ini session = getsession() udb = DBProxy('oneliner') udb.acquire() udb[max([int(key) for key in udb.keys()] or [0]) + 1] = { 'oneliner': msg, 'alias': getsession().handle, 'bbsname': ini.CFG.get('system', 'bbsname'), 'timestamp': time.strftime('%Y-%m-%d %H:%M:%S'), } udb.release() session.buffer_event('oneliner_update', True) session.send_event('global', ('oneliner_update', True))
def chk_thread(thread): """ check if bbs-scene.org thread finished, if so, farm its data and send updates via event 'oneliner_update' if there are any. """ from x84.bbs import getsession, DBProxy import logging log = logging.getLogger(__name__) session = getsession() if thread is not None and not thread.is_alive(): udb = DBProxy('oneliner') udbkeys = udb.keys() nlc = 0 for key, value in thread.content: if key not in udbkeys: udb[key] = value nlc += 1 if nlc: log.debug('%d new entries', nlc) session.buffer_event('oneliner_update', True) else: log.debug('no new %s entries'.format(thread.ident)) return True
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, showart from x84.bbs import disconnect, getch import time import os session, term = getsession(), getterminal() session.activity = 'logging off' handle = session.user.handle or '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.bold_blue_underline(u'p'), term.bold_blue_underline(u'n'), term.red_underline(u'Escape/g'),)) prompt_say = u''.join((term.bold_blue(handle), term.bold_blue(u' SAYS WhAt'), term.bold(': '),)) boards = (('1984.ws', 'x/84 dEfAUlt bOARd', 'Dingo',), ('htc.zapto.org', 'Haunting the Chapel', 'Mercyful fate',), ('bbs.pharcyde.org', 'Pharcyde BBS', 'Access Denied',), ('bloodisland.ph4.se', 'Blood Island/X', 'Xzippo',), ('blackflag.acid.org:2627', 'Piranha: Black Flag', 'Caphood',), ('oddnetwork.org', '79 columns', 'Haliphax'), ('bbs.beardy.se', 'The Swamp', 'Beardy'), ('maze.io', 'rANDOM nOIZE', 'Maze'),) 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 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.bold_blue(u'%*d' % (len('%d' % (dblen,)), idx,)), term.bold_blue(u':'), term.bold_green(msg.ljust(automsg_len)), term.bold(u'\\'), term.bold_blue(asc_ago),)) echo(u'\r\n'.join(term.wrap(disp))) 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 showart( os.path.join(os.path.dirname(__file__), 'art', 'logoff.ans'), 'cp437'): 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)
def poll_network_for_messages(net): " pull for new messages of network, storing locally. " from x84.bbs import Msg, DBProxy from x84.bbs.msgbase import to_localtime log = logging.getLogger(__name__) log.debug(u'[{net[name]}] polling for new messages.'.format(net=net)) try: last_msg_id = get_last_msg_id(net['last_file']) except (OSError, IOError) as err: log.error('[{net[name]}] skipping network: {err}'.format(net=net, err=err)) return msgs = pull_rest(net=net, last_msg_id=last_msg_id) if msgs is not False: log.info('{net[name]} Retrieved {num} messages'.format(net=net, num=len(msgs))) else: log.debug('{net[name]} no messages.'.format(net=net)) return transdb = DBProxy('{0}trans'.format(net['name']), use_session=False) transkeys = transdb.keys() msgs = sorted(msgs, cmp=lambda x, y: cmp(int(x['id']), int(y['id']))) # store messages locally, saving their translated IDs to the transdb for msg in msgs: store_msg = Msg() store_msg.recipient = msg['recipient'] store_msg.author = msg['author'] store_msg.subject = msg['subject'] store_msg.body = msg['body'] store_msg.tags = set(msg['tags']) store_msg.tags.add(u''.join((net['name']))) if msg['recipient'] is None and u'public' not in msg['tags']: log.warn("{net[name]} No recipient (msg_id={msg[id]}), " "adding 'public' tag".format(net=net, msg=msg)) store_msg.tags.add(u'public') if (msg['parent'] is not None and str(msg['parent']) not in transkeys): log.warn('{net[name]} No such parent message ({msg[parent]}, ' 'msg_id={msg[id]}), removing reference.'.format(net=net, msg=msg)) elif msg['parent'] is not None: store_msg.parent = int(transdb[msg['parent']]) if msg['id'] in transkeys: log.warn('{net[name]} dupe (msg_id={msg[id]}) discarded.'.format( net=net, msg=msg)) else: # do not save this message to network, we already received # it from the network, set send_net=False store_msg.save(send_net=False, ctime=to_localtime(msg['ctime'])) with transdb: transdb[msg['id']] = store_msg.idx transkeys.append(msg['id']) log.info( '{net[name]} Processed (msg_id={msg[id]}) => {new_id}'.format( net=net, msg=msg, new_id=store_msg.idx)) if 'last' not in net.keys() or int(net['last']) < int(msg['id']): net['last'] = msg['id'] if 'last' in net.keys(): with open(net['last_file'], 'w') as last_fp: last_fp.write(str(net['last'])) return
def poll_network_for_messages(net): " pull for new messages of network, storing locally. " from x84.bbs import Msg, DBProxy from x84.bbs.msgbase import to_localtime log = logging.getLogger(__name__) log.debug(u'[{net[name]}] polling for new messages.'.format(net=net)) try: last_msg_id = get_last_msg_id(net['last_file']) except (OSError, IOError) as err: log.error('[{net[name]}] skipping network: {err}' .format(net=net, err=err)) return msgs = pull_rest(net=net, last_msg_id=last_msg_id) if msgs is not False: log.info('{net[name]} Retrieved {num} messages' .format(net=net, num=len(msgs))) else: log.debug('{net[name]} no messages.'.format(net=net)) return transdb = DBProxy('{0}trans'.format(net['name']), use_session=False) transkeys = transdb.keys() msgs = sorted(msgs, cmp=lambda x, y: cmp(int(x['id']), int(y['id']))) # store messages locally, saving their translated IDs to the transdb for msg in msgs: store_msg = Msg() store_msg.recipient = msg['recipient'] store_msg.author = msg['author'] store_msg.subject = msg['subject'] store_msg.body = msg['body'] store_msg.tags = set(msg['tags']) store_msg.tags.add(u''.join((net['name']))) if msg['recipient'] is None and u'public' not in msg['tags']: log.warn("{net[name]} No recipient (msg_id={msg[id]}), " "adding 'public' tag".format(net=net, msg=msg)) store_msg.tags.add(u'public') if (msg['parent'] is not None and str(msg['parent']) not in transkeys): log.warn('{net[name]} No such parent message ({msg[parent]}, ' 'msg_id={msg[id]}), removing reference.' .format(net=net, msg=msg)) elif msg['parent'] is not None: store_msg.parent = int(transdb[msg['parent']]) if msg['id'] in transkeys: log.warn('{net[name]} dupe (msg_id={msg[id]}) discarded.' .format(net=net, msg=msg)) else: # do not save this message to network, we already received # it from the network, set send_net=False store_msg.save(send_net=False, ctime=to_localtime(msg['ctime'])) with transdb: transdb[msg['id']] = store_msg.idx transkeys.append(msg['id']) log.info('{net[name]} Processed (msg_id={msg[id]}) => {new_id}' .format(net=net, msg=msg, new_id=store_msg.idx)) if 'last' not in net.keys() or int(net['last']) < int(msg['id']): net['last'] = msg['id'] if 'last' in net.keys(): with open(net['last_file'], 'w') as last_fp: last_fp.write(str(net['last'])) return
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)