Beispiel #1
0
 def callback(iq):
     if iq['type'] != 'result':
         if iq['error']['type'] == 'auth':
             self.core.information(
                 'You are not allowed to see the activity of this contact.',
                 'Error')
         else:
             self.core.information('Error retrieving the activity',
                                   'Error')
         return
     seconds = iq['last_activity']['seconds']
     status = iq['last_activity']['status']
     from_ = iq['from']
     msg = '\x19%s}The last activity of %s was %s ago%s'
     if not safeJID(from_).user:
         msg = '\x19%s}The uptime of %s is %s.' % (
             dump_tuple(get_theme().COLOR_INFORMATION_TEXT), from_,
             common.parse_secs_to_str(seconds))
     else:
         msg = '\x19%s}The last activity of %s was %s ago%s' % (
             dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
             from_,
             common.parse_secs_to_str(seconds),
             (' and his/her last status was %s' %
              status) if status else '',
         )
     self.add_message(msg)
     self.core.refresh_window()
Beispiel #2
0
 def user_left(self, status_message, from_nick):
     """
     The user left the associated MUC
     """
     self.deactivate()
     if not status_message:
         self.add_message(
             '\x191}%(spec)s \x193}%(nick)s\x19%(info_col)s} has left the room'
             % {
                 'nick': from_nick,
                 'spec': get_theme().CHAR_QUIT,
                 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
             },
             typ=2)
     else:
         self.add_message(
             '\x191}%(spec)s \x193}%(nick)s\x19%(info_col)s} has left the room (%(status)s)"'
             % {
                 'nick': from_nick,
                 'spec': get_theme().CHAR_QUIT,
                 'status': status_message,
                 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
             },
             typ=2)
     return self.core.current_tab() is self
Beispiel #3
0
def on_groupchat_subject(self, message):
    """
    Triggered when the topic is changed.
    """
    nick_from = message['mucnick']
    room_from = message.get_mucroom()
    tab = self.get_tab_by_name(room_from, tabs.MucTab)
    subject = message['subject']
    if subject is None or not tab:
        return
    if subject != tab.topic:
        # Do not display the message if the subject did not change or if we
        # receive an empty topic when joining the room.
        if nick_from:
            tab.add_message(_("\x19%(info_col)s}%(nick)s set the subject to: %(subject)s") %
                    {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT), 'nick':nick_from, 'subject':subject},
                    time=None,
                    typ=2)
        else:
            tab.add_message(_("\x19%(info_col)s}The subject is: %(subject)s") %
                    {'subject':subject, 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)},
                    time=None,
                    typ=2)
    tab.topic = subject
    tab.topic_from = nick_from
    if self.get_tab_by_name(room_from, tabs.MucTab) is self.current_tab():
        self.refresh_window()
Beispiel #4
0
 def command_info(self):
     contact = roster[self.get_dest_jid()]
     jid = safeJID(self.get_dest_jid())
     if contact:
         if jid.resource:
             resource = contact[jid.full]
         else:
             resource = contact.get_highest_priority_resource()
     else:
         resource = None
     if resource:
         status = (_('Status: %s') %
                   resource.status) if resource.status else ''
         self._text_buffer.add_message(
             "\x19%(info_col)s}Show: %(show)s, %(status)s\x19o" % {
                 'show': resource.show or 'available',
                 'status': status,
                 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
             })
         return True
     else:
         self._text_buffer.add_message(
             "\x19%(info_col)s}No information available\x19o" %
             {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)})
         return True
Beispiel #5
0
    def command_smp(self, args):
        """
        /otrsmp <ask|answer|abort> [question] [secret]
        """
        if args is None or not args:
            return self.core.command_help('otrsmp')
        length = len(args)
        action = args.pop(0)
        if length == 2:
            question = None
            secret = args.pop(0).encode('utf-8')
        elif length == 3:
            question = args.pop(0).encode('utf-8')
            secret = args.pop(0).encode('utf-8')
        else:
            question = secret = None

        tab = self.api.current_tab()
        name = tab.name
        if isinstance(tab, DynamicConversationTab) and tab.locked_resource:
            name = safeJID(tab.name)
            name.resource = tab.locked_resource
            name = name.full

        format_dict = {
            'jid_c': '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID),
            'info': '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
            'jid': name,
            'bare_jid': safeJID(name).bare
        }

        ctx = self.get_context(name)
        if ctx.state != STATE_ENCRYPTED:
            self.api.information('The current conversation is not encrypted',
                                 'Error')
            return

        if action == 'ask':
            ctx.in_smp = True
            ctx.smp_own = True
            if question:
                ctx.smpInit(secret, question)
            else:
                ctx.smpInit(secret)
            tab.add_message(SMP_INITIATED % format_dict, typ=0)
        elif action == 'answer':
            ctx.smpGotSecret(secret)
        elif action == 'abort':
            if ctx.in_smp:
                ctx.smpAbort()
                tab.add_message(SMP_ABORTED % format_dict, typ=0)
        self.core.refresh_window()
Beispiel #6
0
    def command_smp(self, args):
        """
        /otrsmp <ask|answer|abort> [question] [secret]
        """
        if args is None or not args:
            return self.core.command_help('otrsmp')
        length = len(args)
        action = args.pop(0)
        if length == 2:
            question = None
            secret = args.pop(0).encode('utf-8')
        elif length == 3:
            question = args.pop(0).encode('utf-8')
            secret = args.pop(0).encode('utf-8')
        else:
            question = secret = None

        tab = self.api.current_tab()
        name = tab.name
        if isinstance(tab, DynamicConversationTab) and tab.locked_resource:
            name = safeJID(tab.name)
            name.resource = tab.locked_resource
            name = name.full

        format_dict = {
            'jid_c': '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID),
            'info': '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
            'jid': name,
            'bare_jid': safeJID(name).bare
        }

        ctx = self.get_context(name)
        if ctx.state != STATE_ENCRYPTED:
            self.api.information('The current conversation is not encrypted',
                                 'Error')
            return

        if action == 'ask':
            ctx.in_smp = True
            ctx.smp_own = True
            if question:
                ctx.smpInit(secret, question)
            else:
                ctx.smpInit(secret)
            tab.add_message(SMP_INITIATED % format_dict, typ=0)
        elif action == 'answer':
            ctx.smpGotSecret(secret)
        elif action == 'abort':
            if ctx.in_smp:
                ctx.smpAbort()
                tab.add_message(SMP_ABORTED % format_dict, typ=0)
        self.core.refresh_window()
Beispiel #7
0
    def make_message(txt,
                     time,
                     nickname,
                     nick_color,
                     history,
                     user,
                     identifier,
                     str_time=None,
                     highlight=False,
                     old_message=None,
                     revisions=0,
                     jid=None,
                     ack=None):
        """
        Create a new Message object with parameters, check for /me messages,
        and delayed messages
        """
        time = time or datetime.now()
        if txt.startswith('/me '):
            me = True
            txt = '\x19%s}%s' % (dump_tuple(
                get_theme().COLOR_ME_MESSAGE), txt[4:])
        else:
            me = False
        if history:
            txt = txt.replace(
                '\x19o',
                '\x19o\x19%s}' % dump_tuple(get_theme().COLOR_LOG_MSG))
            str_time = time.strftime("%Y-%m-%d %H:%M:%S")
        else:
            if str_time is None:
                str_time = time.strftime("%H:%M:%S")
            else:
                str_time = ''

        msg = Message(txt='%s\x19o' % (txt.replace('\t', '    '), ),
                      nick_color=nick_color,
                      time=time,
                      str_time=str_time,
                      nickname=nickname,
                      user=user,
                      identifier=identifier,
                      highlight=highlight,
                      me=me,
                      old_message=old_message,
                      revisions=revisions,
                      jid=jid,
                      ack=ack)
        log.debug('Set message %s with %s.', identifier, msg)
        return msg
Beispiel #8
0
    def on_conversation_say(self, msg, tab):
        """
        On message sent
        """
        if isinstance(tab, DynamicConversationTab) and tab.locked_resource:
            jid = safeJID(tab.name)
            jid.resource = tab.locked_resource
            name = jid.full
        else:
            name = tab.name
            jid = safeJID(tab.name)

        format_dict = {
            'jid_c': '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID),
            'info': '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
            'jid': name,
        }

        ctx = None
        default_ctx = self.get_context(name)

        if isinstance(tab, DynamicConversationTab) and not tab.locked_resource:
            log.debug('Unlocked tab %s found, falling back to the first encrypted chat we find.', name)
            ctx = self.find_encrypted_context_with_matching(jid.bare)

        if ctx is None:
            ctx = default_ctx

        if ctx and ctx.state == STATE_ENCRYPTED:
            ctx.sendMessage(0, msg['body'].encode('utf-8'))
            if not tab.send_chat_state('active'):
                tab.send_chat_state('inactive', always_send=True)

            tab.add_message(msg['body'],
                            nickname=self.core.own_nick or tab.own_nick,
                            nick_color=get_theme().COLOR_OWN_NICK,
                            identifier=msg['id'],
                            jid=self.core.xmpp.boundjid,
                            typ=ctx.log)
            # remove everything from the message so that it doesn’t get sent
            del msg['body']
            del msg['replace']
            del msg['html']
        elif ctx and ctx.getPolicy('REQUIRE_ENCRYPTION'):
            tab.add_message(MESSAGE_NOT_SENT % format_dict, typ=0)
            del msg['body']
            del msg['replace']
            del msg['html']
            self.otr_start(tab, name, format_dict)
Beispiel #9
0
    def features_checked(self, iq):
        "Features check callback"
        features = iq['disco_info'].get_features() or []
        before = ('correct' in self.commands, self.remote_supports_attention,
                  self.remote_supports_receipts)
        correct = self._feature_correct(features)
        attention = self._feature_attention(features)
        receipts = self._feature_receipts(features)

        if (correct, attention, receipts) == before and self.__initial_disco:
            return
        else:
            self.__initial_disco = True

        if not (correct or attention or receipts):
            return  # don’t display anything

        ok = get_theme().CHAR_OK
        nope = get_theme().CHAR_EMPTY

        correct = ok if correct else nope
        attention = ok if attention else nope
        receipts = ok if receipts else nope

        msg = ('\x19%s}Contact supports: correction [%s], '
               'attention [%s], receipts [%s].')
        color = dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
        msg = msg % (color, correct, attention, receipts)
        self.add_message(msg, typ=0)
        self.core.refresh_window()
