matrix: Style fixes and cleanup.

This commit is contained in:
Damir Jelić 2018-08-29 19:40:59 +02:00
parent f8a318fef2
commit 05a413f7cb
13 changed files with 1278 additions and 1278 deletions

View file

@ -130,7 +130,8 @@ disable=print-statement,
bad-whitespace,
too-few-public-methods,
too-many-lines,
missing-docstring
missing-docstring,
bad-continuation,
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option

97
main.py
View file

@ -19,72 +19,51 @@ from __future__ import unicode_literals
import socket
import ssl
import time
import pprint
import OpenSSL.crypto as crypto
import textwrap
from itertools import chain
# pylint: disable=redefined-builtin
from builtins import str
from future.utils import bytes_to_native_str as n
from itertools import chain
# pylint: disable=unused-import
from typing import (List, Set, Dict, Tuple, Text, Optional, AnyStr, Deque, Any)
from typing import Any, AnyStr, Deque, Dict, List, Optional, Set, Text, Tuple
import logbook
from logbook import Logger, StderrHandler, StreamHandler
import nio
from nio import TransportType, RemoteTransportError, RemoteProtocolError
from matrix.colors import Formatted
from matrix.utf import utf8_decode
# Weechat searches for the registered callbacks in the scope of the main script
# file, import the callbacks here so weechat can find them.
from matrix.commands import (hook_commands, hook_page_up, matrix_command_cb,
matrix_topic_command_cb, matrix_join_command_cb,
matrix_part_command_cb, matrix_invite_command_cb,
matrix_command_pgup_cb, matrix_redact_command_cb,
matrix_command_buf_clear_cb, matrix_me_command_cb,
matrix_kick_command_cb)
from matrix.buffer import room_buffer_input_cb, room_buffer_close_cb
from matrix.server import (
MatrixServer,
create_default_server,
send_cb,
matrix_timer_cb,
matrix_config_server_read_cb,
matrix_config_server_write_cb,
matrix_config_server_change_cb,
)
from matrix.bar_items import (init_bar_items, matrix_bar_item_name,
matrix_bar_item_plugin, matrix_bar_item_lag,
matrix_bar_item_buffer_modes)
from matrix.completion import (
init_completion, matrix_command_completion_cb,
matrix_server_command_completion_cb, matrix_debug_completion_cb,
matrix_message_completion_cb, matrix_server_completion_cb,
matrix_olm_user_completion_cb, matrix_olm_device_completion_cb,
matrix_user_completion_cb)
from matrix.utils import (key_from_value, server_buffer_prnt,
server_buffer_set_title)
from matrix.config import (
matrix_config_reload_cb,
MatrixConfig,
config_log_level_cb,
config_log_category_cb,
config_server_buffer_cb
)
import OpenSSL.crypto as crypto
from future.utils import bytes_to_native_str as n
from logbook import Logger, StreamHandler
from nio import RemoteProtocolError, RemoteTransportError, TransportType
from matrix import globals as G
from matrix.globals import W, SERVERS, SCRIPT_NAME
from matrix.bar_items import (init_bar_items, matrix_bar_item_buffer_modes,
matrix_bar_item_lag, matrix_bar_item_name,
matrix_bar_item_plugin)
from matrix.buffer import room_buffer_close_cb, room_buffer_input_cb
# Weechat searches for the registered callbacks in the scope of the main script
# file, import the callbacks here so weechat can find them.
from matrix.commands import (hook_commands, hook_page_up,
matrix_command_buf_clear_cb, matrix_command_cb,
matrix_command_pgup_cb, matrix_invite_command_cb,
matrix_join_command_cb, matrix_kick_command_cb,
matrix_me_command_cb, matrix_part_command_cb,
matrix_redact_command_cb, matrix_topic_command_cb)
from matrix.completion import (init_completion, matrix_command_completion_cb,
matrix_debug_completion_cb,
matrix_message_completion_cb,
matrix_olm_device_completion_cb,
matrix_olm_user_completion_cb,
matrix_server_command_completion_cb,
matrix_server_completion_cb,
matrix_user_completion_cb)
from matrix.config import (MatrixConfig, config_log_category_cb,
config_log_level_cb, config_server_buffer_cb,
matrix_config_reload_cb)
from matrix.globals import SCRIPT_NAME, SERVERS, W
from matrix.server import (MatrixServer, create_default_server,
matrix_config_server_change_cb,
matrix_config_server_read_cb,
matrix_config_server_write_cb, matrix_timer_cb,
send_cb)
from matrix.utf import utf8_decode
from matrix.utils import server_buffer_prnt, server_buffer_set_title
# yapf: disable
WEECHAT_SCRIPT_NAME = SCRIPT_NAME

View file

