diff --git a/main.py b/main.py index ac6c95b..ff9db4e 100644 --- a/main.py +++ b/main.py @@ -145,14 +145,6 @@ def print_certificate_info(buff, sock, cert): W.prnt(buff, message) - -@utf8_decode -def matrix_event_timer_cb(server_name, remaining_calls): - server = SERVERS[server_name] - server.handle_events() - return W.WEECHAT_RC_OK - - def wrap_socket(server, file_descriptor): # type: (MatrixServer, int) -> None sock = None # type: socket.socket @@ -399,32 +391,6 @@ def connect_cb(data, status, gnutls_rc, sock, error, ip_address): return W.WEECHAT_RC_OK -@utf8_decode -def room_input_cb(server_name, buffer, input_data): - server = SERVERS[server_name] - - if not server.connected: - message = "{prefix}matrix: you are not connected to the server".format( - prefix=W.prefix("error")) - W.prnt(buffer, message) - return W.WEECHAT_RC_ERROR - - room_id = key_from_value(server.buffers, buffer) - room = server.rooms[room_id] - - formatted_data = Formatted.from_input_line(input_data) - - if room.encrypted: - server.send_room_message(room_id, formatted_data) - return W.WEECHAT_RC_OK - - message = MatrixSendMessage( - server.client, room_id=room_id, formatted_message=formatted_data) - - server.send_or_queue(message) - return W.WEECHAT_RC_OK - - @utf8_decode def room_close_cb(data, buffer): W.prnt("", diff --git a/matrix/bar_items.py b/matrix/bar_items.py index 1f3cfff..5ae77b2 100644 --- a/matrix/bar_items.py +++ b/matrix/bar_items.py @@ -45,13 +45,12 @@ def matrix_bar_item_name(data, item, window, buffer, extra_info): color = ("status_name_ssl" if server.ssl_context.check_hostname else "status_name") - room_id = key_from_value(server.buffers, buffer) - - room = server.rooms[room_id] + room_buffer = server.find_room_from_ptr(buffer) + room = room_buffer.room return "{color}{name}".format( color=W.color(color), - name=room.display_name(server.user_id)) + name=room.display_name()) elif buffer == server.server_buffer: color = ("status_name_ssl" @@ -92,14 +91,14 @@ def matrix_bar_item_buffer_modes(data, item, window, buffer, extra_info): # pylint: disable=unused-argument for server in SERVERS.values(): if buffer in server.buffers.values(): - room_id = key_from_value(server.buffers, buffer) - room = server.rooms[room_id] + room_buffer = server.find_room_from_ptr(buffer) + room = room_buffer.room modes = [] if room.encrypted: modes.append("🔐") - if room.backlog_pending: + if room_buffer.backlog_pending: modes.append("⏳") return "".join(modes) diff --git a/matrix/buffer.py b/matrix/buffer.py index f882117..6aa2973 100644 --- a/matrix/buffer.py +++ b/matrix/buffer.py @@ -20,6 +20,7 @@ from __future__ import unicode_literals import time from builtins import super from functools import partial +from typing import NamedTuple from .globals import W, SERVERS, OPTIONS, SCRIPT_NAME, ENCRYPTION from .utf import utf8_decode @@ -32,29 +33,35 @@ from .utils import ( ) from .plugin_options import RedactType - -from .rooms import ( - RoomNameEvent, - RoomAliasEvent, - RoomMembershipEvent, - RoomTopicEvent, +from nio import ( RoomMessageText, - RoomMessageEmote, - RoomMessageNotice, - RoomMessageMedia, - RoomMessageUnknown, - RoomRedactionEvent, - RoomRedactedMessageEvent, + RoomMemberEvent, + PowerLevelsEvent, RoomEncryptionEvent, - RoomPowerLevels, - UndecryptedEvent + RedactedEvent, + RoomAliasEvent, + RoomTopicEvent, + RoomMessageEmote, + RoomNameEvent ) +OwnMessage = NamedTuple("OwnMessage", [ + ("sender", str), + ("age", int), + ("event_id", str), + ("formatted_message", Formatted) +]) + + +class OwnAction(OwnMessage): + pass + + @utf8_decode def room_buffer_input_cb(server_name, buffer, input_data): server = SERVERS[server_name] - room, room_buffer = server.find_room_from_ptr(buffer) + room_buffer = server.find_room_from_ptr(buffer) if not room_buffer: # TODO log error @@ -66,7 +73,7 @@ def room_buffer_input_cb(server_name, buffer, input_data): formatted_data = Formatted.from_input_line(input_data) - server.send_room_message(room, formatted_data) + server.send_room_message(room_buffer.room, formatted_data) return W.WEECHAT_RC_OK @@ -669,6 +676,7 @@ class WeechatChannelBuffer(object): class RoomBuffer(object): def __init__(self, room, server_name): self.room = room + self.backlog_pending = False # This dict remembers the connection from a user_id to the name we # displayed in the buffer @@ -692,12 +700,14 @@ class RoomBuffer(object): def join(event, date, is_state): user = self.room.users[event.sender] + short_name = shorten_sender(user.user_id) + # TODO make this configurable - if user.name in self.displayed_nicks.values(): + if short_name in self.displayed_nicks.values(): # Use the full user id, but don't include the @ nick = event.sender[1:] else: - nick = user.name + nick = short_name buffer_user = RoomUser(nick, event.sender, user.power_level) self.displayed_nicks[event.sender] = nick @@ -708,11 +718,11 @@ class RoomBuffer(object): self.weechat_buffer.join( buffer_user, - server_ts_to_weechat(event.timestamp), + server_ts_to_weechat(event.server_timestamp), not is_state ) - date = server_ts_to_weechat(event.timestamp) + date = server_ts_to_weechat(event.server_timestamp) if event.content["membership"] == "join": if event.prev_content and "membership" in event.prev_content: @@ -743,7 +753,7 @@ class RoomBuffer(object): self.weechat_buffer.invite(event.state_key, date) return - room_name = self.room.display_name(self.room.own_user_id) + room_name = self.room.display_name() self.weechat_buffer.short_name = room_name def _redact_line(self, event): @@ -808,14 +818,14 @@ class RoomBuffer(object): def _handle_redacted_message(self, event): nick = self.find_nick(event.sender) - date = server_ts_to_weechat(event.timestamp) + date = server_ts_to_weechat(event.server_timestamp) tags = self.get_event_tags(event) tags.append(SCRIPT_NAME + "_redacted") reason = (", reason: \"{reason}\"".format(reason=event.reason) if event.reason else "") - censor = self.find_nick(event.censor) + censor = self.find_nick(event.redacter) data = ("{del_color}<{log_color}Message redacted by: " "{censor}{log_color}{reason}{del_color}>{ncolor}").format( @@ -833,7 +843,7 @@ class RoomBuffer(object): self.weechat_buffer.change_topic( nick, event.topic, - server_ts_to_weechat(event.timestamp), + server_ts_to_weechat(event.server_timestamp), not is_state) @staticmethod @@ -841,12 +851,13 @@ class RoomBuffer(object): return ["matrix_id_{}".format(event.event_id)] def _handle_power_level(self, event): - for user_id in self.room.power_levels: + 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[user_id] + user.power_level = self.room.power_levels.get_user_level( + user_id) # There is no way to change the group of a user without # removing him from the nicklist @@ -854,67 +865,48 @@ class RoomBuffer(object): self.weechat_buffer._add_user_to_nicklist(user) def handle_state_event(self, event): - if isinstance(event, RoomMembershipEvent): + if isinstance(event, RoomMemberEvent): self.handle_membership_events(event, True) elif isinstance(event, RoomTopicEvent): self._handle_topic(event, True) - elif isinstance(event, RoomPowerLevels): + elif isinstance(event, PowerLevelsEvent): self._handle_power_level(event) def handle_timeline_event(self, event): - if isinstance(event, RoomMembershipEvent): + if isinstance(event, RoomMemberEvent): self.handle_membership_events(event, False) elif isinstance(event, (RoomNameEvent, RoomAliasEvent)): - room_name = self.room.display_name(self.room.own_user_id) + room_name = self.room.display_name() self.weechat_buffer.short_name = room_name elif isinstance(event, RoomTopicEvent): self._handle_topic(event, False) - elif isinstance(event, RoomMessageText): - nick = self.find_nick(event.sender) - data = (event.formatted_message.to_weechat() - if event.formatted_message else event.message) - - date = server_ts_to_weechat(event.timestamp) - self.weechat_buffer.message( - nick, - data, - date, - self.get_event_tags(event) - ) - + # Emotes are a subclass of RoomMessageText, so put them before the text + # ones elif isinstance(event, RoomMessageEmote): nick = self.find_nick(event.sender) - date = server_ts_to_weechat(event.timestamp) + date = server_ts_to_weechat(event.server_timestamp) self.weechat_buffer.action( nick, - event.message, + event.body, date, self.get_event_tags(event) ) - elif isinstance(event, RoomMessageNotice): + + elif isinstance(event, RoomMessageText): nick = self.find_nick(event.sender) - date = server_ts_to_weechat(event.timestamp) - self.weechat_buffer.notice( - nick, - event.message, - date, - self.get_event_tags(event) - ) + formatted = None - elif isinstance(event, RoomMessageMedia): - nick = self.find_nick(event.sender) - date = server_ts_to_weechat(event.timestamp) - http_url = mxc_to_http(event.url) - url = http_url if http_url else event.url + if event.formatted_body: + formatted = Formatted.from_html(event.formatted_body) - description = ("/{}".format(event.description) - if event.description else "") - data = "{url}{desc}".format(url=url, desc=description) + data = (formatted.to_weechat() + if formatted else event.body) + date = server_ts_to_weechat(event.server_timestamp) self.weechat_buffer.message( nick, data, @@ -922,24 +914,51 @@ class RoomBuffer(object): self.get_event_tags(event) ) - elif isinstance(event, RoomMessageUnknown): - nick = self.find_nick(event.sender) - date = server_ts_to_weechat(event.timestamp) - data = ("Unknown message of type {t}, body: {body}").format( - t=event.message_type, - body=event.message - ) - self.weechat_buffer.message( - 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.message, + # date, + # self.get_event_tags(event) + # ) - elif isinstance(event, RoomRedactionEvent): - self._redact_line(event) + # elif isinstance(event, RoomMessageMedia): + # nick = self.find_nick(event.sender) + # date = server_ts_to_weechat(event.server_timestamp) + # http_url = mxc_to_http(event.url) + # url = http_url if http_url else event.url - elif isinstance(event, RoomRedactedMessageEvent): + # description = ("/{}".format(event.description) + # if event.description else "") + # data = "{url}{desc}".format(url=url, desc=description) + + # self.weechat_buffer.message( + # nick, + # data, + # date, + # self.get_event_tags(event) + # ) + + # elif isinstance(event, RoomMessageUnknown): + # nick = self.find_nick(event.sender) + # date = server_ts_to_weechat(event.server_timestamp) + # data = ("Unknown message of type {t}, body: {body}").format( + # t=event.message_type, + # body=event.message + # ) + # self.weechat_buffer.message( + # nick, + # data, + # date, + # self.get_event_tags(event) + # ) + + # elif isinstance(event, RoomRedactionEvent): + # self._redact_line(event) + + elif isinstance(event, RedactedEvent): self._handle_redacted_message(event) elif isinstance(event, RoomEncryptionEvent): @@ -951,38 +970,44 @@ class RoomBuffer(object): "this room.") self.weechat_buffer.error(message) - elif isinstance(event, RoomPowerLevels): + elif isinstance(event, PowerLevelsEvent): self._handle_power_level(event) - elif isinstance(event, UndecryptedEvent): - nick = self.find_nick(event.sender) - date = server_ts_to_weechat(event.timestamp) - data = ("Error decrypting event session " - "id: {}".format(event.session_id)) - self.weechat_buffer.message( - nick, - data, - date, - self.get_event_tags(event) - ) + # elif isinstance(event, UndecryptedEvent): + # nick = self.find_nick(event.sender) + # date = server_ts_to_weechat(event.server_timestamp) + # data = ("Error decrypting event session " + # "id: {}".format(event.session_id)) + # self.weechat_buffer.message( + # nick, + # data, + # date, + # self.get_event_tags(event) + # ) else: W.prnt("", "Unhandled event of type {}.".format( type(event).__name__)) def self_message(self, message): + # type: (OwnMessage) -> None nick = self.find_nick(self.room.own_user_id) - data = (message.formatted_message.to_weechat() - if message.formatted_message - else message.message) + data = message.formatted_message.to_weechat() - date = server_ts_to_weechat(message.timestamp) + # TODO event_id tag is missing + date = message.age self.weechat_buffer.self_message(nick, data, date) def self_action(self, message): + # type: (OwnMessage) -> None nick = self.find_nick(self.room.own_user_id) - date = server_ts_to_weechat(message.timestamp) - self.weechat_buffer.self_action(nick, message.message, date) + date = message.age + # TODO event_id tag is missing + self.weechat_buffer.self_action( + nick, + message.formatted_message.to_weechat(), + date + ) def old_redacted(self, event): tags = [ @@ -994,7 +1019,7 @@ class RoomBuffer(object): reason = (", reason: \"{reason}\"".format(reason=event.reason) if event.reason else "") - censor = self.find_nick(event.censor) + censor = self.find_nick(event.redacter) data = ("{del_color}<{log_color}Message redacted by: " "{censor}{log_color}{reason}{del_color}>{ncolor}").format( @@ -1007,7 +1032,7 @@ class RoomBuffer(object): tags += self.get_event_tags(event) nick = self.find_nick(event.sender) user = self.weechat_buffer._get_user(nick) - date = server_ts_to_weechat(event.timestamp) + date = server_ts_to_weechat(event.server_timestamp) self.weechat_buffer._print_message(user, data, date, tags) def old_message(self, event): @@ -1022,7 +1047,7 @@ class RoomBuffer(object): 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.timestamp) + date = server_ts_to_weechat(event.server_timestamp) self.weechat_buffer._print_message(user, data, date, tags) def sort_messages(self): @@ -1062,7 +1087,7 @@ class RoomBuffer(object): for event in events: if isinstance(event, RoomMessageText): self.old_message(event) - elif isinstance(event, RoomRedactedMessageEvent): + elif isinstance(event, RedactedEvent): self.old_redacted(event) self.sort_messages() diff --git a/matrix/commands.py b/matrix/commands.py index 0046526..eb4baff 100644 --- a/matrix/commands.py +++ b/matrix/commands.py @@ -67,23 +67,23 @@ def hook_commands(): 'matrix_command_cb', '') - W.hook_command( - # Command name and short description - 'redact', - 'redact messages', - # Synopsis - ('[:""] []'), - # Description - ("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"), - # Completions - ('%(matrix_messages)'), - # Function name - 'matrix_redact_command_cb', - '') + # W.hook_command( + # # Command name and short description + # 'redact', + # 'redact messages', + # # Synopsis + # ('[:""] []'), + # # Description + # ("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"), + # # Completions + # ('%(matrix_messages)'), + # # Function name + # 'matrix_redact_command_cb', + # '') W.hook_command( # Command name and short description @@ -101,15 +101,15 @@ def hook_commands(): matrix_hook_olm_command() - W.hook_command_run('/topic', 'matrix_command_topic_cb', '') + # W.hook_command_run('/topic', 'matrix_command_topic_cb', '') W.hook_command_run('/buffer clear', 'matrix_command_buf_clear_cb', '') W.hook_command_run('/join', 'matrix_command_join_cb', '') W.hook_command_run('/part', 'matrix_command_part_cb', '') W.hook_command_run('/invite', 'matrix_command_invite_cb', '') W.hook_command_run('/kick', 'matrix_command_kick_cb', '') - if OPTIONS.enable_backlog: - hook_page_up() + # if OPTIONS.enable_backlog: + # hook_page_up() @utf8_decode @@ -123,7 +123,7 @@ def matrix_me_command_cb(data, buffer, args): W.prnt(server.server_buffer, message) return W.WEECHAT_RC_ERROR - room_id = key_from_value(server.buffers, buffer) + room_buffer = server.find_room_from_ptr(buffer) if not args: return W.WEECHAT_RC_OK @@ -131,10 +131,10 @@ def matrix_me_command_cb(data, buffer, args): formatted_data = Formatted.from_input_line(args) message = MatrixEmoteMessage( server.client, - room_id=room_id, + room_id=room_buffer.room.room_id, formatted_message=formatted_data) - if server.rooms[room_id].encrypted: + if room_buffer.room.encrypted: return W.WEECHAT_RC_OK server.send_or_queue(message) @@ -144,15 +144,16 @@ def matrix_me_command_cb(data, buffer, args): elif buffer == server.server_buffer: message = ("{prefix}matrix: command \"me\" must be " "executed on a Matrix channel buffer" - ).format(prefix=W.prefix("error")) + ).format(prefix=W.prefix("error")) W.prnt("", message) return W.WEECHAT_RC_OK def matrix_fetch_old_messages(server, room_id): - room = server.rooms[room_id] + room_buffer = server.find_room_from_id(room_id) + room = room_buffer.room - if room.backlog_pending: + if room_buffer.backlog_pending: return prev_batch = room.prev_batch @@ -165,7 +166,7 @@ def matrix_fetch_old_messages(server, room_id): room_id=room_id, token=prev_batch, limit=OPTIONS.backlog_limit) - room.backlog_pending = True + room_buffer.backlog_pending = True W.bar_item_update("buffer_modes") server.send_or_queue(message) @@ -913,14 +914,15 @@ def matrix_command_topic_cb(data, buffer, command): for server in SERVERS.values(): if buffer in server.buffers.values(): topic = None - room_id = key_from_value(server.buffers, buffer) + room_buffer = server.find_room_from_ptr(buffer) split_command = command.split(' ', 1) if len(split_command) == 2: topic = split_command[1] if not topic: - room = server.rooms[room_id] + room_buffer = server.find_room_from_ptr(buffer) + room = room_buffer.room if not room.topic: return W.WEECHAT_RC_OK @@ -938,8 +940,8 @@ def matrix_command_topic_cb(data, buffer, command): topic=room.topic) date = int(time.time()) - topic_date = room.topic_date.strftime("%a, %d %b %Y " - "%H:%M:%S") + topic_date = room_buffer.weechat_buffer.topic_date.strftime( + "%a, %d %b %Y %H:%M:%S") tags = "matrix_topic,log1" W.prnt_date_tags(buffer, date, tags, message) @@ -958,7 +960,7 @@ def matrix_command_topic_cb(data, buffer, command): return W.WEECHAT_RC_OK_EAT message = MatrixTopicMessage( - server.client, room_id=room_id, topic=topic) + server.client, room_id=room.room_id, topic=topic) server.send_or_queue(message) return W.WEECHAT_RC_OK_EAT diff --git a/matrix/events.py b/matrix/events.py index 0d4ab31..3221516 100644 --- a/matrix/events.py +++ b/matrix/events.py @@ -27,12 +27,9 @@ from operator import itemgetter from matrix.globals import W from matrix.utils import (tags_for_message, sanitize_id, sanitize_token, sanitize_text, tags_from_line_data) -from matrix.rooms import (RoomInfo, RoomMessageText, - RoomMessageEvent, RoomRedactedMessageEvent, - RoomMessageEmote) from matrix.encryption import OlmDeviceKey, OneTimeKey -from .buffer import RoomUser +from .buffer import RoomUser, OwnMessage, OwnAction try: from olm.session import OlmMessage, OlmPreKeyMessage @@ -96,25 +93,6 @@ class MatrixKeyUploadEvent(MatrixEvent): "keys", False, parsed_dict) -class MatrixLoginEvent(MatrixEvent): - - def __init__(self, server, user_id, device_id, access_token): - self.user_id = user_id - self.access_token = access_token - self.device_id = device_id - MatrixEvent.__init__(self, server) - - @classmethod - def from_dict(cls, server, parsed_dict): - try: - return cls(server, sanitize_id(parsed_dict["user_id"]), - sanitize_id(parsed_dict["device_id"]), - sanitize_token(parsed_dict["access_token"])) - except (KeyError, TypeError, ValueError): - return MatrixErrorEvent.from_dict(server, "Error logging in", True, - parsed_dict) - - class MatrixSendEvent(MatrixEvent): def __init__(self, server, room_id, message): @@ -128,11 +106,9 @@ class MatrixSendEvent(MatrixEvent): event_id = sanitize_id(parsed_dict["event_id"]) sender = server.user_id age = 0 - plain_message = message.to_plain() formatted_message = message - message = RoomMessageText(event_id, sender, age, plain_message, - formatted_message) + message = OwnMessage(sender, age, event_id, formatted_message) return cls(server, room_id, message) except (KeyError, TypeError, ValueError): @@ -148,11 +124,9 @@ class MatrixEmoteEvent(MatrixSendEvent): event_id = sanitize_id(parsed_dict["event_id"]) sender = server.user_id age = 0 - plain_message = message.to_plain() formatted_message = message - message = RoomMessageEmote(event_id, sender, age, plain_message, - formatted_message) + message = OwnAction(sender, age, event_id, formatted_message) return cls(server, room_id, message) except (KeyError, TypeError, ValueError): @@ -410,127 +384,3 @@ class MatrixBacklogEvent(MatrixEvent): except (KeyError, ValueError, TypeError): return MatrixErrorEvent.from_dict(server, "Error fetching backlog", False, parsed_dict) - - -class MatrixSyncEvent(MatrixEvent): - - def __init__(self, server, next_batch, room_infos, invited_infos, - one_time_key_count): - self.next_batch = next_batch - self.joined_room_infos = room_infos - self.invited_room_infos = invited_infos - self.one_time_key_count = one_time_key_count - - MatrixEvent.__init__(self, server) - - @staticmethod - def _infos_from_dict(olm, parsed_dict): - join_infos = [] - invite_infos = [] - - for room_id, room_dict in parsed_dict['join'].items(): - if not room_id: - continue - - join_infos.append(RoomInfo.from_dict(olm, room_id, room_dict)) - - return (join_infos, invite_infos) - - @staticmethod - def _get_olm_device_event(server, parsed_dict): - device_key = server.olm.account.identity_keys["curve25519"] - - if device_key not in parsed_dict["content"]["ciphertext"]: - return None - - sender = sanitize_id(parsed_dict["sender"]) - sender_key = sanitize_id(parsed_dict["content"]["sender_key"]) - - ciphertext = parsed_dict["content"]["ciphertext"].pop(device_key) - - message = None - - if ciphertext["type"] == 0: - message = OlmPreKeyMessage(ciphertext["body"]) - elif ciphertext["type"] == 1: - message = OlmMessage(ciphertext["body"]) - else: - raise ValueError("Invalid Olm message type") - - olm = server.olm - plaintext = olm.decrypt(sender, sender_key, message) - - if not plaintext: - return None - - # TODO check sender key - decrypted_sender = plaintext["sender"] - decrypted_recepient = plaintext["recipient"] - decrypted_recepient_key = plaintext["recipient_keys"]["ed25519"] - - if (sender != decrypted_sender or - server.user_id != decrypted_recepient or - olm.account.identity_keys["ed25519"] != - decrypted_recepient_key): - error_message = ("{prefix}matrix: Mismatch in decrypted Olm " - "message").format(prefix=W.prefix("error")) - W.prnt("", error_message) - return None - - if plaintext["type"] != "m.room_key": - return None - - MatrixSyncEvent._handle_key_event(server, sender_key, plaintext) - - @staticmethod - def _handle_key_event(server, sender_key, parsed_dict): - # type: (MatrixServer, str, Dict[Any, Any] -> None - olm = server.olm - content = parsed_dict.pop("content") - - if content["algorithm"] != "m.megolm.v1.aes-sha2": - return - - room_id = content["room_id"] - session_id = content["session_id"] - session_key = content["session_key"] - - if session_id in olm.inbound_group_sessions[room_id]: - return - - olm.create_group_session(room_id, session_id, session_key) - - @staticmethod - def _get_to_device_events(server, parsed_dict): - # type: (MatrixServer, Dict[Any, Any]) -> None - for event in parsed_dict["events"]: - if event["type"] == "m.room.encrypted": - if (event["content"]["algorithm"] == - 'm.olm.v1.curve25519-aes-sha2'): - MatrixSyncEvent._get_olm_device_event(server, event) - - @classmethod - def from_dict(cls, server, parsed_dict): - try: - next_batch = sanitize_id(parsed_dict["next_batch"]) - one_time_key_count = 0 - - if "device_one_time_keys_count" in parsed_dict: - if ("signed_curve25519" in - parsed_dict["device_one_time_keys_count"]): - one_time_key_count = ( - parsed_dict["device_one_time_keys_count"]["signed_curve25519"]) - - MatrixSyncEvent._get_to_device_events( - server, parsed_dict.pop("to_device")) - - room_info_dict = parsed_dict["rooms"] - - join_infos, invite_infos = MatrixSyncEvent._infos_from_dict( - server.olm, room_info_dict) - - return cls(server, next_batch, join_infos, invite_infos, - one_time_key_count) - except (KeyError, ValueError, TypeError): - return MatrixErrorEvent.from_dict(server, "Error syncing", False, - parsed_dict) diff --git a/matrix/rooms.py b/matrix/rooms.py deleted file mode 100644 index 6ad94e5..0000000 --- a/matrix/rooms.py +++ /dev/null @@ -1,642 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright © 2018 Damir Jelić -# -# Permission to use, copy, modify, and/or distribute this software for -# any purpose with or without fee is hereby granted, provided that the -# above copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY -# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER -# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF -# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -from __future__ import unicode_literals - -import json - -from pprint import pformat - -from collections import namedtuple, deque - -from matrix.globals import W - -from matrix.colors import Formatted -from matrix.utils import ( - strip_matrix_server, color_for_tags, server_ts_to_weechat, - sender_to_nick_and_color, add_event_tags, sanitize_id, sanitize_ts, - sanitize_string, sanitize_text, shorten_sender, add_user_to_nicklist, - get_prefix_for_level, sanitize_power_level, string_strikethrough, - line_pointer_and_tags_from_event, sender_to_prefix_and_color) - -PowerLevel = namedtuple('PowerLevel', ['user', 'level']) - - -class MatrixRoom: - - def __init__(self, room_id, own_user_id): - # type: (str) -> None - # yapf: disable - self.room_id = room_id # type: str - self.own_user_id = own_user_id - self.canonical_alias = None # type: str - self.name = None # type: str - self.prev_batch = "" # type: str - self.users = dict() # type: Dict[str, MatrixUser] - self.encrypted = False # type: bool - self.backlog_pending = False # type: bool - self.power_levels = {} - # yapf: enable - - def display_name(self, own_user_id): - """ - Calculate display name for a room. - - Prefer returning the room name if it exists, falling back to - a group-style name if not. - - Mostly follows: - https://matrix.org/docs/spec/client_server/r0.3.0.html#id268 - - An exception is that we prepend '#' before the room name to make it - visually distinct from private messages and unnamed groups of users - ("direct chats") in weechat's buffer list. - """ - if self.is_named(): - return self.named_room_name() - else: - return self.group_name(own_user_id) - - def named_room_name(self): - """ - Returns the name of the room, if it's a named room. Otherwise return - None. - """ - if self.name: - return "#" + self.name - elif self.canonical_alias: - return self.canonical_alias - else: - return None - - def group_name(self, own_user_id): - """ - Returns the group-style name of the room, i.e. a name based on the room - members. - """ - # Sort user display names, excluding our own user and using the - # mxid as the sorting key. - # - # TODO: Hook the user display name disambiguation algorithm here. - # Currently, we use the user display names as is, which may not be - # unique. - users = [user.name for mxid, user - in sorted(self.users.items(), key=lambda t: t[0]) - if mxid != own_user_id] - - num_users = len(users) - - if num_users == 1: - return users[0] - elif num_users == 2: - return " and ".join(users) - elif num_users >= 3: - return "{first_user} and {num} others".format( - first_user=users[0], - num=num_users-1) - else: - return "Empty room?" - - def machine_name(self): - """ - Calculate an unambiguous, unique machine name for a room. - - Either use the more human-friendly canonical alias, if it exists, or - the internal room ID if not. - """ - if self.canonical_alias: - return self.canonical_alias - else: - return self.room_id - - def is_named(self): - """ - Is this a named room? - - A named room is a room with either the name or a canonical alias set. - """ - return self.canonical_alias or self.name - - def is_group(self): - """ - Is this an ad hoc group of users? - - A group is an unnamed room with no canonical alias. - """ - return not self.is_named() - - def _handle_membership(self, event): - if event.content["membership"] == "join": - if event.sender in self.users: - user = self.users[event.sender] - if "display_name" in event.content: - user.display_name = event.content["display_name"] - else: - short_name = shorten_sender(event.sender) - # TODO the default power level doesn't have to be 0 - level = (self.power_levels[event.sender] if event.sender in - self.power_levels else 0) - display_name = (event.content["display_name"] - if "display_name" in event.content else None) - - user = MatrixUser(short_name, display_name, level) - self.users[event.sender] = user - return True - - elif event.content["membership"] == "leave": - if event.state_key in self.users: - del self.users[event.state_key] - return True - - elif event.content["membership"] == "invite": - pass - - def handle_event(self, event): - if isinstance(event, RoomMembershipEvent): - return self._handle_membership(event) - - elif isinstance(event, RoomNameEvent): - self.name = event.name - - elif isinstance(event, RoomAliasEvent): - self.canonical_alias = event.canonical_alias - - elif isinstance(event, RoomEncryptionEvent): - self.encrypted = True - return True - - elif isinstance(event, RoomPowerLevels): - self.power_levels = event.power_levels - - # Update the power levels of the joined users - for user_id, level in self.power_levels.items(): - if user_id in self.users: - self.users[user_id].power_level = level - - return False - - -class MatrixUser: - - def __init__(self, name, display_name=None, power_level=0): - # yapf: disable - self.name = name # type: str - self.display_name = display_name # type: str - self.power_level = power_level # type: int - # yapf: enable - - -class RoomInfo(): - - def __init__(self, room_id, prev_batch, state, timeline): - # type: (str, str, List[Any], List[Any]) -> None - self.room_id = room_id - self.prev_batch = prev_batch - - self.state = deque(state) - self.timeline = deque(timeline) - - @staticmethod - def _message_from_event(event): - # The transaction id will only be present for events that are send out - # from this client, since we print out our own messages as soon as we - # get a receive confirmation from the server we don't care about our - # own messages in a sync event. More info under: - # https://github.com/matrix-org/matrix-doc/blob/master/api/client-server/definitions/event.yaml#L53 - if "transaction_id" in event["unsigned"]: - return None - - if "redacted_by" in event["unsigned"]: - return RoomRedactedMessageEvent.from_dict(event) - - return RoomMessageEvent.from_dict(event) - - @staticmethod - def parse_event(olm, room_id, event_dict): - # type: (Dict[Any, Any]) -> (RoomEvent, RoomEvent) - event = None - - if "redacted_by" in event_dict["unsigned"]: - event = RoomRedactedMessageEvent.from_dict(event_dict) - elif event_dict["type"] == "m.room.message": - event = RoomInfo._message_from_event(event_dict) - elif event_dict["type"] == "m.room.member": - event = RoomMembershipEvent.from_dict(event_dict) - elif event_dict["type"] == "m.room.power_levels": - event = RoomPowerLevels.from_dict(event_dict) - elif event_dict["type"] == "m.room.topic": - event = RoomTopicEvent.from_dict(event_dict) - elif event_dict["type"] == "m.room.redaction": - event = RoomRedactionEvent.from_dict(event_dict) - elif event_dict["type"] == "m.room.name": - event = RoomNameEvent.from_dict(event_dict) - elif event_dict["type"] == "m.room.canonical_alias": - event = RoomAliasEvent.from_dict(event_dict) - elif event_dict["type"] == "m.room.encryption": - event = RoomEncryptionEvent.from_dict(event_dict) - elif event_dict["type"] == "m.room.encrypted": - event = RoomInfo._decrypt_event(olm, room_id, event_dict) - - return event - - @staticmethod - def _decrypt_event(olm, room_id, event_dict): - session_id = event_dict["content"]["session_id"] - ciphertext = event_dict["content"]["ciphertext"] - plaintext, message_index = olm.group_decrypt( - room_id, - session_id, - ciphertext - ) - - if not plaintext: - return UndecryptedEvent.from_dict(event_dict) - - parsed_plaintext = json.loads(plaintext, encoding="utf-8") - - event_dict["content"] = parsed_plaintext["content"] - event_dict["type"] = parsed_plaintext["type"] - - return RoomInfo.parse_event(olm, room_id, event_dict) - - @staticmethod - def _parse_events(olm, room_id, parsed_dict): - events = [] - - for event in parsed_dict: - try: - e = RoomInfo.parse_event(olm, room_id, event) - except (ValueError, TypeError, KeyError) as error: - message = ("{prefix}matrix: Error parsing " - "room event of type {type}: " - "{error}\n{event}").format( - prefix=W.prefix("error"), - type=event["type"], - error=pformat(error), - event=pformat(event)) - W.prnt("", message) - e = BadEvent.from_dict(event) - - events.append(e) - - return events - - @classmethod - def from_dict(cls, olm, room_id, parsed_dict): - prev_batch = sanitize_id(parsed_dict['timeline']['prev_batch']) - - state_dict = parsed_dict['state']['events'] - timeline_dict = parsed_dict['timeline']['events'] - - state_events = RoomInfo._parse_events( - olm, - room_id, - state_dict - ) - timeline_events = RoomInfo._parse_events( - olm, - room_id, - timeline_dict - ) - - return cls( - room_id, - prev_batch, - list(filter(None, state_events)), - list(filter(None, timeline_events)) - ) - - -class RoomEvent(object): - - def __init__(self, event_id, sender, timestamp): - self.event_id = event_id - self.sender = sender - self.timestamp = timestamp - - -class UndecryptedEvent(RoomEvent): - def __init__(self, event_id, sender, timestamp, session_id): - self.session_id = session_id - RoomEvent.__init__(self, event_id, sender, timestamp) - - @classmethod - def from_dict(cls, event): - event_id = (sanitize_id(event["event_id"]) - if "event_id" in event else None) - sender = (sanitize_id(event["sender"]) - if "sender" in event else None) - timestamp = (sanitize_ts(event["origin_server_ts"]) - if "origin_server_ts" in event else None) - session_id = event["content"]["session_id"] - - return cls(event_id, sender, timestamp, session_id) - - -class BadEvent(RoomEvent): - def __init__(self, event_id, sender, timestamp, source): - RoomEvent.__init__(self, event_id, sender, timestamp) - self.source = source - - @classmethod - def from_dict(cls, event): - event_id = (sanitize_id(event["event_id"]) - if "event_id" in event else None) - sender = (sanitize_id(event["sender"]) - if "sender" in event else None) - timestamp = (sanitize_ts(event["origin_server_ts"]) - if "origin_server_ts" in event else None) - source = json.dumps(event) - - return cls(event_id, sender, timestamp, source) - - -class RoomRedactedMessageEvent(RoomEvent): - - def __init__(self, event_id, sender, timestamp, censor, reason=None): - self.censor = censor - self.reason = reason - RoomEvent.__init__(self, event_id, sender, timestamp) - - @classmethod - def from_dict(cls, event): - event_id = sanitize_id(event["event_id"]) - sender = sanitize_id(event["sender"]) - timestamp = sanitize_ts(event["origin_server_ts"]) - - censor = sanitize_id(event['unsigned']['redacted_because']['sender']) - reason = None - - if 'reason' in event['unsigned']['redacted_because']['content']: - reason = sanitize_text( - event['unsigned']['redacted_because']['content']['reason']) - - return cls(event_id, sender, timestamp, censor, reason) - -class RoomMessageEvent(RoomEvent): - - @classmethod - def from_dict(cls, event): - if event['content']['msgtype'] == 'm.text': - return RoomMessageText.from_dict(event) - elif event['content']['msgtype'] == 'm.image': - return RoomMessageMedia.from_dict(event) - elif event['content']['msgtype'] == 'm.audio': - return RoomMessageMedia.from_dict(event) - elif event['content']['msgtype'] == 'm.file': - return RoomMessageMedia.from_dict(event) - elif event['content']['msgtype'] == 'm.video': - return RoomMessageMedia.from_dict(event) - elif event['content']['msgtype'] == 'm.emote': - return RoomMessageEmote.from_dict(event) - elif event['content']['msgtype'] == 'm.notice': - return RoomMessageNotice.from_dict(event) - return RoomMessageUnknown.from_dict(event) - - def _print_message(self, message, room, buff, tags): - nick, color_name = sender_to_nick_and_color(room, self.sender) - color = color_for_tags(color_name) - - event_tags = add_event_tags(self.event_id, nick, color, tags) - - tags_string = ",".join(event_tags) - - prefix, prefix_color = sender_to_prefix_and_color(room, self.sender) - - prefix_string = ("" if not prefix else "{}{}{}".format( - W.color(prefix_color), prefix, W.color("reset"))) - - data = "{prefix}{color}{author}{ncolor}\t{msg}".format( - prefix=prefix_string, - color=W.color(color_name), - author=nick, - ncolor=W.color("reset"), - msg=message) - - date = server_ts_to_weechat(self.timestamp) - W.prnt_date_tags(buff, date, tags_string, data) - - -class RoomMessageSimple(RoomMessageEvent): - - def __init__(self, event_id, sender, timestamp, message, message_type): - self.message = message - self.message_type = message_type - RoomEvent.__init__(self, event_id, sender, timestamp) - - @classmethod - def from_dict(cls, event): - event_id = sanitize_id(event["event_id"]) - sender = sanitize_id(event["sender"]) - timestamp = sanitize_ts(event["origin_server_ts"]) - - message = sanitize_text(event["content"]["body"]) - message_type = sanitize_text(event["content"]["msgtype"]) - - return cls(event_id, sender, timestamp, message, message_type) - - -class RoomMessageUnknown(RoomMessageSimple): - pass - - -class RoomMessageText(RoomMessageEvent): - - def __init__(self, event_id, sender, timestamp, message, formatted_message=None): - self.message = message - self.formatted_message = formatted_message - RoomEvent.__init__(self, event_id, sender, timestamp) - - @classmethod - def from_dict(cls, event): - event_id = sanitize_id(event["event_id"]) - sender = sanitize_id(event["sender"]) - timestamp = sanitize_ts(event["origin_server_ts"]) - - msg = "" - formatted_msg = None - - msg = sanitize_text(event['content']['body']) - - if ('format' in event['content'] and - 'formatted_body' in event['content']): - if event['content']['format'] == "org.matrix.custom.html": - formatted_msg = Formatted.from_html( - sanitize_text(event['content']['formatted_body'])) - - return cls(event_id, sender, timestamp, msg, formatted_msg) - - -class RoomMessageEmote(RoomMessageSimple): - pass - - -class RoomMessageNotice(RoomMessageText): - pass - - -class RoomMessageMedia(RoomMessageEvent): - - def __init__(self, event_id, sender, timestamp, url, description): - self.url = url - self.description = description - RoomEvent.__init__(self, event_id, sender, timestamp) - - @classmethod - def from_dict(cls, event): - event_id = sanitize_id(event["event_id"]) - sender = sanitize_id(event["sender"]) - timestamp = sanitize_ts(event["origin_server_ts"]) - - mxc_url = sanitize_text(event['content']['url']) - description = sanitize_text(event["content"]["body"]) - - return cls(event_id, sender, timestamp, mxc_url, description) - - -class RoomMembershipEvent(RoomEvent): - def __init__( - self, - event_id, - sender, - timestamp, - state_key, - content, - prev_content - ): - self.state_key = state_key - self.content = content - self.prev_content = prev_content - RoomEvent.__init__(self, event_id, sender, timestamp) - - @classmethod - def from_dict(cls, event_dict): - event_id = sanitize_id(event_dict["event_id"]) - sender = sanitize_id(event_dict["sender"]) - timestamp = sanitize_ts(event_dict["origin_server_ts"]) - state_key = sanitize_id(event_dict["state_key"]) - content = event_dict["content"] - prev_content = (event_dict["unsigned"]["prev_content"] - if "prev_content" in event_dict["unsigned"] else None) - - return cls( - event_id, - sender, - timestamp, - state_key, - content, - prev_content - ) - - -class RoomPowerLevels(RoomEvent): - - def __init__(self, event_id, sender, timestamp, power_levels): - self.power_levels = power_levels - RoomEvent.__init__(self, event_id, sender, timestamp) - - @classmethod - def from_dict(cls, event_dict): - event_id = sanitize_id(event_dict["event_id"]) - sender = sanitize_id(event_dict["sender"]) - timestamp = sanitize_ts(event_dict["origin_server_ts"]) - - power_levels = event_dict["content"].pop("users") - - return cls(event_id, sender, timestamp, power_levels) - - -class RoomTopicEvent(RoomEvent): - - def __init__(self, event_id, sender, timestamp, topic): - self.topic = topic - RoomEvent.__init__(self, event_id, sender, timestamp) - - @classmethod - def from_dict(cls, event_dict): - event_id = sanitize_id(event_dict["event_id"]) - sender = sanitize_id(event_dict["sender"]) - timestamp = sanitize_ts(event_dict["origin_server_ts"]) - - topic = sanitize_text(event_dict["content"]["topic"]) - - return cls(event_id, sender, timestamp, topic) - - -class RoomRedactionEvent(RoomEvent): - - def __init__(self, event_id, sender, timestamp, redaction_id, reason=None): - self.redaction_id = redaction_id - self.reason = reason - RoomEvent.__init__(self, event_id, sender, timestamp) - - @classmethod - def from_dict(cls, event_dict): - event_id = sanitize_id(event_dict["event_id"]) - sender = sanitize_id(event_dict["sender"]) - timestamp = sanitize_ts(event_dict["origin_server_ts"]) - - redaction_id = sanitize_id(event_dict["redacts"]) - - reason = (sanitize_text(event_dict["content"]["reason"]) - if "reason" in event_dict["content"] else None) - - return cls(event_id, sender, timestamp, redaction_id, reason) - - -class RoomNameEvent(RoomEvent): - - def __init__(self, event_id, sender, timestamp, name): - self.name = name - RoomEvent.__init__(self, event_id, sender, timestamp) - - @classmethod - def from_dict(cls, event_dict): - event_id = sanitize_id(event_dict["event_id"]) - sender = sanitize_id(event_dict["sender"]) - timestamp = sanitize_ts(event_dict["origin_server_ts"]) - - name = sanitize_string(event_dict['content']['name']) - - return cls(event_id, sender, timestamp, name) - - -class RoomAliasEvent(RoomEvent): - - def __init__(self, event_id, sender, timestamp, canonical_alias): - self.canonical_alias = canonical_alias - RoomEvent.__init__(self, event_id, sender, timestamp) - - @classmethod - def from_dict(cls, event_dict): - event_id = sanitize_id(event_dict["event_id"]) - sender = sanitize_id(event_dict["sender"]) - timestamp = sanitize_ts(event_dict["origin_server_ts"]) - - canonical_alias = sanitize_id(event_dict["content"]["alias"]) - - return cls(event_id, sender, timestamp, canonical_alias) - - -class RoomEncryptionEvent(RoomEvent): - - @classmethod - def from_dict(cls, event_dict): - event_id = sanitize_id(event_dict["event_id"]) - sender = sanitize_id(event_dict["sender"]) - timestamp = sanitize_ts(event_dict["origin_server_ts"]) - - return cls(event_id, sender, timestamp) diff --git a/matrix/server.py b/matrix/server.py index be48fb9..eb8ca05 100644 --- a/matrix/server.py +++ b/matrix/server.py @@ -28,7 +28,7 @@ import json from collections import deque, defaultdict from http_parser.pyparser import HttpParser -from nio import Client, LoginResponse +from nio import Client, LoginResponse, SyncRepsponse from matrix.plugin_options import Option, DebugType from matrix.utils import (key_from_value, prnt_debug, server_buffer_prnt, @@ -37,12 +37,7 @@ from matrix.utils import (key_from_value, prnt_debug, server_buffer_prnt, from matrix.utf import utf8_decode from matrix.globals import W, SERVERS, OPTIONS import matrix.api as API -from .buffer import RoomBuffer -from .rooms import ( - MatrixRoom, - RoomMessageText, - RoomMessageEmote, -) +from .buffer import RoomBuffer, OwnMessage, OwnAction from matrix.api import ( MatrixClient, MatrixSyncMessage, @@ -56,8 +51,6 @@ from matrix.api import ( ) from .events import ( - MatrixLoginEvent, - MatrixSyncEvent, MatrixSendEvent, MatrixBacklogEvent, MatrixErrorEvent, @@ -97,7 +90,6 @@ class MatrixServer: self.user = "" # type: str self.password = "" # type: str - self.rooms = dict() # type: Dict[str, MatrixRoom] self.room_buffers = dict() # type: Dict[str, WeechatChannelBuffer] self.buffers = dict() # type: Dict[str, weechat.buffer] self.server_buffer = None # type: weechat.buffer @@ -610,10 +602,10 @@ class MatrixServer: def query_keys(self): users = [] - for room in self.rooms.values(): - if not room.encrypted: + for room_buffer in self.room_buffers.values(): + if not room_buffer.room.encrypted: continue - users += list(room.users) + users += list(room_buffer.room.users) if not users: return @@ -642,68 +634,13 @@ class MatrixServer: server_buffer_prnt(self, pprint.pformat(message.request.payload)) server_buffer_prnt(self, pprint.pformat(message.response.body)) - def _loop_events(self, info, n): - - for i in range(n+1): - is_state = False - try: - event = info.state.popleft() - is_state = True - except IndexError: - try: - event = info.timeline.popleft() - except IndexError: - return i - - room, room_buffer = self.find_room_from_id(info.room_id) - # The room changed it's members, if the room is encrypted update - # the device list - if room.handle_event(event) and room.encrypted: - self.device_check_timestamp = None - - if is_state: - room_buffer.handle_state_event(event) - else: - room_buffer.handle_timeline_event(event) - - self.event_queue.appendleft(info) - return i - - def handle_events(self): - n = 25 - - while True: - try: - info = self.event_queue.popleft() - except IndexError: - if self.event_queue_timer: - W.unhook(self.event_queue_timer) - self.event_queue_timer = None - - self.sync() - return - - ret = self._loop_events(info, n) - - if ret < n: - n = n - ret - else: - self.event_queue.appendleft(info) - - if not self.event_queue_timer: - hook = W.hook_timer(1 * 100, 0, 0, "matrix_event_timer_cb", - self.name) - self.event_queue_timer = hook - - return - def handle_own_messages(self, room_buffer, message): - if isinstance(message, RoomMessageText): - room_buffer.self_message(message) - return - elif isinstance(message, RoomMessageEmote): + if isinstance(message, OwnAction): room_buffer.self_action(message) return + elif isinstance(message, OwnMessage): + room_buffer.self_message(message) + return raise NotImplementedError("Unsupported message of type {}".format( type(message))) @@ -736,19 +673,18 @@ class MatrixServer: self.sync() - def _queue_joined_info(self, response): - while response.joined_room_infos: - info = response.joined_room_infos.pop() + def _handle_room_info(self, response): + for room_id, join_info in response.rooms.join.items(): + if room_id not in self.buffers: + self.create_room_buffer(room_id) - if info.room_id not in self.buffers: - self.create_room_buffer(info.room_id) + room_buffer = self.find_room_from_id(room_id) - room = self.rooms[info.room_id] + for event in join_info.state: + room_buffer.handle_state_event(event) - if not room.prev_batch: - room.prev_batch = info.prev_batch - - self.event_queue.append(info) + for event in join_info.timeline.events: + room_buffer.handle_timeline_event(event) def _handle_sync(self, response): # we got the same batch again, nothing to do @@ -756,27 +692,20 @@ class MatrixServer: self.sync() return - self._queue_joined_info(response) + self._handle_room_info(response) + # self._queue_joined_info(response) self.next_batch = response.next_batch # self.check_one_time_keys(response.one_time_key_count) - self.handle_events() + # self.handle_events() def handle_matrix_response(self, response): - if isinstance(response, MatrixLoginEvent): - self._handle_login(response) - - elif isinstance(response, MatrixSyncEvent): - self._handle_sync(response) - - elif isinstance(response, MatrixSendEvent): - _, room_buffer = self.find_room_from_id(response.room_id) + if isinstance(response, MatrixSendEvent): + room_buffer = self.find_room_from_id(response.room_id) self.handle_own_messages(room_buffer, response.message) elif isinstance(response, MatrixBacklogEvent): - room, room_buffer = self.find_room_from_id(response.room_id) + room_buffer = self.find_room_from_id(response.room_id) room_buffer.handle_backlog(response.events) - room.prev_batch = response.end_token - room.backlog_pending = False W.bar_item_update("buffer_modes") elif isinstance(response, MatrixErrorEvent): @@ -787,10 +716,14 @@ class MatrixServer: if isinstance(response, LoginResponse): self._handle_login(response) + elif isinstance(response, SyncRepsponse): + self._handle_sync(response) def nio_parse_response(self, response): if isinstance(response, MatrixLoginMessage): self.nio_client.receive("login", response.response.body) + elif isinstance(response, MatrixSyncMessage): + self.nio_client.receive("sync", response.response.body) self.nio_receive() @@ -804,7 +737,7 @@ class MatrixServer: if ('content-type' in message.response.headers and message.response.headers['content-type'] == 'application/json'): - if isinstance(message, MatrixLoginMessage): + if isinstance(message, (MatrixLoginMessage, MatrixSyncMessage)): self.nio_parse_response(message) else: @@ -850,24 +783,21 @@ class MatrixServer: return def create_room_buffer(self, room_id): - room = MatrixRoom(room_id, self.user_id) + room = self.nio_client.rooms[room_id] buf = RoomBuffer(room, self.name) # TODO this should turned into a propper class self.room_buffers[room_id] = buf self.buffers[room_id] = buf.weechat_buffer._ptr - self.rooms[room_id] = room def find_room_from_ptr(self, pointer): room_id = key_from_value(self.buffers, pointer) - room = self.rooms[room_id] room_buffer = self.room_buffers[room_id] - return room, room_buffer + return room_buffer def find_room_from_id(self, room_id): - room = self.rooms[room_id] room_buffer = self.room_buffers[room_id] - return room, room_buffer + return room_buffer @utf8_decode