Beispiel #10
0
    def features_checked(self, iq):
        "Features check callback"
        features = iq['disco_info'].get_features() or []
        before = ('correct' in self.commands,
                  self.remote_supports_attention,
                  self.remote_supports_receipts)
        correct = self._feature_correct(features)
        attention = self._feature_attention(features)
        receipts = self._feature_receipts(features)

        if (correct, attention, receipts) == before and self.__initial_disco:
            return
        else:
            self.__initial_disco = True

        if not (correct or attention or receipts):
            return # don’t display anything

        ok = get_theme().CHAR_OK
        nope = get_theme().CHAR_EMPTY

        correct = ok if correct else nope
        attention = ok if attention else nope
        receipts = ok if receipts else nope

        msg = _('\x19%s}Contact supports: correction [%s], '
                'attention [%s], receipts [%s].')
        color = dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
        msg = msg % (color, correct, attention, receipts)
        self.add_message(msg, typ=0)
        self.core.refresh_window()
Beispiel #11
0
def on_status_codes(self, message):
    """
    Handle groupchat messages with status codes.
    Those are received when a room configuration change occurs.
    """
    room_from = message['from']
    tab = self.get_tab_by_name(room_from, tabs.MucTab)
    status_codes = set([s.attrib['code'] for s in message.findall('{%s}x/{%s}status' % (tabs.NS_MUC_USER, tabs.NS_MUC_USER))])
    if '101' in status_codes:
        self.information('Your affiliation in the room %s changed' % room_from, 'Info')
    elif tab and status_codes:
        show_unavailable = '102' in status_codes
        hide_unavailable = '103' in status_codes
        non_priv = '104' in status_codes
        logging_on = '170' in status_codes
        logging_off = '171' in status_codes
        non_anon = '172' in status_codes
        semi_anon = '173' in status_codes
        full_anon = '174' in status_codes
        modif = False
        if show_unavailable or hide_unavailable or non_priv or logging_off\
                or non_anon or semi_anon or full_anon:
            tab.add_message('\x19%(info_col)s}Info: A configuration change not privacy-related occured.' %
                    {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)},
                    typ=2)
            modif = True
        if show_unavailable:
            tab.add_message('\x19%(info_col)s}Info: The unavailable members are now shown.' %
                    {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)},
                    typ=2)
        elif hide_unavailable:
            tab.add_message('\x19%(info_col)s}Info: The unavailable members are now hidden.' %
                    {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)},
                    typ=2)
        if non_anon:
            tab.add_message('\x191}Warning:\x19%(info_col)s} The room is now not anonymous. (public JID)' %
                    {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)},
                    typ=2)
        elif semi_anon:
            tab.add_message('\x19%(info_col)s}Info: The room is now semi-anonymous. (moderators-only JID)' %
                    {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)},
                    typ=2)
        elif full_anon:
            tab.add_message('\x19%(info_col)s}Info: The room is now fully anonymous.' %
                    {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)},
                    typ=2)
        if logging_on:
            tab.add_message('\x191}Warning: \x19%(info_col)s}This room is publicly logged' %
                    {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)},
                    typ=2)
        elif logging_off:
            tab.add_message('\x19%(info_col)s}Info: This room is not logged anymore.' %
                    {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)},
                    typ=2)
        if modif:
            self.refresh_window()
Beispiel #12
0
    def setState(self, newstate):
        format_dict = {
            'jid_c': '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID),
            'info': '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
            'normal': '\x19%s}' % dump_tuple(get_theme().COLOR_NORMAL_TEXT),
            'jid': self.peer,
            'bare_jid': safeJID(self.peer).bare
        }

        tab = self.core.get_tab_by_name(self.peer)
        if not tab:
            tab = self.core.get_tab_by_name(safeJID(self.peer).bare,
                                            DynamicConversationTab)
            if tab and not tab.locked_resource == safeJID(self.peer).resource:
                tab = None
        if self.state == STATE_ENCRYPTED:
            if newstate == STATE_ENCRYPTED and tab:
                log.debug('OTR conversation with %s refreshed', self.peer)
                if self.getCurrentTrust():
                    msg = OTR_REFRESH_TRUSTED % format_dict
                    tab.add_message(msg, typ=self.log)
                else:
                    msg = OTR_REFRESH_UNTRUSTED % format_dict
                    tab.add_message(msg, typ=self.log)
                hl(tab)
            elif newstate == STATE_FINISHED or newstate == STATE_PLAINTEXT:
                log.debug('OTR conversation with %s finished', self.peer)
                if tab:
                    tab.add_message(OTR_END % format_dict, typ=self.log)
                    hl(tab)
        elif newstate == STATE_ENCRYPTED and tab:
            if self.getCurrentTrust():
                tab.add_message(OTR_START_TRUSTED % format_dict, typ=self.log)
            else:
                format_dict['our_fpr'] = self.user.getPrivkey()
                format_dict['remote_fpr'] = self.getCurrentKey()
                tab.add_message(OTR_TUTORIAL % format_dict, typ=0)
                tab.add_message(OTR_START_UNTRUSTED % format_dict, typ=self.log)
            hl(tab)

        log.debug('Set encryption state of %s to %s', self.peer, states[newstate])
        super(PoezioContext, self).setState(newstate)
        if tab:
            self.core.refresh_window()
            self.core.doupdate()
Beispiel #13
0
    def setState(self, newstate):
        format_dict = {
            'jid_c': '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID),
            'info': '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
            'normal': '\x19%s}' % dump_tuple(get_theme().COLOR_NORMAL_TEXT),
            'jid': self.peer,
            'bare_jid': safeJID(self.peer).bare
        }

        tab = self.core.get_tab_by_name(self.peer)
        if not tab:
            tab = self.core.get_tab_by_name(safeJID(self.peer).bare,
                                            DynamicConversationTab)
            if tab and not tab.locked_resource == safeJID(self.peer).resource:
                tab = None
        if self.state == STATE_ENCRYPTED:
            if newstate == STATE_ENCRYPTED and tab:
                log.debug('OTR conversation with %s refreshed', self.peer)
                if self.getCurrentTrust():
                    msg = OTR_REFRESH_TRUSTED % format_dict
                    tab.add_message(msg, typ=self.log)
                else:
                    msg = OTR_REFRESH_UNTRUSTED % format_dict
                    tab.add_message(msg, typ=self.log)
                hl(tab)
            elif newstate == STATE_FINISHED or newstate == STATE_PLAINTEXT:
                log.debug('OTR conversation with %s finished', self.peer)
                if tab:
                    tab.add_message(OTR_END % format_dict, typ=self.log)
                    hl(tab)
        elif newstate == STATE_ENCRYPTED and tab:
            if self.getCurrentTrust():
                tab.add_message(OTR_START_TRUSTED % format_dict, typ=self.log)
            else:
                format_dict['our_fpr'] = self.user.getPrivkey()
                format_dict['remote_fpr'] = self.getCurrentKey()
                tab.add_message(OTR_TUTORIAL % format_dict, typ=0)
                tab.add_message(OTR_START_UNTRUSTED % format_dict, typ=self.log)
            hl(tab)

        log.debug('Set encryption state of %s to %s', self.peer, states[newstate])
        super(PoezioContext, self).setState(newstate)
        if tab:
            self.core.refresh_window()
            self.core.doupdate()
Beispiel #14
0
    def lock(self, resource):
        """
        Lock the tab to the resource.
        """
        assert(resource)
        if resource != self.locked_resource:
            self.locked_resource = resource
            info = '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
            jid_c = '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID)

            message = ('%(info)sConversation locked to '
                       '%(jid_c)s%(jid)s/%(resource)s%(info)s.') % {
                            'info': info,
                            'jid_c': jid_c,
                            'jid': self.name,
                            'resource': resource}
            self.add_message(message, typ=0)
            self.check_features()
Beispiel #15
0
 def build_message(self, message, timestamp=False, nick_size=10):
     """
     Build a list of lines from a message, without adding it
     to a list
     """
     if message is None:  # line separator
         return [None]
     txt = message.txt
     if not txt:
         return []
     if len(message.str_time) > 8:
         default_color = (FORMAT_CHAR +
                          dump_tuple(get_theme().COLOR_LOG_MSG) + '}')
     else:
         default_color = None
     ret = []
     nick = truncate_nick(message.nickname, nick_size)
     offset = 0
     if message.ack:
         if message.ack > 0:
             offset += poopt.wcswidth(get_theme().CHAR_ACK_RECEIVED) + 1
         else:
             offset += poopt.wcswidth(get_theme().CHAR_NACK) + 1
     if nick:
         offset += poopt.wcswidth(nick) + 2  # + nick + '> ' length
     if message.revisions > 0:
         offset += ceil(log10(message.revisions + 1))
     if message.me:
         offset += 1  # '* ' before and ' ' after
     if timestamp:
         if message.str_time:
             offset += 1 + len(message.str_time)
         if get_theme().CHAR_TIME_LEFT and message.str_time:
             offset += 1
         if get_theme().CHAR_TIME_RIGHT and message.str_time:
             offset += 1
     lines = poopt.cut_text(txt, self.width - offset - 1)
     prepend = default_color if default_color else ''
     attrs = []
     for line in lines:
         saved = Line(msg=message,
                      start_pos=line[0],
                      end_pos=line[1],
                      prepend=prepend)
         attrs = parse_attrs(message.txt[line[0]:line[1]], attrs)
         if attrs:
             prepend = FORMAT_CHAR + FORMAT_CHAR.join(attrs)
         else:
             if default_color:
                 prepend = default_color
             else:
                 prepend = ''
         ret.append(saved)
     return ret