@ -1,9 +1,8 @@
import datetime
import random
import string
import datetime
weechat_base_colors = {
WEECHAT_BASE_COLORS = {
"black": "0",
"red": "1",
"green": "2",
@ -29,11 +28,11 @@ def color(color_name):
escape_codes = []
reset_code = "0"
def make_fg_color(color):
return "38;5;{}".format(color)
def make_fg_color(color_code):
return "38;5;{}".format(color_code)
def make_bg_color(color):
return "48;5;{}".format(color)
def make_bg_color(color_code):
return "48;5;{}".format(color_code)
attributes = {
"bold": "1",
@ -76,21 +75,21 @@ def color(color_name):
stripped_color = fg_color.lstrip("*_|/!")
if stripped_color in weechat_base_colors:
if stripped_color in WEECHAT_BASE_COLORS:
escape_codes.append(
make_fg_color(weechat_base_colors[stripped_color]))
make_fg_color(WEECHAT_BASE_COLORS[stripped_color]))
elif stripped_color.isdigit():
num_color = int(stripped_color)
if num_color >= 0 and num_color < 256:
if 0 <= num_color < 256:
escape_codes.append(make_fg_color(stripped_color))
if bg_color in weechat_base_colors:
escape_codes.append(make_bg_color(weechat_base_colors[bg_color]))
if bg_color in WEECHAT_BASE_COLORS:
escape_codes.append(make_bg_color(WEECHAT_BASE_COLORS[bg_color]))
else:
if bg_color.isdigit():
num_color = int(bg_color)
if num_color >= 0 and num_color < 256:
if 0 <= num_color < 256:
escape_codes.append(make_bg_color(bg_color))
escape_string = "\033[{}{}m".format(reset_code, ";".join(escape_codes))
@ -98,7 +97,7 @@ def color(color_name):
return escape_string
def prefix(prefix):
def prefix(prefix_string):
prefix_to_symbol = {
"error": "=!=",
"network": "--",
@ -107,14 +106,14 @@ def prefix(prefix):
"quit": "<--"
}
if prefix in prefix_to_symbol:
if prefix_string in prefix_to_symbol:
return prefix_to_symbol[prefix]
return ""
def prnt(_, string):
print(string)
def prnt(_, message):
print(message)
def prnt_date_tags(_, date, tags_string, data):
@ -126,44 +125,44 @@ def prnt_date_tags(_, date, tags_string, data):
print(message)
def config_search_section(*args, **kwargs):
def config_search_section(*_, **__):
pass
def config_new_option(*args, **kwargs):
def config_new_option(*_, **__):
pass
def mkdir_home(*args, **kwargs):
def mkdir_home(*_, **__):
return True
def info_get(info, *args):
def info_get(info, *_):
if info == "nick_color_name":
return random.choice(list(weechat_base_colors.keys()))
return random.choice(list(WEECHAT_BASE_COLORS.keys()))
return ""
def buffer_new(*args, **kwargs):
def buffer_new(*_, **__):
return "".join(
random.choice(string.ascii_uppercase + string.digits) for _ in range(8)
)
def buffer_set(*args, **kwargs):
def buffer_set(*_, **__):
return
def nicklist_add_group(*args, **kwargs):
def nicklist_add_group(*_, **__):
return
def nicklist_add_nick(*args, **kwargs):
def nicklist_add_nick(*_, **__):
return
def nicklist_remove_nick(*args, **kwargs):
def nicklist_remove_nick(*_, **__):
return

View file

@ -16,21 +16,20 @@
from __future__ import unicode_literals
from matrix.utf import utf8_decode
from matrix.globals import W, SERVERS
from .globals import SERVERS, W
from .utf import utf8_decode
@utf8_decode
def matrix_bar_item_plugin(data, item, window, buffer, extra_info):
# pylint: disable=unused-argument
for server in SERVERS.values():
if (buffer in server.buffers.values() or
buffer == server.server_buffer):
if buffer in server.buffers.values() or buffer == server.server_buffer:
return "matrix{color}/{color_fg}{name}".format(
color=W.color("bar_delim"),
color_fg=W.color("bar_fg"),
name=server.name)
name=server.name,
)
return ""
@ -40,24 +39,31 @@ def matrix_bar_item_name(data, item, window, buffer, extra_info):
# pylint: disable=unused-argument
for server in SERVERS.values():
if buffer in server.buffers.values():
color = ("status_name_ssl"
if server.ssl_context.check_hostname else "status_name")
color = (
"status_name_ssl"
if server.ssl_context.check_hostname
else "status_name"
)
room_buffer = server.find_room_from_ptr(buffer)
room = room_buffer.room
return "{color}{name}".format(
color=W.color(color),
name=room.display_name())
color=W.color(color), name=room.display_name()
)
elif buffer == server.server_buffer:
color = ("status_name_ssl"
if server.ssl_context.check_hostname else "status_name")
if buffer == server.server_buffer:
color = (
"status_name_ssl"
if server.ssl_context.check_hostname
else "status_name"
)
return "{color}server{del_color}[{color}{name}{del_color}]".format(
color=W.color(color),
del_color=W.color("bar_delim"),
name=server.name)
name=server.name,
)
return ""
@ -66,8 +72,7 @@ def matrix_bar_item_name(data, item, window, buffer, extra_info):
def matrix_bar_item_lag(data, item, window, buffer, extra_info):
# pylint: disable=unused-argument
for server in SERVERS.values():
if (buffer in server.buffers.values() or
buffer == server.server_buffer):
if buffer in server.buffers.values() or buffer == server.server_buffer:
if server.lag >= 500:
color = W.color("irc.color.item_lag_counting")
if server.lag_done:
@ -77,7 +82,8 @@ def matrix_bar_item_lag(data, item, window, buffer, extra_info):
lag_string = "Lag: {color}{lag}{ncolor}".format(
lag=lag.format((server.lag / 1000)),
color=color,
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
return lag_string
return ""

View file

@ -22,42 +22,40 @@ from builtins import super
from functools import partial
from typing import NamedTuple
from . import globals as G
from .globals import W, SERVERS, SCRIPT_NAME
from .utf import utf8_decode
from .colors import Formatted
from .utils import (
shorten_sender,
server_ts_to_weechat,
string_strikethrough,
)
from .config import RedactType
from nio import (
Api,
RoomMessageText,
RoomMemberEvent,
PowerLevelsEvent,
RoomEncryptionEvent,
RedactedEvent,
RedactionEvent,
RoomAliasEvent,
RoomTopicEvent,
RoomEncryptionEvent,
RoomMemberEvent,
RoomMessageEmote,
RoomNameEvent,
RoomMessageMedia,
RoomMessageNotice,
RoomMessageText,
RoomMessageUnknown,
RedactionEvent
RoomNameEvent,
RoomTopicEvent,
)
from . import globals as G
from .colors import Formatted
from .config import RedactType
from .globals import SCRIPT_NAME, SERVERS, W
from .utf import utf8_decode
from .utils import server_ts_to_weechat, shorten_sender, string_strikethrough
OwnMessage = NamedTuple("OwnMessage", [
OwnMessage = NamedTuple(
"OwnMessage",
[
("sender", str),
("age", int),
("event_id", str),
("room_id", str),
("formatted_message", Formatted)
])
("formatted_message", Formatted),
],
)
class OwnAction(OwnMessage):
@ -71,7 +69,7 @@ def room_buffer_input_cb(server_name, buffer, input_data):
if not room_buffer:
# TODO log error
return
return W.WEECHAT_RC_ERROR
if not server.connected:
room_buffer.error("You are not connected to the server")
@ -96,7 +94,7 @@ def room_buffer_close_cb(data, buffer):
class WeechatUser(object):
def __init__(self, nick, host=None, prefix="", join_time=None):
# type: (str, str, str) -> None
# type: (str, str, str, int) -> None
self.nick = nick
self.host = host
self.prefix = prefix
@ -127,7 +125,7 @@ class WeechatUser(object):
class RoomUser(WeechatUser):
def __init__(self, nick, user_id=None, power_level=0, join_time=None):
# type: (str, str, int) -> None
# type: (str, str, int, int) -> None
prefix = self._get_prefix(power_level)
super().__init__(nick, user_id, prefix, join_time)
@ -152,26 +150,22 @@ class RoomUser(WeechatUser):
# type: (int) -> str
if power_level >= 100:
return "&"
elif power_level >= 50:
if power_level >= 50:
return "@"
elif power_level > 0:
if power_level > 0:
return "+"
return ""
class WeechatChannelBuffer(object):
tags = {
"message": [
SCRIPT_NAME + "_message",
"notify_message",
"log1"
],
"message": [SCRIPT_NAME + "_message", "notify_message", "log1"],
"self_message": [
SCRIPT_NAME + "_message",
"notify_none",
"no_highlight",
"self_msg",
"log1"
"log1",
],
"action": [
SCRIPT_NAME + "_message",
@ -179,44 +173,25 @@ class WeechatChannelBuffer(object):
"notify_message",
"log1",
],
"notice": [
SCRIPT_NAME + "_notice",
"notify_message",
"log1",
],
"notice": [SCRIPT_NAME + "_notice", "notify_message", "log1"],
"old_message": [
SCRIPT_NAME + "_message",
"notify_message",
"no_log",
"no_highlight"
"no_highlight",
],
"join": [
SCRIPT_NAME + "_join",
"log4"
],
"part": [
SCRIPT_NAME + "_leave",
"log4"
],
"kick": [
SCRIPT_NAME + "_kick",
"log4"
],
"invite": [
SCRIPT_NAME + "_invite",
"log4"
],
"topic": [
SCRIPT_NAME + "_topic",
"log3",
]
"join": [SCRIPT_NAME + "_join", "log4"],
"part": [SCRIPT_NAME + "_leave", "log4"],
"kick": [SCRIPT_NAME + "_kick", "log4"],
"invite": [SCRIPT_NAME + "_invite", "log4"],
"topic": [SCRIPT_NAME + "_topic", "log3"],
}
membership_messages = {
"join": "has joined",
"part": "has left",
"kick": "has been kicked from",
"invite": "has been invited to"
"invite": "has been invited to",
}
class Line(object):
@ -249,9 +224,7 @@ class WeechatChannelBuffer(object):
@property
def tags(self):
tags_count = W.hdata_get_var_array_size(
self._hdata,
self._ptr,
"tags_array"
self._hdata, self._ptr, "tags_array"
)
tags = [
@ -300,7 +273,7 @@ class WeechatChannelBuffer(object):
tags=None,
prefix=None,
message=None,
highlight=None
highlight=None,
):
new_data = {}
@ -309,7 +282,7 @@ class WeechatChannelBuffer(object):
if date_printed:
new_data["date_printed"] = str(date_printed)
if tags:
new_data["tags_array"] = ','.join(tags)
new_data["tags_array"] = ",".join(tags)
if prefix:
new_data["prefix"] = prefix
if message:
@ -337,8 +310,8 @@ class WeechatChannelBuffer(object):
self.topic_author = ""
self.topic_date = None
W.buffer_set(self._ptr, "localvar_set_type", 'channel')
W.buffer_set(self._ptr, "type", 'formatted')
W.buffer_set(self._ptr, "localvar_set_type", "channel")
W.buffer_set(self._ptr, "type", "formatted")
W.buffer_set(self._ptr, "localvar_set_channel", name)
@ -350,32 +323,16 @@ class WeechatChannelBuffer(object):
# W.buffer_set(self._ptr, "short_name", short_name)
W.nicklist_add_group(
self._ptr,
'',
"000|o",
"weechat.color.nicklist_group",
1
self._ptr, "", "000|o", "weechat.color.nicklist_group", 1
)
W.nicklist_add_group(
self._ptr,
'',
"001|h",
"weechat.color.nicklist_group",
1
self._ptr, "", "001|h", "weechat.color.nicklist_group", 1
)
W.nicklist_add_group(
self._ptr,
'',
"002|v",
"weechat.color.nicklist_group",
1
self._ptr, "", "002|v", "weechat.color.nicklist_group", 1
)
W.nicklist_add_group(
self._ptr,
'',
"999|...",
"weechat.color.nicklist_group",
1
self._ptr, "", "999|...", "weechat.color.nicklist_group", 1
)
W.buffer_set(self._ptr, "nicklist", "1")
@ -385,9 +342,7 @@ class WeechatChannelBuffer(object):
# TODO make this configurable
W.buffer_set(
self._ptr,
"highlight_tags_restrict",
SCRIPT_NAME + "_message"
self._ptr, "highlight_tags_restrict", SCRIPT_NAME + "_message"
)
@property
@ -428,23 +383,18 @@ class WeechatChannelBuffer(object):
@property
def lines(self):
own_lines = W.hdata_pointer(
self._hdata,
self._ptr,
"own_lines"
)
own_lines = W.hdata_pointer(self._hdata, self._ptr, "own_lines")
if own_lines:
hdata_line = W.hdata_get("line")
line_pointer = W.hdata_pointer(
W.hdata_get("lines"), own_lines, "last_line")
W.hdata_get("lines"), own_lines, "last_line"
)
while line_pointer:
data_pointer = W.hdata_pointer(
hdata_line,
line_pointer,
"data"
hdata_line, line_pointer, "data"
)
if data_pointer:
@ -469,9 +419,7 @@ class WeechatChannelBuffer(object):
# type: (str) -> None
""" Print an error to the room buffer """
message = "{prefix}{script}: {message}".format(
prefix=W.prefix("error"),
script=SCRIPT_NAME,
message=string
prefix=W.prefix("error"), script=SCRIPT_NAME, message=string
)
self._print(message)
@ -493,7 +441,7 @@ class WeechatChannelBuffer(object):
color = self._color_for_tags(user.color)
if message_type != "action" and message_type != "notice":
if message_type not in ("action", "notice"):
tags.append("prefix_nick_{color}".format(color=color))
return tags
@ -507,18 +455,23 @@ class WeechatChannelBuffer(object):
return WeechatUser(nick)
def _print_message(self, user, message, date, tags):
prefix_string = ("" if not user.prefix else "{}{}{}".format(
prefix_string = (
""
if not user.prefix
else "{}{}{}".format(
W.color(self._get_prefix_color(user.prefix)),
user.prefix,
W.color("reset")
))
W.color("reset"),
)
)
data = "{prefix}{color}{author}{ncolor}\t{msg}".format(
prefix=prefix_string,
color=W.color(user.color),
author=user.nick,
ncolor=W.color("reset"),
msg=message)
msg=message,
)
self.print_date_tags(data, date, tags)
@ -534,27 +487,32 @@ class WeechatChannelBuffer(object):
def notice(self, nick, message, date, extra_tags=None):
# type: (str, str, int, Optional[List[str]]) -> None
user = self._get_user(nick)
user_prefix = ("" if not user.prefix else "{}{}{}".format(
user_prefix = (
""
if not user.prefix
else "{}{}{}".format(
W.color(self._get_prefix_color(user.prefix)),
user.prefix,
W.color("reset")
))
user_string = "{}{}{}{}".format(
user_prefix,
user.color,
user.nick,
W.color("reset")
W.color("reset"),
)
)
data = ("{prefix}\t{color}Notice"
user_string = "{}{}{}{}".format(
user_prefix, user.color, user.nick, W.color("reset")
)
data = (
"{prefix}\t{color}Notice"
"{del_color}({ncolor}{user}{del_color}){ncolor}"
": {message}").format(prefix=W.prefix("network"),
": {message}"
).format(
prefix=W.prefix("network"),
color=W.color("irc.color.notice"),
del_color=W.color("chat_delimiters"),
ncolor=W.color("reset"),
user=user_string,
message=message)
message=message,
)
tags = self._message_tags(user, "notice") + (extra_tags or [])
self.print_date_tags(data, date, tags)
@ -563,27 +521,33 @@ class WeechatChannelBuffer(object):
self.unmask_smart_filtered_nick(nick)
def _print_action(self, user, message, date, tags):
nick_prefix = ("" if not user.prefix else "{}{}{}".format(
nick_prefix = (
""
if not user.prefix
else "{}{}{}".format(
W.color(self._get_prefix_color(user.prefix)),
user.prefix,
W.color("reset")
))
W.color("reset"),
)
)
data = ("{prefix}{nick_prefix}{nick_color}{author}"
"{ncolor} {msg}").format(
data = (
"{prefix}{nick_prefix}{nick_color}{author}" "{ncolor} {msg}"
).format(
prefix=W.prefix("action"),
nick_prefix=nick_prefix,
nick_color=W.color(user.color),
author=user.nick,
ncolor=W.color("reset"),
msg=message)
msg=message,
)
self.print_date_tags(data, date, tags)
def action(self, nick, message, date, extra_tags=[]):
def action(self, nick, message, date, extra_tags=None):
# type: (str, str, int, Optional[List[str]]) -> None
user = self._get_user(nick)
tags = self._message_tags(user, "action") + extra_tags
tags = self._message_tags(user, "action") + (extra_tags or [])
self._print_action(user, message, date, tags)
user.update_speaking_time(date)
@ -624,9 +588,7 @@ class WeechatChannelBuffer(object):
if not nick_pointer:
group = W.nicklist_search_group(
self._ptr,
"",
self._get_nicklist_group(user)
self._ptr, "", self._get_nicklist_group(user)
)
prefix = user.prefix if user.prefix else " "
W.nicklist_add_nick(
@ -636,22 +598,22 @@ class WeechatChannelBuffer(object):
user.color,
prefix,
self._get_prefix_color(user.prefix),
1
1,
)
def _membership_message(self, user, message_type):
# type: (WeechatUser, str) -> str
action_color = ("green" if message_type == "join"
or message_type == "invite" else "red")
prefix = ("join" if message_type == "join" or message_type == "invite"
else "quit")
action_color = "green" if message_type in ("join", "invite") else "red"
prefix = "join" if message_type in ("join", "invite") else "quit"
membership_message = self.membership_messages[message_type]
message = ("{prefix}{color}{author}{ncolor} "
message = (
"{prefix}{color}{author}{ncolor} "
"{del_color}({host_color}{host}{del_color})"
"{action_color} {message} "
"{channel_color}{room}{ncolor}").format(
"{channel_color}{room}{ncolor}"
).format(
prefix=W.prefix(prefix),
color=W.color(user.color),
author=user.nick,
@ -662,11 +624,12 @@ class WeechatChannelBuffer(object):
action_color=W.color(action_color),
message=membership_message,
channel_color=W.color("chat_channel"),
room=self.short_name)
room=self.short_name,
)
return message
def join(self, user, date, message=True, extra_tags=[]):
def join(self, user, date, message=True, extra_tags=None):
# type: (WeechatUser, int, Optional[bool], Optional[List[str]]) -> None
self._add_user_to_nicklist(user)
self.users[user.nick] = user
@ -681,12 +644,12 @@ class WeechatChannelBuffer(object):
self.print_date_tags(message, date, tags)
self.add_smart_filtered_nick(user.nick)
def invite(self, nick, date, extra_tags=[]):
def invite(self, nick, date, extra_tags=None):
# type: (str, int, Optional[bool], Optional[List[str]]) -> None
user = self._get_user(nick)
tags = self._message_tags(user, "invite")
message = self._membership_message(user, "invite")
self.print_date_tags(message, date, tags + extra_tags)
self.print_date_tags(message, date, tags + (extra_tags or []))
def _remove_user_from_nicklist(self, user):
# type: (WeechatUser) -> None
@ -695,7 +658,7 @@ class WeechatChannelBuffer(object):
if nick_pointer:
W.nicklist_remove_nick(self._ptr, nick_pointer)
def _leave(self, nick, date, message, leave_type, extra_tags):
def _leave(self, nick, date, message, leave_type, extra_tags=None):
# type: (str, int, bool, str, List[str]) -> None
user = self._get_user(nick)
self._remove_user_from_nicklist(user)
@ -708,33 +671,35 @@ class WeechatChannelBuffer(object):
tags.append(SCRIPT_NAME + "_smart_filter")
message = self._membership_message(user, leave_type)
self.print_date_tags(message, date, tags + extra_tags)
self.print_date_tags(message, date, tags + (extra_tags or []))
self.remove_smart_filtered_nick(user.nick)
if user.nick in self.users:
del self.users[user.nick]
def part(self, nick, date, message=True, extra_tags=[]):
def part(self, nick, date, message=True, extra_tags=None):
# type: (str, int, Optional[bool], Optional[List[str]]) -> None
self._leave(nick, date, message, "part", extra_tags)
def kick(self, nick, date, message=True, extra_tags=[]):
def kick(self, nick, date, message=True, extra_tags=None):
# type: (str, int, Optional[bool], Optional[List[str]]) -> None
self._leave(nick, date, message, "kick", extra_tags=[])
self._leave(nick, date, message, "kick", extra_tags)
def _print_topic(self, nick, topic, date):
user = self._get_user(nick)
tags = self._message_tags(user, "topic")
data = ("{prefix}{nick} has changed "
data = (
"{prefix}{nick} has changed "
"the topic for {chan_color}{room}{ncolor} "
"to \"{topic}\"").format(
'to "{topic}"'
).format(
prefix=W.prefix("network"),
nick=user.nick,
chan_color=W.color("chat_channel"),
ncolor=W.color("reset"),
room=self.short_name,
topic=topic
topic=topic,
)
self.print_date_tags(data, date, tags)
@ -799,9 +764,7 @@ class RoomBuffer(object):
self.displayed_nicks = {}
user = shorten_sender(self.room.own_user_id)
self.weechat_buffer = WeechatChannelBuffer(
buffer_name,
server_name,
user
buffer_name, server_name, user
)
def find_nick(self, user_id):
@ -837,11 +800,7 @@ class RoomBuffer(object):
buffer_user.color = "weechat.color.chat_nick_self"
user.nick_color = "weechat.color.chat_nick_self"
self.weechat_buffer.join(
buffer_user,
date,
not is_state
)
self.weechat_buffer.join(buffer_user, date, not is_state)
date = server_ts_to_weechat(event.server_timestamp)
@ -909,22 +868,28 @@ class RoomBuffer(object):
message = line.message
tags = line.tags
reason = ("" if not event.reason else
", reason: \"{reason}\"".format(reason=event.reason))
reason = (
""
if not event.reason
else ', reason: "{reason}"'.format(reason=event.reason)
)
redaction_msg = ("{del_color}<{log_color}Message redacted by: "
redaction_msg = (
"{del_color}<{log_color}Message redacted by: "
"{censor}{log_color}{reason}{del_color}>"
"{ncolor}").format(
"{ncolor}"
).format(
del_color=W.color("chat_delimiters"),
ncolor=W.color("reset"),
log_color=W.color("logger.color.backlog_line"),
censor=censor,
reason=reason)
reason=reason,
)
new_message = ""
if G.CONFIG.look.redaction_type == RedactType.STRIKETHROUGH:
plaintext_msg = W.string_remove_color(message, '')
plaintext_msg = W.string_remove_color(message, "")
new_message = string_strikethrough(plaintext_msg)
elif G.CONFIG.look.redaction_type == RedactType.NOTICE:
new_message = message
@ -944,18 +909,24 @@ class RoomBuffer(object):
tags = self.get_event_tags(event)
tags.append(SCRIPT_NAME + "_redacted")
reason = (", reason: \"{reason}\"".format(reason=event.reason)
if event.reason else "")
reason = (
', reason: "{reason}"'.format(reason=event.reason)
if event.reason
else ""
)
censor = self.find_nick(event.redacter)
data = ("{del_color}<{log_color}Message redacted by: "
"{censor}{log_color}{reason}{del_color}>{ncolor}").format(
data = (
"{del_color}<{log_color}Message redacted by: "
"{censor}{log_color}{reason}{del_color}>{ncolor}"
).format(
del_color=W.color("chat_delimiters"),
ncolor=W.color("reset"),
log_color=W.color("logger.color.backlog_line"),
censor=censor,
reason=reason)
reason=reason,
)
self.weechat_buffer.message(nick, data, date, tags)
@ -966,20 +937,22 @@ class RoomBuffer(object):
nick,
event.topic,
server_ts_to_weechat(event.server_timestamp),
not is_state)
not is_state,
)
@staticmethod
def get_event_tags(event):
return ["matrix_id_{}".format(event.event_id)]
def _handle_power_level(self, event):
def _handle_power_level(self, _):
for user_id in self.room.power_levels.users:
if user_id in self.displayed_nicks:
nick = self.find_nick(user_id)
user = self.weechat_buffer.users[nick]
user.power_level = self.room.power_levels.get_user_level(
user_id)
user_id
)
# There is no way to change the group of a user without
# removing him from the nicklist
@ -994,9 +967,11 @@ class RoomBuffer(object):
elif isinstance(event, PowerLevelsEvent):
self._handle_power_level(event)
elif isinstance(event, RoomEncryptionEvent):
message = ("This room is encrypted, encryption is "
message = (
"This room is encrypted, encryption is "
"currently unsuported. Message sending is disabled for "
"this room.")
"this room."
)
self.weechat_buffer.error(message)
def handle_timeline_event(self, event):
@ -1016,10 +991,7 @@ class RoomBuffer(object):
nick = self.find_nick(event.sender)
date = server_ts_to_weechat(event.server_timestamp)
self.weechat_buffer.action(
nick,
event.body,
date,
self.get_event_tags(event)
nick, event.body, date, self.get_event_tags(event)
)
elif isinstance(event, RoomMessageText):
@ -1029,25 +1001,18 @@ class RoomBuffer(object):
if event.formatted_body:
formatted = Formatted.from_html(event.formatted_body)
data = (formatted.to_weechat()
if formatted else event.body)
data = formatted.to_weechat() if formatted else event.body
date = server_ts_to_weechat(event.server_timestamp)
self.weechat_buffer.message(
nick,
data,
date,
self.get_event_tags(event)
nick, data, date, self.get_event_tags(event)
)
elif isinstance(event, RoomMessageNotice):
nick = self.find_nick(event.sender)
date = server_ts_to_weechat(event.server_timestamp)
self.weechat_buffer.notice(
nick,
event.body,
date,
self.get_event_tags(event)
nick, event.body, date, self.get_event_tags(event)
)
elif isinstance(event, RoomMessageMedia):
@ -1056,15 +1021,11 @@ class RoomBuffer(object):
http_url = Api.mxc_to_http(event.url)
url = http_url if http_url else event.url
description = ("/{}".format(event.body)
if event.body else "")
description = "/{}".format(event.body) if event.body else ""
data = "{url}{desc}".format(url=url, desc=description)
self.weechat_buffer.message(
nick,
data,
date,
self.get_event_tags(event)
nick, data, date, self.get_event_tags(event)
)
elif isinstance(event, RoomMessageUnknown):
@ -1072,10 +1033,7 @@ class RoomBuffer(object):
date = server_ts_to_weechat(event.server_timestamp)
data = ("Unknown message of type {t}").format(t=event.type)
self.weechat_buffer.message(
nick,
data,
date,
self.get_event_tags(event)
nick, data, date, self.get_event_tags(event)
)
elif isinstance(event, RedactionEvent):
@ -1085,9 +1043,11 @@ class RoomBuffer(object):
self._handle_redacted_message(event)
elif isinstance(event, RoomEncryptionEvent):
message = ("This room is encrypted, encryption is "
message = (
"This room is encrypted, encryption is "
"currently unsuported. Message sending is disabled for "
"this room.")
"this room."
)
self.weechat_buffer.error(message)
elif isinstance(event, PowerLevelsEvent):
@ -1106,8 +1066,9 @@ class RoomBuffer(object):
# )
else:
W.prnt("", "Unhandled event of type {}.".format(
type(event).__name__))
W.prnt(
"", "Unhandled event of type {}.".format(type(event).__name__)
)
def self_message(self, message):
# type: (OwnMessage) -> None
@ -1125,10 +1086,7 @@ class RoomBuffer(object):
tags = self.get_event_tags(message)
self.weechat_buffer.self_action(
nick,
message.formatted_message.to_weechat(),
date,
tags
nick, message.formatted_message.to_weechat(), date, tags
)
def old_redacted(self, event):
@ -1136,20 +1094,26 @@ class RoomBuffer(object):
SCRIPT_NAME + "_message",
"notify_message",
"no_log",
"no_highlight"
"no_highlight",
]
reason = (", reason: \"{reason}\"".format(reason=event.reason)
if event.reason else "")
reason = (
', reason: "{reason}"'.format(reason=event.reason)
if event.reason
else ""
)
censor = self.find_nick(event.redacter)
data = ("{del_color}<{log_color}Message redacted by: "
"{censor}{log_color}{reason}{del_color}>{ncolor}").format(
data = (
"{del_color}<{log_color}Message redacted by: "
"{censor}{log_color}{reason}{del_color}>{ncolor}"
).format(
del_color=W.color("chat_delimiters"),
ncolor=W.color("reset"),
log_color=W.color("logger.color.backlog_line"),
censor=censor,
reason=reason)
reason=reason,
)
tags += self.get_event_tags(event)
nick = self.find_nick(event.sender)
@ -1162,12 +1126,15 @@ class RoomBuffer(object):
SCRIPT_NAME + "_message",
"notify_message",
"no_log",
"no_highlight"
"no_highlight",
]
tags += self.get_event_tags(event)
nick = self.find_nick(event.sender)
data = (event.formatted_message.to_weechat()
if event.formatted_message else event.message)
data = (
event.formatted_message.to_weechat()
if event.formatted_message
else event.message
)
user = self.weechat_buffer._get_user(nick)
date = server_ts_to_weechat(event.server_timestamp)
self.weechat_buffer._print_message(user, data, date, tags)
@ -1175,13 +1142,7 @@ class RoomBuffer(object):
def sort_messages(self):
class LineCopy(object):
def __init__(
self,
date,
date_printed,
tags,
prefix,
message,
highlight
self, date, date_printed, tags, prefix, message, highlight
):
self.date = date
self.date_printed = date_printed
@ -1192,18 +1153,25 @@ class RoomBuffer(object):
@classmethod
def from_line(cls, line):
return cls(line.date, line.date_printed, line.tags,
line.prefix, line.message, line.highlight)
return cls(
line.date,
line.date_printed,
line.tags,
line.prefix,
line.message,
line.highlight,
)
lines = [
LineCopy.from_line(line) for line in self.weechat_buffer.lines
]
sorted_lines = sorted(lines, key=lambda line: line.date, reverse=True)
for n, line in enumerate(self.weechat_buffer.lines):
new = sorted_lines[n]
line.update(new.date, new.date_printed, new.tags, new.prefix,
new.message)
for line_number, line in enumerate(self.weechat_buffer.lines):
new = sorted_lines[line_number]
line.update(
new.date, new.date_printed, new.tags, new.prefix, new.message
)
def handle_backlog(self, events):
for event in events:
@ -1230,7 +1198,7 @@ class RoomBuffer(object):
break
if leave_index:
timeline_events = info.timeline.events[leave_index+1:]
timeline_events = info.timeline.events[leave_index + 1 :]
# Handle our leave as a state event since we're not in the
# nicklist anymore but we're already printed out our leave
self.handle_state_event(info.timeline.events[leave_index])

