diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/b64.py | 53 | ||||
-rw-r--r-- | plugins/bob.py | 2 | ||||
-rw-r--r-- | plugins/dice.py | 4 | ||||
-rw-r--r-- | plugins/display_corrections.py | 2 | ||||
-rw-r--r-- | plugins/emoji_ascii.py | 58 | ||||
-rw-r--r-- | plugins/figlet.py | 22 | ||||
-rw-r--r-- | plugins/irc.py | 2 | ||||
-rw-r--r-- | plugins/lastlog.py | 64 | ||||
-rw-r--r-- | plugins/link.py | 2 | ||||
-rw-r--r-- | plugins/marquee.py | 4 | ||||
-rw-r--r-- | plugins/mirror.py | 2 | ||||
-rw-r--r-- | plugins/mpd_client.py | 2 | ||||
-rw-r--r-- | plugins/otr.py | 18 | ||||
-rw-r--r-- | plugins/ping.py | 12 | ||||
-rw-r--r-- | plugins/quote.py | 2 | ||||
-rw-r--r-- | plugins/reorder.py | 2 | ||||
-rw-r--r-- | plugins/replace.py | 4 | ||||
-rw-r--r-- | plugins/send_delayed.py | 2 | ||||
-rw-r--r-- | plugins/server_part.py | 4 | ||||
-rw-r--r-- | plugins/stoi.py | 2 | ||||
-rw-r--r-- | plugins/tell.py | 2 | ||||
-rw-r--r-- | plugins/time_marker.py | 6 | ||||
-rw-r--r-- | plugins/vcard.py | 12 |
23 files changed, 242 insertions, 41 deletions
diff --git a/plugins/b64.py b/plugins/b64.py new file mode 100644 index 00000000..d56ac5b3 --- /dev/null +++ b/plugins/b64.py @@ -0,0 +1,53 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# vim:fenc=utf-8 +# +# Copyright © 2019 Maxime “pep” Buquet <pep@bouah.net> +# +# Distributed under terms of the zlib license. + +""" +Usage +----- + +Base64 encryption plugin. + +This plugin also respects security guidelines listed in XEP-0419. + +.. glossary:: + /b64 + **Usage:** ``/b64`` + + This command enables encryption of outgoing messages for the current + tab. +""" + +from base64 import b64decode, b64encode +from poezio.plugin_e2ee import E2EEPlugin +from slixmpp import Message + + +class Plugin(E2EEPlugin): + """Base64 Plugin""" + + encryption_name = 'base64' + encryption_short_name = 'b64' + eme_ns = 'urn:xmpps:base64:0' + + # This encryption mechanism is using <body/> as a container + replace_body_with_eme = False + + def decrypt(self, message: Message, _tab) -> None: + """ + Decrypt base64 + """ + body = message['body'] + message['body'] = b64decode(body.encode()).decode() + + def encrypt(self, message: Message, _tab) -> None: + """ + Encrypt to base64 + """ + # TODO: Stop using <body/> for this. Put the encoded payload in another element. + body = message['body'] + message['body'] = b64encode(body.encode()).decode() diff --git a/plugins/bob.py b/plugins/bob.py index be56ef4a..2d733e25 100644 --- a/plugins/bob.py +++ b/plugins/bob.py @@ -37,7 +37,7 @@ class Plugin(BasePlugin): default_config = {'bob': {'max_size': 2048, 'max_age': 86400}} def init(self): - for tab in tabs.ConversationTab, tabs.PrivateTab, tabs.MucTab: + for tab in tabs.DynamicConversationTab, tabs.StaticConversationTab, tabs.PrivateTab, tabs.MucTab: self.api.add_tab_command( tab, 'bob', diff --git a/plugins/dice.py b/plugins/dice.py index 376ed26a..f92604e3 100644 --- a/plugins/dice.py +++ b/plugins/dice.py @@ -64,7 +64,7 @@ class Plugin(BasePlugin): default_config = {"dice": {"refresh": 0.5, "default_duration": 5}} def init(self): - for tab_t in [tabs.MucTab, tabs.ConversationTab, tabs.PrivateTab]: + for tab_t in [tabs.MucTab, tabs.DynamicConversationTab, tabs.StaticConversationTab, tabs.PrivateTab]: self.api.add_tab_command( tab_t, 'roll', @@ -95,7 +95,7 @@ class Plugin(BasePlugin): is_muctab = isinstance(tab, tabs.MucTab) msg_id = tab.last_sent_message["id"] increment = self.config.get('refresh') - roll = DiceRoll(duration, num_dice, is_muctab, tab.name, msg_id, + roll = DiceRoll(duration, num_dice, is_muctab, tab.jid, msg_id, increment) event = self.api.create_delayed_event(increment, self.delayed_event, roll) diff --git a/plugins/display_corrections.py b/plugins/display_corrections.py index 22eb196d..e9e8a2e4 100644 --- a/plugins/display_corrections.py +++ b/plugins/display_corrections.py @@ -29,7 +29,7 @@ from poezio import tabs class Plugin(BasePlugin): def init(self): - for tab_type in (tabs.MucTab, tabs.PrivateTab, tabs.ConversationTab): + for tab_type in (tabs.MucTab, tabs.PrivateTab, tabs.DynamicConversationTab, tabs.StaticConversationTab): self.api.add_tab_command( tab_type, 'display_corrections', diff --git a/plugins/emoji_ascii.py b/plugins/emoji_ascii.py new file mode 100644 index 00000000..6629c50e --- /dev/null +++ b/plugins/emoji_ascii.py @@ -0,0 +1,58 @@ +# poezio emoji_ascii plugin +# +# Will translate received Emoji to :emoji: for better display on text terminals, +# and outgoing :emoji: into Emoji on the wire. +# +# Requires emojis.json.gz (MIT licensed) from: +# +# git clone https://github.com/vdurmont/emoji-java +# gzip -9 < ./src/main/resources/emojis.json > poezio/plugins/emojis.json.gz + +# TODOs: +# 1. it messes up your log files (doesn't log original message, logs mutilated :emoji: instead) +# 2. Doesn't work on outgoing direct messages +# 3. Doesn't detect pastes, corrupts jabber:x:foobar +# 4. no auto-completion of emoji aliases +# 5. coloring of converted Emojis to be able to differentiate them from incoming ASCII + +import gzip +import json +import os +import re + +from poezio.plugin import BasePlugin + +class Plugin(BasePlugin): + emoji_to_ascii = {} + ascii_to_emoji = {} + emoji_pattern = None + alias_pattern = None + + def init(self): + emoji_map_file_name = os.path.abspath(os.path.dirname(__file__) + '/emojis.json.gz') + emoji_map_data = gzip.open(emoji_map_file_name, 'r').read().decode('utf-8') + emoji_map = json.loads(emoji_map_data) + for e in emoji_map: + self.emoji_to_ascii[e['emoji']] = ':%s:' % e['aliases'][0] + for alias in e['aliases']: + # work around :iq: and similar country code misdetection + flag = re.match('^[a-z][a-z]$', alias) and "flag" in e["tags"] + if not flag: + self.ascii_to_emoji[':%s:' % alias] = e['emoji'] + self.emoji_pattern = re.compile('|'.join(self.emoji_to_ascii.keys()).replace('*', '\*')) + self.alias_pattern = re.compile('|'.join(self.ascii_to_emoji.keys()).replace('+', '\+')) + + self.api.add_event_handler('muc_msg', self.emoji2alias) + self.api.add_event_handler('conversation_msg', self.emoji2alias) + self.api.add_event_handler('private_msg', self.emoji2alias) + + self.api.add_event_handler('muc_say', self.alias2emoji) + self.api.add_event_handler('private_say', self.alias2emoji) + self.api.add_event_handler('conversation_say', self.alias2emoji) + + + def emoji2alias(self, msg, tab): + msg['body'] = self.emoji_pattern.sub(lambda m: self.emoji_to_ascii[m.group()], msg['body']) + + def alias2emoji(self, msg, tab): + msg['body'] = self.alias_pattern.sub(lambda m: self.ascii_to_emoji[m.group()], msg['body']) diff --git a/plugins/figlet.py b/plugins/figlet.py index b8fcb813..4d4c7577 100644 --- a/plugins/figlet.py +++ b/plugins/figlet.py @@ -11,15 +11,35 @@ Say something in a Chat tab. .. note:: Can create fun things when used with :ref:`The rainbow plugin <rainbow-plugin>`. """ -from poezio.plugin import BasePlugin + import subprocess +from poezio.plugin import BasePlugin + + +def is_figlet() -> bool: + """Ensure figlet exists""" + process = subprocess.Popen( + ['which', 'figlet'], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + return process.wait() == 0 class Plugin(BasePlugin): def init(self): + if not is_figlet(): + self.api.information( + 'Couldn\'t find the figlet program. ' + 'Please install it and reload the plugin.', + 'Error', + ) + return None + self.api.add_event_handler('muc_say', self.figletize) self.api.add_event_handler('conversation_say', self.figletize) self.api.add_event_handler('private_say', self.figletize) + return None def figletize(self, msg, tab): process = subprocess.Popen( diff --git a/plugins/irc.py b/plugins/irc.py index eeef128c..9d981c91 100644 --- a/plugins/irc.py +++ b/plugins/irc.py @@ -376,7 +376,7 @@ class Plugin(BasePlugin): """ gateway = self.config.get('gateway', 'irc.poez.io') current = self.api.current_tab() - current_jid = common.safeJID(current.name) + current_jid = current.jid if not current_jid.server == gateway: self.api.information( 'The current tab does not appear to be an IRC one', 'Warning') diff --git a/plugins/lastlog.py b/plugins/lastlog.py new file mode 100644 index 00000000..314ca75e --- /dev/null +++ b/plugins/lastlog.py @@ -0,0 +1,64 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# vim:fenc=utf-8 +# +# Copyright © 2018 Maxime “pep” Buquet +# Copyright © 2019 Madhur Garg +# +# Distributed under terms of the zlib license. See the COPYING file. + +""" + Search provided string in the buffer and return all results on the screen +""" + +import re +from poezio.plugin import BasePlugin +from poezio import tabs +from poezio.text_buffer import Message, TextBuffer + + +def add_line(text_buffer: TextBuffer, text: str) -> None: + """Adds a textual entry in the TextBuffer""" + text_buffer.add_message( + text, + None, # Time + None, # Nickname + None, # Nick Color + False, # History + None, # User + False, # Highlight + None, # Identifier + None, # str_time + None, # Jid + ) + + +class Plugin(BasePlugin): + """Lastlog Plugin""" + + def init(self): + for tab in tabs.DynamicConversationTab, tabs.StaticConversationTab, tabs.PrivateTab, tabs.MucTab: + self.api.add_tab_command( + tab, + 'lastlog', + self.command_lastlog, + usage='<keyword>', + help='Search <keyword> in the buffer and returns results' + 'on the screen') + + def command_lastlog(self, input_): + """Define lastlog command""" + + text_buffer = self.api.current_tab()._text_buffer + search_re = re.compile(input_, re.I) + + res = [] + add_line(text_buffer, "Lastlog:") + for message in text_buffer.messages: + if message.nickname is not None and \ + search_re.search(message.txt) is not None: + res.append(message) + add_line(text_buffer, "%s" % (message.txt)) + add_line(text_buffer, "End of Lastlog") + self.api.current_tab().text_win.pos = 0 + self.api.current_tab().core.refresh_window() diff --git a/plugins/link.py b/plugins/link.py index 352d403d..59a60c78 100644 --- a/plugins/link.py +++ b/plugins/link.py @@ -97,7 +97,7 @@ app_mapping = { class Plugin(BasePlugin): def init(self): - for _class in (tabs.MucTab, tabs.PrivateTab, tabs.ConversationTab): + for _class in (tabs.MucTab, tabs.PrivateTab, tabs.DynamicConversationTab, tabs.StaticConversationTab): self.api.add_tab_command( _class, 'link', diff --git a/plugins/marquee.py b/plugins/marquee.py index bad06301..80bfbfeb 100644 --- a/plugins/marquee.py +++ b/plugins/marquee.py @@ -56,7 +56,7 @@ class Plugin(BasePlugin): } def init(self): - for tab_t in [tabs.MucTab, tabs.ConversationTab, tabs.PrivateTab]: + for tab_t in [tabs.MucTab, tabs.DynamicConversationTab, tabs.StaticConversationTab, tabs.PrivateTab]: self.add_tab_command( tab_t, 'marquee', self.command_marquee, 'Replicate the <marquee/> behavior in a message') @@ -68,7 +68,7 @@ class Plugin(BasePlugin): tab.command_say(args) is_muctab = isinstance(tab, tabs.MucTab) msg_id = tab.last_sent_message["id"] - jid = tab.name + jid = tab.jid event = self.api.create_delayed_event( self.config.get("refresh"), self.delayed_event, jid, args, msg_id, diff --git a/plugins/mirror.py b/plugins/mirror.py index 116d16b1..55c429a3 100644 --- a/plugins/mirror.py +++ b/plugins/mirror.py @@ -16,7 +16,7 @@ from poezio import tabs class Plugin(BasePlugin): def init(self): - for tab_type in (tabs.MucTab, tabs.PrivateTab, tabs.ConversationTab): + for tab_type in (tabs.MucTab, tabs.PrivateTab, tabs.DynamicConversationTab, tabs.StaticConversationTab): self.api.add_tab_command( tab_type, 'mirror', diff --git a/plugins/mpd_client.py b/plugins/mpd_client.py index a8893999..f1eea902 100644 --- a/plugins/mpd_client.py +++ b/plugins/mpd_client.py @@ -57,7 +57,7 @@ import mpd class Plugin(BasePlugin): def init(self): - for _class in (tabs.ConversationTab, tabs.MucTab, tabs.PrivateTab): + for _class in (tabs.DynamicConversationTab, tabs.StaticConversationTab, tabs.MucTab, tabs.PrivateTab): self.api.add_tab_command( _class, 'mpd', diff --git a/plugins/otr.py b/plugins/otr.py index 909a4ea5..2ddc332b 100644 --- a/plugins/otr.py +++ b/plugins/otr.py @@ -325,7 +325,7 @@ def hl(tab): if tab.state != 'current': tab.state = 'private' - conv_jid = safeJID(tab.name) + conv_jid = tab.jid if 'private' in config.get('beep_on', 'highlight private').split(): if not config.get_by_tabname( 'disable_beep', conv_jid.bare, default=False): @@ -806,7 +806,7 @@ class Plugin(BasePlugin): On message sent """ name = tab.name - jid = safeJID(tab.name) + jid = tab.jid format_dict = { 'jid_c': '\x19%s}' % dump_tuple(get_theme().COLOR_MUC_JID), @@ -846,7 +846,7 @@ class Plugin(BasePlugin): elif not is_relevant(tab) and ctx and ( ctx.state == STATE_ENCRYPTED or ctx.getPolicy('REQUIRE_ENCRYPTION')): - contact = roster[tab.name] + contact = roster[tab.jid.bare] res = [] if contact: res = [resource.jid for resource in contact.resources] @@ -884,13 +884,13 @@ class Plugin(BasePlugin): return self.core.command.help('otr') action = args.pop(0) tab = self.api.current_tab() - name = tab.name + name = tab.jid.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 + 'jid': tab.jid.full, + 'bare_jid': tab.jid.bare, } if action == 'end': # close the session @@ -991,12 +991,12 @@ class Plugin(BasePlugin): question = secret = None tab = self.api.current_tab() - name = tab.name + name = tab.jid.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 + 'jid': tab.jid.full, + 'bare_jid': tab.jid.bare, } ctx = self.get_context(name) diff --git a/plugins/ping.py b/plugins/ping.py index 4868ccf9..7e0098aa 100644 --- a/plugins/ping.py +++ b/plugins/ping.py @@ -22,6 +22,7 @@ Command the current interlocutor. """ +from slixmpp import InvalidJID, JID from poezio.decorators import command_args_parser from poezio.plugin import BasePlugin from poezio.roster import roster @@ -57,7 +58,7 @@ class Plugin(BasePlugin): help='Send an XMPP ping to jid (see XEP-0199).', short='Send a ping.', completion=self.completion_ping) - for _class in (tabs.PrivateTab, tabs.ConversationTab): + for _class in (tabs.PrivateTab, tabs.DynamicConversationTab, tabs.StaticConversationTab): self.api.add_tab_command( _class, 'ping', @@ -116,7 +117,7 @@ class Plugin(BasePlugin): def command_private_ping(self, arg): if arg: return self.command_ping(arg) - self.command_ping(self.api.current_tab().name) + self.command_ping(self.api.current_tab().jid) @command_args_parser.raw def command_muc_ping(self, arg): @@ -124,10 +125,13 @@ class Plugin(BasePlugin): return user = self.api.current_tab().get_user_by_name(arg) if user: - jid = safeJID(self.api.current_tab().name) + jid = self.api.current_tab().jid jid.resource = user.nick else: - jid = safeJID(arg) + try: + jid = JID(arg) + except InvalidJID: + return self.api.information('Invalid JID: %s' % arg, 'Error') self.command_ping(jid.full) @command_args_parser.raw diff --git a/plugins/quote.py b/plugins/quote.py index b412cd9a..20bd9133 100644 --- a/plugins/quote.py +++ b/plugins/quote.py @@ -56,7 +56,7 @@ log = logging.getLogger(__name__) class Plugin(BasePlugin): def init(self): - for _class in (tabs.MucTab, tabs.ConversationTab, tabs.PrivateTab): + for _class in (tabs.MucTab, tabs.DynamicConversationTab, tabs.StaticConversationTab, tabs.PrivateTab): self.api.add_tab_command( _class, 'quote', diff --git a/plugins/reorder.py b/plugins/reorder.py index 7308196d..32fa6639 100644 --- a/plugins/reorder.py +++ b/plugins/reorder.py @@ -112,7 +112,7 @@ def parse_runtime_tablist(tablist): i += 1 result = check_tab(tab) if result: - props.append((i, '%s:%s' % (result, tab.name))) + props.append((i, '%s:%s' % (result, tab.jid.full))) return props diff --git a/plugins/replace.py b/plugins/replace.py index 7e259dab..9646a817 100644 --- a/plugins/replace.py +++ b/plugins/replace.py @@ -102,11 +102,11 @@ def replace_random_user(message, tab): if isinstance(tab, tabs.MucTab): return random.choice(tab.users).nick elif isinstance(tab, tabs.PrivateTab): - return random.choice([JID(tab.name).resource, tab.own_nick]) + return random.choice([tab.jid.resource, tab.own_nick]) else: # that doesn’t make any sense. By why use this pattern in a # ConversationTab anyway? - return str(tab.name) + return tab.jid.full def replace_dice(message, tab): diff --git a/plugins/send_delayed.py b/plugins/send_delayed.py index 846fccd1..e8b00027 100644 --- a/plugins/send_delayed.py +++ b/plugins/send_delayed.py @@ -28,7 +28,7 @@ from poezio import timed_events class Plugin(BasePlugin): def init(self): - for _class in (tabs.PrivateTab, tabs.ConversationTab, tabs.MucTab): + for _class in (tabs.PrivateTab, tabs.DynamicConversationTab, tabs.StaticConversationTab, tabs.MucTab): self.api.add_tab_command( _class, 'send_delayed', diff --git a/plugins/server_part.py b/plugins/server_part.py index 7a71d94b..f29b4099 100644 --- a/plugins/server_part.py +++ b/plugins/server_part.py @@ -39,7 +39,7 @@ class Plugin(BasePlugin): if not args and not isinstance(current_tab, MucTab): return self.core.command_help('server_part') elif not args: - jid = safeJID(current_tab.name).bare + jid = current_tab.jid.bare message = None elif len(args) == 1: jid = safeJID(args[0]).domain @@ -60,6 +60,6 @@ class Plugin(BasePlugin): serv_list = set() for tab in self.core.get_tabs(MucTab): if tab.joined: - serv = safeJID(tab.name).server + serv = tab.jid.server serv_list.add(serv) return Completion(the_input.new_completion, sorted(serv_list), 1, ' ') diff --git a/plugins/stoi.py b/plugins/stoi.py index 04d84881..78c4ed70 100644 --- a/plugins/stoi.py +++ b/plugins/stoi.py @@ -28,7 +28,7 @@ char_we_dont_want = string.punctuation + ' ’„“”…«»' class Plugin(BasePlugin): def init(self): - for tab_type in (tabs.MucTab, tabs.PrivateTab, tabs.ConversationTab): + for tab_type in (tabs.MucTab, tabs.PrivateTab, tabs.DynamicConversationTab, tabs.StaticConversationTab): self.api.add_tab_command( tab_type, 'stoi', diff --git a/plugins/tell.py b/plugins/tell.py index 43a91d8b..614c1ef5 100644 --- a/plugins/tell.py +++ b/plugins/tell.py @@ -75,7 +75,7 @@ class Plugin(BasePlugin): if not self.tabs.get(tab): self.api.information('No message queued.', 'Info') return - build = ['Messages queued for %s:' % tab.name] + build = ['Messages queued for %s:' % tab.jid.bare] for nick, messages in self.tabs[tab].items(): build.append(' for %s:' % nick) for message in messages: diff --git a/plugins/time_marker.py b/plugins/time_marker.py index bd6af1c4..76f7e589 100644 --- a/plugins/time_marker.py +++ b/plugins/time_marker.py @@ -36,7 +36,7 @@ from datetime import datetime, timedelta class Plugin(BasePlugin): def init(self): self.api.add_event_handler("muc_msg", self.on_muc_msg) - # Dict of MucTab.name: last_message date, so we don’t have to + # Dict of MucTab.jid.bare: last_message date, so we don’t have to # retrieve the messages of the given muc to look for the last # message’s date each time. Also, now that I think about it, the # date of the message is not event kept in the Message object, so… @@ -66,8 +66,8 @@ class Plugin(BasePlugin): res += "%s seconds, " % seconds return res[:-2] - last_message_date = self.last_messages.get(tab.name) - self.last_messages[tab.name] = datetime.now() + last_message_date = self.last_messages.get(tab.jid.bare) + self.last_messages[tab.jid.bare] = datetime.now() if last_message_date: delta = datetime.now() - last_message_date if delta >= timedelta(0, self.config.get('delay', 900)): diff --git a/plugins/vcard.py b/plugins/vcard.py index 643dd569..e3a776e3 100644 --- a/plugins/vcard.py +++ b/plugins/vcard.py @@ -61,7 +61,7 @@ class Plugin(BasePlugin): help='Send an XMPP vcard request to jid (see XEP-0054).', short='Send a vcard request.', completion=self.completion_vcard) - for _class in (tabs.PrivateTab, tabs.ConversationTab): + for _class in (tabs.PrivateTab, tabs.DynamicConversationTab, tabs.StaticConversationTab): self.api.add_tab_command( _class, 'vcard', @@ -273,7 +273,7 @@ class Plugin(BasePlugin): if arg: self.command_vcard(arg) return - self.command_vcard(self.api.current_tab().name) + self.command_vcard(self.api.current_tab().jid.full) @command_args_parser.raw def command_muc_vcard(self, arg): @@ -282,10 +282,12 @@ class Plugin(BasePlugin): return user = self.api.current_tab().get_user_by_name(arg) if user: - # No need to use safeJID here, we already know the JID is valid. - jid = JID(self.api.current_tab().name + '/' + user.nick) + jid = self.api.current_tab().jid.bare + '/' + user.nick else: - jid = safeJID(arg) + try: + jid = safeJID(arg) + except InvalidJID: + return self.api.information('Invalid JID: %s' % arg, 'Error') self._get_vcard(jid) @command_args_parser.raw |