Beispiel #16
0
    def unlock(self, from_=None):
        """
        Unlock the tab from a resource. It is now “associated” with the bare
        jid.
        """
        self.remote_wants_chatstates = None
        if self.locked_resource != None:
            self.locked_resource = None
            info = '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
            jid_c = '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID)

            if from_:
                message = ('%(info)sConversation unlocked (received activity'
                           ' from %(jid_c)s%(jid)s%(info)s).') % {
                                'info': info,
                                'jid_c': jid_c,
                                'jid': from_}
                self.add_message(message, typ=0)
            else:
                message = '%sConversation unlocked.' % info
                self.add_message(message, typ=0)
Beispiel #17
0
 def on_blocked_message(self, message):
     """
     When we try to send a message to a blocked contact
     """
     tab = self.core.get_conversation_by_jid(message['from'], False)
     if not tab:
         log.debug('Received message from nonexistent tab: %s', message['from'])
     message = '\x19%(info_col)s}Cannot send message to %(jid)s: contact blocked' % {
             'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
             'jid': message['from'],
         }
     tab.add_message(message)
Beispiel #18
0
    def make_message(txt, time, nickname, nick_color, history, user,
                     identifier, str_time=None, highlight=False,
                     old_message=None, revisions=0, jid=None, ack=None):
        """
        Create a new Message object with parameters, check for /me messages,
        and delayed messages
        """
        time = time or datetime.now()
        if txt.startswith('/me '):
            me = True
            txt = '\x19%s}%s' % (dump_tuple(get_theme().COLOR_ME_MESSAGE),
                                 txt[4:])
        else:
            me = False
        if history:
            txt = txt.replace('\x19o', '\x19o\x19%s}' %
                                dump_tuple(get_theme().COLOR_LOG_MSG))
            str_time = time.strftime("%Y-%m-%d %H:%M:%S")
        else:
            if str_time is None:
                str_time = time.strftime("%H:%M:%S")
            else:
                str_time = ''

        msg = Message(
                txt='%s\x19o'%(txt.replace('\t', '    '),),
                nick_color=nick_color,
                time=time,
                str_time=str_time,
                nickname=nickname,
                user=user,
                identifier=identifier,
                highlight=highlight,
                me=me,
                old_message=old_message,
                revisions=revisions,
                jid=jid,
                ack=ack)
        log.debug('Set message %s with %s.', identifier, msg)
        return msg
Beispiel #19
0
 def on_blocked_message(self, message):
     """
     When we try to send a message to a blocked contact
     """
     tab = self.core.get_conversation_by_jid(message['from'], False)
     if not tab:
         log.debug('Received message from nonexistent tab: %s',
                   message['from'])
     message = '\x19%(info_col)s}Cannot send message to %(jid)s: contact blocked' % {
         'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
         'jid': message['from'],
     }
     tab.add_message(message)
Beispiel #20
0
 def build_message(self, message, timestamp=False):
     """
     Build a list of lines from a message, without adding it
     to a list
     """
     if message is None:  # line separator
         return [None]
     txt = message.txt
     if not txt:
         return []
     if len(message.str_time) > 8:
         default_color = (FORMAT_CHAR + dump_tuple(get_theme().COLOR_LOG_MSG)
                 + '}')
     else:
         default_color = None
     ret = []
     nick = truncate_nick(message.nickname)
     offset = 0
     if message.ack:
         if message.ack > 0:
             offset += poopt.wcswidth(get_theme().CHAR_ACK_RECEIVED) + 1
         else:
             offset += poopt.wcswidth(get_theme().CHAR_NACK) + 1
     if nick:
         offset += poopt.wcswidth(nick) + 2 # + nick + '> ' length
     if message.revisions > 0:
         offset += ceil(log10(message.revisions + 1))
     if message.me:
         offset += 1 # '* ' before and ' ' after
     if timestamp:
         if message.str_time:
             offset += 1 + len(message.str_time)
         if get_theme().CHAR_TIME_LEFT and message.str_time:
             offset += 1
         if get_theme().CHAR_TIME_RIGHT and message.str_time:
             offset += 1
     lines = poopt.cut_text(txt, self.width-offset-1)
     prepend = default_color if default_color else ''
     attrs = []
     for line in lines:
         saved = Line(msg=message, start_pos=line[0], end_pos=line[1], prepend=prepend)
         attrs = parse_attrs(message.txt[line[0]:line[1]], attrs)
         if attrs:
             prepend = FORMAT_CHAR + FORMAT_CHAR.join(attrs)
         else:
             if default_color:
                 prepend = default_color
             else:
                 prepend = ''
         ret.append(saved)
     return ret
Beispiel #21
0
def command_help(self, args):
    """
    /help [command_name]
    """
    if not args:
        color = dump_tuple(get_theme().COLOR_HELP_COMMANDS)
        acc = []
        buff = ['Global commands:']
        for command in self.commands:
            if isinstance(self.commands[command], Command):
                acc.append('  \x19%s}%s\x19o - %s' % (
                               color,
                               command,
                               self.commands[command].short))
            else:
                acc.append('  \x19%s}%s\x19o' % (color, command))
        acc = sorted(acc)
        buff.extend(acc)
        acc = []
        buff.append('Tab-specific commands:')
        commands = self.current_tab().commands
        for command in commands:
            if isinstance(commands[command], Command):
                acc.append('  \x19%s}%s\x19o - %s' % (
                                color,
                                command,
                                commands[command].short))
            else:
                acc.append('  \x19%s}%s\x19o' % (color, command))
        acc = sorted(acc)
        buff.extend(acc)

        msg = '\n'.join(buff)
        msg += _("\nType /help <command_name> to know what each command does")
    else:
        command = args[0].lstrip('/').strip()

        if command in self.current_tab().commands:
            tup = self.current_tab().commands[command]
        elif command in self.commands:
            tup = self.commands[command]
        else:
            self.information(_('Unknown command: %s') % command, 'Error')
            return
        if isinstance(tup, Command):
            msg = _('Usage: /%s %s\n' % (command, tup.usage))
            msg += tup.desc
        else:
            msg = tup[1]
    self.information(msg, 'Help')
Beispiel #22
0
def command_help(self, args):
    """
    /help [command_name]
    """
    if not args:
        color = dump_tuple(get_theme().COLOR_HELP_COMMANDS)
        acc = []
        buff = ['Global commands:']
        for command in self.commands:
            if isinstance(self.commands[command], Command):
                acc.append('  \x19%s}%s\x19o - %s' % (
                               color,
                               command,
                               self.commands[command].short))
            else:
                acc.append('  \x19%s}%s\x19o' % (color, command))
        acc = sorted(acc)
        buff.extend(acc)
        acc = []
        buff.append('Tab-specific commands:')
        commands = self.current_tab().commands
        for command in commands:
            if isinstance(commands[command], Command):
                acc.append('  \x19%s}%s\x19o - %s' % (
                                color,
                                command,
                                commands[command].short))
            else:
                acc.append('  \x19%s}%s\x19o' % (color, command))
        acc = sorted(acc)
        buff.extend(acc)

        msg = '\n'.join(buff)
        msg += _("\nType /help <command_name> to know what each command does")
    else:
        command = args[0].lstrip('/').strip()

        if command in self.current_tab().commands:
            tup = self.current_tab().commands[command]
        elif command in self.commands:
            tup = self.commands[command]
        else:
            self.information(_('Unknown command: %s') % command, 'Error')
            return
        if isinstance(tup, Command):
            msg = _('Usage: /%s %s\n' % (command, tup.usage))
            msg += tup.desc
        else:
            msg = tup[1]
    self.information(msg, 'Help')
Beispiel #23
0
 def user_rejoined(self, nick):
     """
     The user (or at least someone with the same nick) came back in the MUC
     """
     self.activate()
     self.check_features()
     tab = self.core.get_tab_by_name(safeJID(self.name).bare, MucTab)
     color = 3
     if tab and config.get_by_tabname('display_user_color_in_join_part',
                                      self.general_jid):
         user = tab.get_user_by_name(nick)
         if user:
             color = dump_tuple(user.color)
     self.add_message(
         '\x194}%(spec)s \x19%(color)s}%(nick)s\x19%(info_col)s} joined the room'
         % {
             'nick': nick,
             'color': color,
             'spec': get_theme().CHAR_JOIN,
             'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
         },
         typ=2)
     return self.core.current_tab() is self
Beispiel #24
0
 def rename_user(self, old_nick, new_nick):
     """
     The user changed her nick in the corresponding muc: update the tab’s name and
     display a message.
     """
     self.add_message(
         '\x193}%(old)s\x19%(info_col)s} is now known as \x193}%(new)s' % {
             'old': old_nick,
             'new': new_nick,
             'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
         },
         typ=2)
     new_jid = safeJID(self.name).bare + '/' + new_nick
     self.name = new_jid
     return self.core.current_tab() is self
Beispiel #25
0
 def callback(iq):
     if iq['type'] != 'result':
         if iq['error']['type'] == 'auth':
             self.core.information('You are not allowed to see the activity of this contact.', 'Error')
         else:
             self.core.information('Error retrieving the activity', 'Error')
         return
     seconds = iq['last_activity']['seconds']
     status = iq['last_activity']['status']
     from_ = iq['from']
     msg = '\x19%s}The last activity of %s was %s ago%s'
     if not safeJID(from_).user:
         msg = '\x19%s}The uptime of %s is %s.' % (
                 dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
                 from_,
                 common.parse_secs_to_str(seconds))
     else:
         msg = '\x19%s}The last activity of %s was %s ago%s' % (
             dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
             from_,
             common.parse_secs_to_str(seconds),
             (' and his/her last status was %s' % status) if status else '',)
     self.add_message(msg)
     self.core.refresh_window()
