class Sidebar(BoxWidget): signals = ['select', 'search'] def __init__(self, phones): self.phone_edit = EnterEdit('Phone:', '') self.chan_edit = EnterEdit('Chanl:', '') self.call_id_edit = EnterEdit('SipID:', '') self.text_edit = EnterEdit('Find:', '') connect_signal(self.phone_edit, 'enter', self.on_change, 'phone') connect_signal(self.chan_edit, 'enter', self.on_change, 'chan') connect_signal(self.call_id_edit, 'enter', self.on_change, 'call_id') connect_signal(self.text_edit, 'enter', self.on_change, 'text') self.phones_text = Text([('key', 'F4'), ' Phones']) self.head = Pile([ AttrWrap(Text([('key', 'F3'), ' Search']), 'bar'), AttrWrap(self.phone_edit, 'no', 'selection'), AttrWrap(self.chan_edit, 'no', 'selection'), AttrWrap(self.call_id_edit, 'no', 'selection'), Divider('-'), AttrWrap(self.text_edit, 'no', 'selection'), AttrWrap(self.phones_text, 'bar'), ]) self.items = SimpleListWalker([]) self.set_results(phones) self.listbox = ListBox(self.items) self.frame = Frame(self.listbox, header=self.head) def set_results(self, results): self.phones_text.set_text([('key', 'F4'), ' Results (%s)' % len(results)]) self.items[:] = [] group = [] for ref in results: item = RadioButton(group, ref, state=False) connect_signal(item, 'change', self.on_select_phone, ref) item = AttrWrap(item, 'no', 'selection') self.items.append(item) def render(self, size, focus=False): return self.frame.render(size, focus) def keypress(self, size, key): return self.frame.keypress(size, key) # noinspection PyUnusedLocal def on_select_phone(self, button, new_state, call_id): if new_state: self._emit('select', call_id) # noinspection PyUnusedLocal def on_change(self, widget, value, field_name): self._emit('search', field_name, value)
class Client(Component): channel = "client" def init(self, host, port=6667, opts=None): self.host = host self.port = port self.opts = opts self.hostname = gethostname() self.nick = opts.nick self.ircchannel = opts.channel # Add TCPClient and IRC to the system. TCPClient(channel=self.channel).register(self) IRC(channel=self.channel).register(self) self.create_interface() def create_interface(self): self.screen = Screen() self.screen.start() self.screen.register_palette([ ("title", "white", "dark blue", "standout"), ("line", "light gray", "black"), ("help", "white", "dark blue")] ) self.body = ListBox(SimpleListWalker([])) self.lines = self.body.body self.title = Text(MAIN_TITLE) self.header = AttrWrap(self.title, "title") self.help = AttrWrap( Text(HELP_STRINGS["main"]), "help" ) self.input = Edit(caption="%s> " % self.ircchannel) self.footer = Pile([self.help, self.input]) self.top = Frame(self.body, self.header, self.footer) def ready(self, component): """Ready Event This event is triggered by the underlying ``TCPClient`` Component when it is ready to start making a new connection. """ self.fire(connect(self.host, self.port)) def connected(self, host, port): """connected Event This event is triggered by the underlying ``TCPClient`` Component when a successfully connection has been made. """ nick = self.nick hostname = self.hostname name = "%s on %s using circuits/%s" % (nick, hostname, systemVersion) self.fire(NICK(nick)) self.fire(USER(nick, hostname, host, name)) def numeric(self, source, numeric, *args): """Numeric Event This event is triggered by the ``IRC`` Protocol Component when we have received an IRC Numberic Event from server we are connected to. """ if numeric == ERR_NICKNAMEINUSE: self.fire(NICK("{0:s}_".format(args[0]))) elif numeric in (RPL_ENDOFMOTD, ERR_NOMOTD): self.fire(JOIN(self.ircchannel)) @handler("stopped", channel="*") def _on_stopped(self, component): self.screen.stop() @handler("generate_events") def _on_generate_events(self, event): event.reduce_time_left(0) size = self.screen.get_cols_rows() if not select( self.screen.get_input_descriptors(), [], [], 0.1)[0] == []: timeout, keys, raw = self.screen.get_input_nonblocking() for k in keys: if k == "window resize": size = self.screen.get_cols_rows() continue elif k == "enter": self.processCommand(self.input.get_edit_text()) self.input.set_edit_text("") continue self.top.keypress(size, k) self.input.set_edit_text(self.input.get_edit_text() + k) self.update_screen(size) def unknownCommand(self, command): self.lines.append(Text("Unknown command: %s" % command)) def syntaxError(self, command, args, expected): self.lines.append( Text("Syntax error ({0:s}): {1:s} Expected: {2:s}".format( command, args, expected) ) ) def processCommand(self, s): # noqa match = CMD_REGEX.match(s) if match is not None: command = match.groupdict()["command"] if not match.groupdict()["args"] == "": tokens = match.groupdict()["args"].split(" ") else: tokens = [] fn = "cmd" + command.upper() if hasattr(self, fn): f = getattr(self, fn) if callable(f): args, vargs, kwargs, default = getargspec(f) args.remove("self") if len(args) == len(tokens): if len(args) == 0: f() else: f(*tokens) else: if len(tokens) > len(args): if vargs is None: if len(args) > 0: factor = len(tokens) - len(args) + 1 f(*back_merge(tokens, factor)) else: self.syntaxError( command, " ".join(tokens), " ".join( x for x in args + [vargs] if x is not None ) ) else: f(*tokens) elif default is not None and \ len(args) == ( len(tokens) + len(default)): f(*(tokens + list(default))) else: self.syntaxError( command, " ".join(tokens), " ".join( x for x in args + [vargs] if x is not None ) ) else: if self.ircchannel is not None: self.lines.append(Text("<%s> %s" % (self.nick, s))) self.fire(PRIVMSG(self.ircchannel, s)) else: self.lines.append(Text( "No channel joined. Try /join #<channel>")) def cmdEXIT(self, message=""): self.fire(QUIT(message)) raise SystemExit(0) def cmdSERVER(self, host, port=6667): self.fire(connect(host, port)) def cmdSSLSERVER(self, host, port=6697): self.fire(connect(host, port, secure=True)) def cmdJOIN(self, channel): if self.ircchannel is not None: self.cmdPART(self.ircchannel, "Joining %s" % channel) self.fire(JOIN(channel)) self.ircchannel = channel def cmdPART(self, channel=None, message="Leaving"): if channel is None: channel = self.ircchannel if channel is not None: self.fire(PART(channel, message)) self.ircchannel = None def cmdQUOTE(self, message): self.fire(request(Message(message))) def cmdQUIT(self, message="Bye"): self.fire(QUIT(message)) def update_screen(self, size): canvas = self.top.render(size, focus=True) self.screen.draw_screen(size, canvas) @handler("notice", "privmsg") def _on_notice_or_privmsg(self, event, source, target, message): nick, ident, host = source if event.name == "notice": self.lines.append(Text("-%s- %s" % (nick, message))) else: self.lines.append(Text("<%s> %s" % (nick, message)))
class LogDisplay(BoxWidget): def __init__(self, parser, encoding): self.parser = parser self.encoding = encoding self.find = {'ref': '', 'text': ''} self.isolate_filter = (None, None) self.line_collection = None self.jump_stack = [] self.expansions = {} self.show_sip_level = 2 self.show_ladder = False self.show_only_filtered = False self.show_verbose = True self.show_channel = True self.line_no_before_isolate = 0 self.showing_help = False self.walker = LogLineWalker([('Select call on the left side', None)], self.jump, self.expand, self.isolate) self.header = AttrWrap(Text([('key', 'F6'), ' Log']), 'bar') self.listbox = ListBox(self.walker) self.frame = Frame(self.listbox, header=self.header) def render(self, size, focus=False): return self.frame.render(size, focus) def keypress(self, size, key): return self.frame.keypress(size, key) def set_line_collection(self, line_collection): self.jump_stack = [] self.line_collection = line_collection self.walker.lines = line_collection.lines self.walker.set_focus(0) lc, mc = len(line_collection.lines), line_collection.match_count self.header.set_text([ ('key', 'F6'), ' Log lines: %d, matches: %s | ' % (lc, mc), ('key', 's'), '/', ('key', 'S'), ' toggle sip messages/ladders | ', ('key', 'n'), '/', ('key', 'N'), ' next/previous | ', ('key', 'f'), ' toggle filter | ', ('key', 'i'), '/', ('key', 'I'), ' isolate/un-isolate | ', ('key', 'enter'), '/', ('key', 'backspace'), ' jump/back | ', ('key', 'space'), ' expand/collapse', ]) self.line_collection.set_filter(self.show_only_filtered) def help(self): if self.showing_help: self.refresh_log() else: lc = LineCollection({}) for markup in HELP: lc.add(markup) self.set_line_collection(lc) self.showing_help = not self.showing_help @property def compiled_find(self): find_text = self.find['text'] if find_text and len(find_text) > 2: try: find_text = re.compile(find_text) except Exception as e: log.debug('Invalid RE %r: %s', find_text, e) # noinspection PyDictCreation find_map = {self.find['ref']: 'find1'} # possibly override find_map[find_text] = {'style': 'find2', 'jump': True} return find_map def load_result(self, ref): self.isolate_filter = (None, None) self.find['ref'] = ref self.refresh_log() def toggle_filter(self): if not self.line_collection or self.listbox.get_focus()[0] is None: return self.jump_stack = [] self.expansions = {} self.show_only_filtered = not self.show_only_filtered self.listbox.set_focus(0) self.line_collection.set_filter(self.show_only_filtered) self.listbox.set_focus(0) def toggle_sip(self): self.jump_stack = [] self.expansions = {} self.show_sip_level = (self.show_sip_level + 1) % 3 def jump(self, where): cur = self.listbox.get_focus()[1] if where == 'home': self.listbox.set_focus(0) elif where == 'end': self.listbox.set_focus(len(self.line_collection.lines) - 1) elif where == 'next': if self.show_only_filtered: return for line_no in self.line_collection.line_numbers_with_needle: pos = self.line_collection.line_number_map.get(line_no) # + 1 if pos > cur: self.listbox.set_focus(pos) break elif where == 'previous': if self.show_only_filtered: return collection = self.line_collection.line_numbers_with_needle for i in range(len(collection) - 1, -1, -1): line_no = collection[i] pos = self.line_collection.line_number_map.get(line_no) # + 1 if pos < cur: self.listbox.set_focus(pos) break elif where == -1: # Jump back from where we came if self.jump_stack: pos = self.jump_stack.pop() self.listbox.set_focus(pos) else: pos = self.line_collection.line_number_map.get(where) if pos and pos != cur: self.jump_stack.append(cur) self.listbox.set_focus(pos) def expand(self, tag): if self.show_ladder: return # No effect when showing all ladders cur = self.listbox.get_focus()[1] ref_type, ref = ref_tag(tag) # Collapse if ref in self.expansions: old, markups = self.expansions[ref] self.line_collection.remove(old, len(markups)) del self.expansions[ref] self.listbox.set_focus(cur) return # Expand markups = [] if ref_type == 'call_id': dialog = self.parser.find_obj(ref_type, ref) markups = message_sequence_chart(dialog) markups = [[' ' * 9] + m for m in markups] # indent elif ref_type == 'sip_ref': sip = self.parser.find_obj(ref_type, ref) instructions = sip_payload_instructions(sip) markups = [(s, m) for (_l, s, m) in instructions] elif ref_type == 'chan': channel = self.parser.find_obj(ref_type, ref) markups = dial_chart(channel) markups = [[' ' * 9] + m for m in markups] # indent if markups: self.expansions[ref] = (cur + 1, markups) self.line_collection.insert(cur + 1, markups) self.listbox.set_focus(cur) def isolate(self, tag): ref_type, ref = ref_tag(tag) if ref_type and ref: self.line_no_before_isolate = self.listbox.get_focus()[1] self.isolate_filter = (ref_type, ref) self.refresh_log() else: self.isolate_filter = (None, None) self.refresh_log(focus_line=self.line_no_before_isolate) def refresh_log(self, focus_line=False): groups, objects = self.parser.get_linked_objects( self.find['ref'], self.isolate_filter) old_pos = self.listbox.get_focus()[1] warning_count = 0 error_count = 0 lc = LineCollection(self.compiled_find) if objects: # Prepare markup for "Overview" section lc.add([('section', 'Overview ')]) # must be a list for group in groups: tab, tab2 = '= ', ' ' for line_no, what, obj in group.overview: markup = obj dialog = None tag = None if what == 'dialog': sip = obj dialog = sip.dialog style = get_sip_style(sip) if dialog: dialog_status = dialog.dialog_status or '' dialog_ack = dialog.dialog_ack or '' dialog_bye = dialog.bye_addr or '' else: dialog_status = '' dialog_ack = '' dialog_bye = '' markup = [ ('', ' '), ('line-no', '%07d' % (line_no + 1)), ('', ' '), ('mute', '[%s] ' % sip.when), (style, sip.request or sip.status or '?'), ('', ' %s -> %s ' % (sip.from_num, sip.to_num)), ('sip-status', '%s' % (dialog_status or ' ')), ('', ' '), ('sip-method', '%s' % (dialog_ack or ' ')), ] if dialog and dialog.timeout: markup.extend([('', ' '), ('sip-timeout', 'TIMEOUT')]) if dialog_bye: markup.extend([ ('', ' '), ('sip-bye2', 'BYE'), ('mute', ' from '), ('mute', dialog_bye), ]) markup.append(('sip-call-id', ' %s' % sip.call_id)) tag = {'call_id': sip.call_id} elif what == 'channel': channel = obj markup = [('line-no', '%07d' % (line_no + 1)), ('', ' '), ('mute', '[%s] ' % channel.when), ('channel-name', channel.name)] for phone in set(channel.extensions): markup.append(('', ' ')) markup.append(('', phone)) if channel.clid_num: markup.append(('channel-phone', ' (clid:%s)' % channel.clid_num)) for i, app in enumerate(channel.apps): dial_style = get_dial_status_style(app.status) markup.append(('mute', '; ' if i else ': ')) markup.append(('mute', '%s ' % app.app_name)) markup.append(('', app.data or ' ')) markup.append(('mute', ' ')) markup.append((dial_style, app.status)) tag = {'chan': channel.name} elif what == 'astcall': acall = obj markup = [('line-no', '%07d' % (line_no + 1)), ('', ' '), ('mute', '[%s] ' % acall.when), ('acall-id', acall.acall_id)] tag = {'acall_id': acall.acall_id} lc.add(['%s%s%s ' % (tab, what, tab2), markup or '?'], tag=tag) if dialog and dialog.timeout: timeout_line_no, timeout_when = dialog.timeout markup = [('', ' '), ('line-no', '%07d' % (timeout_line_no + 1)), ('mute', ' [%s] ' % timeout_when), ('sip-timeout', 'TIMEOUT')] lc.add(['%s%s%s ' % (tab, ' ', tab2), markup]) if dialog and self.show_ladder: for markup in message_sequence_chart(dialog): lc.add([' ' * 9] + markup) tab, tab2 = ' - ', ' ' lc.add('') # Prepare markup for "Log" section flat = objects.items() flat.sort() lc.add(('section', 'Log')) old_line_no = None for line_no, (style, obj) in flat: # Text is kept as bytes, convert to unicode only when displaying if isinstance(obj, _bytes3): obj = obj.decode(self.encoding, errors='replace') if old_line_no is not None and old_line_no + 1 != line_no: # If Missing single unimportant line, omit "..." if not (style == 'sip' and old_line_no + 2 == line_no): lc.add(('mute', '...')) old_line_no = line_no if style == 'sip': if self.show_sip_level == 0: continue sip = obj line_no = sip.line_no tag = None markup = [('sip-intro', '==== %s ' % sip.when), ('elapsed', '(ela: %s) ' % sip.elapsed_sec)] if self.show_sip_level == 1: if sip.request: markup.append((get_sip_style(sip), str(sip))) else: markup.append(('sip-status', str(sip))) # Adding tag also allows message expansion tag = {'sip_ref': sip.ref} if sip.attempt_no: markup.append( ('sip-retransmit', 'ATTEMPT #%s' % sip.attempt_no)) markup.append(('', ' %s ' % sip.direction)) # markup.append(('sip-direction', ' ')) if sip.direction == 'IN': markup.append(('sip-addr', '%s' % sip.recipient_addr)) markup.append(('', ' <- ')) markup.append(('sip-addr', '%s' % sip.sender_addr)) else: markup.append(('sip-addr', '%s' % sip.sender_addr)) markup.append(('', ' -> ')) markup.append(('sip-addr', '%s' % sip.recipient_addr)) lc.add(markup, tag=tag) if self.show_sip_level == 1: continue instructions = sip_payload_instructions(sip) # We use line_no again on purpose # noinspection PyAssignmentToLoopOrWithParameter for line_no, sty2, markup in instructions: lc.add((sty2, markup), line_no) elif style == 'channel': if self.show_channel: lc.add((style, obj), line_no, { 'Dial': 'asterisk-app', 'Queue': 'asterisk-app', }) elif self.show_verbose: if b'WARNING' in obj: lc.add(('warning', obj), line_no) warning_count += 1 if b'ERROR' in obj: lc.add(('error', obj), line_no) error_count += 1 else: lc.add((style, obj), line_no) old_line_no = line_no if warning_count: lc.lines[0][0].append( ('warning', ' Warnings: %d ' % warning_count)) if error_count: lc.lines[0][0].append(('error', ' Errors: %d ' % error_count)) self.set_line_collection(lc) if focus_line: focus_line = focus_line if isinstance(focus_line, int) else old_pos try: self.listbox.set_focus(focus_line, 'above') except IndexError: pass
def exploreFieldSet(field_set, args, options={}): charset = getTerminalCharset() ui = urwid.curses_display.Screen() ui.register_palette(( ('focus', 'white', 'dark blue'), ('sep', 'white', 'dark red'), ('input', 'black', 'light gray'), )) msgs = [[],[],0] hachoir_log.use_print = False def logger(level, prefix, text, ctxt): if ctxt is not None: c = [] if hasattr(ctxt, "_logger"): c[:0] = [ ctxt._logger() ] if issubclass(ctxt.__class__, Field): ctxt = ctxt["/"] name = logger.objects.get(ctxt) if name: c[:0] = [ name ] if c: text = "[%s] %s" % ('|'.join(c), text) if not isinstance(text, unicode): text = unicode(text, charset) msgs[0].append((level, prefix, text)) logger.objects = WeakKeyDictionary() hachoir_log.on_new_message = logger preload_fields = 1 + max(0, args.preload) log_count = [ 0, 0, 0 ] sep = Separator("log: %%u/%%u/%%u | %s " % _("F1: help")) sep.set_info(*tuple(log_count)) body = Tabbed(sep) help = ('help', ListBox([ Text(getHelpMessage()) ])) logger.objects[field_set] = logger.objects[field_set.stream] = name = u'root' body.append((name, TreeBox(charset, Node(field_set, None), preload_fields, args.path, options))) log = BoxAdapter(ListBox(msgs[1]), 0) log.selectable = lambda: False wrapped_sep = AttrWrap(sep, 'sep') footer = Pile([ ('flow', wrapped_sep), log ]) # awful way to allow the user to hide the log widget log.render = lambda size, focus=False: BoxAdapter.render(log, size[:1], focus) footer.render = lambda (maxcol,), focus=False: Pile.render(footer, (maxcol, sep.rows((maxcol,))+log.height), focus) top = Frame(body, None, footer) def input_enter(w): footer.widget_list[0] = w footer.set_focus(0) top.set_focus('footer') def input_leave(): footer.widget_list[0] = wrapped_sep footer.set_focus(0) top.set_focus('body') input = Input(input_enter, input_leave) def run(): msg = _resize = retry = 0 events = ( "window resize", ) profile_display = args.profile_display while True: for e in events: try: if e == "window resize": size = ui.get_cols_rows() resize = log.height else: e = top.keypress(size, e) if e is None: pass elif e in ('f1', '?'): try: body.select(body.tabs.index(help)) except ValueError: body.append(help) resize = log.height elif e in ('esc', 'ctrl w'): body.close() if body.box_widget is None: return resize = log.height elif e == '+': if log.height: resize = log.height - 1 elif e == '-': resize = log.height + 1 elif e == 'q': return #except AssertionError: # hachoir_log.error(getBacktrace()) except NewTab_Stream, e: stream = e.field.getSubIStream() logger.objects[stream] = e = "%u/%s" % (body.active, e.field.absolute_address) parser = guessParser(stream) if not parser: hachoir_log.error(_("No parser found for %s") % stream.source) else: logger.objects[parser] = e body.append((e, TreeBox(charset, Node(parser, None), preload_fields, None, options))) resize = log.height except NeedInput, e: input.do(*e.args) if profile_display: events = events[1:] break while True: if msgs[0]: for level, prefix, text in msgs[0]: log_count[level] += 1 txt = Text("[%u]%s %s" % (msg, prefix, text)) msg += 1 msgs[1].append(txt) _resize += txt.rows(size[:1]) if log.height < _resize and (resize is None or resize < _resize): resize = _resize log.set_focus(len(msgs[1])-1) sep.set_info(*tuple(log_count)) msgs[0] = [] if resize is not None: body.height = size[1] - sep.rows(size[:1]) - resize if body.height <= 0: resize += body.height - 1 body.height = 1 log.height = resize resize = None canvas = top.render(size, focus=True) if not msgs[0]: _resize = retry = 0 break assert not retry retry += 1 ui.draw_screen(size, canvas) msgs[2] = len(msgs[1]) if profile_display and events: continue while True: events = ui.get_input() if events: break