Exemple #1
0
 def refresh(self):
     log.debug('Refresh: %s', self.__class__.__name__)
     if self.height <= 0:
         return
     if self.pos == 0:
         lines = self.built_lines[-self.height:]
     else:
         lines = self.built_lines[-self.height-self.pos:-self.pos]
     with_timestamps = config.get("show_timestamps")
     nick_size = config.get("max_nick_length")
     self._win.move(0, 0)
     self._win.erase()
     offset = 0
     for y, line in enumerate(lines):
         if line:
             msg = line.msg
             if line.start_pos == 0:
                 offset = self.write_pre_msg(msg, with_timestamps, nick_size)
             elif y == 0:
                 offset = self.compute_offset(msg, with_timestamps, nick_size)
             self.write_text(y, offset, line.prepend
                             + line.msg.txt[line.start_pos:line.end_pos])
         else:
             self.write_line_separator(y)
         if y != self.height-1:
             self.addstr('\n')
     self._win.attrset(0)
     self._refresh()
Exemple #2
0
    def add_message(self, txt, time=None, nickname=None,
                    nick_color=None, history=None, user=None, highlight=False,
                    identifier=None, str_time=None, jid=None, ack=0):
        """
        Create a message and add it to the text buffer
        """
        msg = Message(txt, time, nickname, nick_color, history, user,
                      identifier, str_time=str_time, highlight=highlight,
                      jid=jid, ack=ack)
        self.messages.append(msg)

        while len(self.messages) > self._messages_nb_limit:
            self.messages.pop(0)

        ret_val = 0
        show_timestamps = config.get('show_timestamps')
        nick_size = config.get('max_nick_length')
        for window in self._windows: # make the associated windows
                                     # build the lines from the new message
            nb = window.build_new_message(msg, history=history,
                                          highlight=highlight,
                                          timestamp=show_timestamps,
                                          nick_size=nick_size)
            if ret_val == 0:
                ret_val = nb
            if window.pos != 0:
                window.scroll_up(nb)

        return min(ret_val, 1)
Exemple #3
0
 def modify_message(self, old_id, message) -> None:
     """
     Find a message, and replace it with a new one
     (instead of rebuilding everything in order to correct a message)
     """
     with_timestamps = config.get('show_timestamps')
     nick_size = config.get('max_nick_length')
     for i in range(len(self.built_lines) - 1, -1, -1):
         current = self.built_lines[i]
         if current is not None and current.msg.identifier == old_id:
             index = i
             while (
                     index >= 0
                     and current is not None
                     and current.msg.identifier == old_id
                     ):
                 self.built_lines.pop(index)
                 index -= 1
                 if index >= 0:
                     current = self.built_lines[index]
             index += 1
             lines = build_lines(
                 message, self.width, timestamp=with_timestamps, nick_size=nick_size
             )
             for line in lines:
                 self.built_lines.insert(index, line)
                 index += 1
             break
Exemple #4
0
 def refresh(self) -> None:
     log.debug('Refresh: %s', self.__class__.__name__)
     if self.height <= 0:
         return
     if self.pos == 0:
         lines = self.built_lines[-self.height:]
     else:
         lines = self.built_lines[-self.height - self.pos:-self.pos]
     with_timestamps = config.get("show_timestamps")
     nick_size = config.get("max_nick_length")
     self._win.move(0, 0)
     self._win.erase()
     offset = 0
     for y, line in enumerate(lines):
         if line:
             msg = line.msg
             if line.start_pos == 0:
                 offset = write_pre(msg, self, with_timestamps, nick_size)
             elif y == 0:
                 offset = msg.compute_offset(with_timestamps,
                                             nick_size)
             self.write_text(
                 y, offset,
                 line.prepend + line.msg.txt[line.start_pos:line.end_pos])
         else:
             self.write_line_separator(y)
         if y != self.height - 1:
             self.addstr('\n')
     self._win.attrset(0)
     self._refresh()
Exemple #5
0
 def rebuild_everything(self, room):
     self.built_lines = []
     with_timestamps = config.get('show_timestamps')
     nick_size = config.get('max_nick_length')
     for message in room.messages:
         self.build_new_message(message, clean=False, timestamp=with_timestamps, nick_size=nick_size)
         if self.separator_after is message:
             self.build_new_message(None)
     while len(self.built_lines) > self.lines_nb_limit:
         self.built_lines.pop(0)