Beispiel #26
0
 def user_rejoined(self, nick):
     """
     The user (or at least someone with the same nick) came back in the MUC
     """
     self.activate()
     self.check_features()
     tab = self.core.get_tab_by_name(safeJID(self.name).bare, MucTab)
     color = 3
     if tab and config.get_by_tabname('display_user_color_in_join_part',
                                      self.general_jid):
         user = tab.get_user_by_name(nick)
         if user:
             color = dump_tuple(user.color)
     self.add_message('\x194}%(spec)s \x19%(color)s}%(nick)s\x19%(info_col)s} joined the room' % {'nick':nick, 'color': color, 'spec':get_theme().CHAR_JOIN, 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)}, typ=2)
     return self.core.current_tab() is self
Beispiel #27
0
 def remote_wants_chatstates(self, value):
     old_value = self._remote_wants_chatstates
     self._remote_wants_chatstates = value
     if (old_value is None and value != None) or \
             (old_value != value and value != None):
         ok = get_theme().CHAR_OK
         nope = get_theme().CHAR_EMPTY
         support = ok if value else nope
         if value:
             msg = _('\x19%s}Contact supports chat states [%s].')
         else:
             msg = _('\x19%s}Contact does not support chat states [%s].')
         color = dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
         msg = msg % (color, support)
         self.add_message(msg, typ=0)
         self.core.refresh_window()
Beispiel #28
0
 def remote_wants_chatstates(self, value):
     old_value = self._remote_wants_chatstates
     self._remote_wants_chatstates = value
     if (old_value is None and value != None) or \
             (old_value != value and value != None):
         ok = get_theme().CHAR_OK
         nope = get_theme().CHAR_EMPTY
         support = ok if value else nope
         if value:
             msg = '\x19%s}Contact supports chat states [%s].'
         else:
             msg = '\x19%s}Contact does not support chat states [%s].'
         color = dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
         msg = msg % (color, support)
         self.add_message(msg, typ=0)
         self.core.refresh_window()
