server: Continue nio migration.

This commit is contained in:
Damir Jelić 2018-07-20 17:51:48 +02:00
parent 91eec1ad85
commit 45be743c07
7 changed files with 199 additions and 1069 deletions

34
main.py
View file

@ -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("",

View file

@ -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)

View file

@ -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()

View file

@ -67,23 +67,23 @@ def hook_commands():
'matrix_command_cb',
'')
W.hook_command(
# Command name and short description
'redact',
'redact messages',
# Synopsis
('<message-number>[:"<message-part>"] [<reason>]'),
# 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
# ('<message-number>[:"<message-part>"] [<reason>]'),
# # 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

View file

@ -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)

View file

@ -1,642 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright © 2018 Damir Jelić <poljar@termina.org.uk>
#
# 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)

View file

@ -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