def main(msg=None): """ Main procedure. """ from x84.bbs import Msg, getsession session = getsession() if msg is None: msg = Msg() msg.tags = ('public',) banner() while True: session.activity = 'Constructing a %s message' % ( u'public' if u'public' in msg.tags else u'private',) if not prompt_recipient(msg): break if not prompt_subject(msg): break if not prompt_public(msg): break if not prompt_body(msg): break # XXX if not prompt_tags(msg): break display_msg(msg) if not prompt_send(): break msg.save() return True return False
def main(msg=None): """ Main procedure. """ from x84.bbs import Msg, getsession session = getsession() if msg is None: msg = Msg() msg.tags = ('public', ) banner() while True: session.activity = 'Constructing a %s message' % ( u'public' if u'public' in msg.tags else u'private', ) if not prompt_recipient(msg): break if not prompt_subject(msg): break if not prompt_tags(msg): break if not prompt_public(msg): break if not prompt_body(msg): break display_msg(msg) if not prompt_send(): break msg.save() return True return False
def main(msg=None): """ Main procedure. """ from x84.bbs import Msg, getsession, echo, getterminal from x84.bbs.ini import CFG session, term = getsession(), getterminal() new_message = True if msg is None else False network_tags = None is_network_msg = False if CFG.has_option('msg', 'network_tags'): network_tags = map( str.strip, CFG.get('msg', 'network_tags').split(',')) if new_message: msg = Msg() msg.tags = ('public',) elif network_tags is not None: net_tags = [tag for tag in network_tags if tag in msg.tags] is_network_msg = True if len(net_tags) > 0 else False banner() while True: session.activity = 'Constructing a %s message' % ( u'public' if u'public' in msg.tags else u'private',) if network_tags and new_message: is_network_msg = prompt_network(msg, network_tags) if not prompt_recipient(msg, is_network_msg): break if not prompt_subject(msg): break if not prompt_public(msg): break if not prompt_body(msg): break # XXX if not prompt_tags(msg): break if is_network_msg: # XX move to sub-func how_many = len([tag for tag in network_tags if tag in msg.tags]) if how_many == 0: echo(u''.join((u'\r\n', term.bold_yellow_on_red( u' YOU tOld ME thiS WAS A NEtWORk MESSAGE. ' u'WhY did YOU liE?! '), u'\r\n'))) term.inkey(timeout=7) continue if how_many > 1: echo(u''.join(( u'\r\n', term.bold_yellow_on_red( u' ONlY ONE NEtWORk CAN bE POStEd tO At A tiME, ' u'SORRY '), u'\r\n'))) continue if u'public' not in msg.tags: echo(u''.join((u'\r\n', term.bold_yellow_on_red( u" YOU ShOUldN't SENd PRiVAtE " u"MESSAGES OVER tHE NEtWORk... "), u'\r\n'))) term.inkey(timeout=7) continue display_msg(msg) if not prompt_send(): break msg.save() session.user['msgs_sent'] = session.user.get('msgs_sent', 0) + 1 return True return False
def read_messages(msgs, new): """ Provide message reader UI given message list ``msgs``, with new messages in list ``new``. """ # pylint: disable=R0914,R0912,R0915 # Too many local variables # Too many branches # Too many statements from x84.bbs import timeago, get_msg, getterminal, echo, gosub from x84.bbs import ini, Pager, getsession, getch, Ansi, Msg import x84.default.writemsg session, term = getsession(), getterminal() session.activity = 'reading msgs' # build header len_idx = max([len('%d' % (_idx,)) for _idx in msgs]) len_author = ini.CFG.getint('nua', 'max_user') len_ago = 9 len_subject = ini.CFG.getint('msg', 'max_subject') len_preview = min(len_idx + len_author + len_ago + len_subject + -1, term.width - 2) reply_depth = ini.CFG.getint('msg', 'max_depth') indent_start, indent, indent_end = u'\\', u'-', u'> ' def get_header(msgs_idx): """ Return list of tuples, (idx, unicodestring), suitable for Lightbar. """ import datetime msg_list = list() thread_indent = lambda depth: (term.red( (indent_start + (indent * depth) + indent_end)) if depth else u'') def head(msg, depth=0, maxdepth=reply_depth): """ This recursive routine finds the 'head' message of any relationship, up to maxdepth. """ if (depth <= maxdepth and hasattr(msg, 'parent') and msg.parent is not None): return head(get_msg(msg.parent), depth + 1, maxdepth) return msg.idx, depth for idx in msgs_idx: msg = get_msg(idx) author, subj = msg.author, msg.subject tm_ago = (datetime.datetime.now() - msg.stime).total_seconds() # pylint: disable=W0631 # Using possibly undefined loop variable 'idx' attr = lambda arg: ( term.bold_green(arg) if ( not idx in ALREADY_READ and msg.recipient == session.user.handle) else term.red(arg) if not idx in ALREADY_READ else term.yellow(arg)) status = [u'U' if not idx in ALREADY_READ else u' ', u'D' if idx in DELETED else u' ', ] row_txt = u'%s %s %s %s %s%s ' % ( u''.join(status), attr(str(idx).rjust(len_idx)), attr(author.ljust(len_author)), (timeago(tm_ago)).rjust(len_ago), attr(u'ago'), term.bold_black(':'),) msg_list.append((head(msg), idx, row_txt, subj)) msg_list.sort() return [(idx, row_txt + thread_indent(depth) + subj) for (_threadid, depth), idx, row_txt, subj in msg_list] def get_selector(mailbox, prev_sel=None): """ Provide Lightbar UI element given message mailbox returned from function get_header, and prev_sel as previously instantiated Lightbar. """ from x84.bbs import Lightbar pos = prev_sel.position if prev_sel is not None else (0, 0) sel = Lightbar( height=(term.height / 3 if term.width < 140 else term.height - 3), width=len_preview, yloc=2, xloc=0) sel.glyphs['top-horiz'] = u'' sel.glyphs['left-vert'] = u'' sel.colors['highlight'] = term.yellow_reverse sel.update(mailbox) sel.position = pos return sel def get_reader(): """ Provide Pager UI element for message reading. """ reader_height = (term.height - (term.height / 3) - 2) reader_indent = 2 reader_width = min(term.width - 1, min(term.width - reader_indent, 80)) reader_ypos = ((term.height - 1 ) - reader_height if (term.width - reader_width) < len_preview else 2) reader_height = term.height - reader_ypos - 1 msg_reader = Pager( height=reader_height, width=reader_width, yloc=reader_ypos, xloc=min(len_preview + 2, term.width - reader_width)) msg_reader.glyphs['top-horiz'] = u'' msg_reader.glyphs['right-vert'] = u'' return msg_reader def format_msg(reader, idx): """ Format message of index ``idx`` into Pager instance ``reader``. """ msg = get_msg(idx) sent = msg.stime.strftime(TIME_FMT) to_attr = term.bold_green if ( msg.recipient == session.user.handle) else term.underline ucs = u'\r\n'.join(( (u''.join(( term.yellow('fROM: '), (u'%s' % term.bold(msg.author,)).rjust(len_author), u' ' * (reader.visible_width - (len_author + len(sent))), sent,))), u''.join(( term.yellow('tO: '), to_attr((u'%s' % to_attr(msg.recipient,)).rjust(len_author) if msg.recipient is not None else u'All'),)), (Ansi( term.yellow('tAGS: ') + (u'%s ' % (term.bold(','),)).join(( [term.bold_red(_tag) if _tag in SEARCH_TAGS else term.yellow(_tag) for _tag in msg.tags]))).wrap( reader.visible_width, indent=u' ')), (term.yellow_underline( (u'SUbj: %s' % (msg.subject,)).ljust(reader.visible_width) )), u'', (msg.body),)) return ucs def get_selector_title(mbox, new): """ Returns unicode string suitable for displaying as title of mailbox. """ newmsg = (term.yellow(u' ]-[ ') + term.yellow_reverse(str(len(new))) + term.bold_underline(u' NEW')) if len(new) else u'' return u''.join((term.yellow(u'[ '), term.bold_yellow(str(len(mbox))), term.bold( u' MSG%s' % (u's' if 1 != len(mbox) else u'',)), newmsg, term.yellow(u' ]'),)) dispcmd_mark = lambda idx: ( (term.yellow_underline(u' ') + u':mark' + u' ') if idx not in ALREADY_READ else u'') dispcmd_delete = lambda idx: ( (term.yellow_underline(u'D') + u':elete' + u' ') if idx not in DELETED else u'') dispcmd_tag = lambda idx: ( (term.yellow_underline(u't') + u':ag' + u' ') if allow_tag(idx) else u'') def get_selector_footer(idx): """ Returns unicode string suitable for displaying as footer of mailbox when window is active. """ return u''.join(( term.yellow(u'- '), u''.join(( term.yellow_underline(u'>') + u':read ', term.yellow_underline(u'r') + u':eply ', dispcmd_mark(idx), dispcmd_delete(idx), dispcmd_tag(idx), term.yellow_underline(u'q') + u':uit',)), term.yellow(u' -'),)) def get_reader_footer(idx): """ Returns unicode string suitable for displaying as footer of reader when window is active """ return u''.join(( term.yellow(u'- '), u' '.join(( term.yellow_underline(u'<') + u':back ', term.yellow_underline(u'r') + u':eply ', dispcmd_delete(idx), dispcmd_tag(idx), term.yellow_underline(u'q') + u':uit',)), term.yellow(u' -'),)) def refresh(reader, selector, mbox, new): """ Returns unicode string suitable for refreshing the screen. """ if READING: reader.colors['border'] = term.bold_yellow selector.colors['border'] = term.bold_black else: reader.colors['border'] = term.bold_black selector.colors['border'] = term.bold_yellow title = get_selector_title(mbox, new) padd_attr = (term.bold_yellow if not READING else term.bold_black) sel_padd_right = padd_attr( u'-' + selector.glyphs['bot-horiz'] * ( selector.visible_width - len(Ansi(title)) - 7) + u'-\u25a0-' if READING else u'- -') sel_padd_left = padd_attr( selector.glyphs['bot-horiz'] * 3) idx = selector.selection[0] return u''.join((term.move(0, 0), term.clear, u'\r\n', u'// REAdiNG MSGS ..'.center(term.width).rstrip(), selector.refresh(), selector.border() if READING else reader.border(), reader.border() if READING else selector.border(), selector.title( sel_padd_left + title + sel_padd_right), selector.footer(get_selector_footer(idx) ) if not READING else u'', reader.footer(get_reader_footer(idx) ) if READING else u'', reader.refresh(), )) echo((u'\r\n' + term.clear_eol) * (term.height - 1)) dirty = 2 msg_selector = None msg_reader = None idx = None # pylint: disable=W0603 # Using the global statement global READING while (msg_selector is None and msg_reader is None ) or not (msg_selector.quit or msg_reader.quit): if session.poll_event('refresh'): dirty = 2 if dirty: if dirty == 2: mailbox = get_header(msgs) msg_selector = get_selector(mailbox, msg_selector) idx = msg_selector.selection[0] msg_reader = get_reader() msg_reader.update(format_msg(msg_reader, idx)) echo(refresh(msg_reader, msg_selector, msgs, new)) dirty = 0 inp = getch(1) if inp in (u'r', u'R'): reply_to = get_msg(idx) reply_msg = Msg() reply_msg.recipient = reply_to.author reply_msg.tags = reply_to.tags reply_msg.subject = reply_to.subject reply_msg.parent = reply_to.idx # quote between 30 and 79, 'screen width - 4' as variable dist. reply_msg.body = quote_body(reply_to, max(30, min(79, term.width - 4))) echo(term.move(term.height, 0) + u'\r\n') if gosub('writemsg', reply_msg): reply_msg.save() dirty = 2 READING = False else: dirty = 1 mark_read(idx) # also mark as read # 't' uses writemsg.prompt_tags() routine, how confusing .. elif inp in (u't',) and allow_tag(idx): echo(term.move(term.height, 0)) msg = get_msg(idx) if x84.default.writemsg.prompt_tags(msg): msg.save() dirty = 2 # spacebar marks as read, goes to next message elif inp in (u' ',): dirty = 2 if mark_read(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False # D marks as deleted, goes to next message elif inp in (u'D',): dirty = 2 if mark_delete(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False # U undeletes, does not move. elif inp in (u'U',): dirty = 2 if mark_undelete(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False if READING: echo(msg_reader.process_keystroke(inp)) # left, <, or backspace moves UI if inp in (term.KEY_LEFT, u'<', u'h', '\b', term.KEY_BACKSPACE): READING = False dirty = 1 else: echo(msg_selector.process_keystroke(inp)) idx = msg_selector.selection[0] # right, >, or enter marks message read, moves UI if inp in (u'\r', term.KEY_ENTER, u'>', u'l', 'L', term.KEY_RIGHT): dirty = 2 if mark_read(idx) else 1 READING = True elif msg_selector.moved: dirty = 1 echo(term.move(term.height, 0) + u'\r\n') return
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 read_messages(msgs, new): """ Provide message reader UI given message list ``msgs``, with new messages in list ``new``. """ # pylint: disable=R0914,R0912,R0915 # Too many local variables # Too many branches # Too many statements from x84.bbs import timeago, get_msg, getterminal, echo, gosub from x84.bbs import ini, Pager, getsession, getch, Msg import x84.default.writemsg session, term = getsession(), getterminal() session.activity = 'reading msgs' # build header len_idx = max([len('%d' % (_idx, )) for _idx in msgs]) len_author = ini.CFG.getint('nua', 'max_user') len_ago = 9 len_subject = ini.CFG.getint('msg', 'max_subject') len_preview = min(len_idx + len_author + len_ago + len_subject + -1, term.width - 2) reply_depth = ini.CFG.getint('msg', 'max_depth') indent_start, indent, indent_end = u'\\', u'-', u'> ' def get_header(msgs_idx): """ Return list of tuples, (idx, unicodestring), suitable for Lightbar. """ import datetime msg_list = list() thread_indent = lambda depth: (term.red( (indent_start + (indent * depth) + indent_end)) if depth else u'') def head(msg, depth=0, maxdepth=reply_depth): """ This recursive routine finds the 'head' message of any relationship, up to maxdepth. """ if (depth <= maxdepth and hasattr(msg, 'parent') and msg.parent is not None): return head(get_msg(msg.parent), depth + 1, maxdepth) return msg.idx, depth for idx in msgs_idx: msg = get_msg(idx) author, subj = msg.author, msg.subject tm_ago = (datetime.datetime.now() - msg.stime).total_seconds() # pylint: disable=W0631 # Using possibly undefined loop variable 'idx' attr = lambda arg: (term.bold_green(arg) if (not idx in ALREADY_READ and msg.recipient == session.user.handle) else term.red(arg) if not idx in ALREADY_READ else term.yellow(arg )) status = [ u'U' if not idx in ALREADY_READ else u' ', u'D' if idx in DELETED else u' ', ] row_txt = u'%s %s %s %s %s%s ' % ( u''.join(status), attr(str(idx).rjust(len_idx)), attr(author.ljust(len_author)), (timeago(tm_ago)).rjust(len_ago), attr(u'ago'), term.bold_black(':'), ) msg_list.append((head(msg), idx, row_txt, subj)) msg_list.sort(reverse=True) return [(idx, row_txt + thread_indent(depth) + subj) for (_threadid, depth), idx, row_txt, subj in msg_list] def get_selector(mailbox, prev_sel=None): """ Provide Lightbar UI element given message mailbox returned from function get_header, and prev_sel as previously instantiated Lightbar. """ from x84.bbs import Lightbar pos = prev_sel.position if prev_sel is not None else (0, 0) sel = Lightbar(height=(term.height / 3 if term.width < 140 else term.height - 3), width=len_preview, yloc=2, xloc=0) sel.glyphs['top-horiz'] = u'' sel.glyphs['left-vert'] = u'' sel.colors['highlight'] = term.yellow_reverse sel.update(mailbox) sel.position = pos return sel def get_reader(): """ Provide Pager UI element for message reading. """ reader_height = (term.height - (term.height / 3) - 2) reader_indent = 2 reader_width = min(term.width - 1, min(term.width - reader_indent, 80)) reader_ypos = ((term.height - 1) - reader_height if (term.width - reader_width) < len_preview else 2) reader_height = term.height - reader_ypos - 1 msg_reader = Pager(height=reader_height, width=reader_width, yloc=reader_ypos, xloc=min(len_preview + 2, term.width - reader_width)) msg_reader.glyphs['top-horiz'] = u'' msg_reader.glyphs['right-vert'] = u'' return msg_reader def format_msg(reader, idx): """ Format message of index ``idx`` into Pager instance ``reader``. """ msg = get_msg(idx) sent = msg.stime.strftime(TIME_FMT) to_attr = term.bold_green if ( msg.recipient == session.user.handle) else term.underline ucs = u'\r\n'.join(( (u''.join(( term.yellow('fROM: '), (u'%s' % term.bold(msg.author, )).rjust(len_author), u' ' * (reader.visible_width - (len_author + len(sent))), sent, ))), u''.join(( term.yellow('tO: '), to_attr(( u'%s' % to_attr(msg.recipient, ) ).rjust(len_author) if msg.recipient is not None else u'All'), )), (u'\r\n'.join((term.wrap( term.yellow('tAGS: ') + (u'%s ' % (term.bold(','), )).join(([ term.bold_red(_tag) if _tag in SEARCH_TAGS else term.yellow(_tag) for _tag in msg.tags ])), reader.visible_width, subsequent_indent=u' ' * 6)))), (term.yellow_underline( (u'SUbj: %s' % (msg.subject, )).ljust(reader.visible_width))), u'', (msg.body), )) return ucs def get_selector_title(mbox, new): """ Returns unicode string suitable for displaying as title of mailbox. """ newmsg = (term.yellow(u' ]-[ ') + term.yellow_reverse(str(len(new))) + term.bold_underline(u' NEW')) if len(new) else u'' return u''.join(( term.yellow(u'[ '), term.bold_yellow(str(len(mbox))), term.bold(u' MSG%s' % (u's' if 1 != len(mbox) else u'', )), newmsg, term.yellow(u' ]'), )) dispcmd_mark = lambda idx: ((term.yellow_underline(u' ') + u':mark' + u' ') if idx not in ALREADY_READ else u'') dispcmd_delete = lambda idx: ( (term.yellow_underline(u'D') + u':elete' + u' ') if idx not in DELETED else u'') dispcmd_tag = lambda idx: ((term.yellow_underline(u't') + u':ag' + u' ') if allow_tag(idx) else u'') def get_selector_footer(idx): """ Returns unicode string suitable for displaying as footer of mailbox when window is active. """ return u''.join(( term.yellow(u'- '), u''.join(( term.yellow_underline(u'>') + u':read ', term.yellow_underline(u'r') + u':eply ', dispcmd_mark(idx), dispcmd_delete(idx), dispcmd_tag(idx), term.yellow_underline(u'q') + u':uit', )), term.yellow(u' -'), )) def get_reader_footer(idx): """ Returns unicode string suitable for displaying as footer of reader when window is active """ return u''.join(( term.yellow(u'- '), u' '.join(( term.yellow_underline(u'<') + u':back ', term.yellow_underline(u'r') + u':eply ', dispcmd_delete(idx), dispcmd_tag(idx), term.yellow_underline(u'q') + u':uit', )), term.yellow(u' -'), )) def refresh(reader, selector, mbox, new): """ Returns unicode string suitable for refreshing the screen. """ from x84.bbs import getsession session = getsession() if READING: reader.colors['border'] = term.bold_yellow selector.colors['border'] = term.bold_black else: reader.colors['border'] = term.bold_black selector.colors['border'] = term.bold_yellow title = get_selector_title(mbox, new) padd_attr = (term.bold_yellow if not READING else term.bold_black) sel_padd_right = padd_attr( u'-' + selector.glyphs['bot-horiz'] * (selector.visible_width - term.length(title) - 7) + u'-\u25a0-' if READING else u'- -') sel_padd_left = padd_attr(selector.glyphs['bot-horiz'] * 3) idx = selector.selection[0] return u''.join(( term.move(0, 0), term.clear, u'\r\n', u'// REAdiNG MSGS ..'.center(term.width).rstrip(), selector.refresh(), selector.border() if READING else reader.border(), reader.border() if READING else selector.border(), selector.title(sel_padd_left + title + sel_padd_right), selector.footer(get_selector_footer(idx)) if not READING else u'', reader.footer(get_reader_footer(idx)) if READING else u'', reader.refresh(), )) echo((u'\r\n' + term.clear_eol) * (term.height - 1)) dirty = 2 msg_selector = None msg_reader = None idx = None # pylint: disable=W0603 # Using the global statement global READING while (msg_selector is None and msg_reader is None) or not (msg_selector.quit or msg_reader.quit): if session.poll_event('refresh'): dirty = 2 if dirty: if dirty == 2: mailbox = get_header(msgs) msg_selector = get_selector(mailbox, msg_selector) idx = msg_selector.selection[0] msg_reader = get_reader() msg_reader.update(format_msg(msg_reader, idx)) echo(refresh(msg_reader, msg_selector, msgs, new)) dirty = 0 inp = getch(1) if inp in (u'r', u'R'): reply_to = get_msg(idx) reply_msg = Msg() reply_msg.recipient = reply_to.author reply_msg.tags = reply_to.tags reply_msg.subject = reply_to.subject reply_msg.parent = reply_to.idx # quote between 30 and 79, 'screen width - 4' as variable dist. reply_msg.body = quote_body(reply_to, max(30, min(79, term.width - 4))) echo(term.move(term.height, 0) + u'\r\n') if gosub('writemsg', reply_msg): reply_msg.save() dirty = 2 READING = False else: dirty = 1 mark_read(idx) # also mark as read # 't' uses writemsg.prompt_tags() routine, how confusing .. elif inp in (u't', ) and allow_tag(idx): echo(term.move(term.height, 0)) msg = get_msg(idx) if x84.default.writemsg.prompt_tags(msg): msg.save() session.user['msgs_sent'] = session.user.get('msgs_sent', 0) + 1 dirty = 2 # spacebar marks as read, goes to next message elif inp in (u' ', ): dirty = 2 if mark_read(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False # D marks as deleted, goes to next message elif inp in (u'D', ): dirty = 2 if mark_delete(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False # U undeletes, does not move. elif inp in (u'U', ): dirty = 2 if mark_undelete(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False if READING: echo(msg_reader.process_keystroke(inp)) # left, <, or backspace moves UI if inp in (term.KEY_LEFT, u'<', u'h', '\b', term.KEY_BACKSPACE): READING = False dirty = 1 else: echo(msg_selector.process_keystroke(inp)) idx = msg_selector.selection[0] # right, >, or enter marks message read, moves UI if inp in (u'\r', term.KEY_ENTER, u'>', u'l', 'L', term.KEY_RIGHT): dirty = 2 if mark_read(idx) else 1 READING = True elif msg_selector.moved: dirty = 1 echo(term.move(term.height, 0) + u'\r\n') return
def main(msg=None): """ Main procedure. """ from x84.bbs import Msg, getsession, echo, getterminal from x84.bbs.ini import CFG session, term = getsession(), getterminal() new_message = True if msg is None else False network_tags = None is_network_msg = False if CFG.has_option('msg', 'network_tags'): network_tags = map( str.strip, CFG.get('msg', 'network_tags').split(',')) if CFG.has_option('msg', 'server_tags'): if network_tags is None: network_tags = list() network_tags += map( str.strip, CFG.get('msg', 'server_tags').split(',')) if new_message: msg = Msg() msg.tags = ('public',) elif network_tags is not None: net_tags = [tag for tag in network_tags if tag in msg.tags] is_network_msg = True if len(net_tags) > 0 else False banner() while True: session.activity = 'Constructing a %s message' % ( u'public' if u'public' in msg.tags else u'private',) if network_tags and new_message: is_network_msg = prompt_network(msg, network_tags) if not prompt_recipient(msg, is_network_msg): break if not prompt_subject(msg): break if not prompt_public(msg): break if not prompt_body(msg): break # XXX if not prompt_tags(msg): break if is_network_msg: # XX move to sub-func how_many = len([tag for tag in network_tags if tag in msg.tags]) if how_many == 0: echo(u''.join((u'\r\n', term.bold_yellow_on_red( u' YOU tOld ME thiS WAS A NEtWORk MESSAGE. ' u'WhY did YOU liE?! '), u'\r\n'))) term.inkey(timeout=7) continue if how_many > 1: echo(u''.join(( u'\r\n', term.bold_yellow_on_red( u' ONlY ONE NEtWORk CAN bE POStEd tO At A tiME, ' u'SORRY '), u'\r\n'))) continue if u'public' not in msg.tags: echo(u''.join((u'\r\n', term.bold_yellow_on_red( u" YOU ShOUldN't SENd PRiVAtE " u"MESSAGES OVER tHE NEtWORk... "), u'\r\n'))) term.inkey(timeout=7) continue display_msg(msg) if not prompt_send(): break msg.save() session.user['msgs_sent'] = session.user.get('msgs_sent', 0) + 1 return True return False