Beispiel #29
0
 def command_info(self):
     contact = roster[self.get_dest_jid()]
     jid = safeJID(self.get_dest_jid())
     if contact:
         if jid.resource:
             resource = contact[jid.full]
         else:
             resource = contact.get_highest_priority_resource()
     else:
         resource = None
     if resource:
         status = ('Status: %s' % resource.status) if resource.status else ''
         self._text_buffer.add_message("\x19%(info_col)s}Show: %(show)s, %(status)s\x19o" % {
             'show': resource.show or 'available', 'status': status, 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)})
         return True
     else:
         self._text_buffer.add_message("\x19%(info_col)s}No information available\x19o" % {'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)})
         return True
Beispiel #30
0
    def on_conversation_msg(self, msg, tab):
        """
        Message received
        """
        format_dict = {
            'jid_c': '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID),
            'info':  '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
            'jid': msg['from']
        }
        try:
            ctx = self.get_context(msg['from'])
            txt, tlvs = ctx.receiveMessage(msg["body"].encode('utf-8'))

            # SMP
            if tlvs:
                self.handle_tlvs(tlvs, ctx, tab, format_dict)
        except UnencryptedMessage as err:
            # received an unencrypted message inside an OTR session
            self.unencrypted_message_received(err, ctx, msg, tab, format_dict)
            self.otr_start(tab, tab.name, format_dict)
            return
        except NotOTRMessage as err:
            # ignore non-otr messages
            # if we expected an OTR message, we would have
            # got an UnencryptedMesssage
            # but do an additional check because of a bug with potr and py3k
            if ctx.state != STATE_PLAINTEXT or ctx.getPolicy('REQUIRE_ENCRYPTION'):
                self.unencrypted_message_received(err, ctx, msg, tab, format_dict)
                self.otr_start(tab, tab.name, format_dict)
            return
        except ErrorReceived as err:
            # Received an OTR error
            format_dict['err'] = err.args[0].error.decode('utf-8', errors='replace')
            tab.add_message(OTR_ERROR % format_dict, typ=0)
            del msg['body']
            del msg['html']
            hl(tab)
            self.core.refresh_window()
            return
        except NotEncryptedError as err:
            # Encrypted message received, but unreadable as we do not have
            # an OTR session in place.
            text = MESSAGE_UNREADABLE % format_dict
            tab.add_message(text, jid=msg['from'], typ=0)
            hl(tab)
            del msg['body']
            del msg['html']
            self.core.refresh_window()
            return
        except crypt.InvalidParameterError:
            # Malformed OTR payload and stuff
            text = MESSAGE_INVALID % format_dict
            tab.add_message(text, jid=msg['from'], typ=0)
            hl(tab)
            del msg['body']
            del msg['html']
            self.core.refresh_window()
            return
        except Exception:
            # Unexpected error
            import traceback
            exc = traceback.format_exc()
            format_dict['exc'] = exc
            tab.add_message(POTR_ERROR % format_dict, typ=0)
            log.error('Unspecified error in the OTR plugin', exc_info=True)
            return
        # No error, proceed with the message
        self.encrypted_message_received(msg, ctx, tab, txt)
Beispiel #31
0
def test_dump_tuple():
    assert dump_tuple((1, 2)) == '1,2'
    assert dump_tuple((1, )) == '1'
    assert dump_tuple((1, 2, 'u')) == '1,2,u'
Beispiel #32
0
    def setState(self, newstate):
        color_jid = '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID)
        color_info = '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT)

        tab = self.core.get_tab_by_name(self.peer)
        if not tab:
            tab = self.core.get_tab_by_name(
                safeJID(self.peer).bare, DynamicConversationTab)
            if tab and not tab.locked_resource == safeJID(self.peer).resource:
                tab = None
        if self.state == STATE_ENCRYPTED:
            if newstate == STATE_ENCRYPTED:
                log.debug('OTR conversation with %s refreshed', self.peer)
                if tab:
                    if self.getCurrentTrust():
                        msg = _('%(info)sRefreshed \x19btrusted\x19o%(info)s'
                                ' OTR conversation with %(jid_c)s%(jid)s') % {
                                    'info': color_info,
                                    'jid_c': color_jid,
                                    'jid': self.peer
                                }
                        tab.add_message(msg, typ=self.log)
                    else:
                        msg = _('%(info)sRefreshed \x19buntrusted\x19o%(info)s'
                                ' OTR conversation with %(jid_c)s%(jid)s'
                                '%(info)s, key: \x19o%(key)s') % {
                                    'jid': self.peer,
                                    'key': self.getCurrentKey(),
                                    'info': color_info,
                                    'jid_c': color_jid
                                }

                        tab.add_message(msg, typ=self.log)
                    hl(tab)
            elif newstate == STATE_FINISHED or newstate == STATE_PLAINTEXT:
                log.debug('OTR conversation with %s finished', self.peer)
                if tab:
                    tab.add_message('%sEnded OTR conversation with %s%s' %
                                    (color_info, color_jid, self.peer),
                                    typ=self.log)
                    hl(tab)
        else:
            if newstate == STATE_ENCRYPTED:
                if tab:
                    if self.getCurrentTrust():
                        msg = _('%(info)sStarted a \x19btrusted\x19o%(info)s '
                                'OTR conversation with %(jid_c)s%(jid)s') % {
                                    'jid': self.peer,
                                    'info': color_info,
                                    'jid_c': color_jid
                                }
                        tab.add_message(msg, typ=self.log)
                    else:
                        msg = _(
                            '%(info)sStarted an \x19buntrusted\x19o%(info)s'
                            ' OTR conversation with %(jid_c)s%(jid)s'
                            '%(info)s, key: \x19o%(key)s') % {
                                'jid': self.peer,
                                'key': self.getCurrentKey(),
                                'info': color_info,
                                'jid_c': color_jid
                            }
                        tab.add_message(msg, typ=self.log)
                    hl(tab)

        log.debug('Set encryption state of %s to %s', self.peer,
                  states[newstate])
        super(PoezioContext, self).setState(newstate)
        if tab:
            self.core.refresh_window()
            self.core.doupdate()
Beispiel #33
0
    def on_conversation_msg(self, msg, tab):
        color_jid = '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID)
        color_info = '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
        try:
            ctx = self.get_context(msg['from'])
            txt, tlvs = ctx.receiveMessage(msg["body"].encode('utf-8'))
        except UnencryptedMessage as err:
            # received an unencrypted message inside an OTR session
            text = _('%(info)sThe following message from %(jid_c)s%(jid)s'
                     '%(info)s was \x19bnot\x19o%(info)s encrypted:'
                     '\x19o\n%(msg)s') % {
                         'info': color_info,
                         'jid_c': color_jid,
                         'jid': msg['from'],
                         'msg': err.args[0].decode('utf-8')
                     }
            tab.add_message(text, jid=msg['from'], typ=0)
            del msg['body']
            del msg['html']
            hl(tab)
            self.core.refresh_window()
            return
        except ErrorReceived as err:
            # Received an OTR error
            text = _('%(info)sReceived the following error from '
                     '%(jid_c)s%(jid)s%(info)s:\x19o %(err)s') % {
                         'jid': msg['from'],
                         'err': err.args[0],
                         'info': color_info,
                         'jid_c': color_jid
                     }

            tab.add_message(text, typ=0)
            del msg['body']
            del msg['html']
            hl(tab)
            self.core.refresh_window()
            return
        except NotOTRMessage as err:
            # ignore non-otr messages
            # if we expected an OTR message, we would have
            # got an UnencryptedMesssage
            # but do an additional check because of a bug with py3k
            if ctx.state != STATE_PLAINTEXT or ctx.getPolicy(
                    'REQUIRE_ENCRYPTION'):

                text = _('%(info)sThe following message from '
                         '%(jid_c)s%(jid)s%(info)s was \x19b'
                         'not\x19o%(info)s encrypted:\x19o\n%(msg)s') % {
                             'jid': msg['from'],
                             'msg': err.args[0].decode('utf-8'),
                             'info': color_info,
                             'jid_c': color_jid
                         }
                tab.add_message(text, jid=msg['from'], typ=ctx.log)
                del msg['body']
                del msg['html']
                hl(tab)
                self.core.refresh_window()
                return
            return
        except NotEncryptedError as err:
            text = _('%(info)sAn encrypted message from %(jid_c)s%(jid)s'
                     '%(info)s was received but is unreadable, as you are'
                     ' not currently communicating privately.') % {
                         'info': color_info,
                         'jid_c': color_jid,
                         'jid': msg['from']
                     }
            tab.add_message(text, jid=msg['from'], typ=0)
            hl(tab)
            del msg['body']
            del msg['html']
            self.core.refresh_window()
            return
        except crypt.InvalidParameterError:
            tab.add_message(
                '%sThe message from %s%s%s could not be decrypted.' %
                (color_info, color_jid, msg['from'], color_info),
                jid=msg['from'],
                typ=0)
            hl(tab)
            del msg['body']
            del msg['html']
            self.core.refresh_window()
            return
        except:
            tab.add_message(
                '%sAn unspecified error in the OTR plugin occured' %
                color_info,
                typ=0)
            log.error('Unspecified error in the OTR plugin', exc_info=True)
            return

        # remove xhtml
        del msg['html']
        del msg['body']

        if not txt:
            return
        if isinstance(tab, PrivateTab):
            user = tab.parent_muc.get_user_by_name(msg['from'].resource)
            nick_color = None
        else:
            user = None
            nick_color = get_theme().COLOR_REMOTE_USER

        body = txt.decode()
        decode_entities = self.config.get_by_tabname('decode_entities',
                                                     msg['from'].bare,
                                                     default=True)
        decode_newlines = self.config.get_by_tabname('decode_newlines',
                                                     msg['from'].bare,
                                                     default=True)
        if self.config.get_by_tabname('decode_xhtml',
                                      msg['from'].bare,
                                      default=True):
            try:
                body = xhtml.xhtml_to_poezio_colors(body, force=True)
            except Exception:
                if decode_entities:
                    body = html.unescape(body)
                if decode_newlines:
                    body = body.replace('<br/>', '\n').replace('<br>', '\n')
        else:
            if decode_entities:
                body = html.unescape(body)
            if decode_newlines:
                body = body.replace('<br/>', '\n').replace('<br>', '\n')
        tab.add_message(body,
                        nickname=tab.nick,
                        jid=msg['from'],
                        forced_user=user,
                        typ=ctx.log,
                        nick_color=nick_color)
        hl(tab)
        self.core.refresh_window()
        del msg['body']
Beispiel #34
0
    def command_otr(self, arg):
        """
        /otr [start|refresh|end|fpr|ourfpr]
        """
        arg = arg.strip()
        tab = self.api.current_tab()
        name = tab.name
        color_jid = '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID)
        color_info = '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
        color_normal = '\x19%s}' % dump_tuple(get_theme().COLOR_NORMAL_TEXT)
        if isinstance(tab, DynamicConversationTab) and tab.locked_resource:
            name = safeJID(tab.name)
            name.resource = tab.locked_resource
            name = name.full
        if arg == 'end':  # close the session
            context = self.get_context(name)
            context.disconnect()
            if isinstance(tab,
                          DynamicConversationTab) and not tab.locked_resource:
                ctx = self.find_encrypted_context_with_matching(
                    safeJID(name).bare)
                ctx.disconnect()

        elif arg == 'start' or arg == 'refresh':
            otr = self.get_context(name)
            secs = self.config.get('timeout', 3)
            if isinstance(tab, DynamicConversationTab) and tab.locked_resource:
                was_locked = True
            else:
                was_locked = False

            def notify_otr_timeout():
                nonlocal otr
                if isinstance(tab, DynamicConversationTab) and not was_locked:
                    if tab.locked_resource:
                        name = safeJID(tab.name)
                        name.resource = tab.locked_resource
                        name = name.full
                        otr = self.get_context(name)
                if otr.state != STATE_ENCRYPTED:
                    text = _('%(jid_c)s%(jid)s%(info)s did not enable'
                             ' OTR after %(sec)s seconds.') % {
                                 'jid': tab.name,
                                 'info': color_info,
                                 'jid_c': color_jid,
                                 'sec': secs
                             }
                    tab.add_message(text, typ=0)
                    self.core.refresh_window()

            if secs > 0:
                event = self.api.create_delayed_event(secs, notify_otr_timeout)
                self.api.add_timed_event(event)
            self.core.xmpp.send_message(mto=name,
                                        mtype='chat',
                                        mbody=self.contexts[name].sendMessage(
                                            0, b'?OTRv?').decode())
            text = _(
                '%(info)sOTR request to %(jid_c)s%(jid)s%(info)s sent.') % {
                    'jid': tab.name,
                    'info': color_info,
                    'jid_c': color_jid
                }
            tab.add_message(text, typ=0)
        elif arg == 'ourfpr':
            fpr = self.account.getPrivkey()
            text = _(
                '%(info)sYour OTR key fingerprint is %(norm)s%(fpr)s.') % {
                    'jid': tab.name,
                    'info': color_info,
                    'norm': color_normal,
                    'fpr': fpr
                }
            tab.add_message(text, typ=0)
        elif arg == 'fpr':
            if name in self.contexts:
                ctx = self.contexts[name]
                if ctx.getCurrentKey() is not None:
                    text = _('%(info)sThe key fingerprint for %(jid_c)s'
                             '%(jid)s%(info)s is %(norm)s%(fpr)s%(info)s.') % {
                                 'jid': tab.name,
                                 'info': color_info,
                                 'norm': color_normal,
                                 'jid_c': color_jid,
                                 'fpr': ctx.getCurrentKey()
                             }
                    tab.add_message(text, typ=0)
                else:
                    text = _('%(jid_c)s%(jid)s%(info)s has no'
                             ' key currently in use.') % {
                                 'jid': tab.name,
                                 'info': color_info,
                                 'jid_c': color_jid
                             }
                    tab.add_message(text, typ=0)
        elif arg == 'drop':
            # drop the privkey (and obviously, end the current conversations before that)
            for context in self.contexts.values():
                if context.state not in (STATE_FINISHED, STATE_PLAINTEXT):
                    context.disconnect()
            self.account.drop_privkey()
            tab.add_message('%sPrivate key dropped.' % color_info, typ=0)
        elif arg == 'trust':
            ctx = self.get_context(name)
            key = ctx.getCurrentKey()
            if key:
                fpr = key.cfingerprint()
            else:
                return
            if not ctx.getCurrentTrust():
                ctx.setTrust(fpr, 'verified')
                self.account.saveTrusts()
                text = _('%(info)sYou added %(jid_c)s%(jid)s%(info)s with key '
                         '\x19o%(key)s%(info)s to your trusted list.') % {
                             'jid': ctx.trustName,
                             'key': key,
                             'info': color_info,
                             'jid_c': color_jid
                         }
                tab.add_message(text, typ=0)
        elif arg == 'untrust':
            ctx = self.get_context(name)
            key = ctx.getCurrentKey()
            if key:
                fpr = key.cfingerprint()
            else:
                return
            if ctx.getCurrentTrust():
                ctx.setTrust(fpr, '')
                self.account.saveTrusts()
                text = _(
                    '%(info)sYou removed %(jid_c)s%(jid)s%(info)s with '
                    'key \x19o%(key)s%(info)s from your trusted list.') % {
                        'jid': ctx.trustName,
                        'key': key,
                        'info': color_info,
                        'jid_c': color_jid
                    }

                tab.add_message(text, typ=0)
        self.core.refresh_window()
Beispiel #35
0
    def get_logs(self, jid, nb=10):
        """
        Get the nb last messages from the log history for the given jid.
        Note that a message may be more than one line in these files, so
        this function is a little bit more complicated than “read the last
        nb lines”.
        """
        if config.get_by_tabname('load_log', jid) <= 0:
            return

        if not config.get_by_tabname('use_log', jid):
            return

        if nb <= 0:
            return

        self.check_and_create_log_dir(jid, open_fd=False)

        try:
            fd = open(os.path.join(log_dir, jid), 'rb')
        except:
            log.error('Unable to open the log file (%s)',
                    os.path.join(log_dir, jid),
                    exc_info=True)
            return
        if not fd:
            return

        # read the needed data from the file, we just search nb messages by
        # searching "\nM" nb times from the end of the file.  We use mmap to
        # do that efficiently, instead of seek()s and read()s which are costly.
        with fd:
            try:
                m = mmap.mmap(fd.fileno(), 0, prot=mmap.PROT_READ)
            except Exception: # file probably empty
                log.error('Unable to mmap the log file for (%s)',
                        os.path.join(log_dir, jid),
                        exc_info=True)
                return
            pos = m.rfind(b"\nM") # start of messages begin with MI or MR,
                                  # after a \n
            # number of message found so far
            count = 0
            while pos != -1 and count < nb-1:
                count += 1
                pos = m.rfind(b"\nM", 0, pos)
            if pos == -1:       # If we don't have enough lines in the file
                pos = 1         # 1, because we do -1 just on the next line
                                # to get 0 (start of the file)
            lines = m[pos-1:].decode(errors='replace').splitlines()

        messages = []
        color = '\x19%s}' % dump_tuple(get_theme().COLOR_LOG_MSG)

        # now convert that data into actual Message objects
        idx = 0
        while idx < len(lines):
            if lines[idx].startswith(' '): # should not happen ; skip
                idx += 1
                log.debug('fail?')
                continue
            tup = parse_message_line(lines[idx])
            idx += 1
            if not tup or 7 > len(tup) > 10: # skip
                log.debug('format? %s', tup)
                continue
            time = [int(i) for index, i in enumerate(tup) if index < 6]
            message = {'lines': [],
                       'history': True,
                       'time': common.get_local_time(datetime(*time))}
            size = int(tup[6])
            if len(tup) == 8: #info line
                message['lines'].append(color+tup[7])
            else: # message line
                message['nickname'] = tup[7]
                message['lines'].append(color+tup[8])
            while size != 0 and idx < len(lines):
                message['lines'].append(lines[idx][1:])
                size -= 1
                idx += 1
            message['txt'] = '\n'.join(message['lines'])
            del message['lines']
            messages.append(message)

        return messages
Beispiel #36
0
def command_set(self, args):
    """
    /set [module|][section] <option> [value]
    """
    if args is None or len(args) == 0:
        config_dict = config.to_dict()
        lines = []
        theme = get_theme()
        for section_name, section in config_dict.items():
            lines.append('\x19%(section_col)s}[%(section)s]\x19o' %
                    {
                        'section': section_name,
                        'section_col': dump_tuple(theme.COLOR_INFORMATION_TEXT),
                    })
            for option_name, option_value in section.items():
                lines.append('%s\x19%s}=\x19o%s' % (option_name,
                                                    dump_tuple(theme.COLOR_REVISIONS_MESSAGE),
                                                    option_value))
        info = ('Current  options:\n%s' % '\n'.join(lines), 'Info')
    elif len(args) == 1:
        option = args[0]
        value = config.get(option)
        if value is None and '=' in option:
            args = option.split('=', 1)
        info = ('%s=%s' % (option, value), 'Info')
    if len(args) == 2:
        if '|' in args[0]:
            plugin_name, section = args[0].split('|')[:2]
            if not section:
                section = plugin_name
            option = args[1]
            if not plugin_name in self.plugin_manager.plugins:
                file_name = self.plugin_manager.plugins_conf_dir
                file_name = os.path.join(file_name, plugin_name + '.cfg')
                plugin_config = PluginConfig(file_name, plugin_name)
            else:
                plugin_config = self.plugin_manager.plugins[plugin_name].config
            value = plugin_config.get(option, default='', section=section)
            info = ('%s=%s' % (option, value), 'Info')
        else:
            possible_section = args[0]
            if config.has_section(possible_section):
                section = possible_section
                option = args[1]
                value = config.get(option, section=section)
                info = ('%s=%s' % (option, value), 'Info')
            else:
                option = args[0]
                value = args[1]
                info = config.set_and_save(option, value)
                self.trigger_configuration_change(option, value)
    elif len(args) == 3:
        if '|' in args[0]:
            plugin_name, section = args[0].split('|')[:2]
            if not section:
                section = plugin_name
            option = args[1]
            value = args[2]
            if not plugin_name in self.plugin_manager.plugins:
                file_name = self.plugin_manager.plugins_conf_dir
                file_name = os.path.join(file_name, plugin_name + '.cfg')
                plugin_config = PluginConfig(file_name, plugin_name)
            else:
                plugin_config = self.plugin_manager.plugins[plugin_name].config
            info = plugin_config.set_and_save(option, value, section)
        else:
            if args[0] == '.':
                name = safeJID(self.current_tab().name).bare
                if not name:
                    self.information(_('Invalid tab to use the "." argument.'),
                                     _('Error'))
                    return
                section = name
            else:
                section = args[0]
            option = args[1]
            value = args[2]
            info = config.set_and_save(option, value, section)
            self.trigger_configuration_change(option, value)
    elif len(args) > 3:
        return self.command_help('set')
    self.call_for_resize()
    self.information(*info)
Beispiel #37
0
 def user_left(self, status_message, from_nick):
     """
     The user left the associated MUC
     """
     self.deactivate()
     if not status_message:
         self.add_message(_('\x191}%(spec)s \x193}%(nick)s\x19%(info_col)s} has left the room') % {'nick':from_nick, 'spec':get_theme().CHAR_QUIT, 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)}, typ=2)
     else:
         self.add_message(_('\x191}%(spec)s \x193}%(nick)s\x19%(info_col)s} has left the room (%(status)s)"') % {'nick':from_nick, 'spec':get_theme().CHAR_QUIT, 'status': status_message, 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)}, typ=2)
     return self.core.current_tab() is self
