def log_roster_change(self, jid, message): """ Log a roster change """ if not config.get_by_tabname('use_log', jid): return True self._check_and_create_log_dir('', open_fd=False) if not self._roster_logfile: try: self._roster_logfile = open(os.path.join( log_dir, 'roster.log'), 'a', encoding='utf-8') except IOError: log.error('Unable to create the log file (%s)', os.path.join(log_dir, 'roster.log'), exc_info=True) return False try: str_time = common.get_utc_time().strftime('%Y%m%dT%H:%M:%SZ') message = clean_text(message) lines = message.split('\n') first_line = lines.pop(0) nb_lines = str(len(lines)).zfill(3) self._roster_logfile.write('MI %s %s %s %s\n' % (str_time, nb_lines, jid, first_line)) for line in lines: self._roster_logfile.write(' %s\n' % line) self._roster_logfile.flush() except: log.error('Unable to write in the log file (%s)', os.path.join(log_dir, 'roster.log'), exc_info=True) return False return True
def rainbowize(self, msg, tab): msg['body'] = ''.join([ '%s%s' % ( rand_color(), char, ) for char in xhtml.clean_text(msg['body']) ])
def build_log_message(nick: str, msg: str, date: Optional[datetime] = None, typ: int = 1) -> str: """ Create a log message from a nick, a message, optionally a date and type message types: 0 = Don’t log 1 = Message 2 = Status/whatever """ if not typ: return '' msg = clean_text(msg) time = common.get_utc_time() if date is None else common.get_utc_time(date) str_time = time.strftime('%Y%m%dT%H:%M:%SZ') prefix = 'MR' if typ == 1 else 'MI' lines = msg.split('\n') first_line = lines.pop(0) nb_lines = str(len(lines)).zfill(3) if nick: nick = '<' + nick + '>' logged_msg = '%s %s %s %s %s\n' % (prefix, str_time, nb_lines, nick, first_line) else: logged_msg = '%s %s %s %s\n' % (prefix, str_time, nb_lines, first_line) return logged_msg + ''.join(' %s\n' % line for line in lines)
def build_log_message(nick, msg, date=None, typ=1): """ Create a log message from a nick, a message, optionally a date and type message types: 0 = Don’t log 1 = Message 2 = Status/whatever """ if not typ: return '' msg = clean_text(msg) if date is None: str_time = common.get_utc_time().strftime('%Y%m%dT%H:%M:%SZ') else: str_time = common.get_utc_time(date).strftime('%Y%m%dT%H:%M:%SZ') if typ == 1: prefix = 'MR' else: prefix = 'MI' lines = msg.split('\n') first_line = lines.pop(0) nb_lines = str(len(lines)).zfill(3) if nick: nick = '<' + nick + '>' logged_msg = '%s %s %s %s %s\n' % (prefix, str_time, nb_lines, nick, first_line) else: logged_msg = '%s %s %s %s\n' % (prefix, str_time, nb_lines, first_line) return logged_msg + ''.join(' %s\n' % line for line in lines)
def log_roster_change(self, jid: str, message: str) -> bool: """ Log a roster change """ if not config.get_by_tabname('use_log', jid): return True self._check_and_create_log_dir('', open_fd=False) filename = log_dir / 'roster.log' if not self._roster_logfile: try: self._roster_logfile = filename.open('a', encoding='utf-8') except IOError: log.error( 'Unable to create the log file (%s)', filename, exc_info=True) return False try: str_time = common.get_utc_time().strftime('%Y%m%dT%H:%M:%SZ') message = clean_text(message) lines = message.split('\n') first_line = lines.pop(0) nb_lines = str(len(lines)).zfill(3) self._roster_logfile.write( 'MI %s %s %s %s\n' % (str_time, nb_lines, jid, first_line)) for line in lines: self._roster_logfile.write(' %s\n' % line) self._roster_logfile.flush() except: log.error( 'Unable to write in the log file (%s)', filename, exc_info=True) return False return True
def command_say(self, line, attention=False, correct=False): msg = self.core.xmpp.make_message(self.get_dest_jid()) msg['type'] = 'chat' msg['body'] = line if not self.nick_sent: msg['nick'] = self.core.own_nick self.nick_sent = True # trigger the event BEFORE looking for colors. # and before displaying the message in the window # This lets a plugin insert \x19xxx} colors, that will # be converted in xhtml. self.core.events.trigger('conversation_say', msg, self) if not msg['body']: self.cancel_paused_delay() self.text_win.refresh() self.input.refresh() return replaced = False if correct or msg['replace']['id']: msg['replace']['id'] = self.last_sent_message['id'] if config.get_by_tabname('group_corrections', self.name): try: self.modify_message(msg['body'], self.last_sent_message['id'], msg['id'], jid=self.core.xmpp.boundjid, nickname=self.core.own_nick) replaced = True except: log.error('Unable to correct a message', exc_info=True) else: del msg['replace'] if msg['body'].find('\x19') != -1: msg.enable('html') msg['html']['body'] = xhtml.poezio_colors_to_html(msg['body']) msg['body'] = xhtml.clean_text(msg['body']) if (config.get_by_tabname('send_chat_states', self.general_jid) and self.remote_wants_chatstates is not False): needed = 'inactive' if self.inactive else 'active' msg['chat_state'] = needed if attention and self.remote_supports_attention: msg['attention'] = True self.core.events.trigger('conversation_say_after', msg, self) if not msg['body']: self.cancel_paused_delay() self.text_win.refresh() self.input.refresh() return if not replaced: self.add_message(msg['body'], nickname=self.core.own_nick, nick_color=get_theme().COLOR_OWN_NICK, identifier=msg['id'], jid=self.core.xmpp.boundjid, typ=1) self.last_sent_message = msg if self.remote_supports_receipts: msg._add_receipt = True msg.send() self.cancel_paused_delay() self.text_win.refresh() self.input.refresh()
def command_say(self, line, attention=False, correct=False): msg = self.core.xmpp.make_message(self.get_dest_jid()) msg['type'] = 'chat' msg['body'] = line if not self.nick_sent: msg['nick'] = self.core.own_nick self.nick_sent = True # trigger the event BEFORE looking for colors. # and before displaying the message in the window # This lets a plugin insert \x19xxx} colors, that will # be converted in xhtml. self.core.events.trigger('conversation_say', msg, self) if not msg['body']: self.cancel_paused_delay() self.text_win.refresh() self.input.refresh() return replaced = False if correct or msg['replace']['id']: msg['replace']['id'] = self.last_sent_message['id'] if config.get_by_tabname('group_corrections', self.name): try: self.modify_message(msg['body'], self.last_sent_message['id'], msg['id'], jid=self.core.xmpp.boundjid, nickname=self.core.own_nick) replaced = True except CorrectionError: log.error('Unable to correct a message', exc_info=True) else: del msg['replace'] if msg['body'].find('\x19') != -1: msg.enable('html') msg['html']['body'] = xhtml.poezio_colors_to_html(msg['body']) msg['body'] = xhtml.clean_text(msg['body']) if (config.get_by_tabname('send_chat_states', self.general_jid) and self.remote_wants_chatstates is not False): needed = 'inactive' if self.inactive else 'active' msg['chat_state'] = needed if attention and self.remote_supports_attention: msg['attention'] = True self.core.events.trigger('conversation_say_after', msg, self) if not msg['body']: self.cancel_paused_delay() self.text_win.refresh() self.input.refresh() return if not replaced: self.add_message(msg['body'], nickname=self.core.own_nick, nick_color=get_theme().COLOR_OWN_NICK, identifier=msg['id'], jid=self.core.xmpp.boundjid, typ=1) self.last_sent_message = msg if self.remote_supports_receipts: msg._add_receipt = True msg.send() self.cancel_paused_delay() self.text_win.refresh() self.input.refresh()
def find_message(self, txt): messages = self.api.get_conversation_messages() if not messages: return None for message in messages[::-1]: if clean_text(message.txt) == txt: return message return None
def log_message(self, jid, nick, msg, date=None, typ=1): """ log the message in the appropriate jid's file type: 0 = Don’t log 1 = Message 2 = Status/whatever """ if not typ: return True jid = str(jid).replace('/', '\\') if not config.get_by_tabname('use_log', jid): return True if jid in self._fds.keys(): fd = self._fds[jid] else: fd = self._check_and_create_log_dir(jid) if not fd: return True try: msg = clean_text(msg) if date is None: str_time = common.get_utc_time().strftime('%Y%m%dT%H:%M:%SZ') else: str_time = common.get_utc_time(date).strftime( '%Y%m%dT%H:%M:%SZ') if typ == 1: prefix = 'MR' else: prefix = 'MI' lines = msg.split('\n') first_line = lines.pop(0) nb_lines = str(len(lines)).zfill(3) if nick: nick = '<' + nick + '>' fd.write(' '.join((prefix, str_time, nb_lines, nick, ' ' + first_line, '\n'))) else: fd.write(' '.join( (prefix, str_time, nb_lines, first_line, '\n'))) for line in lines: fd.write(' %s\n' % line) except: log.error('Unable to write in the log file (%s)', os.path.join(log_dir, jid), exc_info=True) return False else: try: fd.flush() # TODO do something better here? except: log.error('Unable to flush the log file (%s)', os.path.join(log_dir, jid), exc_info=True) return False return True
def log_message(self, jid, nick, msg, date=None, typ=1): """ log the message in the appropriate jid's file type: 0 = Don’t log 1 = Message 2 = Status/whatever """ if not typ: return True jid = str(jid).replace('/', '\\') if not config.get_by_tabname('use_log', jid): return True if jid in self._fds.keys(): fd = self._fds[jid] else: fd = self._check_and_create_log_dir(jid) if not fd: return True try: msg = clean_text(msg) if date is None: str_time = common.get_utc_time().strftime('%Y%m%dT%H:%M:%SZ') else: str_time = common.get_utc_time(date).strftime('%Y%m%dT%H:%M:%SZ') if typ == 1: prefix = 'MR' else: prefix = 'MI' lines = msg.split('\n') first_line = lines.pop(0) nb_lines = str(len(lines)).zfill(3) if nick: nick = '<' + nick + '>' fd.write(' '.join((prefix, str_time, nb_lines, nick, ' '+first_line, '\n'))) else: fd.write(' '.join((prefix, str_time, nb_lines, first_line, '\n'))) for line in lines: fd.write(' %s\n' % line) except: log.error('Unable to write in the log file (%s)', os.path.join(log_dir, jid), exc_info=True) return False else: try: fd.flush() # TODO do something better here? except: log.error('Unable to flush the log file (%s)', os.path.join(log_dir, jid), exc_info=True) return False return True
def command_marquee(self, args): tab = self.api.current_tab() args = xhtml.clean_text(xhtml.convert_simple_to_full_colors(args)) tab.command_say(args) is_muctab = isinstance(tab, tabs.MucTab) msg_id = tab.last_sent_message["id"] jid = tab.jid event = self.api.create_delayed_event( self.config.get("refresh"), self.delayed_event, jid, args, msg_id, 1, 0, is_muctab) self.api.add_timed_event(event)
def command_marquee(self, args): tab = self.api.current_tab() args = xhtml.clean_text(xhtml.convert_simple_to_full_colors(args)) tab.command_say(args) is_muctab = isinstance(tab, tabs.MucTab) msg_id = tab.last_sent_message["id"] jid = tab.name event = self.api.create_delayed_event( self.config.get("refresh"), self.delayed_event, jid, args, msg_id, 1, 0, is_muctab) self.api.add_timed_event(event)
def find_link(self, nb): messages = self.api.get_conversation_messages() if not messages: return None for message in messages[::-1]: matches = url_pattern.findall(clean_text(message.txt)) if matches: for url in matches[::-1]: if nb == 1: return url else: nb -= 1 return None
def completion_quote(self, the_input): def message_match(msg): return input_message.lower() in clean_text(msg.txt).lower() messages = self.api.get_conversation_messages() if not messages: return text = the_input.get_text() args = common.shell_split(text) if not text.endswith(' '): input_message = args[-1] messages = list(filter(message_match, messages)) elif len(args) > 1: return False return the_input.auto_completion([clean_text(msg.txt) for msg in messages[::-1]], '')
def command_dump(self, args): """/dump <filename>""" if args is None: return self.core.command.help('dump') if self.filters: xml = self.filtered_buffer.messages[:] else: xml = self.core_buffer.messages[:] text = '\n'.join(('%s %s %s' % (msg.str_time, msg.nickname, clean_text(msg.txt)) for msg in xml)) filename = os.path.expandvars(os.path.expanduser(args[0])) try: with open(filename, 'w') as fd: fd.write(text) except Exception as e: self.core.information('Could not write the XML dump: %s' % e, 'Error')
def generate_xhtml_message(self, arg): if not arg: return try: body = xhtml.clean_text(xhtml.xhtml_to_poezio_colors(arg)) ET.fromstring(arg) except: self.core.information('Could not send custom xhtml', 'Error') log.error('/xhtml: Unable to send custom xhtml', exc_info=True) return msg = self.core.xmpp.make_message(self.get_dest_jid()) msg['body'] = body msg.enable('html') msg['html']['body'] = arg return msg
def completion_quote(self, the_input): def message_match(msg): return input_message.lower() in clean_text(msg.txt).lower() messages = self.api.get_conversation_messages() if not messages: return text = the_input.get_text() args = common.shell_split(text) if not text.endswith(' '): input_message = args[-1] messages = list(filter(message_match, messages)) elif len(args) > 1: return False return Completion(the_input.auto_completion, [clean_text(msg.txt) for msg in messages[::-1]], '')
def command_quote(self, args): args = common.shell_split(args) if len(args) == 1: message = args[-1] else: return self.api.run_command('/help quote') message = self.find_message(message) if message: before = self.config.get('before_quote', '') % {'nick': message.nickname or '', 'time': message.str_time} after = self.config.get('after_quote', '') % {'nick': message.nickname or '', 'time': message.str_time} self.core.insert_input_text('%(before)s%(quote)s%(after)s' % {'before': before.replace('\\n', '\n').replace('[SP]', ' '), 'quote': clean_text(message.txt), 'after': after.replace('\\n', '\n').replace('[SP]', ' ')}) else: self.api.information('No message found', 'Warning')
def last_words_completion(self): """ Complete the input with words recently said """ # build the list of the recent words char_we_dont_want = string.punctuation + ' ’„“”…«»' words = [] for msg in self._text_buffer.messages[:-40:-1]: if not msg: continue txt = xhtml.clean_text(msg.txt) for char in char_we_dont_want: txt = txt.replace(char, ' ') for word in txt.split(): if len(word) >= 4 and word not in words: words.append(word) words.extend([word for word in config.get('words').split(':') if word]) self.input.auto_completion(words, ' ', quotify=False)
def command_say(self, line: str, attention: bool = False, correct: bool = False) -> None: if not self.on: return our_jid = JID(self.jid.bare) our_jid.resource = self.own_nick msg = self.core.xmpp.make_message( mto=self.jid.full, mfrom=our_jid, ) msg['type'] = 'chat' msg['body'] = line x = ET.Element('{%s}x' % NS_MUC_USER) msg.append(x) # trigger the event BEFORE looking for colors. # This lets a plugin insert \x19xxx} colors, that will # be converted in xhtml. self.core.events.trigger('private_say', msg, self) if not msg['body']: return if correct or msg['replace']['id']: msg['replace']['id'] = self.last_sent_message['id'] else: del msg['replace'] if msg['body'].find('\x19') != -1: msg.enable('html') msg['html']['body'] = xhtml.poezio_colors_to_html(msg['body']) msg['body'] = xhtml.clean_text(msg['body']) if config.get_by_tabname('send_chat_states', self.general_jid): needed = 'inactive' if self.inactive else 'active' msg['chat_state'] = needed if attention: msg['attention'] = True self.core.events.trigger('private_say_after', msg, self) if not msg['body']: return self.set_last_sent_message(msg, correct=correct) self.core.handler.on_groupchat_private_message(msg, sent=True) msg._add_receipt = True msg.send() self.cancel_paused_delay()
def stoi(self, args): messages = self.api.get_conversation_messages() if not messages: # Do nothing if the conversation doesn’t contain any message return last_message = messages[-1] txt = xhtml.clean_text(last_message.txt) for char in char_we_dont_want: txt = txt.replace(char, ' ') if txt.strip(): last_word = txt.split()[-1] else: last_word = "vide" intro = "C'est toi " if random.getrandbits(1) else "Stoi " if last_word[0] in 'aeiouAEIOUÀàÉéÈè': msg = intro + ('l’%s' % last_word) else: msg = intro + ('le %s' % last_word) self.api.send_message(msg)
def update_filters(self, matcher): if not self.filters: messages = self.core_buffer.messages[:] self.filtered_buffer.messages = [] self.core_buffer.del_window(self.text_win) self.filtered_buffer.add_window(self.text_win) else: messages = self.filtered_buffer.messages self.filtered_buffer.messages = [] self.filters.append(matcher) new_messages = [] for msg in messages: try: if msg.txt.strip() and self.match_stanza(ElementBase(ET.fromstring(clean_text(msg.txt)))): new_messages.append(msg) except ET.ParseError: log.debug('Malformed XML : %s', msg.txt, exc_info=True) self.filtered_buffer.messages = new_messages self.text_win.rebuild_everything(self.filtered_buffer) self.gen_filter_repr()
def command_say(self, line, attention=False, correct=False): msg = self.core.xmpp.make_message(mto=self.get_dest_jid(), mfrom=self.core.xmpp.boundjid) msg['type'] = 'chat' msg['body'] = line if not self.nick_sent: msg['nick'] = self.core.own_nick self.nick_sent = True # trigger the event BEFORE looking for colors. # and before displaying the message in the window # This lets a plugin insert \x19xxx} colors, that will # be converted in xhtml. self.core.events.trigger('conversation_say', msg, self) if not msg['body']: return replaced = False if correct or msg['replace']['id']: msg['replace']['id'] = self.last_sent_message['id'] else: del msg['replace'] if msg['body'].find('\x19') != -1: msg.enable('html') msg['html']['body'] = xhtml.poezio_colors_to_html(msg['body']) msg['body'] = xhtml.clean_text(msg['body']) if config.get_by_tabname('send_chat_states', self.general_jid): needed = 'inactive' if self.inactive else 'active' msg['chat_state'] = needed if attention: msg['attention'] = True self.core.events.trigger('conversation_say_after', msg, self) if not msg['body']: return self.last_sent_message = msg self.core.handler.on_normal_message(msg) msg._add_receipt = True msg.send() self.cancel_paused_delay()
def command_quote(self, args): args = common.shell_split(args) if len(args) == 1: message = args[-1] else: return self.api.run_command('/help quote') message = self.find_message(message) if message: before = self.config.get('before_quote', '') % { 'nick': message.nickname or '', 'time': message.str_time } after = self.config.get('after_quote', '') % { 'nick': message.nickname or '', 'time': message.str_time } self.core.insert_input_text( '%(before)s%(quote)s%(after)s' % { 'before': before.replace('\\n', '\n').replace('[SP]', ' '), 'quote': clean_text(message.txt), 'after': after.replace('\\n', '\n').replace('[SP]', ' ') }) else: self.api.information('No message found', 'Warning')
def command_say(self, line, attention=False, correct=False): if not self.on: return echo_message = JID(self.name).resource != self.own_nick msg = self.core.xmpp.make_message(self.name) msg['type'] = 'chat' msg['body'] = line # trigger the event BEFORE looking for colors. # This lets a plugin insert \x19xxx} colors, that will # be converted in xhtml. self.core.events.trigger('private_say', msg, self) if not msg['body']: self.cancel_paused_delay() self.text_win.refresh() self.input.refresh() return user = self.parent_muc.get_user_by_name(self.own_nick) replaced = False if correct or msg['replace']['id']: msg['replace']['id'] = self.last_sent_message['id'] if (config.get_by_tabname('group_corrections', self.name) and echo_message): try: self.modify_message( msg['body'], self.last_sent_message['id'], msg['id'], user=user, jid=self.core.xmpp.boundjid, nickname=self.own_nick) replaced = True except: log.error('Unable to correct a message', exc_info=True) else: del msg['replace'] if msg['body'].find('\x19') != -1: msg.enable('html') msg['html']['body'] = xhtml.poezio_colors_to_html(msg['body']) msg['body'] = xhtml.clean_text(msg['body']) if config.get_by_tabname('send_chat_states', self.general_jid): needed = 'inactive' if self.inactive else 'active' msg['chat_state'] = needed if attention: msg['attention'] = True self.core.events.trigger('private_say_after', msg, self) if not msg['body']: self.cancel_paused_delay() self.text_win.refresh() self.input.refresh() return if not replaced and echo_message: self.add_message( msg['body'], nickname=self.own_nick or self.core.own_nick, forced_user=user, nick_color=get_theme().COLOR_OWN_NICK, identifier=msg['id'], jid=self.core.xmpp.boundjid, typ=1) self.last_sent_message = msg msg._add_receipt = True msg.send() self.cancel_paused_delay() self.text_win.refresh() self.input.refresh()
def test_clean_text(): example_string = '\x191}Toto \x192,-1}titi\x19b Tata' assert clean_text(example_string) == 'Toto titi Tata' clean_string = 'toto titi tata' assert clean_text(clean_string) == clean_string
def add_spaces(self, msg, tab): msg['body'] = " ".join(x for x in xhtml.clean_text(msg['body']))
def revstr(self, msg, tab): msg['body'] = xhtml.clean_text(msg['body'])[::-1]
def caps(self, msg, tab): msg['body'] = xhtml.clean_text(msg['body']).upper()
def message_match(msg): return input_message.lower() in clean_text(msg.txt).lower()
def whiteify(msg, _): msg['body'] = '\x197}' + xhtml.clean_text(msg['body'])
def shuffle(self, msg, tab): split = xhtml.clean_text(msg['body']).split() shuffle(split) msg['body'] = ' '.join(split)