View file

@ -18,34 +18,34 @@
from __future__ import unicode_literals
import html
import re
import textwrap
# pylint: disable=redefined-builtin
from builtins import str
from collections import namedtuple
from matrix import globals as G
from matrix.globals import W
from matrix.utils import string_strikethrough
import re
import textwrap
import webcolors
from pygments import highlight
from pygments.lexers import guess_lexer, get_lexer_by_name
from pygments.formatter import Formatter
from pygments.lexers import get_lexer_by_name, guess_lexer
from pygments.util import ClassNotFound
from . import globals as G
from .globals import W
from .utils import string_strikethrough
try:
from HTMLParser import HTMLParser
except ImportError:
from html.parser import HTMLParser
import html
FormattedString = namedtuple('FormattedString', ['text', 'attributes'])
FormattedString = namedtuple("FormattedString", ["text", "attributes"])
class Formatted():
class Formatted:
def __init__(self, substrings):
# type: (List[FormattedString]) -> None
self.substrings = substrings
@ -55,7 +55,7 @@ class Formatted():
return textwrap.TextWrapper(
width=67,
initial_indent="{}> ".format(W.color(G.CONFIG.color.quote)),
subsequent_indent="{}> ".format(W.color(G.CONFIG.color.quote))
subsequent_indent="{}> ".format(W.color(G.CONFIG.color.quote)),
)
def is_formatted(self):
@ -89,21 +89,22 @@ class Formatted():
# Markdown bold
elif line[i] == "*":
if attributes["italic"] and not line[i-1].isspace():
if attributes["italic"] and not line[i - 1].isspace():
if text:
substrings.append(FormattedString(
text, attributes.copy()))
substrings.append(
FormattedString(text, attributes.copy())
)
text = ""
attributes["italic"] = not attributes["italic"]
i = i + 1
continue
elif attributes["italic"] and line[i-1].isspace():
elif attributes["italic"] and line[i - 1].isspace():
text = text + line[i]
i = i + 1
continue
elif i+1 < len(line) and line[i+1].isspace():
elif i + 1 < len(line) and line[i + 1].isspace():
text = text + line[i]
i = i + 1
continue
@ -201,27 +202,34 @@ class Formatted():
def add_attribute(string, name, value):
if name == "bold" and value:
return "{bold_on}{text}{bold_off}".format(
bold_on="<strong>", text=string, bold_off="</strong>")
elif name == "italic" and value:
bold_on="<strong>", text=string, bold_off="</strong>"
)
if name == "italic" and value:
return "{italic_on}{text}{italic_off}".format(
italic_on="<em>", text=string, italic_off="</em>")
elif name == "underline" and value:
italic_on="<em>", text=string, italic_off="</em>"
)
if name == "underline" and value:
return "{underline_on}{text}{underline_off}".format(
underline_on="<u>", text=string, underline_off="</u>")
elif name == "strikethrough" and value:
underline_on="<u>", text=string, underline_off="</u>"
)
if name == "strikethrough" and value:
return "{strike_on}{text}{strike_off}".format(
strike_on="<del>", text=string, strike_off="</del>")
elif name == "quote" and value:
strike_on="<del>", text=string, strike_off="</del>"
)
if name == "quote" and value:
return "{quote_on}{text}{quote_off}".format(
quote_on="<blockquote>",
text=string,
quote_off="</blockquote>")
elif name == "fgcolor" and value:
quote_off="</blockquote>",
)
if name == "fgcolor" and value:
return "{color_on}{text}{color_off}".format(
color_on="<font color={color}>".format(
color=color_weechat_to_html(value)),
color=color_weechat_to_html(value)
),
text=string,
color_off="</font>")
color_off="</font>",
)
return string
@ -261,28 +269,32 @@ class Formatted():
return "{bold_on}{text}{bold_off}".format(
bold_on=W.color("bold"),
text=string,
bold_off=W.color("-bold"))
bold_off=W.color("-bold"),
)
elif name == "italic" and value:
if name == "italic" and value:
return "{italic_on}{text}{italic_off}".format(
italic_on=W.color("italic"),
text=string,
italic_off=W.color("-italic"))
italic_off=W.color("-italic"),
)
elif name == "underline" and value:
if name == "underline" and value:
return "{underline_on}{text}{underline_off}".format(
underline_on=W.color("underline"),
text=string,
underline_off=W.color("-underline"))
underline_off=W.color("-underline"),
)
elif name == "strikethrough" and value:
if name == "strikethrough" and value:
return string_strikethrough(string)
elif name == "quote" and value:
if name == "quote" and value:
return self.textwrapper.fill(
W.string_remove_color(string.replace("\n", ""), ""))
W.string_remove_color(string.replace("\n", ""), "")
)
elif name == "code" and value:
if name == "code" and value:
try:
lexer = get_lexer_by_name(value)
except ClassNotFound:
@ -292,17 +304,19 @@ class Formatted():
# from the output
return highlight(string, lexer, WeechatFormatter())[:-1]
elif name == "fgcolor" and value:
if name == "fgcolor" and value:
return "{color_on}{text}{color_off}".format(
color_on=W.color(value),
text=string,
color_off=W.color("resetcolor"))
color_off=W.color("resetcolor"),
)
elif name == "bgcolor" and value:
if name == "bgcolor" and value:
return "{color_on}{text}{color_off}".format(
color_on=W.color("," + value),
text=string,
color_off=W.color("resetcolor"))
color_off=W.color("resetcolor"),
)
return string
@ -313,17 +327,18 @@ class Formatted():
# We need to handle strikethrough first, since doing
# a strikethrough followed by other attributes succeeds in the
# terminal, but doing it the other way around results in garbage.
if 'strikethrough' in attributes:
text = add_attribute(text, 'strikethrough',
attributes['strikethrough'])
attributes.pop('strikethrough')
if "strikethrough" in attributes:
text = add_attribute(
text, "strikethrough", attributes["strikethrough"]
)
attributes.pop("strikethrough")
for key, value in attributes.items():
text = add_attribute(text, key, value)
return text
weechat_strings = map(format_string, self.substrings)
return re.sub(r'\n+', '\n', "".join(weechat_strings)).strip()
return re.sub(r"\n+", "\n", "".join(weechat_strings)).strip()
# TODO this should be a typed dict.
@ -335,7 +350,7 @@ DEFAULT_ATRIBUTES = {
"quote": False,
"code": None,
"fgcolor": None,
"bgcolor": None
"bgcolor": None,
}
@ -566,7 +581,7 @@ def color_line_to_weechat(color_string):
"96": "250",
"97": "254",
"98": "231",
"99": "default"
"99": "default",
}
assert color_string in line_colors
@ -623,7 +638,7 @@ def colour_find_rgb(r, g, b):
cb = q2c[qb]
# If we have hit the colour exactly, return early.
if (cr == r and cg == g and cb == b):
if cr == r and cg == g and cb == b:
return 16 + (36 * qr) + (6 * qg) + qb
# Work out the closest grey (average of RGB).
@ -964,7 +979,6 @@ def color_weechat_to_html(color):
# yapf: enable
if color in weechat_basic_colors:
return hex_colors[weechat_basic_colors[color]]
else:
return hex_colors[color]
@ -977,7 +991,8 @@ class WeechatFormatter(Formatter):
start = end = ""
if style["color"]:
start += "{}".format(
W.color(color_html_to_weechat(str(style["color"]))))
W.color(color_html_to_weechat(str(style["color"])))
)
end = "{}".format(W.color("resetcolor")) + end
if style["bold"]:
start += W.color("bold")
@ -985,13 +1000,13 @@ class WeechatFormatter(Formatter):
if style["italic"]:
start += W.color("italic")
end = W.color("-italic") + end
if style['underline']:
if style["underline"]:
start += W.color("underline")
end = W.color("-underline") + end
self.styles[token] = (start, end)
def format(self, tokensource, outfile):
lastval = ''
lastval = ""
lasttype = None
for ttype, value in tokensource:

View file

@ -15,18 +15,17 @@
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
from __future__ import unicode_literals
import argparse
import re
from builtins import str
import re
import argparse
import matrix.globals
from matrix.globals import W, SERVERS
from matrix.utf import utf8_decode
from matrix.utils import key_from_value, tags_from_line_data
from matrix.server import MatrixServer
from matrix.colors import Formatted
from . import globals as G
from .colors import Formatted
from .globals import SERVERS, W
from .server import MatrixServer
from .utf import utf8_decode
from .utils import key_from_value, tags_from_line_data
class ParseError(Exception):
@ -34,15 +33,15 @@ class ParseError(Exception):
class WeechatArgParse(argparse.ArgumentParser):
def print_usage(self, file):
def print_usage(self, file=None):
pass
def error(self, message):
m = ("{prefix}Error: {message} for command {command} "
"(see /help {command})").format(prefix=W.prefix("error"),
message=message,
command=self.prog)
W.prnt("", m)
message = (
"{prefix}Error: {message} for command {command} "
"(see /help {command})"
).format(prefix=W.prefix("error"), message=message, command=self.prog)
W.prnt("", message)
raise ParseError
@ -95,49 +94,59 @@ class WeechatCommandParser(object):
def hook_commands():
W.hook_command(
# Command name and short description
'matrix',
'Matrix chat protocol command',
"matrix",
"Matrix chat protocol command",
# Synopsis
('server add <server-name> <hostname>[:<port>] ||'
'server delete|list|listfull <server-name> ||'
'connect <server-name> ||'
'disconnect <server-name> ||'
'reconnect <server-name> ||'
'help <matrix-command>'),
(
"server add <server-name> <hostname>[:<port>] ||"
"server delete|list|listfull <server-name> ||"
"connect <server-name> ||"
"disconnect <server-name> ||"
"reconnect <server-name> ||"
"help <matrix-command>"
),
# Description
(' server: list, add, or remove Matrix servers\n'
' connect: connect to Matrix servers\n'
'disconnect: disconnect from one or all Matrix servers\n'
' reconnect: reconnect to server(s)\n\n'
' help: show detailed command help\n\n'
'Use /matrix help [command] to find out more.\n'),
(
" server: list, add, or remove Matrix servers\n"
" connect: connect to Matrix servers\n"
"disconnect: disconnect from one or all Matrix servers\n"
" reconnect: reconnect to server(s)\n\n"
" help: show detailed command help\n\n"
"Use /matrix help [command] to find out more.\n"
),
# Completions
('server %(matrix_server_commands)|%* ||'
'connect %(matrix_servers) ||'
'disconnect %(matrix_servers) ||'
'reconnect %(matrix_servers) ||'
'help %(matrix_commands)'),
(
"server %(matrix_server_commands)|%* ||"
"connect %(matrix_servers) ||"
"disconnect %(matrix_servers) ||"
"reconnect %(matrix_servers) ||"
"help %(matrix_commands)"
),
# Function name
'matrix_command_cb',
'')
"matrix_command_cb",
"",
)
W.hook_command(
# Command name and short description
'redact',
'redact messages',
"redact",
"redact messages",
# Synopsis
('<message-number>[:"<message-part>"] [<reason>]'),
# Description
("message-number: number of message to redact (starting from 1 for\n"
(
"message-number: number of message to redact (starting from 1 for\n"
" the last message received, counting up)\n"
" message-part: an initial part of the message (ignored, only used\n"
" as visual feedback when using completion)\n"
" reason: the redaction reason\n"),
" reason: the redaction reason\n"
),
# Completions
('%(matrix_messages)'),
("%(matrix_messages)"),
# Function name
'matrix_redact_command_cb',
'')
"matrix_redact_command_cb",
"",
)
W.hook_command(
# Command name and short description
@ -146,13 +155,13 @@ def hook_commands():
# Synopsis
("[<topic>|-delete]"),
# Description
(" topic: topic to set\n"
"-delete: delete room topic"),
(" topic: topic to set\n" "-delete: delete room topic"),
# Completions
"",
# Callback
"matrix_topic_command_cb",
"")
"",
)
W.hook_command(
# Command name and short description
@ -166,7 +175,8 @@ def hook_commands():
"",
# Callback
"matrix_me_command_cb",
"")
"",
)
W.hook_command(
# Command name and short description
@ -175,13 +185,16 @@ def hook_commands():
# Synopsis
("<user-id> [<reason>]"),
# Description
("user-id: user-id to kick\n"
" reason: reason why the user was kicked"),
(
"user-id: user-id to kick\n"
" reason: reason why the user was kicked"
),
# Completions
("%(matrix_users)"),
# Callback
"matrix_kick_command_cb",
"")
"",
)
W.hook_command(
# Command name and short description
@ -195,7 +208,8 @@ def hook_commands():
("%(matrix_users)"),
# Callback
"matrix_invite_command_cb",
"")
"",
)
W.hook_command(
# Command name and short description
@ -204,13 +218,16 @@ def hook_commands():
# Synopsis
("<room-id>|<room-alias>"),
# Description
(" room-id: room-id of the room to join\n"
"room-alias: room alias of the room to join"),
(
" room-id: room-id of the room to join\n"
"room-alias: room alias of the room to join"
),
# Completions
"",
# Callback
"matrix_join_command_cb",
"")
"",
)
W.hook_command(
# Command name and short description
@ -224,9 +241,10 @@ def hook_commands():
"",
# Callback
"matrix_part_command_cb",
"")
"",
)
W.hook_command_run('/buffer clear', 'matrix_command_buf_clear_cb', '')
W.hook_command_run("/buffer clear", "matrix_command_buf_clear_cb", "")
# if OPTIONS.enable_backlog:
# hook_page_up()
@ -238,8 +256,9 @@ def matrix_me_command_cb(data, buffer, args):
if buffer in server.buffers.values():
if not server.connected:
message = ("{prefix}matrix: you are not connected to "
"the server").format(prefix=W.prefix("error"))
message = (
"{prefix}matrix: you are not connected to " "the server"
).format(prefix=W.prefix("error"))
W.prnt(server.server_buffer, message)
return W.WEECHAT_RC_ERROR
@ -253,13 +272,16 @@ def matrix_me_command_cb(data, buffer, args):
server.room_send_message(room_buffer, formatted_data, "m.emote")
return W.WEECHAT_RC_OK
elif buffer == server.server_buffer:
message = ("{prefix}matrix: command \"me\" must be "
if buffer == server.server_buffer:
message = (
'{prefix}matrix: command "me" must be '
"executed on a Matrix channel buffer"
).format(prefix=W.prefix("error"))
W.prnt("", message)
return W.WEECHAT_RC_OK
return W.WEECHAT_RC_OK
@utf8_decode
def matrix_topic_command_cb(data, buffer, args):
@ -269,8 +291,9 @@ def matrix_topic_command_cb(data, buffer, args):
for server in SERVERS.values():
if buffer == server.server_buffer:
server.error("command \"topic\" must be "
"executed on a Matrix room buffer")
server.error(
'command "topic" must be ' "executed on a Matrix room buffer"
)
return W.WEECHAT_RC_OK
room = server.find_room_from_ptr(buffer)
@ -310,15 +333,17 @@ def matrix_fetch_old_messages(server, room_id):
def check_server_existence(server_name, servers):
if server_name not in servers:
message = "{prefix}matrix: No such server: {server}".format(
prefix=W.prefix("error"), server=server_name)
prefix=W.prefix("error"), server=server_name
)
W.prnt("", message)
return False
return True
def hook_page_up():
OPTIONS.page_up_hook = W.hook_command_run('/window page_up',
'matrix_command_pgup_cb', '')
G.CONFIG.page_up_hook = W.hook_command_run(
"/window page_up", "matrix_command_pgup_cb", ""
)
@utf8_decode
@ -345,7 +370,8 @@ def matrix_command_pgup_cb(data, buffer, command):
window = W.window_search_with_buffer(buffer)
first_line_displayed = bool(
W.window_get_integer(window, "first_line_displayed"))
W.window_get_integer(window, "first_line_displayed")
)
if first_line_displayed:
room_id = key_from_value(server.buffers, buffer)
@ -382,9 +408,11 @@ def matrix_part_command_cb(data, buffer, args):
if not room_id:
if buffer == server.server_buffer:
server.error("command \"part\" must be "
server.error(
'command "part" must be '
"executed on a Matrix room buffer or a room "
"name needs to be given")
"name needs to be given"
)
return W.WEECHAT_RC_OK
room_buffer = server.find_room_from_ptr(buffer)
@ -404,8 +432,9 @@ def matrix_invite_command_cb(data, buffer, args):
for server in SERVERS.values():
if buffer == server.server_buffer:
server.error("command \"invite\" must be "
"executed on a Matrix room buffer")
server.error(
'command "invite" must be ' "executed on a Matrix room buffer"
)
return W.WEECHAT_RC_OK
room = server.find_room_from_ptr(buffer)
@ -429,8 +458,9 @@ def matrix_kick_command_cb(data, buffer, args):
for server in SERVERS.values():
if buffer == server.server_buffer:
server.error("command \"kick\" must be "
"executed on a Matrix room buffer")
server.error(
'command "kick" must be ' "executed on a Matrix room buffer"
)
return W.WEECHAT_RC_OK
room = server.find_room_from_ptr(buffer)
@ -449,22 +479,24 @@ def matrix_kick_command_cb(data, buffer, args):
def event_id_from_line(buf, target_number):
# type: (weechat.buffer, int) -> str
own_lines = W.hdata_pointer(W.hdata_get('buffer'), buf, 'own_lines')
own_lines = W.hdata_pointer(W.hdata_get("buffer"), buf, "own_lines")
if own_lines:
line = W.hdata_pointer(W.hdata_get('lines'), own_lines, 'last_line')
line = W.hdata_pointer(W.hdata_get("lines"), own_lines, "last_line")
line_number = 1
while line:
line_data = W.hdata_pointer(W.hdata_get('line'), line, 'data')
line_data = W.hdata_pointer(W.hdata_get("line"), line, "data")
if line_data:
tags = tags_from_line_data(line_data)
# Only count non redacted user messages
if ("matrix_message" in tags and
'matrix_redacted' not in tags and
"matrix_new_redacted" not in tags):
if (
"matrix_message" in tags
and "matrix_redacted" not in tags
and "matrix_new_redacted" not in tags
):
if line_number == target_number:
for tag in tags:
@ -474,7 +506,7 @@ def event_id_from_line(buf, target_number):
line_number += 1
line = W.hdata_move(W.hdata_get('line'), line, -1)
line = W.hdata_move(W.hdata_get("line"), line, -1)
return ""
@ -488,7 +520,8 @@ def matrix_redact_command_cb(data, buffer, args):
matches = re.match(r"(\d+)(:\".*\")? ?(.*)?", args)
if not matches:
message = ("{prefix}matrix: Invalid command "
message = (
"{prefix}matrix: Invalid command "
"arguments (see /help redact)"
).format(prefix=W.prefix("error"))
W.prnt("", message)
@ -500,9 +533,10 @@ def matrix_redact_command_cb(data, buffer, args):
event_id = event_id_from_line(buffer, line)
if not event_id:
message = ("{prefix}matrix: No such message with number "
"{number} found").format(
prefix=W.prefix("error"), number=line)
message = (
"{prefix}matrix: No such message with number "
"{number} found"
).format(prefix=W.prefix("error"), number=line)
W.prnt("", message)
return W.WEECHAT_RC_OK
@ -510,8 +544,9 @@ def matrix_redact_command_cb(data, buffer, args):
return W.WEECHAT_RC_OK
elif buffer == server.server_buffer:
message = ("{prefix}matrix: command \"redact\" must be "
if buffer == server.server_buffer:
message = (
'{prefix}matrix: command "redact" must be '
"executed on a Matrix channel buffer"
).format(prefix=W.prefix("error"))
W.prnt("", message)
@ -522,8 +557,9 @@ def matrix_redact_command_cb(data, buffer, args):
def matrix_command_help(args):
if not args:
message = ("{prefix}matrix: Too few arguments for command "
"\"/matrix help\" (see /matrix help help)"
message = (
"{prefix}matrix: Too few arguments for command "
'"/matrix help" (see /matrix help help)'
).format(prefix=W.prefix("error"))
W.prnt("", message)
return
@ -532,46 +568,56 @@ def matrix_command_help(args):
message = ""
if command == "connect":
message = ("{delimiter_color}[{ncolor}matrix{delimiter_color}] "
message = (
"{delimiter_color}[{ncolor}matrix{delimiter_color}] "
"{ncolor}{cmd_color}/connect{ncolor} "
"<server-name> [<server-name>...]"
"\n\n"
"connect to Matrix server(s)"
"\n\n"
"server-name: server to connect to"
"(internal name)").format(
"(internal name)"
).format(
delimiter_color=W.color("chat_delimiters"),
cmd_color=W.color("chat_buffer"),
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
elif command == "disconnect":
message = ("{delimiter_color}[{ncolor}matrix{delimiter_color}] "
message = (
"{delimiter_color}[{ncolor}matrix{delimiter_color}] "
"{ncolor}{cmd_color}/disconnect{ncolor} "
"<server-name> [<server-name>...]"
"\n\n"
"disconnect from Matrix server(s)"
"\n\n"
"server-name: server to disconnect"
"(internal name)").format(
"(internal name)"
).format(
delimiter_color=W.color("chat_delimiters"),
cmd_color=W.color("chat_buffer"),
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
elif command == "reconnect":
message = ("{delimiter_color}[{ncolor}matrix{delimiter_color}] "
message = (
"{delimiter_color}[{ncolor}matrix{delimiter_color}] "
"{ncolor}{cmd_color}/reconnect{ncolor} "
"<server-name> [<server-name>...]"
"\n\n"
"reconnect to Matrix server(s)"
"\n\n"
"server-name: server to reconnect"
"(internal name)").format(
"(internal name)"
).format(
delimiter_color=W.color("chat_delimiters"),
cmd_color=W.color("chat_buffer"),
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
elif command == "server":
message = ("{delimiter_color}[{ncolor}matrix{delimiter_color}] "
message = (
"{delimiter_color}[{ncolor}matrix{delimiter_color}] "
"{ncolor}{cmd_color}/server{ncolor} "
"add <server-name> <hostname>[:<port>]"
"\n "
@ -592,28 +638,34 @@ def matrix_command_help(args):
"Examples:"
"\n /matrix server listfull"
"\n /matrix server add matrix matrix.org:80"
"\n /matrix server del matrix").format(
"\n /matrix server del matrix"
).format(
delimiter_color=W.color("chat_delimiters"),
cmd_color=W.color("chat_buffer"),
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
elif command == "help":
message = ("{delimiter_color}[{ncolor}matrix{delimiter_color}] "
message = (
"{delimiter_color}[{ncolor}matrix{delimiter_color}] "
"{ncolor}{cmd_color}/help{ncolor} "
"<matrix-command> [<matrix-command>...]"
"\n\n"
"display help about Matrix commands"
"\n\n"
"matrix-command: a Matrix command name"
"(internal name)").format(
"(internal name)"
).format(
delimiter_color=W.color("chat_delimiters"),
cmd_color=W.color("chat_buffer"),
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
else:
message = ("{prefix}matrix: No help available, \"{command}\" "
"is not a matrix command").format(
prefix=W.prefix("error"), command=command)
message = (
'{prefix}matrix: No help available, "{command}" '
"is not a matrix command"
).format(prefix=W.prefix("error"), command=command)
W.prnt("", "")
W.prnt("", message)
@ -622,7 +674,6 @@ def matrix_command_help(args):
def matrix_server_command_listfull(args):
def get_value_string(value, default_value):
if value == default_value:
if not value:
@ -632,7 +683,8 @@ def matrix_server_command_listfull(args):
value_string = "{color}{value}{ncolor}".format(
color=W.color("chat_value"),
value=value,
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
return value_string
@ -650,14 +702,17 @@ def matrix_server_command_listfull(args):
else:
connected = "not connected"
message = ("Server: {server_color}{server}{delimiter_color}"
message = (
"Server: {server_color}{server}{delimiter_color}"
" [{ncolor}{connected}{delimiter_color}]"
"{ncolor}").format(
"{ncolor}"
).format(
server_color=W.color("chat_server"),
server=server.name,
delimiter_color=W.color("chat_delimiters"),
connected=connected,
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
W.prnt("", message)
@ -703,7 +758,7 @@ def matrix_server_command_listfull(args):
if value:
value = "(hidden)"
value_string = get_value_string(value, '')
value_string = get_value_string(value, "")
message = " password . . : {value}".format(value=value_string)
W.prnt("", message)
@ -715,14 +770,17 @@ def matrix_server_command_delete(args):
server = SERVERS[server_name]
if server.connected:
message = ("{prefix}matrix: you can not delete server "
message = (
"{prefix}matrix: you can not delete server "
"{color}{server}{ncolor} because you are "
"connected to it. Try \"/matrix disconnect "
"{color}{server}{ncolor}\" before.").format(
'connected to it. Try "/matrix disconnect '
'{color}{server}{ncolor}" before.'
).format(
prefix=W.prefix("error"),
color=W.color("chat_server"),
ncolor=W.color("reset"),
server=server.name)
server=server.name,
)
W.prnt("", message)
return
@ -735,11 +793,13 @@ def matrix_server_command_delete(args):
for option in server.config._option_ptrs.values():
W.config_option_free(option)
message = ("matrix: server {color}{server}{ncolor} has been "
"deleted").format(
message = (
"matrix: server {color}{server}{ncolor} has been " "deleted"
).format(
server=server.name,
color=W.color("chat_server"),
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
del SERVERS[server.name]
server = None
@ -749,14 +809,16 @@ def matrix_server_command_delete(args):
def matrix_server_command_add(args):
if len(args) < 2:
message = ("{prefix}matrix: Too few arguments for command "
"\"/matrix server add\" (see /matrix help server)").format(
prefix=W.prefix("error"))
message = (
"{prefix}matrix: Too few arguments for command "
'"/matrix server add" (see /matrix help server)'
).format(prefix=W.prefix("error"))
W.prnt("", message)
return
elif len(args) > 4:
message = ("{prefix}matrix: Too many arguments for command "
"\"/matrix server add\" (see /matrix help server)"
if len(args) > 4:
message = (
"{prefix}matrix: Too many arguments for command "
'"/matrix server add" (see /matrix help server)'
).format(prefix=W.prefix("error"))
W.prnt("", message)
return
@ -769,16 +831,19 @@ def matrix_server_command_add(args):
server_name = args[0]
if server_name in SERVERS:
message = ("{prefix}matrix: server {color}{server}{ncolor} "
"already exists, can't add it").format(
message = (
"{prefix}matrix: server {color}{server}{ncolor} "
"already exists, can't add it"
).format(
prefix=W.prefix("error"),
color=W.color("chat_server"),
server=server_name,
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
W.prnt("", message)
return
server = MatrixServer(server_name, matrix.globals.CONFIG)
server = MatrixServer(server_name, G.CONFIG._ptr)
SERVERS[server.name] = server
if len(args) >= 2:
@ -788,20 +853,21 @@ def matrix_server_command_add(args):
host, port = args[1], None
return_code = W.config_option_set(
server.config._option_ptrs["address"],
host,
1
server.config._option_ptrs["address"], host, 1
)
if return_code == W.WEECHAT_CONFIG_OPTION_SET_ERROR:
remove_server(server)
message = ("{prefix}Failed to set address for server "
message = (
"{prefix}Failed to set address for server "
"{color}{server}{ncolor}, failed to add "
"server.").format(
"server."
).format(
prefix=W.prefix("error"),
color=W.color("chat_server"),
server=server.name,
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
W.prnt("", message)
server = None
@ -809,19 +875,20 @@ def matrix_server_command_add(args):
if port:
return_code = W.config_option_set(
server.config._option_ptrs["port"],
port,
1
server.config._option_ptrs["port"], port, 1
)
if return_code == W.WEECHAT_CONFIG_OPTION_SET_ERROR:
remove_server(server)
message = ("{prefix}Failed to set port for server "
message = (
"{prefix}Failed to set port for server "
"{color}{server}{ncolor}, failed to add "
"server.").format(
"server."
).format(
prefix=W.prefix("error"),
color=W.color("chat_server"),
server=server.name,
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
W.prnt("", message)
server = None
@ -830,20 +897,21 @@ def matrix_server_command_add(args):
if len(args) >= 3:
user = args[2]
return_code = W.config_option_set(
server.config._option_ptrs["username"],
user,
1
server.config._option_ptrs["username"], user, 1
)
if return_code == W.WEECHAT_CONFIG_OPTION_SET_ERROR:
remove_server(server)
message = ("{prefix}Failed to set user for server "
message = (
"{prefix}Failed to set user for server "
"{color}{server}{ncolor}, failed to add "
"server.").format(
"server."
).format(
prefix=W.prefix("error"),
color=W.color("chat_server"),
server=server.name,
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
W.prnt("", message)
server = None
@ -853,28 +921,31 @@ def matrix_server_command_add(args):
password = args[3]
return_code = W.config_option_set(
server.config._option_ptrs["password"],
password,
1
server.config._option_ptrs["password"], password, 1
)
if return_code == W.WEECHAT_CONFIG_OPTION_SET_ERROR:
remove_server(server)
message = ("{prefix}Failed to set password for server "
message = (
"{prefix}Failed to set password for server "
"{color}{server}{ncolor}, failed to add "
"server.").format(
"server."
).format(
prefix=W.prefix("error"),
color=W.color("chat_server"),
server=server.name,
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
W.prnt("", message)
server = None
return
message = ("matrix: server {color}{server}{ncolor} "
"has been added").format(
message = (
"matrix: server {color}{server}{ncolor} " "has been added"
).format(
server=server.name,
color=W.color("chat_server"),
ncolor=W.color("reset"))
ncolor=W.color("reset"),
)
W.prnt("", message)
@ -883,23 +954,28 @@ def matrix_server_command(command, args):
if SERVERS:
W.prnt("", "\nAll matrix servers:")
for server in SERVERS:
W.prnt("", " {color}{server}".format(
color=W.color("chat_server"), server=server))
W.prnt(
"",
" {color}{server}".format(
color=W.color("chat_server"), server=server
),
)
# TODO the argument for list and listfull is used as a match word to
# find/filter servers, we're currently match exactly to the whole name
if command == 'list':
if command == "list":
list_servers(args)
elif command == 'listfull':
elif command == "listfull":
matrix_server_command_listfull(args)
elif command == 'add':
elif command == "add":
matrix_server_command_add(args)
elif command == 'delete':
elif command == "delete":
matrix_server_command_delete(args)
else:
message = ("{prefix}matrix: Error: unknown matrix server command, "
"\"{command}\" (type /matrix help server for help)").format(
prefix=W.prefix("error"), command=command)
message = (
"{prefix}matrix: Error: unknown matrix server command, "
'"{command}" (type /matrix help server for help)'
).format(prefix=W.prefix("error"), command=command)
W.prnt("", message)
@ -921,41 +997,44 @@ def matrix_command_cb(data, buffer, args):
server.access_token = ""
server.disconnect(reconnect=False)
split_args = list(filter(bool, args.split(' ')))
split_args = list(filter(bool, args.split(" ")))
if len(split_args) < 1:
message = ("{prefix}matrix: Too few arguments for command "
"\"/matrix\" "
"(see /help matrix)").format(prefix=W.prefix("error"))
message = (
"{prefix}matrix: Too few arguments for command "
'"/matrix" '
"(see /help matrix)"
).format(prefix=W.prefix("error"))
W.prnt("", message)
return W.WEECHAT_RC_ERROR
command, args = split_args[0], split_args[1:]
if command == 'connect':
if command == "connect":
connect_server(args)
elif command == 'disconnect':
elif command == "disconnect":
disconnect_server(args)
elif command == 'reconnect':
elif command == "reconnect":
disconnect_server(args)
connect_server(args)
elif command == 'server':
elif command == "server":
if len(args) >= 1:
subcommand, args = args[0], args[1:]
matrix_server_command(subcommand, args)
else:
matrix_server_command("list", "")
elif command == 'help':
elif command == "help":
matrix_command_help(args)
else:
message = ("{prefix}matrix: Error: unknown matrix command, "
"\"{command}\" (type /help matrix for help)").format(
prefix=W.prefix("error"), command=command)
message = (
"{prefix}matrix: Error: unknown matrix command, "
'"{command}" (type /help matrix for help)'
).format(prefix=W.prefix("error"), command=command)
W.prnt("", message)
return W.WEECHAT_RC_OK

View file

@ -16,29 +16,32 @@
from __future__ import unicode_literals
from matrix.globals import SERVERS, W
from matrix.utf import utf8_decode
from matrix.globals import W, SERVERS
from matrix.utils import tags_from_line_data
def add_servers_to_completion(completion):
for server_name in SERVERS:
W.hook_completion_list_add(completion, server_name, 0,
W.WEECHAT_LIST_POS_SORT)
W.hook_completion_list_add(
completion, server_name, 0, W.WEECHAT_LIST_POS_SORT
)
@utf8_decode
def matrix_server_command_completion_cb(data, completion_item, buffer,
completion):
def matrix_server_command_completion_cb(
data, completion_item, buffer, completion
):
buffer_input = W.buffer_get_string(buffer, "input").split()
args = buffer_input[1:]
commands = ['add', 'delete', 'list', 'listfull']
commands = ["add", "delete", "list", "listfull"]
def complete_commands():
for command in commands:
W.hook_completion_list_add(completion, command, 0,
W.WEECHAT_LIST_POS_SORT)
W.hook_completion_list_add(
completion, command, 0, W.WEECHAT_LIST_POS_SORT
)
if len(args) == 1:
complete_commands()
@ -47,11 +50,11 @@ def matrix_server_command_completion_cb(data, completion_item, buffer,
if args[1] not in commands:
complete_commands()
else:
if args[1] == 'delete' or args[1] == 'listfull':
if args[1] == "delete" or args[1] == "listfull":
add_servers_to_completion(completion)
elif len(args) == 3:
if args[1] == 'delete' or args[1] == 'listfull':
if args[1] == "delete" or args[1] == "listfull":
if args[2] not in SERVERS:
add_servers_to_completion(completion)
@ -67,18 +70,25 @@ def matrix_server_completion_cb(data, completion_item, buffer, completion):
@utf8_decode
def matrix_command_completion_cb(data, completion_item, buffer, completion):
for command in [
"connect", "disconnect", "reconnect", "server", "help", "debug"
"connect",
"disconnect",
"reconnect",
"server",
"help",
"debug",
]:
W.hook_completion_list_add(completion, command, 0,
W.WEECHAT_LIST_POS_SORT)
W.hook_completion_list_add(
completion, command, 0, W.WEECHAT_LIST_POS_SORT
)
return W.WEECHAT_RC_OK
@utf8_decode
def matrix_debug_completion_cb(data, completion_item, buffer, completion):
for debug_type in ["messaging", "network", "timing"]:
W.hook_completion_list_add(completion, debug_type, 0,
W.WEECHAT_LIST_POS_SORT)
W.hook_completion_list_add(
completion, debug_type, 0, W.WEECHAT_LIST_POS_SORT
)
return W.WEECHAT_RC_OK
@ -88,36 +98,42 @@ REDACTION_COMP_LEN = 50
@utf8_decode
def matrix_message_completion_cb(data, completion_item, buffer, completion):
own_lines = W.hdata_pointer(W.hdata_get('buffer'), buffer, 'own_lines')
own_lines = W.hdata_pointer(W.hdata_get("buffer"), buffer, "own_lines")
if own_lines:
line = W.hdata_pointer(W.hdata_get('lines'), own_lines, 'last_line')
line = W.hdata_pointer(W.hdata_get("lines"), own_lines, "last_line")
line_number = 1
while line:
line_data = W.hdata_pointer(W.hdata_get('line'), line, 'data')
line_data = W.hdata_pointer(W.hdata_get("line"), line, "data")
if line_data:
message = W.hdata_string(
W.hdata_get('line_data'), line_data, 'message')
W.hdata_get("line_data"), line_data, "message"
)
tags = tags_from_line_data(line_data)
# Only add non redacted user messages to the completion
if (message and 'matrix_message' in tags and
'matrix_redacted' not in tags):
if (
message
and "matrix_message" in tags
and "matrix_redacted" not in tags
):
if len(message) > REDACTION_COMP_LEN + 2:
message = (message[:REDACTION_COMP_LEN] + '..')
message = message[:REDACTION_COMP_LEN] + ".."
item = ("{number}:\"{message}\"").format(
number=line_number, message=message)
item = ('{number}:"{message}"').format(
number=line_number, message=message
)
W.hook_completion_list_add(completion, item, 0,
W.WEECHAT_LIST_POS_END)
W.hook_completion_list_add(
completion, item, 0, W.WEECHAT_LIST_POS_END
)
line_number += 1
line = W.hdata_move(W.hdata_get('line'), line, -1)
line = W.hdata_move(W.hdata_get("line"), line, -1)
return W.WEECHAT_RC_OK
@ -126,7 +142,7 @@ def server_from_buffer(buffer):
for server in SERVERS.values():
if buffer in server.buffers.values():
return server
elif buffer == server.server_buffer:
if buffer == server.server_buffer:
return server
return None
@ -141,8 +157,9 @@ def matrix_olm_user_completion_cb(data, completion_item, buffer, completion):
olm = server.olm
for user in olm.device_keys:
W.hook_completion_list_add(completion, user, 0,
W.WEECHAT_LIST_POS_SORT)
W.hook_completion_list_add(
completion, user, 0, W.WEECHAT_LIST_POS_SORT
)
return W.WEECHAT_RC_OK
@ -169,8 +186,9 @@ def matrix_olm_device_completion_cb(data, completion_item, buffer, completion):
return W.WEECHAT_RC_OK
for device in olm.device_keys[user]:
W.hook_completion_list_add(completion, device.device_id, 0,
W.WEECHAT_LIST_POS_SORT)
W.hook_completion_list_add(
completion, device.device_id, 0, W.WEECHAT_LIST_POS_SORT
)
return W.WEECHAT_RC_OK
@ -178,8 +196,9 @@ def matrix_olm_device_completion_cb(data, completion_item, buffer, completion):
@utf8_decode
def matrix_user_completion_cb(data, completion_item, buffer, completion):
def add_user(completion, user):
W.hook_completion_list_add(completion, user, 0,
W.WEECHAT_LIST_POS_SORT)
W.hook_completion_list_add(
completion, user, 0, W.WEECHAT_LIST_POS_SORT
)
for server in SERVERS.values():
if buffer == server.server_buffer:
@ -201,26 +220,58 @@ def matrix_user_completion_cb(data, completion_item, buffer, completion):
def init_completion():
W.hook_completion("matrix_server_commands", "Matrix server completion",
"matrix_server_command_completion_cb", "")
W.hook_completion(
"matrix_server_commands",
"Matrix server completion",
"matrix_server_command_completion_cb",
"",
)
W.hook_completion("matrix_servers", "Matrix server completion",
"matrix_server_completion_cb", "")
W.hook_completion(
"matrix_servers",
"Matrix server completion",
"matrix_server_completion_cb",
"",
)
W.hook_completion("matrix_commands", "Matrix command completion",
"matrix_command_completion_cb", "")
W.hook_completion(
"matrix_commands",
"Matrix command completion",
"matrix_command_completion_cb",
"",
)
W.hook_completion("matrix_messages", "Matrix message completion",
"matrix_message_completion_cb", "")
W.hook_completion(
"matrix_messages",
"Matrix message completion",
"matrix_message_completion_cb",
"",
)
W.hook_completion("matrix_debug_types", "Matrix debugging type completion",
"matrix_debug_completion_cb", "")
W.hook_completion(
"matrix_debug_types",
"Matrix debugging type completion",
"matrix_debug_completion_cb",
"",
)
W.hook_completion("olm_user_ids", "Matrix olm user id completion",
"matrix_olm_user_completion_cb", "")
W.hook_completion(
"olm_user_ids",
"Matrix olm user id completion",
"matrix_olm_user_completion_cb",
"",
)
W.hook_completion("olm_devices", "Matrix olm device id completion",
"matrix_olm_device_completion_cb", "")
W.hook_completion(
"olm_devices",
"Matrix olm device id completion",
"matrix_olm_device_completion_cb",
"",
)
W.hook_completion("matrix_users", "Matrix user id completion",
"matrix_user_completion_cb", "")
W.hook_completion(
"matrix_users",
"Matrix user id completion",
"matrix_user_completion_cb",
"",
)

View file

@ -16,16 +16,16 @@
# from __future__ import unicode_literals
from builtins import super
from collections import namedtuple
from enum import Enum, unique
import nio
import logbook
import nio
from . import globals as G
from matrix.globals import W, SERVERS, SCRIPT_NAME
from matrix.globals import SCRIPT_NAME, SERVERS, W
from matrix.utf import utf8_decode
from enum import Enum, unique
from collections import namedtuple
from . import globals as G
@unique
@ -49,20 +49,22 @@ class DebugType(Enum):
TIMING = 2
class Option(namedtuple(
'Option',
class Option(
namedtuple(
"Option",
[
'name',
'type',
'string_values',
'min',
'max',
'value',
'description',
'cast_func',
'change_callback'
]
)):
"name",
"type",
"string_values",
"min",
"max",
"value",
"description",
"cast_func",
"change_callback",
],
)
):
__slots__ = ()
def __new__(
@ -75,7 +77,7 @@ class Option(namedtuple(
value,
description,
cast=None,
change_callback=None
change_callback=None,
):
return super().__new__(
cls,
@ -87,12 +89,10 @@ class Option(namedtuple(
value,
description,
cast,
change_callback
change_callback,
)
@utf8_decode
def matrix_config_reload_cb(data, config_file):
return W.WEECHAT_RC_OK
@ -121,8 +121,7 @@ def config_server_buffer_cb(data, option):
@utf8_decode
def config_log_level_cb(data, option):
change_log_level(
G.CONFIG.network.debug_category,
G.CONFIG.network.debug_level
G.CONFIG.network.debug_category, G.CONFIG.network.debug_level
)
return 1
@ -132,8 +131,7 @@ def config_log_category_cb(data, option):
change_log_level(G.CONFIG.debug_category, logbook.ERROR)
G.CONFIG.debug_category = G.CONFIG.network.debug_category
change_log_level(
G.CONFIG.network.debug_category,
G.CONFIG.network.debug_level
G.CONFIG.network.debug_category, G.CONFIG.network.debug_level
)
return 1
@ -141,11 +139,11 @@ def config_log_category_cb(data, option):
def level_to_logbook(value):
if value == 0:
return logbook.ERROR
elif value == 1:
if value == 1:
return logbook.WARNING
elif value == 2:
if value == 2:
return logbook.INFO
elif value == 3:
if value == 3:
return logbook.DEBUG
return logbook.ERROR
@ -154,13 +152,13 @@ def level_to_logbook(value):
def logbook_category(value):
if value == 0:
return "all"
elif value == 1:
if value == 1:
return "http"
elif value == 2:
if value == 2:
return "client"
elif value == 3:
if value == 3:
return "events"
elif value == 4:
if value == 4:
return "responses"
return "all"
@ -169,9 +167,7 @@ def logbook_category(value):
class WeechatConfig(object):
def __init__(self, sections):
self._ptr = W.config_new(
SCRIPT_NAME,
SCRIPT_NAME + "_config_reload_cb",
""
SCRIPT_NAME, SCRIPT_NAME + "_config_reload_cb", ""
)
for section in sections:
@ -180,8 +176,11 @@ class WeechatConfig(object):
setattr(self, name, section_class(name, self._ptr, options))
def free(self):
for section in [getattr(self, a) for a in dir(self) if
isinstance(getattr(self, a), ConfigSection)]:
for section in [
getattr(self, a)
for a in dir(self)
if isinstance(getattr(self, a), ConfigSection)
]:
section.free()
W.config_free(self._ptr)
@ -190,9 +189,9 @@ class WeechatConfig(object):
return_code = W.config_read(self._ptr)
if return_code == W.WEECHAT_CONFIG_READ_OK:
return True
elif return_code == W.WEECHAT_CONFIG_READ_MEMORY_ERROR:
if return_code == W.WEECHAT_CONFIG_READ_MEMORY_ERROR:
return False
elif return_code == W.WEECHAT_CONFIG_READ_FILE_NOT_FOUND:
if return_code == W.WEECHAT_CONFIG_READ_FILE_NOT_FOUND:
return True
return False
@ -201,8 +200,9 @@ class ConfigSection(object):
@classmethod
def build(cls, name, options):
def constructor(self, name, config_ptr, options):
self._ptr = W.config_new_section(config_ptr, name, 0, 0, "", "",
"", "", "", "", "", "", "", "")
self._ptr = W.config_new_section(
config_ptr, name, 0, 0, "", "", "", "", "", "", "", "", "", ""
)
self._config_ptr = config_ptr
self._option_ptrs = {}
@ -211,18 +211,13 @@ class ConfigSection(object):
attributes = {
option.name: cls.option_property(
option.name,
option.type,
cast_func=option.cast_func
) for option in options
option.name, option.type, cast_func=option.cast_func
)
for option in options
}
attributes["__init__"] = constructor
section_class = type(
name.title() + "Section",
(cls,),
attributes
)
section_class = type(name.title() + "Section", (cls,), attributes)
return section_class
def free(self):
@ -232,10 +227,24 @@ class ConfigSection(object):
def _add_option(self, option):
cb = option.change_callback.__name__ if option.change_callback else ""
option_ptr = W.config_new_option(
self._config_ptr, self._ptr, option.name, option.type,
option.description, option.string_values, option.min,
option.max, option.value, option.value, 0, "", "",
cb, "", "", "")
self._config_ptr,
self._ptr,
option.name,
option.type,
option.description,
option.string_values,
option.min,
option.max,
option.value,
option.value,
0,
"",
"",
cb,
"",
"",
"",
)
self._option_ptrs[option.name] = option_ptr
@ -249,25 +258,21 @@ class ConfigSection(object):
def str_evaluate_getter(self):
return W.string_eval_expression(
W.config_string(self._option_ptrs[name]),
{},
{},
{}
W.config_string(self._option_ptrs[name]), {}, {}, {}
)
def int_getter(self):
if cast_func:
return cast_func(W.config_integer(self._option_ptrs[name]))
else:
return W.config_integer(self._option_ptrs[name])
if option_type == "string" or option_type == "color":
if option_type in ("string", "color"):
if evaluate:
return property(str_evaluate_getter)
return property(str_getter)
elif option_type == "boolean":
if option_type == "boolean":
return property(bool_getter)
elif option_type == "integer":
if option_type == "integer":
return property(int_getter)
@ -276,45 +281,111 @@ class MatrixConfig(WeechatConfig):
self.debug_buffer = ""
self.debug_category = "all"
self.page_up_hook = None
look_options = [
Option("redactions", "integer", "strikethrough|notice|delete", 0,
0, "strikethrough",
("Only notice redactions, strike through or delete "
"redacted messages"), RedactType),
Option("server_buffer", "integer",
"merge_with_core|merge_without_core|independent", 0, 0,
"merge_with_core", "Merge server buffers", ServerBufferType,
config_server_buffer_cb)
Option(
"redactions",
"integer",
"strikethrough|notice|delete",
0,
0,
"strikethrough",
(
"Only notice redactions, strike through or delete "
"redacted messages"
),
RedactType,
),
Option(
"server_buffer",
"integer",
"merge_with_core|merge_without_core|independent",
0,
0,
"merge_with_core",
"Merge server buffers",
ServerBufferType,
config_server_buffer_cb,
),
]
network_options = [
Option("max_initial_sync_events", "integer", "", 1, 10000, "30",
("How many events to fetch during the initial sync")),
Option("max_backlog_sync_events", "integer", "", 1, 100, "10",
("How many events to fetch during backlog fetching")),
Option("fetch_backlog_on_pgup", "boolean", "", 0, 0, "on",
("Fetch messages in the backlog on a window page up event")
Option(
"max_initial_sync_events",
"integer",
"",
1,
10000,
"30",
("How many events to fetch during the initial sync"),
),
Option("debug_level", "integer", "error|warn|info|debug", 0, 0,
"error", "Enable network protocol debugging.",
level_to_logbook, config_log_level_cb),
Option("debug_category", "integer",
Option(
"max_backlog_sync_events",
"integer",
"",
1,
100,
"10",
("How many events to fetch during backlog fetching"),
),
Option(
"fetch_backlog_on_pgup",
"boolean",
"",
0,
0,
"on",
("Fetch messages in the backlog on a window page up event"),
),
Option(
"debug_level",
"integer",
"error|warn|info|debug",
0,
0,
"error",
"Enable network protocol debugging.",
level_to_logbook,
config_log_level_cb,
),
Option(
"debug_category",
"integer",
"all|http|client|events|responses",
0, 0, "all", "Debugging category", logbook_category),
Option("debug_buffer", "boolean", "", 0, 0, "off",
("Use a separate buffer for debug logs.")),
0,
0,
"all",
"Debugging category",
logbook_category,
),
Option(
"debug_buffer",
"boolean",
"",
0,
0,
"off",
("Use a separate buffer for debug logs."),
),
]
color_options = [
Option("quote", "color", "", 0, 0, "lightgreen",
("Color for matrix style blockquotes"))
Option(
"quote",
"color",
"",
0,
0,
"lightgreen",
("Color for matrix style blockquotes"),
)
]
sections = [
("network", network_options),
("look", look_options),
("color", color_options)
("color", color_options),
]
super().__init__(sections)
@ -322,10 +393,23 @@ class MatrixConfig(WeechatConfig):
# The server section is essentially a section with subsections and no
# options, handle that case independently.
W.config_new_section(
self._ptr, "server", 0, 0, "matrix_config_server_read_cb", "",
"matrix_config_server_write_cb", "", "", "", "", "", "", "")
self._ptr,
"server",
0,
0,
"matrix_config_server_read_cb",
"",
"matrix_config_server_write_cb",
"",
"",
"",
"",
"",
"",
"",
)
def free(self):
section_ptr = W.config_search_section(self._ptr, 'server')
section_ptr = W.config_search_section(self._ptr, "server")
W.config_section_free(section_ptr)
super().free()

View file

@ -18,13 +18,19 @@ from __future__ import unicode_literals
import sys
from matrix.utf import WeechatWrapper
from .utf import WeechatWrapper
if False:
from typing import Dict
try:
import weechat
W = weechat if sys.hexversion >= 0x3000000 else WeechatWrapper(weechat)
except ImportError:
import matrix._weechat as weechat
W = weechat
SERVERS = dict() # type: Dict[str, MatrixServer]

View file

@ -17,30 +17,28 @@
from __future__ import unicode_literals
import os
import ssl
import socket
import time
import pprint
from collections import deque, defaultdict
import socket
import ssl
import time
from collections import defaultdict, deque
from nio import (
HttpClient,
LocalProtocolError,
LoginResponse,
SyncRepsponse,
RoomSendResponse,
SyncRepsponse,
TransportResponse,
TransportType,
LocalProtocolError
)
from matrix.utils import (key_from_value, server_buffer_prnt,
create_server_buffer)
from matrix.utf import utf8_decode
from . import globals as G
from matrix.globals import W, SERVERS, SCRIPT_NAME
from .buffer import RoomBuffer, OwnMessage, OwnAction
from .config import Option, ServerBufferType, ConfigSection
from .buffer import OwnAction, OwnMessage, RoomBuffer
from .config import ConfigSection, Option, ServerBufferType
from .globals import SCRIPT_NAME, SERVERS, W
from .utf import utf8_decode
from .utils import create_server_buffer, key_from_value, server_buffer_prnt
try:
FileNotFoundError
@ -56,39 +54,101 @@ class ServerConfig(ConfigSection):
self._option_ptrs = {}
options = [
Option('autoconnect', 'boolean', '', 0, 0, 'off',
("automatically connect to the matrix server when weechat "
"is starting")),
Option('address', 'string', '', 0, 0, '',
"Hostname or IP address for the server"),
Option('port', 'integer', '', 0, 65535, '443',
"Port for the server"),
Option('proxy', 'string', '', 0, 0, '',
("Name of weechat proxy to use (see /help proxy)")),
Option('ssl_verify', 'boolean', '', 0, 0, 'on',
("Check that the SSL connection is fully trusted")),
Option('username', 'string', '', 0, 0, '',
"Username to use on server"),
Option(
'password', 'string', '', 0, 0, '',
("Password for server (note: content is evaluated, see /help "
"eval)")),
Option('device_name', 'string', '', 0, 0, 'Weechat Matrix',
"Device name to use while logging in to the matrix server"),
"autoconnect",
"boolean",
"",
0,
0,
"off",
(
"automatically connect to the matrix server when weechat "
"is starting"
),
),
Option(
"address",
"string",
"",
0,
0,
"",
"Hostname or IP address for the server",
),
Option(
"port", "integer", "", 0, 65535, "443", "Port for the server"
),
Option(
"proxy",
"string",
"",
0,
0,
"",
("Name of weechat proxy to use (see /help proxy)"),
),
Option(
"ssl_verify",
"boolean",
"",
0,
0,
"on",
("Check that the SSL connection is fully trusted"),
),
Option(
"username", "string", "", 0, 0, "", "Username to use on server"
),
Option(
"password",
"string",
"",
0,
0,
"",
(
"Password for server (note: content is evaluated, see "
"/help eval)"
),
),
Option(
"device_name",
"string",
"",
0,
0,
"Weechat Matrix",
"Device name to use while logging in to the matrix server",
),
]
section = W.config_search_section(config_ptr, 'server')
section = W.config_search_section(config_ptr, "server")
self._ptr = section
for option in options:
option_name = "{server}.{option}".format(
server=self._server_name, option=option.name)
server=self._server_name, option=option.name
)
self._option_ptrs[option.name] = W.config_new_option(
config_ptr, section, option_name, option.type,
option.description, option.string_values, option.min,
option.max, option.value, option.value, 0, "", "",
"matrix_config_server_change_cb", self._server_name, "", "")
config_ptr,
section,
option_name,
option.type,
option.description,
option.string_values,
option.min,
option.max,
option.value,
option.value,
0,
"",
"",
"matrix_config_server_change_cb",
self._server_name,
"",
"",
)
autoconnect = ConfigSection.option_property("autoconnect", "boolean")
address = ConfigSection.option_property("address", "string")
@ -98,9 +158,7 @@ class ServerConfig(ConfigSection):
username = ConfigSection.option_property("username", "string")
device_name = ConfigSection.option_property("device_name", "string")
password = ConfigSection.option_property(
"password",
"string",
evaluate=True
"password", "string", evaluate=True
)
def free(self):
@ -169,12 +227,13 @@ class MatrixServer(object):
def _create_session_dir(self):
path = os.path.join("matrix", self.name)
if not W.mkdir_home(path, 0o700):
message = ("{prefix}matrix: Error creating server session "
"directory").format(prefix=W.prefix("error"))
message = (
"{prefix}matrix: Error creating server session " "directory"
).format(prefix=W.prefix("error"))
W.prnt("", message)
def get_session_path(self):
home_dir = W.info_get('weechat_dir', '')
home_dir = W.info_get("weechat_dir", "")
return os.path.join(home_dir, "matrix", self.name)
def _load_device_id(self):
@ -184,8 +243,8 @@ class MatrixServer(object):
if not os.path.isfile(path):
return
with open(path, 'r') as f:
device_id = f.readline().rstrip()
with open(path, "r") as device_file:
device_id = device_file.readline().rstrip()
if device_id:
self.device_id = device_id
@ -193,11 +252,11 @@ class MatrixServer(object):
file_name = "{}{}".format(self.config.username, ".device_id")
path = os.path.join(self.get_session_path(), file_name)
with open(path, 'w') as f:
f.write(self.device_id)
with open(path, "w") as device_file:
device_file.write(self.device_id)
def _change_client(self):
host = ':'.join([self.config.address, str(self.config.port)])
host = ":".join([self.config.address, str(self.config.port)])
self.client = HttpClient(host, self.config.username, self.device_id)
def update_option(self, option, option_name):
@ -255,14 +314,17 @@ class MatrixServer(object):
strerr = error.strerror if error.strerror else "Unknown reason"
strerr = errno + strerr
error_message = ("{prefix}Error while writing to "
"socket: {error}").format(
prefix=W.prefix("network"), error=strerr)
error_message = (
"{prefix}Error while writing to " "socket: {error}"
).format(prefix=W.prefix("network"), error=strerr)
server_buffer_prnt(self, error_message)
server_buffer_prnt(
self, ("{prefix}matrix: disconnecting from server..."
).format(prefix=W.prefix("network")))
self,
("{prefix}matrix: disconnecting from server...").format(
prefix=W.prefix("network")
),
)
self.disconnect()
return False
@ -273,10 +335,15 @@ class MatrixServer(object):
server_buffer_prnt(
self,
"{prefix}matrix: Error while writing to socket".format(
prefix=W.prefix("network")))
prefix=W.prefix("network")
),
)
server_buffer_prnt(
self, ("{prefix}matrix: disconnecting from server..."
).format(prefix=W.prefix("network")))
self,
("{prefix}matrix: disconnecting from server...").format(
prefix=W.prefix("network")
),
)
self.disconnect()
return False
@ -286,7 +353,6 @@ class MatrixServer(object):
return True
def _abort_send(self):
self.current_message = None
self.send_buffer = ""
def _finalize_send(self):
@ -316,8 +382,9 @@ class MatrixServer(object):
return True
def reconnect(self):
message = ("{prefix}matrix: reconnecting to server..."
).format(prefix=W.prefix("network"))
message = ("{prefix}matrix: reconnecting to server...").format(
prefix=W.prefix("network")
)
server_buffer_prnt(self, message)
@ -336,9 +403,9 @@ class MatrixServer(object):
else:
self.reconnect_delay = 10
message = ("{prefix}matrix: reconnecting to server in {t} "
"seconds").format(
prefix=W.prefix("network"), t=self.reconnect_delay)
message = (
"{prefix}matrix: reconnecting to server in {t} " "seconds"
).format(prefix=W.prefix("network"), t=self.reconnect_delay)
server_buffer_prnt(self, message)
@ -364,7 +431,6 @@ class MatrixServer(object):
self.access_token = ""
self.send_buffer = b""
self.current_message = None
self.transport_type = None
try:
@ -378,8 +444,9 @@ class MatrixServer(object):
self.reconnect_time = None
if self.server_buffer:
message = ("{prefix}matrix: disconnected from server"
).format(prefix=W.prefix("network"))
message = ("{prefix}matrix: disconnected from server").format(
prefix=W.prefix("network")
)
server_buffer_prnt(self, message)
if reconnect:
@ -390,13 +457,15 @@ class MatrixServer(object):
if not self.config.address or not self.config.port:
W.prnt("", self.config.address)
message = "{prefix}Server address or port not set".format(
prefix=W.prefix("error"))
prefix=W.prefix("error")
)
W.prnt("", message)
return False
if not self.config.username or not self.config.password:
message = "{prefix}User or password not set".format(
prefix=W.prefix("error"))
prefix=W.prefix("error")
)
W.prnt("", message)
return False
@ -407,54 +476,59 @@ class MatrixServer(object):
create_server_buffer(self)
if not self.timer_hook:
self.timer_hook = W.hook_timer(1 * 1000, 0, 0, "matrix_timer_cb",
self.name)
self.timer_hook = W.hook_timer(
1 * 1000, 0, 0, "matrix_timer_cb", self.name
)
ssl_message = " (SSL)" if self.ssl_context.check_hostname else ""
message = ("{prefix}matrix: Connecting to "
"{server}:{port}{ssl}...").format(
message = (
"{prefix}matrix: Connecting to " "{server}:{port}{ssl}..."
).format(
prefix=W.prefix("network"),
server=self.config.address,
port=self.config.port,
ssl=ssl_message)
ssl=ssl_message,
)
W.prnt(self.server_buffer, message)
W.hook_connect(self.config.proxy,
self.config.address, self.config.port,
1, 0, "", "connect_cb",
self.name)
W.hook_connect(
self.config.proxy,
self.config.address,
self.config.port,
1,
0,
"",
"connect_cb",
self.name,
)
return True
def schedule_sync(self):
self.sync_time = time.time()
def sync(self, timeout=None, filter=None):
def sync(self, timeout=None, sync_filter=None):
# type: (Optional[int], Optional[Dict[Any, Any]]) -> None
self.sync_time = None
_, request = self.client.sync(timeout, filter)
_, request = self.client.sync(timeout, sync_filter)
self.send_or_queue(request)
def login(self):
# type: () -> None
if self.client.logged_in:
msg = ("{prefix}{script_name}: Already logged in, "
"syncing...").format(
prefix=W.prefix("network"),
script_name=SCRIPT_NAME
)
msg = (
"{prefix}{script_name}: Already logged in, " "syncing..."
).format(prefix=W.prefix("network"), script_name=SCRIPT_NAME)
W.prnt(self.server_buffer, msg)
timeout = (0 if self.transport_type == TransportType.HTTP
else 30000)
timeout = 0 if self.transport_type == TransportType.HTTP else 30000
sync_filter = {"room": {"timeline": {"limit": 5000}}}
self.sync(timeout, sync_filter)
return
_, request = self.client.login(
self.config.password,
self.config.device_name
self.config.password, self.config.device_name
)
self.send_or_queue(request)
@ -469,30 +543,24 @@ class MatrixServer(object):
return
_, request = self.client.room_put_state(
room_buffer.room.room_id,
event_type,
body
room_buffer.room.room_id, event_type, body
)
self.send_or_queue(request)
def room_send_redaction(self, room_buffer, event_id, reason=None):
_, request = self.client.room_redact(
room_buffer.room.room_id,
event_id,
reason)
room_buffer.room.room_id, event_id, reason
)
self.send_or_queue(request)
def room_kick(self, room_buffer, user_id, reason=None):
_, request = self.client.room_kick(
room_buffer.room.room_id,
user_id,
reason)
room_buffer.room.room_id, user_id, reason
)
self.send_or_queue(request)
def room_invite(self, room_buffer, user_id):
_, request = self.client.room_invite(
room_buffer.room.room_id,
user_id)
_, request = self.client.room_invite(room_buffer.room.room_id, user_id)
self.send_or_queue(request)
def room_join(self, room_id):
@ -514,11 +582,7 @@ class MatrixServer(object):
message_class = OwnMessage
own_message = message_class(
self.user_id,
0,
"",
room_buffer.room.room_id,
formatted
self.user_id, 0, "", room_buffer.room.room_id, formatted
)
body = {"msgtype": msgtype, "body": formatted.to_plain()}
@ -528,20 +592,22 @@ class MatrixServer(object):
body["formatted_body"] = formatted.to_html()
uuid, request = self.client.room_send(
room_buffer.room.room_id,
"m.room.message",
body
room_buffer.room.room_id, "m.room.message", body
)
self.own_message_queue[uuid] = own_message
self.send_or_queue(request)
def _print_message_error(self, message):
server_buffer_prnt(self,
("{prefix}Unhandled {status_code} error, please "
"inform the developers about this.").format(
prefix=W.prefix("error"),
status_code=message.response.status))
server_buffer_prnt(
self,
(
"{prefix}Unhandled {status_code} error, please "
"inform the developers about this."
).format(
prefix=W.prefix("error"), status_code=message.response.status
),
)
server_buffer_prnt(self, pprint.pformat(message.__class__.__name__))
server_buffer_prnt(self, pprint.pformat(message.request.payload))
@ -555,21 +621,13 @@ class MatrixServer(object):
if isinstance(message, OwnAction):
room_buffer.self_action(message)
return
elif isinstance(message, OwnMessage):
if isinstance(message, OwnMessage):
room_buffer.self_message(message)
return
raise NotImplementedError("Unsupported message of type {}".format(
type(message)))
def _handle_erorr_response(self, response):
message = ("{prefix}matrix: {error}").format(
prefix=W.prefix("error"), error=self.error_message)
W.prnt(self.server.server_buffer, message)
if self.fatal:
self.server.disconnect(reconnect=False)
raise NotImplementedError(
"Unsupported message of type {}".format(type(message))
)
def _handle_login(self, response):
self.access_token = response.access_token
@ -579,7 +637,8 @@ class MatrixServer(object):
self.save_device_id()
message = "{prefix}matrix: Logged in as {user}".format(
prefix=W.prefix("network"), user=self.user_id)
prefix=W.prefix("network"), user=self.user_id
)
W.prnt(self.server_buffer, message)
@ -590,12 +649,10 @@ class MatrixServer(object):
sync_filter = {
"room": {
"timeline": {
"limit": G.CONFIG.network.max_initial_sync_events
"timeline": {"limit": G.CONFIG.network.max_initial_sync_events}
}
}
}
self.sync(timeout=0, filter=sync_filter)
self.sync(timeout=0, sync_filter=sync_filter)
def _handle_room_info(self, response):
for room_id, info in response.rooms.invite.items():
@ -604,12 +661,13 @@ class MatrixServer(object):
if room:
if room.inviter:
inviter_msg = " by {}{}".format(
W.color("chat_nick_other"),
room.inviter)
W.color("chat_nick_other"), room.inviter
)
else:
inviter_msg = ""
self.info("You have been invited to {} {}({}{}{}){}"
self.info(
"You have been invited to {} {}({}{}{}){}"
"{}".format(
room.display_name(),
W.color("chat_delimiters"),
@ -617,8 +675,9 @@ class MatrixServer(object):
room_id,
W.color("chat_delimiters"),
W.color("reset"),
inviter_msg
))
inviter_msg,
)
)
else:
self.info("You have been invited to {}.".format(room_id))
@ -647,13 +706,17 @@ class MatrixServer(object):
self.schedule_sync()
def handle_transport_response(self, response):
self.error(("Error with response of type type: {}, "
"error code {}").format(
response.request_info.type, response.status_code))
self.error(
("Error with response of type type: {}, " "error code {}").format(
response.request_info.type, response.status_code
)
)
# TODO better error handling.
if (response.request_info.type == "sync" or
response.request_info.type == "login"):
if (
response.request_info.type == "sync"
or response.request_info.type == "login"
):
self.disconnect()
def handle_response(self, response):
@ -681,8 +744,6 @@ class MatrixServer(object):
elif isinstance(response, RoomSendResponse):
self.handle_own_messages(response)
return
def create_room_buffer(self, room_id):
room = self.client.rooms[room_id]
buf = RoomBuffer(room, self.name)
@ -722,8 +783,7 @@ class MatrixServer(object):
break
if first:
num = W.buffer_get_integer(
W.buffer_search_main(),
"number"
W.buffer_search_main(), "number"
)
W.buffer_unmerge(buf, num + 1)
if buf is not first:
@ -734,13 +794,14 @@ class MatrixServer(object):
@utf8_decode
def matrix_config_server_read_cb(data, config_file, section, option_name,
value):
def matrix_config_server_read_cb(
data, config_file, section, option_name, value
):
return_code = W.WEECHAT_CONFIG_OPTION_SET_ERROR
if option_name:
server_name, option = option_name.rsplit('.', 1)
server_name, option = option_name.rsplit(".", 1)
server = None
if server_name in SERVERS:
@ -752,9 +813,7 @@ def matrix_config_server_read_cb(data, config_file, section, option_name,
# Ignore invalid options
if option in server.config._option_ptrs:
return_code = W.config_option_set(
server.config._option_ptrs[option],
value,
1
server.config._option_ptrs[option], value, 1
)
# TODO print out error message in case of erroneous return_code
@ -796,8 +855,11 @@ def matrix_timer_cb(server_name, remaining_calls):
current_time = time.time()
if ((not server.connected) and server.reconnect_time and
current_time >= (server.reconnect_time + server.reconnect_delay)):
if (
(not server.connected)
and server.reconnect_time
and current_time >= (server.reconnect_time + server.reconnect_delay)
):
server.reconnect()
return W.WEECHAT_RC_OK
@ -844,7 +906,7 @@ def matrix_timer_cb(server_name, remaining_calls):
def create_default_server(config_file):
server = MatrixServer('matrix_org', config_file._ptr)
server = MatrixServer("matrix_org", config_file._ptr)
SERVERS[server.name] = server
option = W.config_get(SCRIPT_NAME + ".server." + server.name + ".address")

View file

@ -28,7 +28,7 @@ import sys
# pylint: disable=redefined-builtin
from builtins import bytes, str
from collections import Mapping, Iterable
from collections import Iterable, Mapping
from functools import wraps
# These functions were written by Trygve Aaberge for wee-slack and are under a
@ -39,13 +39,11 @@ from functools import wraps
class WeechatWrapper(object):
def __init__(self, wrapped_class):
self.wrapped_class = wrapped_class
# Helper method used to encode/decode method calls.
def wrap_for_utf8(self, method):
def hooked(*args, **kwargs):
result = method(*encode_to_utf8(args), **encode_to_utf8(kwargs))
# Prevent wrapped_class from becoming unwrapped
@ -69,7 +67,8 @@ class WeechatWrapper(object):
def prnt_date_tags(self, buffer, date, tags, message):
message = message.replace("\n", "\n \t")
return self.wrap_for_utf8(self.wrapped_class.prnt_date_tags)(
buffer, date, tags, message)
buffer, date, tags, message
)
def utf8_decode(function):
@ -92,7 +91,7 @@ def utf8_decode(function):
def decode_from_utf8(data):
if isinstance(data, bytes):
return data.decode('utf-8')
return data.decode("utf-8")
if isinstance(data, str):
return data
elif isinstance(data, Mapping):
@ -104,7 +103,7 @@ def decode_from_utf8(data):
def encode_to_utf8(data):
if isinstance(data, str):
return data.encode('utf-8')
return data.encode("utf-8")
if isinstance(data, bytes):
return data
elif isinstance(data, Mapping):

View file

@ -15,18 +15,10 @@
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
from __future__ import unicode_literals
from builtins import str
import time
import math
from matrix import globals as G
from matrix.globals import W, SERVERS
try:
from urlparse import urlparse
except ImportError:
from urllib.parse import urlparse
from .globals import W
def key_from_value(dictionary, value):
@ -45,11 +37,13 @@ def server_buffer_prnt(server, string):
def tags_from_line_data(line_data):
# type: (weechat.hdata) -> List[str]
tags_count = W.hdata_get_var_array_size(
W.hdata_get('line_data'), line_data, 'tags_array')
W.hdata_get("line_data"), line_data, "tags_array"
)
tags = [
W.hdata_string(
W.hdata_get('line_data'), line_data, '%d|tags_array' % i)
W.hdata_get("line_data"), line_data, "%d|tags_array" % i
)
for i in range(tags_count)
]
@ -59,16 +53,15 @@ def tags_from_line_data(line_data):
def create_server_buffer(server):
# type: (MatrixServer) -> None
buffer_name = "server.{}".format(server.name)
server.server_buffer = W.buffer_new(buffer_name, "server_buffer_cb",
server.name, "", "")
server.server_buffer = W.buffer_new(
buffer_name, "server_buffer_cb", server.name, "", ""
)
server_buffer_set_title(server)
W.buffer_set(server.server_buffer, "short_name", server.name)
W.buffer_set(server.server_buffer, "localvar_set_type", 'server')
W.buffer_set(server.server_buffer, "localvar_set_type", "server")
W.buffer_set(
server.server_buffer,
"localvar_set_nick",
server.config.username
server.server_buffer, "localvar_set_nick", server.config.username
)
W.buffer_set(server.server_buffer, "localvar_set_server", server.name)
W.buffer_set(server.server_buffer, "localvar_set_channel", server.name)
@ -84,18 +77,12 @@ def server_buffer_set_title(server):
ip_string = ""
title = ("Matrix: {address}:{port}{ip}").format(
address=server.config.address, port=server.config.port, ip=ip_string)
address=server.config.address, port=server.config.port, ip=ip_string
)
W.buffer_set(server.server_buffer, "title", title)
def color_for_tags(color):
if color == "weechat.color.chat_nick_self":
option = W.config_get(color)
return W.config_string(option)
return color
def server_ts_to_weechat(timestamp):
# type: (float) -> int
date = int(timestamp / 1000)
@ -112,241 +99,5 @@ def shorten_sender(sender):
return strip_matrix_server(sender)[1:]
def sender_to_prefix_and_color(room, sender):
if sender in room.users:
user = room.users[sender]
prefix = user.prefix
prefix_color = get_prefix_color(prefix)
return prefix, prefix_color
return None, None
def sender_to_nick_and_color(room, sender):
nick = sender
nick_color_name = "default"
if sender in room.users:
user = room.users[sender]
nick = (user.display_name if user.display_name else user.name)
nick_color_name = user.nick_color
else:
nick = sender
nick_color_name = W.info_get("nick_color_name", nick)
return (nick, nick_color_name)
def tags_for_message(message_type):
default_tags = {
"message": ["matrix_message", "notify_message", "log1"],
"backlog":
["matrix_message", "notify_message", "no_log", "no_highlight"]
}
return default_tags[message_type]
def add_event_tags(event_id, nick, color=None, tags=[]):
tags.append("nick_{nick}".format(nick=nick))
if color:
tags.append("prefix_nick_{color}".format(color=color_for_tags(color)))
tags.append("matrix_id_{event_id}".format(event_id=event_id))
return tags
def sanitize_token(string):
# type: (str) -> str
string = sanitize_string(string)
if len(string) > 512:
raise ValueError
if string == "":
raise ValueError
return string
def sanitize_string(string):
# type: (str) -> str
if not isinstance(string, str):
raise TypeError
# string keys can have empty string values sometimes (e.g. room names that
# got deleted)
if string == "":
return None
remap = {
ord('\b'): None,
ord('\f'): None,
ord('\n'): None,
ord('\r'): None,
ord('\t'): None,
ord('\0'): None
}
return string.translate(remap)
def sanitize_id(string):
# type: (str) -> str
string = sanitize_string(string)
if len(string) > 128:
raise ValueError
if string == "":
raise ValueError
return string
def sanitize_int(number, minimum=None, maximum=None):
# type: (int, int, int) -> int
if not isinstance(number, int):
raise TypeError
if math.isnan(number):
raise ValueError
if math.isinf(number):
raise ValueError
if minimum:
if number < minimum:
raise ValueError
if maximum:
if number > maximum:
raise ValueError
return number
def sanitize_ts(timestamp):
# type: (int) -> int
return sanitize_int(timestamp, 0)
def sanitize_power_level(level):
# type: (int) -> int
return sanitize_int(level, 0, 100)
def sanitize_text(string):
# type: (str) -> str
if not isinstance(string, str):
raise TypeError
# yapf: disable
remap = {
ord('\b'): None,
ord('\f'): None,
ord('\r'): None,
ord('\0'): None
}
# yapf: enable
return string.translate(remap)
def add_user_to_nicklist(buf, user_id, user):
group_name = "999|..."
if user.power_level >= 100:
group_name = "000|o"
elif user.power_level >= 50:
group_name = "001|h"
elif user.power_level > 0:
group_name = "002|v"
group = W.nicklist_search_group(buf, "", group_name)
prefix = user.prefix if user.prefix else " "
# TODO make it configurable so we can use a display name or user_id here
W.nicklist_add_nick(buf, group, user_id, user.nick_color, prefix,
get_prefix_color(user.prefix), 1)
def get_prefix_for_level(level):
# type: (int) -> str
if level >= 100:
return "&"
elif level >= 50:
return "@"
elif level > 0:
return "+"
return ""
# TODO make this configurable
def get_prefix_color(prefix):
# type: (str) -> str
if prefix == "&":
return "lightgreen"
elif prefix == "@":
return "lightgreen"
elif prefix == "+":
return "yellow"
return ""
def string_strikethrough(string):
return "".join(["{}\u0336".format(c) for c in string])
def line_pointer_and_tags_from_event(buff, event_id):
# type: (str, str) -> str
own_lines = W.hdata_pointer(W.hdata_get('buffer'), buff, 'own_lines')
if own_lines:
hdata_line = W.hdata_get('line')
line_pointer = W.hdata_pointer(
W.hdata_get('lines'), own_lines, 'last_line')
while line_pointer:
data_pointer = W.hdata_pointer(hdata_line, line_pointer, 'data')
if data_pointer:
tags = tags_from_line_data(data_pointer)
message_id = event_id_from_tags(tags)
if event_id == message_id:
return data_pointer, tags
line_pointer = W.hdata_move(hdata_line, line_pointer, -1)
return None, []
def event_id_from_tags(tags):
# type: (List[str]) -> str
for tag in tags:
if tag.startswith("matrix_id"):
return tag[10:]
return ""
def mxc_to_http(mxc):
# type: (str) -> str
url = urlparse(mxc)
if url.scheme != "mxc":
return None
if not url.netloc or not url.path:
return None
return "https://{}/_matrix/media/r0/download/{}{}".format(
url.netloc,
url.netloc,
url.path
)