Beispiel #38
0
def command_set(self, args):
    """
    /set [module|][section] <option> [value]
    """
    if args is None or len(args) == 0:
        config_dict = config.to_dict()
        lines = []
        theme = get_theme()
        for section_name, section in config_dict.items():
            lines.append(
                '\x19%(section_col)s}[%(section)s]\x19o' % {
                    'section': section_name,
                    'section_col': dump_tuple(theme.COLOR_INFORMATION_TEXT),
                })
            for option_name, option_value in section.items():
                lines.append(
                    '%s\x19%s}=\x19o%s' %
                    (option_name, dump_tuple(
                        theme.COLOR_REVISIONS_MESSAGE), option_value))
        info = ('Current  options:\n%s' % '\n'.join(lines), 'Info')
    elif len(args) == 1:
        option = args[0]
        value = config.get(option)
        if value is None and '=' in option:
            args = option.split('=', 1)
        info = ('%s=%s' % (option, value), 'Info')
    if len(args) == 2:
        if '|' in args[0]:
            plugin_name, section = args[0].split('|')[:2]
            if not section:
                section = plugin_name
            option = args[1]
            if not plugin_name in self.plugin_manager.plugins:
                file_name = self.plugin_manager.plugins_conf_dir
                file_name = os.path.join(file_name, plugin_name + '.cfg')
                plugin_config = PluginConfig(file_name, plugin_name)
            else:
                plugin_config = self.plugin_manager.plugins[plugin_name].config
            value = plugin_config.get(option, default='', section=section)
            info = ('%s=%s' % (option, value), 'Info')
        else:
            possible_section = args[0]
            if config.has_section(possible_section):
                section = possible_section
                option = args[1]
                value = config.get(option, section=section)
                info = ('%s=%s' % (option, value), 'Info')
            else:
                option = args[0]
                value = args[1]
                info = config.set_and_save(option, value)
                self.trigger_configuration_change(option, value)
    elif len(args) == 3:
        if '|' in args[0]:
            plugin_name, section = args[0].split('|')[:2]
            if not section:
                section = plugin_name
            option = args[1]
            value = args[2]
            if not plugin_name in self.plugin_manager.plugins:
                file_name = self.plugin_manager.plugins_conf_dir
                file_name = os.path.join(file_name, plugin_name + '.cfg')
                plugin_config = PluginConfig(file_name, plugin_name)
            else:
                plugin_config = self.plugin_manager.plugins[plugin_name].config
            info = plugin_config.set_and_save(option, value, section)
        else:
            if args[0] == '.':
                name = safeJID(self.current_tab().name).bare
                if not name:
                    self.information('Invalid tab to use the "." argument.',
                                     'Error')
                    return
                section = name
            else:
                section = args[0]
            option = args[1]
            value = args[2]
            info = config.set_and_save(option, value, section)
            self.trigger_configuration_change(option, value)
    elif len(args) > 3:
        return self.command_help('set')
    self.information(*info)
Beispiel #39
0
    def command_otr(self, arg):
        """
        /otr [start|refresh|end|fpr|ourfpr]
        """
        args = common.shell_split(arg)
        if not args:
            return self.core.command_help('otr')
        action = args.pop(0)
        tab = self.api.current_tab()
        name = tab.name
        if isinstance(tab, DynamicConversationTab) and tab.locked_resource:
            name = safeJID(tab.name)
            name.resource = tab.locked_resource
            name = name.full
        format_dict = {
            'jid_c': '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID),
            'info': '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
            'normal': '\x19%s}' % dump_tuple(get_theme().COLOR_NORMAL_TEXT),
            'jid': name,
            'bare_jid': safeJID(name).bare
        }

        if action == 'end': # close the session
            context = self.get_context(name)
            context.disconnect()
            if isinstance(tab, DynamicConversationTab):
                ctx = self.find_encrypted_context_with_matching(safeJID(name).bare)
                while ctx is not None:
                    ctx.disconnect()
                    ctx = self.find_encrypted_context_with_matching(safeJID(name).bare)
        elif action == 'start' or action == 'refresh':
            self.otr_start(tab, name, format_dict)
        elif action == 'ourfpr':
            format_dict['fpr'] = self.account.getPrivkey()
            tab.add_message(OTR_OWN_FPR % format_dict, typ=0)
        elif action == 'fpr':
            if name in self.contexts:
                ctx = self.contexts[name]
                if ctx.getCurrentKey() is not None:
                    format_dict['fpr'] = ctx.getCurrentKey()
                    tab.add_message(OTR_REMOTE_FPR % format_dict, typ=0)
                else:
                    tab.add_message(OTR_NO_FPR % format_dict, typ=0)
        elif action == 'drop':
            # drop the privkey (and obviously, end the current conversations before that)
            for context in self.contexts.values():
                if context.state not in (STATE_FINISHED, STATE_PLAINTEXT):
                    context.disconnect()
            self.account.drop_privkey()
            tab.add_message(KEY_DROPPED % format_dict, typ=0)
        elif action == 'trust':
            ctx = self.get_context(name)
            key = ctx.getCurrentKey()
            if key:
                fpr = key.cfingerprint()
            else:
                return
            if not ctx.getCurrentTrust():
                format_dict['key'] = key
                ctx.setTrust(fpr, 'verified')
                self.account.saveTrusts()
                tab.add_message(TRUST_ADDED % format_dict, typ=0)
        elif action == 'untrust':
            ctx = self.get_context(name)
            key = ctx.getCurrentKey()
            if key:
                fpr = key.cfingerprint()
            else:
                return
            if ctx.getCurrentTrust():
                format_dict['key'] = key
                ctx.setTrust(fpr, '')
                self.account.saveTrusts()
                tab.add_message(TRUST_REMOVED % format_dict, typ=0)
        self.core.refresh_window()
