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') 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 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 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.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.core.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 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 do_notify(self, message, fro): body = clean_text(get_body_from_message_stanza(message)) if not body: return command = self.config.get('command', '').strip() if not command: self.core.information('No notification command was provided in the configuration file', 'Warning') return self.core.exec_command(command % {'body':pipes.quote(body), 'from':pipes.quote(fro)}) after_command = self.config.get('after_command', '').strip() if not after_command: return delayed_event = DelayedEvent(self.config.get('delay', 1), self.core.exec_command, after_command % {'body':pipes.quote(body), 'from':pipes.quote(fro)}) self.core.add_timed_event(delayed_event)
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 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 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 do_notify(self, message, fro): body = clean_text(get_body_from_message_stanza(message)) if not body: return command_str = self.config.get('command', '').strip() if not command_str: self.core.information('No notification command was provided in the configuration file', 'Warning') return command = [arg % {'body': body.replace('\n', ' '), 'from': fro} for arg in shlex.split(command_str)] self.core.exec_command(command) after_command_str = self.config.get('after_command', '').strip() if not after_command_str: return after_command = [arg % {'body': body.replace('\n', ' '), 'from': fro} for arg in shlex.split(after_command_str)] delayed_event = DelayedEvent(self.config.get('delay', 1), self.core.exec_command, after_command) self.core.add_timed_event(delayed_event)
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: if self.match_stanza(ElementBase(ET.fromstring(clean_text(msg.txt)))): new_messages.append(msg) self.filtered_buffer.messages = new_messages self.text_win.rebuild_everything(self.filtered_buffer) self.gen_filter_repr()
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 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 = list() 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 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: if self.match_stanza( ElementBase(ET.fromstring(clean_text(msg.txt)))): new_messages.append(msg) self.filtered_buffer.messages = new_messages self.text_win.rebuild_everything(self.filtered_buffer) self.gen_filter_repr()
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 = list() 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 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 command_quote(self, args): args = common.shell_split(args) if len(args) in (1, 2): timestamp = args[-1] else: return self.core.command_help('quote') if re.match(timestamp_re, timestamp) is None: return self.core.information('Timestamp has a wrong format.', 'Warning') message = self.find_message_with_timestamp(timestamp) 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.core.information('No message found for timestamp %s.' % timestamp, 'Warning')
def log_message(self, jid, nick, msg): """ log the message in the appropriate jid's file """ if jid in self.fds.keys(): fd = self.fds[jid] else: fd = self.check_and_create_log_dir(jid) if not fd: return try: msg = clean_text(msg) if nick: fd.write(datetime.now().strftime('%d-%m-%y [%H:%M:%S] ')+nick+': '+msg+'\n') else: fd.write(datetime.now().strftime('%d-%m-%y [%H:%M:%S] ')+'* '+msg+'\n') except IOError: pass else: fd.flush() # TODO do something better here?
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_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 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 setoilette(self, msg, tab): """ split body, get html toilet result, remove title, convert to poezio style """ msgsplit = xhtml.clean_text(msg['body']).split() # check if ok if len(msgsplit) > 2 and self.nocommand(msgsplit[0]) and self.nocommand(msgsplit[1]) and self.nocommand(' '.join(msgsplit[2:])): xhtml_result = None try: # -f == --font && -E == --export <format> process = subprocess.Popen(['toilet', '-E', 'html', '-f', msgsplit[0], '--filter', msgsplit[1], ' '.join(msgsplit[2:])], stdout=subprocess.PIPE) xhtml_result = process.communicate()[0].decode('utf-8') except: xhtml_result = None if xhtml_result: # remove title titlefind = xhtml_result.find('<title>') if titlefind: xhtml_result = xhtml_result[:titlefind] + xhtml_result[xhtml_result.find('</title>')+8:] # convert to poezio color ## not work like wanted, color not show result = "\n" + xhtml.xhtml_to_poezio_colors(xhtml_result) msg['body'] = result else: msg['body'] = ' '.join(msgsplit[2:])
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 caps(self, msg, tab): msg['body'] = xhtml.clean_text(msg['body']).upper()
def whiteify(msg, _): msg['body'] = '\x197}' + xhtml.clean_text(msg['body'])
def message_match(msg): return input_message.lower() in clean_text(msg.txt).lower()
def rainbowize(self, msg, tab): msg['body'] = ''.join(['%s%s' % (rand_color(),char,) for char in xhtml.clean_text(msg['body'])])
def rainbowize(self, msg, tab): msg["body"] = "".join(["%s%s" % (rand_color(), char) for char in xhtml.clean_text(msg["body"])])
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 shuffle(self, msg, tab): split = xhtml.clean_text(msg['body']).split() shuffle(split) msg['body'] = ' '.join(split)