def prompt_tags(msg): """ Prompt for and return tags wished for message. """ # 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 session, term = getsession(), getterminal() tagdb = DBProxy('tags') msg_onlymods = (u"\r\nONlY MEMbERS Of thE '%s' OR '%s' " "GROUP MAY CREAtE NEW tAGS." % ( term.bold_yellow('sysop'), term.bold_blue('moderator'),)) msg_invalidtag = u"\r\n'%s' is not a valid tag." prompt_tags1 = u"ENtER %s, COMMA-dEliMitEd. " % ( term.bold_red('TAG(s)'),) prompt_tags2 = u"OR '/list', %s:quit\r\n : " % ( term.bold_yellow_underline('Escape'),) while True: # Accept user input for multiple 'tag's, or /list command echo(u'\r\n\r\n') echo(prompt_tags1) echo(prompt_tags2) width = term.width - 6 sel_tags = u', '.join(msg.tags) inp_tags = LineEditor(width, sel_tags).read() if inp_tags is not None and 0 == len(inp_tags.strip()): # no tags must be (private ..) msg.tags = set() return True if inp_tags is None or inp_tags.strip().lower() == '/quit': return False elif inp_tags.strip().lower() == '/list': # list all available tags, and number of messages 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(%d)' % (_key, len(_value),) for (_key, _value) in all_tags])) ).wrap(term.width - 2)) continue echo(u'\r\n') # search input as valid tag(s) tags = set([inp.strip().lower() for inp in inp_tags.split(',')]) err = False for tag in tags.copy(): if not tag in tagdb and not ( 'sysop' in session.user.groups or 'moderator' in session.user.groups): tags.remove(tag) echo(msg_invalidtag % (term.bold_red(tag),)) err = True if err: echo(msg_onlymods) continue msg.tags = tags return True
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 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 x84net_requeue(): # a message failed to queue for delivery, but hellbeard # really wanted to see em, so re-queue. from x84.bbs import DBProxy, echo from pprint import pformat queuedb = DBProxy('x84netqueues') with queuedb: queuedb['264'] = 1 echo('-') echo(pformat(queuedb.items())) echo('-')
def maybe_expunge_records(): """ Check ceiling of database keys; trim-to MAX_HISTORY. """ udb = DBProxy('oneliner') expunged = 0 with udb: if len(udb) > MAX_HISTORY + 10: contents = DBProxy('oneliner').copy() _sorted = sorted( ((value, key) for (key, value) in contents.items()), key=lambda _valkey: keysort_by_datetime(_valkey[0])) for expunged, (_, key) in enumerate( _sorted[len(udb) - MAX_HISTORY:]): del udb[key] if expunged: log = logging.getLogger(__name__) log.info('expunged %d records from database', expunged)
def maybe_expunge_records(): """ Check ceiling of database keys; trim-to MAX_HISTORY. """ udb = DBProxy('oneliner') expunged = 0 with udb: if len(udb) > MAX_HISTORY + 10: contents = DBProxy('oneliner').copy() _sorted = sorted( ((value, key) for (key, value) in contents.items()), key=lambda _valkey: keysort_by_datetime(_valkey[0])) for expunged, (_, key) in enumerate(_sorted[len(udb) - MAX_HISTORY:]): del udb[key] if expunged: log = logging.getLogger(__name__) log.info('expunged %d records from database', expunged)
def lc_retrieve(): """ Returns tuple of ([nicknames,] u'text'), where 'text' describes in Ansi color the last callers to the system, and 'nicknames' is simply a list of last callers (for lightbar selection key). """ # pylint: disable=R0914 # Too many local variables from x84.bbs import get_user, ini, timeago, getterminal from x84.bbs import DBProxy import time term = getterminal() udb = DBProxy('lastcalls') # re-order by time called; unfortunate ..; note that sqlite # encodes unicode as utf-8; but doesn't decode it on retrieval, # of dict keys; possible upstream patching opportunity here, sortdb = {} for ((handle), (tm_lc, _nc, origin)) in (udb.items()): while tm_lc in sortdb: tm_lc += 0.1 sortdb[tm_lc] = [handle.decode('utf-8'), _nc, origin] padd_handle = (ini.CFG.getint('nua', 'max_user') + 2) padd_origin = (ini.CFG.getint('nua', 'max_location') + 2) rstr = u'' nicks = [] for tm_lc, (handle, _nc, origin) in (reversed(sorted(sortdb.items()))): try: is_sysop = 'sysop' in get_user(handle).groups except KeyError: # anonymous/deleted accts, is_sysop = False rstr += (term.bold_red(u'@') if is_sysop else u'' ) + (term.ljust(handle, (padd_handle - (2 if is_sysop else 1)))) rstr += term.red(origin.ljust(padd_origin)) rstr += timeago(time.time() - tm_lc) rstr += u'\n' nicks.append(handle) return (nicks, rstr.rstrip())
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
def prompt_tags(msg): """ Prompt for and return tags wished for message. """ # pylint: disable=R0914,W0603 # Too many local variables # Using the global statement from x84.bbs import DBProxy, echo, getterminal, getsession from x84.bbs import LineEditor, ini session, term = getsession(), getterminal() tagdb = DBProxy('tags') # version 1.0.9 introduced new ini option; set defaults for # those missing it from 1.0.8 upgrades. import ConfigParser try: moderated_tags = ini.CFG.getboolean('msg', 'moderated_tags') except ConfigParser.NoOptionError: moderated_tags = False try: moderated_groups = set(ini.CFG.get('msg', 'tag_moderator_groups' ).split()) except ConfigParser.NoOptionError: moderated_groups = ('sysop', 'moderator',) msg_onlymods = (u"\r\nONlY MEMbERS Of GROUPS %s MAY CREAtE NEW tAGS." % ( ", ".join(["'%s'".format(term.bold_yellow(grp) for grp in moderated_groups)]))) msg_invalidtag = u"\r\n'%s' is not a valid tag." prompt_tags1 = u"ENtER %s, COMMA-dEliMitEd. " % (term.bold_red('TAG(s)'),) prompt_tags2 = u"OR '/list', %s:quit\r\n : " % ( term.bold_yellow_underline('Escape'),) while True: # Accept user input for multiple 'tag's, or /list command echo(u'\r\n\r\n') echo(prompt_tags1) echo(prompt_tags2) width = term.width - 6 sel_tags = u', '.join(msg.tags) inp_tags = LineEditor(width, sel_tags).read() if inp_tags is not None and 0 == len(inp_tags.strip()): # no tags must be (private ..) msg.tags = set() return True if inp_tags is None or inp_tags.strip().lower() == '/quit': return False elif inp_tags.strip().lower() == '/list': # list all available tags, and number of messages 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(u', '.join((term.wrap([u'%s(%d)' % (_key, len(_value),) for (_key, _value) in all_tags])) ), term.width - 2) continue echo(u'\r\n') # search input as valid tag(s) tags = set([inp.strip().lower() for inp in inp_tags.split(',')]) # if the tag is new, and the user's group is not in # tag_moderator_groups, then dissallow such tag if # 'moderated_tags = yes' in ini cfg if moderated_tags: err = False for tag in tags.copy(): if not tag in tagdb and not ( session.users.groups & moderated_groups): tags.remove(tag) echo(msg_invalidtag % (term.bold_red(tag),)) err = True if err: echo(msg_onlymods) continue msg.tags = tags return True
def prompt_tags(msg): """ Prompt for and return tags wished for message. """ # 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, ini session, term = getsession(), getterminal() tagdb = DBProxy('tags') # version 1.0.9 introduced new ini option; set defaults for # those missing it from 1.0.8 upgrades. import ConfigParser try: moderated_tags = ini.CFG.getboolean('msg', 'moderated_tags') except ConfigParser.NoOptionError: moderated_tags = False try: moderated_groups = set( ini.CFG.get('msg', 'tag_moderator_groups').split()) except ConfigParser.NoOptionError: moderated_groups = ( 'sysop', 'moderator', ) msg_onlymods = ( u"\r\nONlY MEMbERS Of GROUPS %s MAY CREAtE NEW tAGS." % (", ".join( ["'%s'".format(term.bold_yellow(grp) for grp in moderated_groups)]))) msg_invalidtag = u"\r\n'%s' is not a valid tag." prompt_tags1 = u"ENtER %s, COMMA-dEliMitEd. " % (term.bold_red('TAG(s)'), ) prompt_tags2 = u"OR '/list', %s:quit\r\n : " % ( term.bold_yellow_underline('Escape'), ) while True: # Accept user input for multiple 'tag's, or /list command echo(u'\r\n\r\n') echo(prompt_tags1) echo(prompt_tags2) width = term.width - 6 sel_tags = u', '.join(msg.tags) inp_tags = LineEditor(width, sel_tags).read() if inp_tags is not None and 0 == len(inp_tags.strip()): # no tags must be (private ..) msg.tags = set() return True if inp_tags is None or inp_tags.strip().lower() == '/quit': return False elif inp_tags.strip().lower() == '/list': # list all available tags, and number of messages 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(%d)' % ( _key, len(_value), ) for (_key, _value) in all_tags ]))).wrap(term.width - 2)) continue echo(u'\r\n') # search input as valid tag(s) tags = set([inp.strip().lower() for inp in inp_tags.split(',')]) # if the tag is new, and the user's group is not in # tag_moderator_groups, then dissallow such tag if # 'moderated_tags = yes' in ini cfg if moderated_tags: err = False for tag in tags.copy(): if not tag in tagdb and not (session.users.groups & moderated_groups): tags.remove(tag) echo(msg_invalidtag % (term.bold_red(tag), )) err = True if err: echo(msg_onlymods) continue msg.tags = tags return True
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' ### 尝试 session.log.info("Hick3") ### 获取所有 tag tagdb = DBProxy('tags') all_tags = sorted(tagdb.items()) session.log.info(all_tags) ### 尝试直接调出显示的 message ,第二个参数应该是标识为未读的 msg = new = [1, 2, 3, 4,5 ,6, 7, 8,9] read_messages(msg, new) return ### 首先是显示提示输入的 tag 的标签 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'))) ### 默认就往这里了, 提示输入 tag else: # 默认 tag 为 public SEARCH_TAGS = set(['hick3']) # 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>', ])) ### 直到有选择 tags , 保存到 session.user 中 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,: list_msgs 根据 tags 获得所有记录,看情形这个信息量大了有问题哈 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 ### 分 tag 和是否未读,删除等统计 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 # 根君上面的用户选择,读取消息, 某次记录 log msgs 和 new 都是帖子 id 的 set # read target messages # session.log.info(msgs) # session.log.info(new) read_messages(msgs, new)
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' ### 尝试 session.log.info("Hick3") ### 获取所有 tag tagdb = DBProxy('tags') all_tags = sorted(tagdb.items()) session.log.info(all_tags) ### 尝试直接调出显示的 message ,第二个参数应该是标识为未读的 msg = new = [1, 2, 3, 4, 5, 6, 7, 8, 9] read_messages(msg, new) return ### 首先是显示提示输入的 tag 的标签 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'))) ### 默认就往这里了, 提示输入 tag else: # 默认 tag 为 public SEARCH_TAGS = set(['hick3']) # 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>', ])) ### 直到有选择 tags , 保存到 session.user 中 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,: list_msgs 根据 tags 获得所有记录,看情形这个信息量大了有问题哈 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 ### 分 tag 和是否未读,删除等统计 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 # 根君上面的用户选择,读取消息, 某次记录 log msgs 和 new 都是帖子 id 的 set # read target messages # session.log.info(msgs) # session.log.info(new) read_messages(msgs, new)