Beispiel #40
0
    def get_logs(self, jid, nb=10):
        """
        Get the nb last messages from the log history for the given jid.
        Note that a message may be more than one line in these files, so
        this function is a little bit more complicated than “read the last
        nb lines”.
        """
        if config.get_by_tabname('load_log', jid) <= 0:
            return

        if not config.get_by_tabname('use_log', jid):
            return

        if nb <= 0:
            return

        self.check_and_create_log_dir(jid, open_fd=False)

        try:
            fd = open(os.path.join(log_dir, jid), 'rb')
        except FileNotFoundError:
            log.info('Non-existing log file (%s)',
                     os.path.join(log_dir, jid),
                     exc_info=True)
            return
        except OSError:
            log.error('Unable to open the log file (%s)',
                      os.path.join(log_dir, jid),
                      exc_info=True)
            return
        if not fd:
            return

        # read the needed data from the file, we just search nb messages by
        # searching "\nM" nb times from the end of the file.  We use mmap to
        # do that efficiently, instead of seek()s and read()s which are costly.
        with fd:
            try:
                m = mmap.mmap(fd.fileno(), 0, prot=mmap.PROT_READ)
            except Exception:  # file probably empty
                log.error('Unable to mmap the log file for (%s)',
                          os.path.join(log_dir, jid),
                          exc_info=True)
                return
            pos = m.rfind(b"\nM")  # start of messages begin with MI or MR,
            # after a \n
            # number of message found so far
            count = 0
            while pos != -1 and count < nb - 1:
                count += 1
                pos = m.rfind(b"\nM", 0, pos)
            if pos == -1:  # If we don't have enough lines in the file
                pos = 1  # 1, because we do -1 just on the next line
                # to get 0 (start of the file)
            lines = m[pos - 1:].decode(errors='replace').splitlines()

        messages = []
        color = '\x19%s}' % dump_tuple(get_theme().COLOR_LOG_MSG)

        # now convert that data into actual Message objects
        idx = 0
        while idx < len(lines):
            if lines[idx].startswith(' '):  # should not happen ; skip
                idx += 1
                log.debug('fail?')
                continue
            tup = parse_message_line(lines[idx])
            idx += 1
            if not tup or 7 > len(tup) > 10:  # skip
                log.debug('format? %s', tup)
                continue
            time = [int(i) for index, i in enumerate(tup) if index < 6]
            message = {
                'lines': [],
                'history': True,
                'time': common.get_local_time(datetime(*time))
            }
            size = int(tup[6])
            if len(tup) == 8:  #info line
                message['lines'].append(color + tup[7])
            else:  # message line
                message['nickname'] = tup[7]
                message['lines'].append(color + tup[8])
            while size != 0 and idx < len(lines):
                message['lines'].append(lines[idx][1:])
                size -= 1
                idx += 1
            message['txt'] = '\n'.join(message['lines'])
            del message['lines']
            messages.append(message)

        return messages
Beispiel #41
0
    def command_otr(self, arg):
        """
        /otr [start|refresh|end|fpr|ourfpr]
        """
        arg = arg.strip()
        tab = self.api.current_tab()
        name = tab.name
        color_jid = '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID)
        color_info = '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
        color_normal = '\x19%s}' % dump_tuple(get_theme().COLOR_NORMAL_TEXT)
        if isinstance(tab, DynamicConversationTab) and tab.locked_resource:
            name = safeJID(tab.name)
            name.resource = tab.locked_resource
            name = name.full
        if arg == 'end': # close the session
            context = self.get_context(name)
            context.disconnect()
            if isinstance(tab, DynamicConversationTab) and not tab.locked_resource:
                ctx = self.find_encrypted_context_with_matching(safeJID(name).bare)
                ctx.disconnect()

        elif arg == 'start' or arg == 'refresh':
            otr = self.get_context(name)
            secs = self.config.get('timeout', 3)
            if isinstance(tab, DynamicConversationTab) and tab.locked_resource:
                was_locked = True
            else:
                was_locked = False
            def notify_otr_timeout():
                nonlocal otr
                if isinstance(tab, DynamicConversationTab) and not was_locked:
                    if tab.locked_resource:
                        name = safeJID(tab.name)
                        name.resource = tab.locked_resource
                        name = name.full
                        otr = self.get_context(name)
                if otr.state != STATE_ENCRYPTED:
                    text = _('%(jid_c)s%(jid)s%(info)s did not enable'
                             ' OTR after %(sec)s seconds.') % {
                                     'jid': tab.name,
                                     'info': color_info,
                                     'jid_c': color_jid,
                                     'sec': secs}
                    tab.add_message(text, typ=0)
                    self.core.refresh_window()
            if secs > 0:
                event = self.api.create_delayed_event(secs, notify_otr_timeout)
                self.api.add_timed_event(event)
            self.core.xmpp.send_message(mto=name, mtype='chat',
                mbody=self.contexts[name].sendMessage(0, b'?OTRv?').decode())
            text = _('%(info)sOTR request to %(jid_c)s%(jid)s%(info)s sent.') % {
                         'jid': tab.name,
                         'info': color_info,
                         'jid_c': color_jid}
            tab.add_message(text, typ=0)
        elif arg == 'ourfpr':
            fpr = self.account.getPrivkey()
            text = _('%(info)sYour OTR key fingerprint is %(norm)s%(fpr)s.') % {
                         'jid': tab.name,
                         'info': color_info,
                         'norm': color_normal,
                         'fpr': fpr}
            tab.add_message(text, typ=0)
        elif arg == 'fpr':
            if name in self.contexts:
                ctx = self.contexts[name]
                if ctx.getCurrentKey() is not None:
                    text = _('%(info)sThe key fingerprint for %(jid_c)s'
                             '%(jid)s%(info)s is %(norm)s%(fpr)s%(info)s.') % {
                                 'jid': tab.name,
                                 'info': color_info,
                                 'norm': color_normal,
                                 'jid_c': color_jid,
                                 'fpr': ctx.getCurrentKey()}
                    tab.add_message(text, typ=0)
                else:
                    text = _('%(jid_c)s%(jid)s%(info)s has no'
                             ' key currently in use.') % {
                                 'jid': tab.name,
                                 'info': color_info,
                                 'jid_c': color_jid}
                    tab.add_message(text, typ=0)
        elif arg == 'drop':
            # drop the privkey (and obviously, end the current conversations before that)
            for context in self.contexts.values():
                if context.state not in (STATE_FINISHED, STATE_PLAINTEXT):
                    context.disconnect()
            self.account.drop_privkey()
            tab.add_message('%sPrivate key dropped.' % color_info, typ=0)
        elif arg == 'trust':
            ctx = self.get_context(name)
            key = ctx.getCurrentKey()
            if key:
                fpr = key.cfingerprint()
            else:
                return
            if not ctx.getCurrentTrust():
                ctx.setTrust(fpr, 'verified')
                self.account.saveTrusts()
                text = _('%(info)sYou added %(jid_c)s%(jid)s%(info)s with key '
                         '\x19o%(key)s%(info)s to your trusted list.') % {
                                 'jid': ctx.trustName,
                                 'key': key,
                                 'info': color_info,
                                 'jid_c': color_jid}
                tab.add_message(text, typ=0)
        elif arg == 'untrust':
            ctx = self.get_context(name)
            key = ctx.getCurrentKey()
            if key:
                fpr = key.cfingerprint()
            else:
                return
            if ctx.getCurrentTrust():
                ctx.setTrust(fpr, '')
                self.account.saveTrusts()
                text = _('%(info)sYou removed %(jid_c)s%(jid)s%(info)s with '
                         'key \x19o%(key)s%(info)s from your trusted list.') % {
                                 'jid': ctx.trustName,
                                 'key': key,
                                 'info': color_info,
                                 'jid_c': color_jid}

                tab.add_message(text, typ=0)
        self.core.refresh_window()
Beispiel #42
0
    def on_conversation_msg(self, msg, tab):
        color_jid = '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID)
        color_info = '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
        try:
            ctx = self.get_context(msg['from'])
            txt, tlvs = ctx.receiveMessage(msg["body"].encode('utf-8'))
        except UnencryptedMessage as err:
            # received an unencrypted message inside an OTR session
            text = _('%(info)sThe following message from %(jid_c)s%(jid)s'
                     '%(info)s was \x19bnot\x19o%(info)s encrypted:'
                     '\x19o\n%(msg)s') % {
                             'info': color_info,
                             'jid_c': color_jid,
                             'jid': msg['from'],
                             'msg': err.args[0].decode('utf-8')}
            tab.add_message(text, jid=msg['from'],
                            typ=0)
            del msg['body']
            del msg['html']
            hl(tab)
            self.core.refresh_window()
            return
        except ErrorReceived as err:
            # Received an OTR error
            text = _('%(info)sReceived the following error from '
                     '%(jid_c)s%(jid)s%(info)s:\x19o %(err)s') % {
                             'jid': msg['from'],
                             'err': err.args[0],
                             'info': color_info,
                             'jid_c': color_jid}

            tab.add_message(text, typ=0)
            del msg['body']
            del msg['html']
            hl(tab)
            self.core.refresh_window()
            return
        except NotOTRMessage as err:
            # ignore non-otr messages
            # if we expected an OTR message, we would have
            # got an UnencryptedMesssage
            # but do an additional check because of a bug with py3k
            if ctx.state != STATE_PLAINTEXT or ctx.getPolicy('REQUIRE_ENCRYPTION'):

                text = _('%(info)sThe following message from '
                         '%(jid_c)s%(jid)s%(info)s was \x19b'
                         'not\x19o%(info)s encrypted:\x19o\n%(msg)s') % {
                                 'jid': msg['from'],
                                 'msg': err.args[0].decode('utf-8'),
                                 'info': color_info,
                                 'jid_c': color_jid}
                tab.add_message(text, jid=msg['from'],
                                typ=ctx.log)
                del msg['body']
                del msg['html']
                hl(tab)
                self.core.refresh_window()
                return
            return
        except NotEncryptedError as err:
            text = _('%(info)sAn encrypted message from %(jid_c)s%(jid)s'
                     '%(info)s was received but is unreadable, as you are'
                     ' not currently communicating privately.') % {
                             'info': color_info,
                             'jid_c': color_jid,
                             'jid': msg['from']}
            tab.add_message(text, jid=msg['from'],
                            typ=0)
            hl(tab)
            del msg['body']
            del msg['html']
            self.core.refresh_window()
            return
        except crypt.InvalidParameterError:
            tab.add_message('%sThe message from %s%s%s could not be decrypted.'
                            % (color_info, color_jid, msg['from'], color_info),
                            jid=msg['from'], typ=0)
            hl(tab)
            del msg['body']
            del msg['html']
            self.core.refresh_window()
            return
        except:
            tab.add_message('%sAn unspecified error in the OTR plugin occured'
                            % color_info,
                            typ=0)
            log.error('Unspecified error in the OTR plugin', exc_info=True)
            return

        # remove xhtml
        del msg['html']
        del msg['body']

        if not txt:
            return
        if isinstance(tab, PrivateTab):
            user = tab.parent_muc.get_user_by_name(msg['from'].resource)
            nick_color = None
        else:
            user = None
            nick_color = get_theme().COLOR_REMOTE_USER

        body = txt.decode()
        decode_entities = self.config.get_by_tabname('decode_entities',
                                                     msg['from'].bare,
                                                     default=True)
        decode_newlines = self.config.get_by_tabname('decode_newlines',
                                                     msg['from'].bare,
                                                     default=True)
        if self.config.get_by_tabname('decode_xhtml', msg['from'].bare, default=True):
            try:
                body = xhtml.xhtml_to_poezio_colors(body, force=True)
            except Exception:
                if decode_entities:
                    body = html.unescape(body)
                if decode_newlines:
                    body = body.replace('<br/>', '\n').replace('<br>', '\n')
        else:
            if decode_entities:
                body = html.unescape(body)
            if decode_newlines:
                body = body.replace('<br/>', '\n').replace('<br>', '\n')
        tab.add_message(body, nickname=tab.nick, jid=msg['from'],
                        forced_user=user, typ=ctx.log,
                        nick_color=nick_color)
        hl(tab)
        self.core.refresh_window()
        del msg['body']
