aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-09-30 22:05:41 +0200
committerdec05eba <dec05eba@protonmail.com>2020-09-30 22:05:41 +0200
commit9602603135f456d906192112288dcd84429c8fee (patch)
tree6a6dafff82f3e38b8e18b74f474ef61965917339 /src
parente1a8d10b61c5f8ca092ba3aa458b661da29ba447 (diff)
Matrix: implement message editing
Diffstat (limited to 'src')
-rw-r--r--src/Body.cpp8
-rw-r--r--src/Entry.cpp11
-rw-r--r--src/QuickMedia.cpp57
-rw-r--r--src/Text.cpp4
-rw-r--r--src/plugins/Matrix.cpp271
5 files changed, 306 insertions, 45 deletions
diff --git a/src/Body.cpp b/src/Body.cpp
index 5927831..13e3d7d 100644
--- a/src/Body.cpp
+++ b/src/Body.cpp
@@ -550,11 +550,11 @@ namespace QuickMedia {
}
void Body::draw_item(sf::RenderWindow &window, BodyItem *item, sf::Vector2f pos, sf::Vector2f size) {
- //sf::Vector2u window_size = window.getSize();
- // glEnable(GL_SCISSOR_TEST);
- //glScissor(pos.x, (int)window_size.y - (int)pos.y - (int)pos.y, size.x, size.y);
+ sf::Vector2u window_size = window.getSize();
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(pos.x, (int)window_size.y - (int)pos.y - (int)size.y, size.x, size.y);
draw_item(window, item, pos, size, get_item_height(item) + spacing_y, -1, Json::nullValue);
- //glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_SCISSOR_TEST);
}
void Body::draw_item(sf::RenderWindow &window, BodyItem *item, const sf::Vector2f &pos, const sf::Vector2f &size, const float item_height, const int item_index, const Json::Value &content_progress) {
diff --git a/src/Entry.cpp b/src/Entry.cpp
index 977feab..a3c576f 100644
--- a/src/Entry.cpp
+++ b/src/Entry.cpp
@@ -13,7 +13,7 @@ namespace QuickMedia {
on_submit_callback(nullptr),
text("", font, cjk_font, 18, 0.0f),
width(0.0f),
- background(sf::Vector2f(1.0f, 1.0f), 10.0f, 10),
+ background(sf::Vector2f(1.0f, 1.0f), 7.0f, 10),
placeholder(placeholder_text, *font, 18)
{
text.setEditable(true);
@@ -54,6 +54,15 @@ namespace QuickMedia {
text.setEditable(editable);
}
+ void Entry::set_text(std::string new_text) {
+ text.setString(std::move(new_text));
+ }
+
+ void Entry::move_caret_to_end() {
+ text.updateGeometry();
+ text.moveCaretToEnd();
+ }
+
void Entry::set_position(const sf::Vector2f &pos) {
background.setPosition(pos);
text.setPosition(pos + sf::Vector2f(background_margin_horizontal, background_margin_vertical));
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index c3e61fe..ecb44d5 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -3346,20 +3346,21 @@ namespace QuickMedia {
enum class ChatState {
NAVIGATING,
TYPING_MESSAGE,
- REPLYING
+ REPLYING,
+ EDITING
};
Page new_page = Page::CHAT;
ChatState chat_state = ChatState::NAVIGATING;
- std::shared_ptr<BodyItem> replying_to_message;
+ std::shared_ptr<BodyItem> currently_operating_on_item;
sf::Text replying_to_text("Replying to:", *font, 18);
sf::Sprite logo_sprite(plugin_logo);
Entry chat_input("Press ctrl+m to begin writing a message...", font.get(), cjk_font.get());
chat_input.set_editable(false);
- chat_input.on_submit_callback = [matrix, &chat_input, &tabs, &selected_tab, &current_room_id, &new_page, &chat_state, &replying_to_message](const sf::String &text) mutable {
+ chat_input.on_submit_callback = [matrix, &chat_input, &tabs, &selected_tab, &current_room_id, &new_page, &chat_state, &currently_operating_on_item](const sf::String &text) mutable {
if(tabs[selected_tab].type == ChatTabType::MESSAGES) {
if(text.isEmpty())
return false;
@@ -3397,15 +3398,26 @@ namespace QuickMedia {
}
} else if(chat_state == ChatState::REPLYING) {
// TODO: Make asynchronous
- if(matrix->post_reply(current_room_id, text, replying_to_message->userdata) == PluginResult::OK) {
+ if(matrix->post_reply(current_room_id, text, currently_operating_on_item->userdata) == PluginResult::OK) {
chat_input.set_editable(false);
chat_state = ChatState::NAVIGATING;
- replying_to_message = nullptr;
+ currently_operating_on_item = nullptr;
return true;
} else {
show_notification("QuickMedia", "Failed to post matrix reply", Urgency::CRITICAL);
return false;
}
+ } else if(chat_state == ChatState::EDITING) {
+ // TODO: Make asynchronous
+ if(matrix->post_edit(current_room_id, text, currently_operating_on_item->userdata) == PluginResult::OK) {
+ chat_input.set_editable(false);
+ chat_state = ChatState::NAVIGATING;
+ currently_operating_on_item = nullptr;
+ return true;
+ } else {
+ show_notification("QuickMedia", "Failed to post matrix edit", Urgency::CRITICAL);
+ return false;
+ }
}
}
return false;
@@ -3545,12 +3557,34 @@ namespace QuickMedia {
std::shared_ptr<BodyItem> selected = tabs[selected_tab].body->get_selected_shared();
if(selected) {
chat_state = ChatState::REPLYING;
- replying_to_message = selected;
+ currently_operating_on_item = selected;
chat_input.set_editable(true);
+ replying_to_text.setString("Replying to:");
} else {
// TODO: Show inline notification
show_notification("QuickMedia", "No message selected for replying");
}
+ } else if(tabs[selected_tab].type == ChatTabType::MESSAGES && event.key.control && event.key.code == sf::Keyboard::E) {
+ std::shared_ptr<BodyItem> selected = tabs[selected_tab].body->get_selected_shared();
+ if(selected) {
+ if(!selected->url.empty()) { // cant edit messages that are image/video posts
+ // TODO: Show inline notification
+ show_notification("QuickMedia", "You can only edit messages with no file attached to it");
+ } else if(!matrix->was_message_posted_by_me(current_room_id, selected->userdata)) {
+ // TODO: Show inline notification
+ show_notification("QuickMedia", "You can't edit a message that was posted by somebody else");
+ } else {
+ chat_state = ChatState::EDITING;
+ currently_operating_on_item = selected;
+ chat_input.set_editable(true);
+ chat_input.set_text(selected->get_description()); // TODO: Description? it may change in the future, in which case this should be edited
+ chat_input.move_caret_to_end();
+ replying_to_text.setString("Editing message:");
+ }
+ } else {
+ // TODO: Show inline notification
+ show_notification("QuickMedia", "No message selected for editing");
+ }
}
}
@@ -3559,7 +3593,7 @@ namespace QuickMedia {
chat_state = ChatState::TYPING_MESSAGE;
}
- if((chat_state == ChatState::TYPING_MESSAGE || chat_state == ChatState::REPLYING) && tabs[selected_tab].type == ChatTabType::MESSAGES) {
+ if((chat_state == ChatState::TYPING_MESSAGE || chat_state == ChatState::REPLYING || chat_state == ChatState::EDITING) && tabs[selected_tab].type == ChatTabType::MESSAGES) {
if(event.type == sf::Event::TextEntered) {
//chat_input.onTextEntered(event.text.unicode);
// TODO: Also show typing event when ctrl+v pasting?
@@ -3573,8 +3607,9 @@ namespace QuickMedia {
}
} else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) {
chat_input.set_editable(false);
+ chat_input.set_text("");
chat_state = ChatState::NAVIGATING;
- replying_to_message = nullptr;
+ currently_operating_on_item = nullptr;
}
//chat_input.on_event(event);
chat_input.process_event(event);
@@ -3799,11 +3834,11 @@ namespace QuickMedia {
window.draw(gradient_points, 4, sf::Quads); // Note: sf::Quads doesn't work with egl
}
- if(chat_state == ChatState::REPLYING) {
+ if(chat_state == ChatState::REPLYING || chat_state == ChatState::EDITING) {
const float margin = 5.0f;
const float replying_to_text_height = replying_to_text.getLocalBounds().height + margin;
- const float item_height = std::min(body_size.y - replying_to_text_height - margin, tabs[MESSAGES_TAB_INDEX].body->get_item_height(replying_to_message.get()) + margin);
+ const float item_height = std::min(body_size.y - replying_to_text_height - margin, tabs[MESSAGES_TAB_INDEX].body->get_item_height(currently_operating_on_item.get()) + margin);
sf::RectangleShape overlay(sf::Vector2f(window_size.x, window_size.y - tab_shade_height - chat_input_height_full));
overlay.setPosition(0.0f, tab_shade_height);
@@ -3821,7 +3856,7 @@ namespace QuickMedia {
replying_to_text.setPosition(body_item_pos.x, body_item_pos.y - replying_to_text_height);
window.draw(replying_to_text);
- tabs[MESSAGES_TAB_INDEX].body->draw_item(window, replying_to_message.get(), body_item_pos, body_item_size);
+ tabs[MESSAGES_TAB_INDEX].body->draw_item(window, currently_operating_on_item.get(), body_item_pos, body_item_size);
}
if(tabs[selected_tab].type == ChatTabType::MESSAGES && !tabs[selected_tab].body->is_last_item_fully_visible()) {
diff --git a/src/Text.cpp b/src/Text.cpp
index 5e0ad87..fb1373c 100644
--- a/src/Text.cpp
+++ b/src/Text.cpp
@@ -164,6 +164,10 @@ namespace QuickMedia
return editable;
}
+ void Text::moveCaretToEnd() {
+ caretIndex = vertices_linear.size();
+ }
+
float Text::getWidth() const
{
return boundingBox.width;
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index 50be2de..b93164e 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -140,6 +140,7 @@ namespace QuickMedia {
auto room_it = room_data_by_id.find(room_id_str);
if(room_it == room_data_by_id.end()) {
auto room_data = std::make_unique<RoomData>();
+ room_data->id = room_id_json.asString();
room_data_by_id.insert(std::make_pair(room_id_str, std::move(room_data)));
room_name = room_id_str;
fprintf(stderr, "Missing room %s from /sync, adding in joined_rooms\n", room_id_str.c_str());
@@ -268,6 +269,7 @@ namespace QuickMedia {
auto room_it = room_data_by_id.find(room_id_str);
if(room_it == room_data_by_id.end()) {
auto room_data = std::make_unique<RoomData>();
+ room_data->id = room_id_str;
room_data_by_id.insert(std::make_pair(room_id_str, std::move(room_data)));
room_it = room_data_by_id.find(room_id_str); // TODO: Get iterator from above insert
}
@@ -294,6 +296,7 @@ namespace QuickMedia {
auto room_it = room_data_by_id.find(room_id_str);
if(room_it == room_data_by_id.end()) {
auto room_data = std::make_unique<RoomData>();
+ room_data->id = room_id_str;
room_data_by_id.insert(std::make_pair(room_id_str, std::move(room_data)));
room_it = room_data_by_id.find(room_id_str); // TODO: Get iterator from above insert
}
@@ -442,53 +445,45 @@ namespace QuickMedia {
if(!body_json.isString())
continue;
- bool is_reply = false;
+ std::string replaces_event_id;
const Json::Value &relates_to_json = content_json["m.relates_to"];
if(relates_to_json.isObject()) {
- const Json::Value &in_reply_to_json = relates_to_json["m.in_reply_to"];
- is_reply = in_reply_to_json.isObject();
+ const Json::Value &replaces_event_id_json = relates_to_json["event_id"];
+ const Json::Value &rel_type_json = relates_to_json["rel_type"];
+ if(replaces_event_id_json.isString() && rel_type_json.isString() && strcmp(rel_type_json.asCString(), "m.replace") == 0)
+ replaces_event_id = replaces_event_id_json.asString();
}
+ auto message = std::make_shared<Message>();
+
if(strcmp(content_type.asCString(), "m.text") == 0) {
- auto message = std::make_shared<Message>();
- message->user_id = user_it->second;
- message->event_id = event_id_str;
- message->body = body_json.asString();
message->type = MessageType::TEXT;
- message->is_reply = is_reply;
- new_messages.push_back(message);
- room_data->message_by_event_id[event_id_str] = message;
} else if(strcmp(content_type.asCString(), "m.image") == 0) {
const Json::Value &url_json = content_json["url"];
if(!url_json.isString() || strncmp(url_json.asCString(), "mxc://", 6) != 0)
continue;
- auto message = std::make_shared<Message>();
- message->user_id = user_it->second;
- message->event_id = event_id_str;
- message->body = body_json.asString();
message->url = homeserver + "/_matrix/media/r0/download/" + url_json.asString().substr(6);
message->thumbnail_url = message_content_extract_thumbnail_url(content_json, homeserver);
message->type = MessageType::IMAGE;
- message->is_reply = is_reply;
- new_messages.push_back(message);
- room_data->message_by_event_id[event_id_str] = message;
} else if(strcmp(content_type.asCString(), "m.video") == 0) {
const Json::Value &url_json = content_json["url"];
if(!url_json.isString() || strncmp(url_json.asCString(), "mxc://", 6) != 0)
continue;
- auto message = std::make_shared<Message>();
- message->event_id = event_id_str;
- message->user_id = user_it->second;
- message->body = body_json.asString();
message->url = homeserver + "/_matrix/media/r0/download/" + url_json.asString().substr(6);
message->thumbnail_url = message_content_extract_thumbnail_url(content_json, homeserver);
message->type = MessageType::VIDEO;
- message->is_reply = is_reply;
- new_messages.push_back(message);
- room_data->message_by_event_id[event_id_str] = message;
+ } else {
+ continue;
}
+
+ message->user_id = user_it->second;
+ message->event_id = event_id_str;
+ message->body = body_json.asString();
+ message->replaces_event_id = std::move(replaces_event_id);
+ new_messages.push_back(message);
+ room_data->message_by_event_id[event_id_str] = message;
}
// TODO: Loop and std::move instead? doesn't insert create copies?
@@ -774,9 +769,13 @@ namespace QuickMedia {
static std::string create_body_for_message_reply(const RoomData *room_data, const Message *message, const std::string &body) {
std::string related_to_body;
switch(message->type) {
- case MessageType::TEXT:
- related_to_body = message->body;
+ case MessageType::TEXT: {
+ if(!message->replaces_event_id.empty() && strncmp(message->body.c_str(), " * ", 3) == 0)
+ related_to_body = message->body.substr(3);
+ else
+ related_to_body = message->body;
break;
+ }
case MessageType::IMAGE:
related_to_body = "sent an image";
break;
@@ -795,7 +794,13 @@ namespace QuickMedia {
return PluginResult::ERR;
}
- Message *relates_to_message = (Message*)relates_to;
+ Message *relates_to_message_raw = (Message*)relates_to;
+ std::shared_ptr<Message> relates_to_message_shared = room_it->second->message_by_event_id[relates_to_message_raw->event_id];
+ std::shared_ptr<Message> relates_to_message_original = get_edited_message_original_message(room_it->second.get(), relates_to_message_shared);
+ if(!relates_to_message_original) {
+ fprintf(stderr, "Failed to get the original message for message with event id: %s\n", relates_to_message_raw->event_id.c_str());
+ return PluginResult::ERR;
+ }
char random_characters[18];
if(!generate_random_characters(random_characters, sizeof(random_characters)))
@@ -804,14 +809,14 @@ namespace QuickMedia {
std::string random_readable_chars = random_characters_to_readable_string(random_characters, sizeof(random_characters));
Json::Value in_reply_to_json(Json::objectValue);
- in_reply_to_json["event_id"] = relates_to_message->event_id;
+ in_reply_to_json["event_id"] = relates_to_message_original->event_id;
Json::Value relates_to_json(Json::objectValue);
relates_to_json["m.in_reply_to"] = std::move(in_reply_to_json);
Json::Value request_data(Json::objectValue);
request_data["msgtype"] = message_type_to_request_msg_type_str(MessageType::TEXT);
- request_data["body"] = create_body_for_message_reply(room_it->second.get(), relates_to_message, body);
+ request_data["body"] = create_body_for_message_reply(room_it->second.get(), relates_to_message_raw, body); // Yes, the reply is to the edited message but the event_id reference is to the original message...
request_data["m.relates_to"] = std::move(relates_to_json);
Json::StreamWriterBuilder builder;
@@ -856,6 +861,204 @@ namespace QuickMedia {
return PluginResult::OK;
}
+ PluginResult Matrix::post_edit(const std::string &room_id, const std::string &body, void *relates_to) {
+ auto room_it = room_data_by_id.find(room_id);
+ if(room_it == room_data_by_id.end()) {
+ fprintf(stderr, "Error: no such room: %s\n", room_id.c_str());
+ return PluginResult::ERR;
+ }
+
+ Message *relates_to_message_raw = (Message*)relates_to;
+ std::shared_ptr<Message> relates_to_message_shared = room_it->second->message_by_event_id[relates_to_message_raw->event_id];
+ std::shared_ptr<Message> relates_to_message_original = get_edited_message_original_message(room_it->second.get(), relates_to_message_shared);
+ if(!relates_to_message_original) {
+ fprintf(stderr, "Failed to get the original message for message with event id: %s\n", relates_to_message_raw->event_id.c_str());
+ return PluginResult::ERR;
+ }
+
+ char random_characters[18];
+ if(!generate_random_characters(random_characters, sizeof(random_characters)))
+ return PluginResult::ERR;
+
+ std::string random_readable_chars = random_characters_to_readable_string(random_characters, sizeof(random_characters));
+
+ std::string formatted_body;
+ bool contains_formatted_text = false;
+ int line = 0;
+ string_split(body, '\n', [&formatted_body, &contains_formatted_text, &line](const char *str, size_t size){
+ if(line > 0)
+ formatted_body += "<br/>";
+ if(size > 0 && str[0] == '>') {
+ std::string line(str, size);
+ html_escape_sequences(line);
+ formatted_body += "<font color=\"#789922\">";
+ formatted_body += line;
+ formatted_body += "</font>";
+ contains_formatted_text = true;
+ } else {
+ formatted_body.append(str, size);
+ }
+ ++line;
+ return true;
+ });
+
+ Json::Value new_content_json(Json::objectValue);
+ new_content_json["msgtype"] = "m.text";
+ new_content_json["body"] = body;
+ if(contains_formatted_text) {
+ new_content_json["format"] = "org.matrix.custom.html";
+ new_content_json["formatted_body"] = formatted_body;
+ }
+
+ Json::Value relates_to_json(Json::objectValue);
+ relates_to_json["event_id"] = relates_to_message_original->event_id;
+ relates_to_json["rel_type"] = "m.replace";
+
+ Json::Value request_data(Json::objectValue);
+ request_data["msgtype"] = message_type_to_request_msg_type_str(MessageType::TEXT);
+ request_data["body"] = " * " + body;
+ if(contains_formatted_text) {
+ request_data["format"] = "org.matrix.custom.html";
+ request_data["formatted_body"] = " * " + formatted_body;
+ }
+ request_data["m.new_content"] = std::move(new_content_json);
+ request_data["m.relates_to"] = std::move(relates_to_json);
+
+ Json::StreamWriterBuilder builder;
+ builder["commentStyle"] = "None";
+ builder["indentation"] = "";
+
+ std::vector<CommandArg> additional_args = {
+ { "-X", "PUT" },
+ { "-H", "content-type: application/json" },
+ { "-H", "Authorization: Bearer " + access_token },
+ { "--data-binary", Json::writeString(builder, std::move(request_data)) }
+ };
+
+ char request_url[512];
+ snprintf(request_url, sizeof(request_url), "%s/_matrix/client/r0/rooms/%s/send/m.room.message/m%ld.%.*s", homeserver.c_str(), room_id.c_str(), time(NULL), (int)random_readable_chars.size(), random_readable_chars.c_str());
+ fprintf(stderr, "Post message to |%s|\n", request_url);
+
+ std::string server_response;
+ if(download_to_string(request_url, server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK)
+ return PluginResult::NET_ERR;
+
+ if(server_response.empty())
+ return PluginResult::ERR;
+
+ Json::Value json_root;
+ Json::CharReaderBuilder json_builder;
+ std::unique_ptr<Json::CharReader> json_reader(json_builder.newCharReader());
+ std::string json_errors;
+ if(!json_reader->parse(&server_response[0], &server_response[server_response.size()], &json_root, &json_errors)) {
+ fprintf(stderr, "Matrix post message response parse error: %s\n", json_errors.c_str());
+ return PluginResult::ERR;
+ }
+
+ if(!json_root.isObject())
+ return PluginResult::ERR;
+
+ const Json::Value &event_id_json = json_root["event_id"];
+ if(!event_id_json.isString())
+ return PluginResult::ERR;
+
+ fprintf(stderr, "Matrix post edit, response event id: %s\n", event_id_json.asCString());
+ return PluginResult::OK;
+ }
+
+ // TODO: Right now this recursively calls /rooms/<room_id>/context/<event_id> and trusts server to not make it recursive. To make this robust, check iteration count and do not trust server.
+ // TODO: Optimize?
+ std::shared_ptr<Message> Matrix::get_edited_message_original_message(RoomData *room_data, std::shared_ptr<Message> message) {
+ if(message->replaces_event_id.empty())
+ return message;
+
+ auto message_it = room_data->message_by_event_id.find(message->replaces_event_id);
+ if(message_it == room_data->message_by_event_id.end()) {
+ Json::Value request_data(Json::objectValue);
+ request_data["lazy_load_members"] = true;
+
+ Json::StreamWriterBuilder builder;
+ builder["commentStyle"] = "None";
+ builder["indentation"] = "";
+
+ std::vector<CommandArg> additional_args = {
+ { "-H", "Authorization: Bearer " + access_token }
+ };
+
+ std::string filter = url_param_encode(Json::writeString(builder, std::move(request_data)));
+
+ char url[512];
+ snprintf(url, sizeof(url), "%s/_matrix/client/r0/rooms/%s/context/%s?limit=0&filter=%s", homeserver.c_str(), room_data->id.c_str(), message->event_id.c_str(), filter.c_str());
+ fprintf(stderr, "get message context, url: |%s|\n", url);
+
+ std::string server_response;
+ if(download_to_string(url, server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK)
+ return nullptr;
+
+ if(server_response.empty())
+ return nullptr;
+
+ Json::Value json_root;
+ Json::CharReaderBuilder json_builder;
+ std::unique_ptr<Json::CharReader> json_reader(json_builder.newCharReader());
+ std::string json_errors;
+ if(!json_reader->parse(&server_response[0], &server_response[server_response.size()], &json_root, &json_errors)) {
+ fprintf(stderr, "Matrix /rooms/<room_id>/context/<event_id> response parse error: %s\n", json_errors.c_str());
+ return nullptr;
+ }
+
+ if(!json_root.isObject())
+ return nullptr;
+
+ const Json::Value &event_json = json_root["event"];
+ if(!event_json.isObject())
+ return nullptr;
+
+ const Json::Value &event_id_json = event_json["event_id"];
+ if(!event_id_json.isString())
+ return nullptr;
+
+ const Json::Value &content_json = event_json["content"];
+ if(!content_json.isObject())
+ return nullptr;
+
+ const Json::Value &body_json = content_json["body"];
+ if(!body_json.isString())
+ return nullptr;
+
+ std::string replaces_event_id;
+ const Json::Value &relates_to_json = content_json["m.relates_to"];
+ if(relates_to_json.isObject()) {
+ const Json::Value &event_id_json = relates_to_json["event_id"];
+ const Json::Value &rel_type_json = relates_to_json["rel_type"];
+ if(event_id_json.isString() && rel_type_json.isString() && strcmp(rel_type_json.asCString(), "m.replace") == 0)
+ replaces_event_id = event_id_json.asString();
+ }
+
+ const Json::Value &content_type = content_json["msgtype"];
+ if(!content_type.isString())
+ return nullptr;
+
+ auto new_message = std::make_shared<Message>();
+ new_message->user_id = -1;
+ new_message->event_id = event_id_json.asString();
+ new_message->replaces_event_id = std::move(replaces_event_id);
+ if(strcmp(content_type.asCString(), "m.text") == 0) {
+ new_message->type = MessageType::TEXT;
+ } else if(strcmp(content_type.asCString(), "m.image") == 0) {
+ new_message->type = MessageType::IMAGE;
+ } else if(strcmp(content_type.asCString(), "m.video") == 0) {
+ new_message->type = MessageType::VIDEO;
+ } else {
+ return nullptr;
+ }
+
+ return get_edited_message_original_message(room_data, std::move(new_message));
+ } else {
+ return get_edited_message_original_message(room_data, message_it->second);
+ }
+ }
+
// Returns empty string on error
static const char* file_get_filename(const std::string &filepath) {
size_t index = filepath.rfind('/');
@@ -1155,4 +1358,14 @@ namespace QuickMedia {
return PluginResult::OK;
}
+
+ bool Matrix::was_message_posted_by_me(const std::string &room_id, void *message) const {
+ auto room_it = room_data_by_id.find(room_id);
+ if(room_it == room_data_by_id.end()) {
+ fprintf(stderr, "Error: no such room: %s\n", room_id.c_str());
+ return false;
+ }
+ Message *message_typed = (Message*)message;
+ return user_id == room_it->second->user_info[message_typed->user_id].user_id;
+ }
} \ No newline at end of file