Exemple #6
0
    def refresh(self, roster: Roster) -> None:
        """
        We display a number of lines from the roster cache
        (and rebuild it if needed)
        """
        log.debug('Refresh: %s', self.__class__.__name__)
        self.build_roster_cache(roster)
        # make sure we are within bounds
        self.move_cursor_up((
            self.roster_len + self.pos) if self.pos >= self.roster_len else 0)
        if not self.roster_cache:
            self.selected_row = None
        self._win.erase()
        self._win.move(0, 0)
        self.draw_roster_information(roster)
        y = 1
        group = "none"
        # scroll down if needed
        if self.start_pos + self.height <= self.pos + 2:
            self.scroll_down(self.pos - self.start_pos - self.height +
                             (self.height // 2))
        # draw the roster from the cache
        roster_view = self.roster_cache[self.start_pos - 1:self.start_pos +
                                        self.height]

        options = {
            'show_roster_sub': config.get('show_roster_subscriptions'),
            'show_s2s_errors': config.get('show_s2s_errors'),
            'show_roster_jids': config.get('show_roster_jids')
        }

        for item in roster_view:
            draw_selected = False
            if y - 2 + self.start_pos == self.pos:
                draw_selected = True
                self.selected_row = item

            if isinstance(item, RosterGroup):
                self.draw_group(y, item, draw_selected)
                group = item.name
            elif isinstance(item, Contact):
                self.draw_contact_line(y, item, draw_selected, group,
                                       **options)
            elif isinstance(item, Resource):
                self.draw_resource_line(y, item, draw_selected)

            y += 1

        if self.start_pos > 1:
            self.draw_plus(1)
        if self.start_pos + self.height - 2 < self.roster_len:
            self.draw_plus(self.height - 1)
        self._refresh()
Exemple #7
0
    def refresh(self, roster: Roster) -> None:
        """
        We display a number of lines from the roster cache
        (and rebuild it if needed)
        """
        log.debug('Refresh: %s', self.__class__.__name__)
        self.build_roster_cache(roster)
        # make sure we are within bounds
        self.move_cursor_up((self.roster_len +
                             self.pos) if self.pos >= self.roster_len else 0)
        if not self.roster_cache:
            self.selected_row = None
        self._win.erase()
        self._win.move(0, 0)
        self.draw_roster_information(roster)
        y = 1
        group = "none"
        # scroll down if needed
        if self.start_pos + self.height <= self.pos + 2:
            self.scroll_down(self.pos - self.start_pos - self.height +
                             (self.height // 2))
        # draw the roster from the cache
        roster_view = self.roster_cache[self.start_pos - 1:self.start_pos +
                                        self.height]

        options = {
            'show_roster_sub': config.get('show_roster_subscriptions'),
            'show_s2s_errors': config.get('show_s2s_errors'),
            'show_roster_jids': config.get('show_roster_jids')
        }

        for item in roster_view:
            draw_selected = False
            if y - 2 + self.start_pos == self.pos:
                draw_selected = True
                self.selected_row = item

            if isinstance(item, RosterGroup):
                self.draw_group(y, item, draw_selected)
                group = item.name
            elif isinstance(item, Contact):
                self.draw_contact_line(y, item, draw_selected, group,
                                       **options)
            elif isinstance(item, Resource):
                self.draw_resource_line(y, item, draw_selected)

            y += 1

        if self.start_pos > 1:
            self.draw_plus(1)
        if self.start_pos + self.height - 2 < self.roster_len:
            self.draw_plus(self.height - 1)
        self._refresh()
 def set(self, the_input):
     """Completion for /set"""
     args = common.shell_split(the_input.text)
     n = the_input.get_argument_position(quoted=True)
     if n >= len(args):
         args.append('')
     if n == 1:
         if '|' in args[1]:
             plugin_name, section = args[1].split('|')[:2]
             if plugin_name not in self.core.plugin_manager.plugins:
                 return the_input.new_completion([], n, quotify=True)
             plugin = self.core.plugin_manager.plugins[plugin_name]
             end_list = ['%s|%s' % (plugin_name, section) for section in plugin.config.sections()]
         else:
             end_list = set(config.options('Poezio'))
             end_list.update(config.default.get('Poezio', {}))
             end_list = list(end_list)
             end_list.sort()
     elif n == 2:
         if '|' in args[1]:
             plugin_name, section = args[1].split('|')[:2]
             if plugin_name not in self.core.plugin_manager.plugins:
                 return the_input.new_completion([''], n, quotify=True)
             plugin = self.core.plugin_manager.plugins[plugin_name]
             end_list = set(plugin.config.options(section or plugin_name))
             if plugin.config.default:
                 end_list.update(plugin.config.default.get(section or plugin_name, {}))
             end_list = list(end_list)
             end_list.sort()
         elif not config.has_option('Poezio', args[1]):
             if config.has_section(args[1]):
                 end_list = config.options(args[1])
                 end_list.append('')
             else:
                 end_list = []
         else:
             end_list = [str(config.get(args[1], '')), '']
     elif n == 3:
         if '|' in args[1]:
             plugin_name, section = args[1].split('|')[:2]
             if plugin_name not in self.core.plugin_manager.plugins:
                 return the_input.new_completion([''], n, quotify=True)
             plugin = self.core.plugin_manager.plugins[plugin_name]
             end_list = [str(plugin.config.get(args[2], '', section or plugin_name)), '']
         else:
             if not config.has_section(args[1]):
                 end_list = ['']
             else:
                 end_list = [str(config.get(args[2], '', args[1])), '']
     else:
         return False
     return the_input.new_completion(end_list, n, quotify=True)
Exemple #9
0
 def set(self, the_input):
     """Completion for /set"""
     args = common.shell_split(the_input.text)
     n = the_input.get_argument_position(quoted=True)
     if n >= len(args):
         args.append('')
     if n == 1:
         if '|' in args[1]:
             plugin_name, section = args[1].split('|')[:2]
             if plugin_name not in self.core.plugin_manager.plugins:
                 return Completion(the_input.new_completion, [], n, quotify=True)
             plugin = self.core.plugin_manager.plugins[plugin_name]
             end_list = ['%s|%s' % (plugin_name, section) for section in plugin.config.sections()]
         else:
             end_list = set(config.options('Poezio'))
             end_list.update(config.default.get('Poezio', {}))
             end_list = list(end_list)
             end_list.sort()
     elif n == 2:
         if '|' in args[1]:
             plugin_name, section = args[1].split('|')[:2]
             if plugin_name not in self.core.plugin_manager.plugins:
                 return Completion(the_input.new_completion, [''], n, quotify=True)
             plugin = self.core.plugin_manager.plugins[plugin_name]
             end_list = set(plugin.config.options(section or plugin_name))
             if plugin.config.default:
                 end_list.update(plugin.config.default.get(section or plugin_name, {}))
             end_list = list(end_list)
             end_list.sort()
         elif not config.has_option('Poezio', args[1]):
             if config.has_section(args[1]):
                 end_list = config.options(args[1])
                 end_list.append('')
             else:
                 end_list = []
         else:
             end_list = [str(config.get(args[1], '')), '']
     elif n == 3:
         if '|' in args[1]:
             plugin_name, section = args[1].split('|')[:2]
             if plugin_name not in self.core.plugin_manager.plugins:
                 return Completion(the_input.new_completion, [''], n, quotify=True)
             plugin = self.core.plugin_manager.plugins[plugin_name]
             end_list = [str(plugin.config.get(args[2], '', section or plugin_name)), '']
         else:
             if not config.has_section(args[1]):
                 end_list = ['']
             else:
                 end_list = [str(config.get(args[2], '', args[1])), '']
     else:
         return False
     return Completion(the_input.new_completion, end_list, n, quotify=True)
Exemple #10
0
 def rebuild_everything(self, room):
     self.built_lines = []
     with_timestamps = config.get('show_timestamps')
     nick_size = config.get('max_nick_length')
     for message in room.messages:
         self.build_new_message(message,
                                clean=False,
                                timestamp=with_timestamps,
                                nick_size=nick_size)
         if self.separator_after is message:
             self.build_new_message(None)
     while len(self.built_lines) > self.lines_nb_limit:
         self.built_lines.pop(0)
 def start(self):
     """
     Connect and process events.
     """
     custom_host = config.get('custom_host')
     custom_port = config.get('custom_port', 5222)
     if custom_port == -1:
         custom_port = 5222
     if custom_host:
         self.connect((custom_host, custom_port))
     elif custom_port != 5222 and custom_port != -1:
         self.connect((self.boundjid.host, custom_port))
     else:
         self.connect()
Exemple #12
0
 def start(self):
     """
     Connect and process events.
     """
     custom_host = config.get('custom_host')
     custom_port = config.get('custom_port', 5222)
     if custom_port == -1:
         custom_port = 5222
     if custom_host:
         self.connect((custom_host, custom_port))
     elif custom_port != 5222 and custom_port != -1:
         self.connect((self.boundjid.host, custom_port))
     else:
         self.connect()
Exemple #13
0
    def add_message(self,
                    txt: str,
                    time: Optional[datetime] = None,
                    nickname: Optional[str] = None,
                    nick_color: Optional[Tuple] = None,
                    history: bool = False,
                    user: Optional[str] = None,
                    highlight: bool = False,
                    identifier: Optional[str] = None,
                    str_time: Optional[str] = None,
                    jid: Optional[str] = None,
                    ack: int = 0) -> int:
        """
        Create a message and add it to the text buffer
        """
        msg = Message(
            txt,
            time,
            nickname,
            nick_color,
            history,
            user,
            identifier,
            str_time=str_time,
            highlight=highlight,
            jid=jid,
            ack=ack)
        self.messages.append(msg)

        while len(self.messages) > self._messages_nb_limit:
            self.messages.pop(0)

        ret_val = 0
        show_timestamps = config.get('show_timestamps')
        nick_size = config.get('max_nick_length')
        for window in self._windows:  # make the associated windows
            # build the lines from the new message
            nb = window.build_new_message(
                msg,
                history=history,
                highlight=highlight,
                timestamp=show_timestamps,
                nick_size=nick_size)
            if ret_val == 0:
                ret_val = nb
            if window.pos != 0:
                window.scroll_up(nb)

        return min(ret_val, 1)
Exemple #14
0
    def get_remote(self, xmpp, information, callback):
        """Add the remotely stored bookmarks to the list."""
        force = config.get('force_remote_bookmarks')
        if xmpp.anon or not (any(self.available_storage.values()) or force):
            information('No remote bookmark storage available', 'Warning')
            return

        if force and not any(self.available_storage.values()):
            old_callback = callback
            method = 'pep' if self.preferred == 'pep' else 'privatexml'

            def new_callback(result):
                if result['type'] != 'error':
                    self.available_storage[method] = True
                    old_callback(result)
                else:
                    information('No remote bookmark storage available',
                                'Warning')

            callback = new_callback

        if self.preferred == 'pep':
            self.get_pep(xmpp, callback=callback)
        else:
            self.get_privatexml(xmpp, callback=callback)
Exemple #15
0
def reload_theme() -> Optional[str]:
    theme_name = config.get('theme')
    global theme
    if theme_name == 'default' or not theme_name.strip():
        theme = Theme()
        return None
    new_theme = None
    exc = None
    try:
        loader = finder.find_module(theme_name, load_path)
        if not loader:
            return 'Failed to load the theme %s' % theme_name
        new_theme = loader.load_module()
    except Exception as e:
        log.error('Failed to load the theme %s', theme_name, exc_info=True)
        exc = e

    if not new_theme:
        return 'Failed to load theme: %s' % exc

    if hasattr(new_theme, 'theme'):
        theme = new_theme.theme
        prepare_ccolor_palette(theme)
        return None
    return 'No theme present in the theme file'
Exemple #16
0
 def refresh_tab_win(self):
     if config.get('enable_vertical_tab_list'):
         left_tab_win = self.core.left_tab_win
         if left_tab_win and not self.size.core_degrade_x:
             left_tab_win.refresh()
     elif not self.size.core_degrade_y:
         self.core.tab_win.refresh()
Exemple #17
0
    def init(self):
        self.key = config.get("key").encode('utf-8')
        length = 32 - (len(self.key) % 32)
        self.key += bytes([length]) * length


        # TODO: add real help/usage information to the commands…
        self.api.add_command("rot", self.command_rot, "rot n encodes the given message")
        self.api.add_command("bin", self.command_bin, "bin")
        self.api.add_command("hex", self.command_hex, "hex")
        self.api.add_command("enc", self.command_enc, "enc")
        self.api.add_command('rot_decode', self.command_rot_decode,
                    usage='<message>',
                    help='Decode the message you typed if it exists.',
                    short='Decode a message.',
                    completion=self.message_completion)
        self.api.add_command("mono_crack", self.command_mono_crack, usage="<message>",
                    help="mono decode", short="decode", completion=self.message_completion)
        self.api.add_command("bin_decode", self.command_bin_decode, usage="<message>",
                    help="binary decode", short='binary', completion=self.message_completion)
        self.api.add_command("crack", self.command_crack, usage="<message>",
                    help="binary decode", short='binary', completion=self.message_completion)

        # insert event handler at the end (-1) so we're always behind the lima-gold one
        self.api.add_event_handler("muc_msg", self.muc_message, position=-1)

        # preload german dict
        self.get_dict("de")
Exemple #18
0
 def refresh(self, jid, contact, window, chatstate, information):
     # contact can be None, if we receive a message
     # from someone not in our roster. In this case, we display
     # only the maximum information from the message we can get.
     log.debug('Refresh: %s', self.__class__.__name__)
     jid = safeJID(jid)
     if contact:
         if jid.resource:
             resource = contact[jid.full]
         else:
             resource = contact.get_highest_priority_resource()
     else:
         resource = None
     # if contact is None, then resource is None too:
     # user is not in the roster so we know almost nothing about it
     # If contact is a Contact, then
     # resource can now be a Resource: user is in the roster and online
     # or resource is None: user is in the roster but offline
     self._win.erase()
     if config.get('show_jid_in_conversations'):
         self.write_contact_jid(jid)
     self.write_contact_information(contact)
     self.write_resource_information(resource)
     self.print_scroll_position(window)
     self.write_chatstate(chatstate)
     self.write_additional_information(information, jid)
     self.finish_line(get_theme().COLOR_INFORMATION_BAR)
     self._refresh()
Exemple #19
0
 def __init__(self) -> None:
     self._image = None  # type: Optional[Image.Image]
     Win.__init__(self)
     if config.get('image_use_half_blocks'):
         self._display_avatar = self._display_avatar_half_blocks  # type: Callable[[int, int], None]
     else:
         self._display_avatar = self._display_avatar_full_blocks
Exemple #20
0
 def callback(iq):
     if iq['type'] == 'result':
         self.core.information('Password updated', 'Account')
         if config.get('password'):
             config.silent_set('password', args[0])
     else:
         self.core.information('Unable to change the password', 'Account')
Exemple #21
0
 def refresh_tab_win(self):
     if config.get('enable_vertical_tab_list'):
         left_tab_win = self.core.left_tab_win
         if left_tab_win and not self.size.core_degrade_x:
             left_tab_win.refresh()
     elif not self.size.core_degrade_y:
         self.core.tab_win.refresh()
Exemple #22
0
def reload_theme() -> Optional[str]:
    theme_name = config.get('theme')
    global theme
    if theme_name == 'default' or not theme_name.strip():
        theme = Theme()
        return None
    new_theme = None
    exc = None
    try:
        loader = finder.find_module(theme_name, load_path)
        if not loader:
            return 'Failed to load the theme %s' % theme_name
        new_theme = loader.load_module()
    except Exception as e:
        log.error('Failed to load the theme %s', theme_name, exc_info=True)
        exc = e

    if not new_theme:
        return 'Failed to load theme: %s' % exc

    if hasattr(new_theme, 'theme'):
        theme = new_theme.theme
        prepare_ccolor_palette(theme)
        return None
    return 'No theme present in the theme file'
Exemple #23
0
    def get_remote(self, xmpp, information, callback):
        """Add the remotely stored bookmarks to the list."""
        force = config.get('force_remote_bookmarks')
        if xmpp.anon or not (any(self.available_storage.values()) or force):
            information('No remote bookmark storage available', 'Warning')
            return

        if force and not any(self.available_storage.values()):
            old_callback = callback
            method = 'pep' if self.preferred == 'pep' else 'privatexml'

            def new_callback(result):
                if result['type'] != 'error':
                    self.available_storage[method] = True
                    old_callback(result)
                else:
                    information('No remote bookmark storage available',
                                'Warning')

            callback = new_callback

        if self.preferred == 'pep':
            self.get_pep(xmpp, callback=callback)
        else:
            self.get_privatexml(xmpp, callback=callback)
Exemple #24
0
 def refresh(self, jid, contact, window, chatstate, information):
     # contact can be None, if we receive a message
     # from someone not in our roster. In this case, we display
     # only the maximum information from the message we can get.
     log.debug('Refresh: %s', self.__class__.__name__)
     jid = safeJID(jid)
     if contact:
         if jid.resource:
             resource = contact[jid.full]
         else:
             resource = contact.get_highest_priority_resource()
     else:
         resource = None
     # if contact is None, then resource is None too:
     # user is not in the roster so we know almost nothing about it
     # If contact is a Contact, then
     # resource can now be a Resource: user is in the roster and online
     # or resource is None: user is in the roster but offline
     self._win.erase()
     if config.get('show_jid_in_conversations'):
         self.write_contact_jid(jid)
     self.write_contact_information(contact)
     self.write_resource_information(resource)
     self.print_scroll_position(window)
     self.write_chatstate(chatstate)
     self.write_additional_information(information, jid)
     self.finish_line(get_theme().COLOR_INFORMATION_BAR)
     self._refresh()
Exemple #25
0
 def get_local(self):
     """Add the locally stored bookmarks to the list."""
     rooms = config.get('rooms')
     if not rooms:
         return
     rooms = rooms.split(':')
     for room in rooms:
         try:
             jid = JID(room)
         except InvalidJID:
             continue
         if jid.bare == '':
             continue
         if jid.resource != '':
             nick = jid.resource
         else:
             nick = None
         passwd = config.get_by_tabname(
             'password', jid.bare, fallback=False) or None
         b = Bookmark(jid.bare,
                      jid.user,
                      autojoin=True,
                      nick=nick,
                      password=passwd,
                      method='local')
         self.append(b)
Exemple #26
0
 def __init__(self):
     self._image = None
     Win.__init__(self)
     if config.get('image_use_half_blocks'):
         self._display_avatar = self._display_avatar_half_blocks
     else:
         self._display_avatar = self._display_avatar_full_blocks
Exemple #27
0
    def bookmark_local(self, the_input):
        """Completion for /bookmark_local"""
        n = the_input.get_argument_position(quoted=True)
        args = common.shell_split(the_input.text)

        if n >= 2:
            return False
        if len(args) == 1:
            args.append('')
        jid = safeJID(args[1])

        if jid.server and (jid.resource or jid.full.endswith('/')):
            tab = self.core.tabs.by_name_and_class(jid.bare, tabs.MucTab)
            nicks = [tab.own_nick] if tab else []
            default = os.environ.get('USER') if os.environ.get(
                'USER') else 'poezio'
            nick = config.get('default_nick')
            if not nick:
                if default not in nicks:
                    nicks.append(default)
            else:
                if nick not in nicks:
                    nicks.append(nick)
            jids_list = ['%s/%s' % (jid.bare, nick) for nick in nicks]
            return Completion(
                the_input.new_completion, jids_list, 1, quotify=True)
        muc_list = [tab.name for tab in self.core.get_tabs(tabs.MucTab)]
        muc_list.append('*')
        return Completion(the_input.new_completion, muc_list, 1, quotify=True)
Exemple #28
0
def update_themes_dir(option: Optional[str] = None,
                      value: Optional[str] = None):
    global load_path
    load_path = []

    # import from the git sources
    default_dir = path.join(
        path.dirname(path.dirname(__file__)), 'data/themes')
    if path.exists(default_dir):
        load_path.append(default_dir)

    # import from the user-defined prefs
    themes_dir_str = config.get('themes_dir')
    themes_dir = Path(themes_dir_str).expanduser(
    ) if themes_dir_str else xdg.DATA_HOME / 'themes'
    try:
        themes_dir.mkdir(parents=True, exist_ok=True)
    except OSError:
        log.exception('Unable to create the themes dir (%s):', themes_dir)
    else:
        load_path.append(str(themes_dir))

    # system-wide import
    try:
        import poezio_themes
    except ImportError:
        pass
    else:
        if poezio_themes.__path__:
            load_path.append(list(poezio_themes.__path__)[0])

    log.debug('Theme load path: %s', load_path)
Exemple #29
0
    def bookmark_local(self, the_input):
        """Completion for /bookmark_local"""
        n = the_input.get_argument_position(quoted=True)
        args = common.shell_split(the_input.text)

        if n >= 2:
            return False
        if len(args) == 1:
            args.append('')
        jid = safeJID(args[1])

        if jid.server and (jid.resource or jid.full.endswith('/')):
            tab = self.core.get_tab_by_name(jid.bare, tabs.MucTab)
            nicks = [tab.own_nick] if tab else []
            default = os.environ.get('USER') if os.environ.get('USER') else 'poezio'
            nick = config.get('default_nick')
            if not nick:
                if default not in nicks:
                    nicks.append(default)
            else:
                if nick not in nicks:
                    nicks.append(nick)
            jids_list = ['%s/%s' % (jid.bare, nick) for nick in nicks]
            return Completion(the_input.new_completion, jids_list, 1, quotify=True)
        muc_list = [tab.name for tab in self.core.get_tabs(tabs.MucTab)]
        muc_list.append('*')
        return Completion(the_input.new_completion, muc_list, 1, quotify=True)
Exemple #30
0
def update_themes_dir(option: Optional[str] = None,
                      value: Optional[str] = None):
    global load_path
    load_path = []

    # import from the git sources
    default_dir = path.join(path.dirname(path.dirname(__file__)),
                            'data/themes')
    if path.exists(default_dir):
        load_path.append(default_dir)

    # import from the user-defined prefs
    themes_dir_str = config.get('themes_dir')
    themes_dir = Path(themes_dir_str).expanduser(
    ) if themes_dir_str else xdg.DATA_HOME / 'themes'
    try:
        themes_dir.mkdir(parents=True, exist_ok=True)
    except OSError:
        log.exception('Unable to create the themes dir (%s):', themes_dir)
    else:
        load_path.append(str(themes_dir))

    # system-wide import
    try:
        import poezio_themes
    except ImportError:
        pass
    else:
        if poezio_themes.__path__:
            load_path.append(list(poezio_themes.__path__)[0])

    log.debug('Theme load path: %s', load_path)
Exemple #31
0
 def __init__(self) -> None:
     self._image = None  # type: Optional[Image]
     Win.__init__(self)
     if config.get('image_use_half_blocks'):
         self._display_avatar = self._display_avatar_half_blocks  # type: Callable[[int, int], None]
     else:
         self._display_avatar = self._display_avatar_full_blocks
Exemple #32
0
    def join(self, args):
        """
        /join [room][/nick] [password]
        """
        if len(args) == 0:
            room, nick = self._empty_join()
        else:
            room, nick = self._parse_join_jid(args[0])
        if not room and not nick:
            return  # nothing was parsed

        room = room.lower()
        if nick == '':
            nick = self.core.own_nick

        # a password is provided
        if len(args) == 2:
            password = args[1]
        else:
            password = config.get_by_tabname('password', room, fallback=False)

        if room in self.core.pending_invites:
            del self.core.pending_invites[room]

        tab = self.core.tabs.by_name_and_class(room, tabs.MucTab)
        # New tab
        if tab is None:
            tab = self.core.open_new_room(room, nick, password=password)
            tab.join()
        else:
            self.core.focus_tab(tab)
            if tab.own_nick == nick and tab.joined:
                self.core.information('/join: Nothing to do.', 'Info')
            else:
                tab.command_part('')
                tab.own_nick = nick
                tab.password = password
                tab.join()

        if config.get('bookmark_on_join'):
            method = 'remote' if config.get(
                'use_remote_bookmarks') else 'local'
            self._add_bookmark('%s/%s' % (room, nick), True, password, method)

        if tab == self.core.tabs.current_tab:
            tab.refresh()
            self.core.doupdate()
Exemple #33
0
 def goto_build_lines(self, new_date):
     text_buffer = self._text_buffer
     built_lines = []
     message_count = 0
     timestamp = config.get('show_timestamps')
     nick_size = config.get('max_nick_length')
     for message in text_buffer.messages:
         # Build lines of a message
         txt = message.txt
         nick = truncate_nick(message.nickname, nick_size)
         offset = 0
         theme = get_theme()
         if message.ack:
             if message.ack > 0:
                 offset += poopt.wcswidth(theme.CHAR_ACK_RECEIVED) + 1
             else:
                 offset += poopt.wcswidth(theme.CHAR_NACK) + 1
         if nick:
             offset += poopt.wcswidth(nick) + 2
         if message.revisions > 0:
             offset += ceil(log10(message.revisions + 1))
         if message.me:
             offset += 1
         if timestamp:
             if message.str_time:
                 offset += 1 + len(message.str_time)
             if theme.CHAR_TIME_LEFT and message.str_time:
                 offset += 1
             if theme.CHAR_TIME_RIGHT and message.str_time:
                 offset += 1
         lines = poopt.cut_text(txt, self.text_win.width - offset - 1)
         for line in lines:
             built_lines.append(line)
         # Find the message with timestamp less than or equal to the queried
         # timestamp and goto that location in the tab.
         if message.time <= new_date:
             message_count += 1
             if len(self.text_win.built_lines
                    ) - self.text_win.height >= len(built_lines):
                 self.text_win.pos = len(
                     self.text_win.built_lines
                 ) - self.text_win.height - len(built_lines) + 1
             else:
                 self.text_win.pos = 0
     if message_count == 0:
         self.text_win.scroll_up(len(self.text_win.built_lines))
     self.core.refresh_window()
Exemple #34
0
    def join(self, args):
        """
        /join [room][/nick] [password]
        """
        if len(args) == 0:
            room, nick = self._empty_join()
        else:
            room, nick = self._parse_join_jid(args[0])
        if not room and not nick:
            return  # nothing was parsed

        room = room.lower()
        if nick == '':
            nick = self.core.own_nick

        # a password is provided
        if len(args) == 2:
            password = args[1]
        else:
            password = config.get_by_tabname('password', room, fallback=False)

        if room in self.core.pending_invites:
            del self.core.pending_invites[room]

        tab = self.core.get_tab_by_name(room, tabs.MucTab)
        # New tab
        if tab is None:
            tab = self.core.open_new_room(room, nick, password=password)
            tab.join()
        else:
            self.core.focus_tab_named(tab.name)
            if tab.own_nick == nick and tab.joined:
                self.core.information('/join: Nothing to do.', 'Info')
            else:
                tab.command_part('')
                tab.own_nick = nick
                tab.password = password
                tab.join()

        if config.get('bookmark_on_join'):
            method = 'remote' if config.get(
                'use_remote_bookmarks') else 'local'
            self._add_bookmark('%s/%s' % (room, nick), True, password, method)

        if tab == self.core.current_tab():
            tab.refresh()
            self.core.doupdate()
Exemple #35
0
 def refresh(self) -> None:
     height, width = self._win.getmaxyx()
     self._win.erase()
     sorted_tabs = [tab for tab in self.core.tabs if tab]
     theme = get_theme()
     if not config.get('show_inactive_tabs'):
         sorted_tabs = [
             tab for tab in sorted_tabs
             if tab.vertical_color != theme.COLOR_VERTICAL_TAB_NORMAL
         ]
     nb_tabs = len(sorted_tabs)
     use_nicks = config.get('use_tab_nicks')
     if nb_tabs >= height:
         # TODO: As sorted_tabs filters out gap tabs this ensures pos is
         # always set, preventing UnboundLocalError. Now is this how this
         # should be fixed.
         pos = 0
         for y, tab in enumerate(sorted_tabs):
             if tab.vertical_color == theme.COLOR_VERTICAL_TAB_CURRENT:
                 pos = y
                 break
         # center the current tab as much as possible
         if pos < height // 2:
             sorted_tabs = sorted_tabs[:height]
         elif nb_tabs - pos <= height // 2:
             sorted_tabs = sorted_tabs[-height:]
         else:
             sorted_tabs = sorted_tabs[pos - height // 2:pos + height // 2]
     asc_sort = (config.get('vertical_tab_list_sort') == 'asc')
     for y, tab in enumerate(sorted_tabs):
         color = tab.vertical_color
         if asc_sort:
             y = height - y - 1
         self.addstr(y, 0, "%2d" % tab.nb,
                     to_curses_attr(theme.COLOR_VERTICAL_TAB_NUMBER))
         self.addstr('.')
         if use_nicks:
             self.addnstr("%s" % tab.get_nick(), width - 4,
                          to_curses_attr(color))
         else:
             self.addnstr("%s" % tab.name, width - 4, to_curses_attr(color))
     separator = to_curses_attr(theme.COLOR_VERTICAL_SEPARATOR)
     self._win.attron(separator)
     self._win.vline(0, width - 1, curses.ACS_VLINE, height)
     self._win.attroff(separator)
     self._refresh()
Exemple #36
0
 def callback(iq):
     if iq['type'] == 'result':
         self.core.information('Password updated', 'Account')
         if config.get('password'):
             config.silent_set('password', args[0])
     else:
         self.core.information('Unable to change the password',
                               'Account')
Exemple #37
0
 def tab_win_height() -> int:
     """
     Returns 1 or 0, depending on if we are using the vertical tab list
     or not.
     """
     if config.get('enable_vertical_tab_list'):
         return 0
     return 1
Exemple #38
0
 def tab_win_height() -> int:
     """
     Returns 1 or 0, depending on if we are using the vertical tab list
     or not.
     """
     if config.get('enable_vertical_tab_list'):
         return 0
     return 1
Exemple #39
0
 def __init__(self):
     Input.__init__(self)
     self.help_message = ''
     self.current_completed = ''
     self.key_func['^R'] = self.toggle_search
     self.search = False
     if config.get('separate_history'):
         self.history = list()
Exemple #40
0
 def initial_set_plugins_dir(self):
     """
     Set the plugins_dir on start
     """
     plugins_dir = config.get('plugins_dir')
     self.plugins_dir = Path(plugins_dir).expanduser(
     ) if plugins_dir else xdg.DATA_HOME / 'plugins'
     self.check_create_plugins_dir()
Exemple #41
0
 def initial_set_plugins_conf_dir(self):
     """
     Create the plugins_conf_dir
     """
     plugins_conf_dir = config.get('plugins_conf_dir')
     self.plugins_conf_dir = Path(plugins_conf_dir).expanduser(
     ) if plugins_conf_dir else xdg.CONFIG_HOME / 'plugins'
     self.check_create_plugins_conf_dir()
Exemple #42
0
 def initial_set_plugins_conf_dir(self):
     """
     Create the plugins_conf_dir
     """
     plugins_conf_dir = config.get('plugins_conf_dir')
     self.plugins_conf_dir = Path(plugins_conf_dir).expanduser(
     ) if plugins_conf_dir else xdg.CONFIG_HOME / 'plugins'
     self.check_create_plugins_conf_dir()
Exemple #43
0
 def initial_set_plugins_dir(self):
     """
     Set the plugins_dir on start
     """
     plugins_dir = config.get('plugins_dir')
     self.plugins_dir = Path(plugins_dir).expanduser(
     ) if plugins_dir else xdg.DATA_HOME / 'plugins'
     self.check_create_plugins_dir()
Exemple #44
0
    def refresh(self):
        log.debug('Refresh: %s', self.__class__.__name__)
        self._win.erase()
        self.addstr(0, 0, "[",
                    to_curses_attr(get_theme().COLOR_INFORMATION_BAR))

        create_gaps = config.get('create_gaps')
        show_names = config.get('show_tab_names')
        show_nums = config.get('show_tab_numbers')
        use_nicks = config.get('use_tab_nicks')
        show_inactive = config.get('show_inactive_tabs')
        # ignore any remaining gap tabs if the feature is not enabled
        if create_gaps:
            sorted_tabs = self.core.tabs[:]
        else:
            sorted_tabs = [tab for tab in self.core.tabs if tab]

        for nb, tab in enumerate(sorted_tabs):
            if not tab: continue
            color = tab.color
            if not show_inactive and color is get_theme().COLOR_TAB_NORMAL:
                continue
            try:
                if show_nums or not show_names:
                    self.addstr("%s" % str(nb), to_curses_attr(color))
                    if show_names:
                        self.addstr(' ', to_curses_attr(color))
                if show_names:
                    if use_nicks:
                        self.addstr("%s" % str(tab.get_nick()),
                                    to_curses_attr(color))
                    else:
                        self.addstr("%s" % tab.name, to_curses_attr(color))
                self.addstr("|",
                            to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
            except:  # end of line
                break
        (y, x) = self._win.getyx()
        self.addstr(y, x - 1, '] ',
                    to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
        (y, x) = self._win.getyx()
        remaining_size = self.width - x
        self.addnstr(' ' * remaining_size, remaining_size,
                     to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
        self._refresh()
Exemple #45
0
 def __init__(self) -> None:
     Input.__init__(self)
     self.help_message = ''
     self.histo_pos = -1
     self.current_completed = ''
     self.key_func['^R'] = self.toggle_search
     self.search = False
     if config.get('separate_history'):
         self.history = []  # type: List[str]
Exemple #46
0
 def __init__(self):
     Input.__init__(self)
     self.help_message = ''
     self.histo_pos = -1
     self.current_completed = ''
     self.key_func['^R'] = self.toggle_search
     self.search = False
     if config.get('separate_history'):
         self.history = list()
Exemple #47
0
    def command_reorder(self) -> None:
        """
        /reorder
        """
        tabs_spec = parse_config(self.config)
        if not tabs_spec:
            self.api.information('Invalid reorder config', 'Error')
            return None

        old_tabs = self.core.tabs.get_tabs()
        roster = old_tabs.pop(0)

        create_gaps = config.get('create_gaps')

        new_tabs = [roster]
        last = 0
        for pos in sorted(tabs_spec):
            if create_gaps and pos > last + 1:
                new_tabs += [
                    tabs.GapTab(self.core) for i in range(pos - last - 1)
                ]
            cls, jid = tabs_spec[pos]
            try:
                jid = JID(jid)
                tab = self.core.tabs.by_name_and_class(str(jid), cls=cls)
                if tab and tab in old_tabs:
                    new_tabs.append(tab)
                    old_tabs.remove(tab)
                else:
                    self.api.information('Tab %s not found. Creating it' % jid,
                                         'Warning')
                    # TODO: Add support for MucTab. Requires nickname.
                    if cls in (tabs.DynamicConversationTab,
                               tabs.StaticConversationTab):
                        new_tab = cls(self.core, jid)
                        new_tabs.append(new_tab)
                    else:
                        new_tabs.append(tabs.GapTab(self.core))
            except:
                self.api.information('Failed to create tab \'%s\'.' % jid,
                                     'Error')
                if create_gaps:
                    new_tabs.append(tabs.GapTab(self.core))
            finally:
                last = pos

        for tab in old_tabs:
            if tab:
                new_tabs.append(tab)

        # TODO: Ensure we don't break poezio and call this with whatever
        # tablist we have. The roster tab at least needs to be in there.
        self.core.tabs.replace_tabs(new_tabs)
        self.core.refresh_window()

        return None
Exemple #48
0
    def quit(self, args):
        """
        /quit [message]
        """
        if not self.core.xmpp.is_connected():
            self.core.exit()
            return

        msg = args[0]
        if config.get('enable_user_mood'):
            self.core.xmpp.plugin['xep_0107'].stop()
        if config.get('enable_user_activity'):
            self.core.xmpp.plugin['xep_0108'].stop()
        if config.get('enable_user_gaming'):
            self.core.xmpp.plugin['xep_0196'].stop()
        self.core.save_config()
        self.core.plugin_manager.disable_plugins()
        self.core.disconnect(msg)
        self.core.xmpp.add_event_handler("disconnected", self.core.exit, disposable=True)
Exemple #49
0
 def __init__(self):
     self.bookmarks = []  # type: List[Bookmark]
     preferred = config.get('use_bookmarks_method').lower()
     if preferred not in ('pep', 'privatexml'):
         preferred = 'privatexml'
     self.preferred = preferred
     self.available_storage = {
         'privatexml': False,
         'pep': False,
     }
Exemple #50
0
 def __init__(self):
     self.bookmarks = []  # type: List[Bookmark]
     preferred = config.get('use_bookmarks_method').lower()
     if preferred not in ('pep', 'privatexml'):
         preferred = 'privatexml'
     self.preferred = preferred
     self.available_storage = {
         'privatexml': False,
         'pep': False,
     }
Exemple #51
0
 def __init__(self) -> None:
     Input.__init__(self)
     self.help_message = ''
     self.histo_pos = -1
     self.current_completed = ''
     self.key_func['^R'] = self.toggle_search
     self.search = False
     if config.get('separate_history'):
         # pylint: disable=assigning-non-slot
         self.history = []  # type: List[str]
Exemple #52
0
 def modify_message(self, old_id, message):
     """
     Find a message, and replace it with a new one
     (instead of rebuilding everything in order to correct a message)
     """
     with_timestamps = config.get('show_timestamps')
     nick_size = config.get('max_nick_length')
     for i in range(len(self.built_lines)-1, -1, -1):
         if self.built_lines[i] and self.built_lines[i].msg.identifier == old_id:
             index = i
             while index >= 0 and self.built_lines[index] and self.built_lines[index].msg.identifier == old_id:
                 self.built_lines.pop(index)
                 index -= 1
             index += 1
             lines = self.build_message(message, timestamp=with_timestamps, nick_size=nick_size)
             for line in lines:
                 self.built_lines.insert(index, line)
                 index += 1
             break
Exemple #53
0
    def quit(self, args):
        """
        /quit [message]
        """
        if not self.core.xmpp.is_connected():
            self.core.exit()
            return

        msg = args[0]
        if config.get('enable_user_mood'):
            self.core.xmpp.plugin['xep_0107'].stop()
        if config.get('enable_user_activity'):
            self.core.xmpp.plugin['xep_0108'].stop()
        if config.get('enable_user_gaming'):
            self.core.xmpp.plugin['xep_0196'].stop()
        self.core.save_config()
        self.core.plugin_manager.disable_plugins()
        self.core.disconnect(msg)
        self.core.xmpp.add_event_handler("disconnected", self.core.exit, disposable=True)
Exemple #54
0
 def refresh(self) -> None:
     height, width = self._win.getmaxyx()
     self._win.erase()
     sorted_tabs = [tab for tab in self.core.tabs if tab]
     theme = get_theme()
     if not config.get('show_inactive_tabs'):
         sorted_tabs = [
             tab for tab in sorted_tabs
             if tab.vertical_color != theme.COLOR_VERTICAL_TAB_NORMAL
         ]
     nb_tabs = len(sorted_tabs)
     use_nicks = config.get('use_tab_nicks')
     if nb_tabs >= height:
         for y, tab in enumerate(sorted_tabs):
             if tab.vertical_color == theme.COLOR_VERTICAL_TAB_CURRENT:
                 pos = y
                 break
         # center the current tab as much as possible
         if pos < height // 2:
             sorted_tabs = sorted_tabs[:height]
         elif nb_tabs - pos <= height // 2:
             sorted_tabs = sorted_tabs[-height:]
         else:
             sorted_tabs = sorted_tabs[pos - height // 2:pos + height // 2]
     asc_sort = (config.get('vertical_tab_list_sort') == 'asc')
     for y, tab in enumerate(sorted_tabs):
         color = tab.vertical_color
         if asc_sort:
             y = height - y - 1
         self.addstr(y, 0, "%2d" % tab.nb,
                     to_curses_attr(theme.COLOR_VERTICAL_TAB_NUMBER))
         self.addstr('.')
         if use_nicks:
             self.addnstr("%s" % tab.get_nick(), width - 4,
                          to_curses_attr(color))
         else:
             self.addnstr("%s" % tab.name, width - 4, to_curses_attr(color))
     separator = to_curses_attr(theme.COLOR_VERTICAL_SEPARATOR)
     self._win.attron(separator)
     self._win.vline(0, width - 1, curses.ACS_VLINE, height)
     self._win.attroff(separator)
     self._refresh()
Exemple #55
0
    def __init__(self, messages_nb_limit: Optional[int] = None) -> None:

        if messages_nb_limit is None:
            messages_nb_limit = config.get('max_messages_in_memory')
        self._messages_nb_limit = messages_nb_limit  # type: int
        # Message objects
        self.messages = []  # type: List[Message]
        # we keep track of one or more windows
        # so we can pass the new messages to them, as they are added, so
        # they (the windows) can build the lines from the new message
        self._windows = []
Exemple #56
0
def hl(tab):
    """
    Make a tab beep and change its status.
    """
    if tab.state != 'current':
        tab.state = 'private'

    conv_jid = safeJID(tab.name)
    if 'private' in config.get('beep_on', 'highlight private').split():
        if not config.get_by_tabname('disable_beep', conv_jid.bare, default=False):
            curses.beep()
Exemple #57
0
    def refresh(self) -> None:
        log.debug('Refresh: %s', self.__class__.__name__)
        self._win.erase()
        theme = get_theme()
        self.addstr(0, 0, "[",
                    to_curses_attr(theme.COLOR_INFORMATION_BAR))

        show_names = config.get('show_tab_names')
        show_nums = config.get('show_tab_numbers')
        use_nicks = config.get('use_tab_nicks')
        show_inactive = config.get('show_inactive_tabs')

        for nb, tab in enumerate(self.core.tabs):
            if not tab:
                continue
            color = tab.color
            if not show_inactive and color is theme.COLOR_TAB_NORMAL:
                continue
            try:
                if show_nums or not show_names:
                    self.addstr("%s" % str(nb), to_curses_attr(color))
                    if show_names:
                        self.addstr(' ', to_curses_attr(color))
                if show_names:
                    if use_nicks:
                        self.addstr("%s" % str(tab.get_nick()),
                                    to_curses_attr(color))
                    else:
                        self.addstr("%s" % tab.name, to_curses_attr(color))
                self.addstr("|",
                            to_curses_attr(theme.COLOR_INFORMATION_BAR))
            except:  # end of line
                break
        (y, x) = self._win.getyx()
        self.addstr(y, x - 1, '] ',
                    to_curses_attr(theme.COLOR_INFORMATION_BAR))
        (y, x) = self._win.getyx()
        remaining_size = self.width - x
        self.addnstr(' ' * remaining_size, remaining_size,
                     to_curses_attr(theme.COLOR_INFORMATION_BAR))
        self._refresh()
Exemple #58
0
    def refresh(self):
        log.debug('Refresh: %s', self.__class__.__name__)
        self._win.erase()
        self.addstr(0, 0, "[", to_curses_attr(get_theme().COLOR_INFORMATION_BAR))

        create_gaps = config.get('create_gaps')
        show_names = config.get('show_tab_names')
        show_nums = config.get('show_tab_numbers')
        use_nicks = config.get('use_tab_nicks')
        show_inactive = config.get('show_inactive_tabs')
        # ignore any remaining gap tabs if the feature is not enabled
        if create_gaps:
            sorted_tabs = self.core.tabs[:]
        else:
            sorted_tabs = [tab for tab in self.core.tabs if tab]

        for nb, tab in enumerate(sorted_tabs):
            if not tab: continue
            color = tab.color
            if not show_inactive and color is get_theme().COLOR_TAB_NORMAL:
                continue
            try:
                if show_nums or not show_names:
                    self.addstr("%s" % str(nb), to_curses_attr(color))
                    if show_names:
                        self.addstr(' ', to_curses_attr(color))
                if show_names:
                    if use_nicks:
                        self.addstr("%s" % str(tab.get_nick()), to_curses_attr(color))
                    else:
                        self.addstr("%s" % tab.name, to_curses_attr(color))
                self.addstr("|", to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
            except:             # end of line
                break
        (y, x) = self._win.getyx()
        self.addstr(y, x-1, '] ', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
        (y, x) = self._win.getyx()
        remaining_size = self.width - x
        self.addnstr(' '*remaining_size, remaining_size,
                     to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
        self._refresh()
Exemple #59
0
    def __init__(self, lines_nb_limit=None):
        if lines_nb_limit is None:
            lines_nb_limit = config.get('max_lines_in_memory')
        Win.__init__(self)
        self.lines_nb_limit = lines_nb_limit
        self.pos = 0
        self.built_lines = []   # Each new message is built and kept here.
        # on resize, we rebuild all the messages

        self.lock = False
        self.lock_buffer = []
        self.separator_after = None
Exemple #60
0
 def toggle_offline_show(self):
     """
     Show or hide offline contacts
     """
     option = 'roster_show_offline'
     value = config.get(option)
     success = config.silent_set(option, str(not value))
     roster.modified()
     if not success:
         self.core.information('Unable to write in the config file',
                               'Error')
     return True