Beispiel #43
0
    def setState(self, newstate):
        color_jid = '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID)
        color_info = '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT)

        tab = self.core.get_tab_by_name(self.peer)
        if not tab:
            tab = self.core.get_tab_by_name(safeJID(self.peer).bare,
                                            DynamicConversationTab)
            if tab and not tab.locked_resource == safeJID(self.peer).resource:
                tab = None
        if self.state == STATE_ENCRYPTED:
            if newstate == STATE_ENCRYPTED:
                log.debug('OTR conversation with %s refreshed', self.peer)
                if tab:
                    if self.getCurrentTrust():
                        msg = _('%(info)sRefreshed \x19btrusted\x19o%(info)s'
                                ' OTR conversation with %(jid_c)s%(jid)s') % {
                                        'info': color_info,
                                        'jid_c': color_jid,
                                        'jid': self.peer
                                        }
                        tab.add_message(msg, typ=self.log)
                    else:
                        msg = _('%(info)sRefreshed \x19buntrusted\x19o%(info)s'
                                ' OTR conversation with %(jid_c)s%(jid)s'
                                '%(info)s, key: \x19o%(key)s') % {
                                   'jid': self.peer,
                                   'key': self.getCurrentKey(),
                                   'info': color_info,
                                   'jid_c': color_jid}

                        tab.add_message(msg, typ=self.log)
                    hl(tab)
            elif newstate == STATE_FINISHED or newstate == STATE_PLAINTEXT:
                log.debug('OTR conversation with %s finished', self.peer)
                if tab:
                    tab.add_message('%sEnded OTR conversation with %s%s' % (
                                        color_info, color_jid, self.peer),
                                    typ=self.log)
                    hl(tab)
        else:
            if newstate == STATE_ENCRYPTED:
                if tab:
                    if self.getCurrentTrust():
                        msg = _('%(info)sStarted a \x19btrusted\x19o%(info)s '
                                'OTR conversation with %(jid_c)s%(jid)s') % {
                                        'jid': self.peer,
                                        'info': color_info,
                                        'jid_c': color_jid}
                        tab.add_message(msg, typ=self.log)
                    else:
                        msg = _('%(info)sStarted an \x19buntrusted\x19o%(info)s'
                                ' OTR conversation with %(jid_c)s%(jid)s'
                                '%(info)s, key: \x19o%(key)s') % {
                                        'jid': self.peer,
                                        'key': self.getCurrentKey(),
                                        'info': color_info,
                                        'jid_c': color_jid}
                        tab.add_message(msg, typ=self.log)
                    hl(tab)

        log.debug('Set encryption state of %s to %s', self.peer, states[newstate])
        super(PoezioContext, self).setState(newstate)
        if tab:
            self.core.refresh_window()
            self.core.doupdate()
Beispiel #44
0
 def rename_user(self, old_nick, new_nick):
     """
     The user changed her nick in the corresponding muc: update the tab’s name and
     display a message.
     """
     self.add_message('\x193}%(old)s\x19%(info_col)s} is now known as \x193}%(new)s' % {'old':old_nick, 'new':new_nick, 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)}, typ=2)
     new_jid = safeJID(self.name).bare+'/'+new_nick
     self.name = new_jid
     return self.core.current_tab() is self
Beispiel #45
0
def test_dump_tuple():
    assert dump_tuple((1, 2)) == '1,2'
    assert dump_tuple((1, )) == '1'
    assert dump_tuple((1, 2, 'u')) == '1,2,u'
Beispiel #46
0
    def on_conversation_msg(self, msg, tab):
        """
        Message received
        """
        format_dict = {
            'jid_c': '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID),
            'info':  '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
            'jid': msg['from']
        }
        try:
            ctx = self.get_context(msg['from'])
            txt, tlvs = ctx.receiveMessage(msg["body"].encode('utf-8'))

            # SMP
            if tlvs:
                self.handle_tlvs(tlvs, ctx, tab, format_dict)
        except UnencryptedMessage as err:
            # received an unencrypted message inside an OTR session
            self.unencrypted_message_received(err, ctx, msg, tab, format_dict)
            self.otr_start(tab, tab.name, format_dict)
            return
        except NotOTRMessage as err:
            # ignore non-otr messages
            # if we expected an OTR message, we would have
            # got an UnencryptedMesssage
            # but do an additional check because of a bug with potr and py3k
            if ctx.state != STATE_PLAINTEXT or ctx.getPolicy('REQUIRE_ENCRYPTION'):
                self.unencrypted_message_received(err, ctx, msg, tab, format_dict)
                self.otr_start(tab, tab.name, format_dict)
            return
        except ErrorReceived as err:
            # Received an OTR error
            format_dict['err'] = err.args[0].error.decode('utf-8', errors='replace')
            tab.add_message(OTR_ERROR % format_dict, typ=0)
            del msg['body']
            del msg['html']
            hl(tab)
            self.core.refresh_window()
            return
        except NotEncryptedError as err:
            # Encrypted message received, but unreadable as we do not have
            # an OTR session in place.
            text = MESSAGE_UNREADABLE % format_dict
            tab.add_message(text, jid=msg['from'], typ=0)
            hl(tab)
            del msg['body']
            del msg['html']
            self.core.refresh_window()
            return
        except crypt.InvalidParameterError:
            # Malformed OTR payload and stuff
            text = MESSAGE_INVALID % format_dict
            tab.add_message(text, jid=msg['from'], typ=0)
            hl(tab)
            del msg['body']
            del msg['html']
            self.core.refresh_window()
            return
        except Exception:
            # Unexpected error
            import traceback
            exc = traceback.format_exc()
            format_dict['exc'] = exc
            tab.add_message(POTR_ERROR % format_dict, typ=0)
            log.error('Unspecified error in the OTR plugin', exc_info=True)
            return
        # No error, proceed with the message
        self.encrypted_message_received(msg, ctx, tab, txt)
Beispiel #47
0
    def command_otr(self, arg):
        """
        /otr [start|refresh|end|fpr|ourfpr]
        """
        args = common.shell_split(arg)
        if not args:
            return self.core.command_help('otr')
        action = args.pop(0)
        tab = self.api.current_tab()
        name = tab.name
        if isinstance(tab, DynamicConversationTab) and tab.locked_resource:
            name = safeJID(tab.name)
            name.resource = tab.locked_resource
            name = name.full
        format_dict = {
            'jid_c': '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID),
            'info': '\x19%s}' % dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
            'normal': '\x19%s}' % dump_tuple(get_theme().COLOR_NORMAL_TEXT),
            'jid': name,
            'bare_jid': safeJID(name).bare
        }

        if action == 'end': # close the session
            context = self.get_context(name)
            context.disconnect()
            if isinstance(tab, DynamicConversationTab):
                ctx = self.find_encrypted_context_with_matching(safeJID(name).bare)
                while ctx is not None:
                    ctx.disconnect()
                    ctx = self.find_encrypted_context_with_matching(safeJID(name).bare)
        elif action == 'start' or action == 'refresh':
            self.otr_start(tab, name, format_dict)
        elif action == 'ourfpr':
            format_dict['fpr'] = self.account.getPrivkey()
            tab.add_message(OTR_OWN_FPR % format_dict, typ=0)
        elif action == 'fpr':
            if name in self.contexts:
                ctx = self.contexts[name]
                if ctx.getCurrentKey() is not None:
                    format_dict['fpr'] = ctx.getCurrentKey()
                    tab.add_message(OTR_REMOTE_FPR % format_dict, typ=0)
                else:
                    tab.add_message(OTR_NO_FPR % format_dict, typ=0)
        elif action == 'drop':
            # drop the privkey (and obviously, end the current conversations before that)
            for context in self.contexts.values():
                if context.state not in (STATE_FINISHED, STATE_PLAINTEXT):
                    context.disconnect()
            self.account.drop_privkey()
            tab.add_message(KEY_DROPPED % format_dict, typ=0)
        elif action == 'trust':
            ctx = self.get_context(name)
            key = ctx.getCurrentKey()
            if key:
                fpr = key.cfingerprint()
            else:
                return
            if not ctx.getCurrentTrust():
                format_dict['key'] = key
                ctx.setTrust(fpr, 'verified')
                self.account.saveTrusts()
                tab.add_message(TRUST_ADDED % format_dict, typ=0)
        elif action == 'untrust':
            ctx = self.get_context(name)
            key = ctx.getCurrentKey()
            if key:
                fpr = key.cfingerprint()
            else:
                return
            if ctx.getCurrentTrust():
                format_dict['key'] = key
                ctx.setTrust(fpr, '')
                self.account.saveTrusts()
                tab.add_message(TRUST_REMOVED % format_dict, typ=0)
        self.core.refresh_window()