aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-10-16 23:45:05 +0200
committerdec05eba <dec05eba@protonmail.com>2020-10-16 23:45:05 +0200
commit3f9185ad357fb70138d3ea301cd9ac0ee0de0704 (patch)
tree92f8b35b5f4334ebb1889a53fca811f21c094b20 /src
parent0f6813a68d7f54c811b5040bdea37ca7b7e1b86e (diff)
Matrix: use room object instead of room id
Diffstat (limited to 'src')
-rw-r--r--src/QuickMedia.cpp289
-rw-r--r--src/plugins/Matrix.cpp297
2 files changed, 284 insertions, 302 deletions
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index cec81c6..249f38f 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -2807,8 +2807,13 @@ namespace QuickMedia {
while (current_page == PageType::CHAT_LOGIN) {
while (window.pollEvent(event)) {
- base_event_handler(event, PageType::EXIT, body.get(), nullptr, false, false);
- if(event.type == sf::Event::Resized || event.type == sf::Event::GainedFocus) {
+ if(event.type == sf::Event::Resized) {
+ window_size.x = event.size.width;
+ window_size.y = event.size.height;
+ sf::FloatRect visible_area(0, 0, window_size.x, window_size.y);
+ window.setView(sf::View(visible_area));
+ redraw = true;
+ } else if(event.type == sf::Event::GainedFocus) {
redraw = true;
} else if(event.type == sf::Event::TextEntered) {
inputs[focused_input]->onTextEntered(event.text.unicode);
@@ -2867,6 +2872,29 @@ namespace QuickMedia {
}
}
+ static BodyItems messages_to_body_items(const Messages &messages) {
+ BodyItems result_items(messages.size());
+ for(size_t i = 0; i < messages.size(); ++i) {
+ auto &message = messages[i];
+ auto body_item = BodyItem::create("");
+ body_item->set_author(message->user->display_name);
+ body_item->set_description(message->body);
+ body_item->set_timestamp(message->timestamp);
+ if(!message->thumbnail_url.empty())
+ body_item->thumbnail_url = message->thumbnail_url;
+ else if(!message->url.empty() && message->type == MessageType::IMAGE)
+ body_item->thumbnail_url = message->url;
+ else
+ body_item->thumbnail_url = message->user->avatar_url;
+ // TODO: Show image thumbnail inline instead of url to image and showing it as the thumbnail of the body item
+ body_item->url = message->url;
+ body_item->author_color = message->user->display_name_color;
+ body_item->userdata = (void*)message.get(); // Note: message has to be valid as long as body_item is used!
+ result_items[i] = std::move(body_item);
+ }
+ return result_items;
+ }
+
void Program::chat_page() {
assert(strcmp(plugin_name, "matrix") == 0);
@@ -2910,13 +2938,13 @@ namespace QuickMedia {
time_t last_read_message_timestamp;
};
- std::unordered_map<std::string, RoomBodyData> body_items_by_room_id;
- std::string current_room_id;
+ std::unordered_map<std::shared_ptr<RoomData>, RoomBodyData> body_items_by_room;
+ std::shared_ptr<RoomData> current_room;
RoomBodyData *current_room_body_data = nullptr;
bool is_window_focused = window.hasFocus();
- auto process_new_room_messages = [this, &body_items_by_room_id, &current_room_id, &is_window_focused](RoomSyncMessages &room_sync_messages, bool only_show_mentions) mutable {
+ auto process_new_room_messages = [this, &body_items_by_room, &current_room, &is_window_focused](RoomSyncMessages &room_sync_messages, bool only_show_mentions) mutable {
for(auto &[room, messages] : room_sync_messages) {
bool was_mentioned = false;
for(auto &message : messages) {
@@ -2924,20 +2952,20 @@ namespace QuickMedia {
was_mentioned = true;
message->mentions_me = false;
// TODO: What if the message or username begins with "-"? also make the notification image be the avatar of the user
- if(!is_window_focused || room->id != current_room_id)
+ if(!is_window_focused || room != current_room)
show_notification("QuickMedia matrix - " + matrix->message_get_author_displayname(message.get()) + " (" + room->name + ")", message->body);
}
}
- auto room_body_item_it = body_items_by_room_id.find(room->id);
- if(room_body_item_it == body_items_by_room_id.end())
+ auto room_body_item_it = body_items_by_room.find(room);
+ if(room_body_item_it == body_items_by_room.end())
continue;
- // TODO: this wont always because we dont display all types of messages from server, such as "joined", "left", "kicked", "banned", "changed avatar", "changed display name", etc.
+ // TODO: this wont always work because we dont display all types of messages from server, such as "joined", "left", "kicked", "banned", "changed avatar", "changed display name", etc.
// TODO: Update local marker when another client with our user sets read marker, in that case our read marker (room->get_user_read_marker) will be updated.
bool unread_messages_previous_session = false;
if(!messages.empty()) {
- std::shared_ptr<UserInfo> me = matrix->get_me(room->id);
+ std::shared_ptr<UserInfo> me = matrix->get_me(room);
if(me && room->get_user_read_marker(me) != messages.back()->event_id)
unread_messages_previous_session = true;
}
@@ -2983,7 +3011,10 @@ namespace QuickMedia {
chat_input.draw_background = false;
chat_input.set_editable(false);
- chat_input.on_submit_callback = [this, &chat_input, &tabs, &selected_tab, &current_room_id, &new_page, &chat_state, &currently_operating_on_item](const std::string &text) mutable {
+ chat_input.on_submit_callback = [this, &chat_input, &tabs, &selected_tab, &current_room, &new_page, &chat_state, &currently_operating_on_item](const std::string &text) mutable {
+ if(!current_room)
+ return false;
+
if(tabs[selected_tab].type == ChatTabType::MESSAGES) {
if(text.empty())
return false;
@@ -3010,7 +3041,7 @@ namespace QuickMedia {
if(chat_state == ChatState::TYPING_MESSAGE) {
// TODO: Make asynchronous
- if(matrix->post_message(current_room_id, text, std::nullopt, std::nullopt) == PluginResult::OK) {
+ if(matrix->post_message(current_room, text, std::nullopt, std::nullopt) == PluginResult::OK) {
chat_input.set_editable(false);
chat_state = ChatState::NAVIGATING;
return true;
@@ -3020,7 +3051,7 @@ namespace QuickMedia {
}
} else if(chat_state == ChatState::REPLYING) {
// TODO: Make asynchronous
- if(matrix->post_reply(current_room_id, text, currently_operating_on_item->userdata) == PluginResult::OK) {
+ if(matrix->post_reply(current_room, text, currently_operating_on_item->userdata) == PluginResult::OK) {
chat_input.set_editable(false);
chat_state = ChatState::NAVIGATING;
currently_operating_on_item = nullptr;
@@ -3031,7 +3062,7 @@ namespace QuickMedia {
}
} else if(chat_state == ChatState::EDITING) {
// TODO: Make asynchronous
- if(matrix->post_edit(current_room_id, text, currently_operating_on_item->userdata) == PluginResult::OK) {
+ if(matrix->post_edit(current_room, text, currently_operating_on_item->userdata) == PluginResult::OK) {
chat_input.set_editable(false);
chat_state = ChatState::NAVIGATING;
currently_operating_on_item = nullptr;
@@ -3046,20 +3077,18 @@ namespace QuickMedia {
};
struct SyncFutureResult {
- BodyItems body_items;
- BodyItems rooms_body_items;
+ Rooms rooms;
RoomSyncMessages room_sync_messages;
};
std::future<SyncFutureResult> sync_future;
bool sync_running = false;
- std::string sync_future_room_id;
sf::Clock sync_timer;
sf::Int32 sync_min_time_ms = 0; // Sync immediately the first time
- std::future<BodyItems> previous_messages_future;
+ std::future<Messages> previous_messages_future;
bool fetching_previous_messages_running = false;
- std::string previous_messages_future_room_id;
+ std::shared_ptr<RoomData> previous_messages_future_room;
const float tab_spacer_height = 0.0f;
sf::Vector2f body_pos;
@@ -3099,11 +3128,11 @@ namespace QuickMedia {
auto room_avatar_thumbnail_data = std::make_shared<ThumbnailData>();
AsyncImageLoader async_image_loader;
- auto typing_async_func = [this](bool new_state, std::string room_id) {
+ auto typing_async_func = [this](bool new_state, std::shared_ptr<RoomData> room) {
if(new_state) {
- matrix->on_start_typing(room_id);
+ matrix->on_start_typing(room);
} else {
- matrix->on_stop_typing(room_id);
+ matrix->on_stop_typing(room);
}
};
std::vector<std::future<void>> typing_futures;
@@ -3187,6 +3216,57 @@ namespace QuickMedia {
return result;
};
+ auto add_new_messages_to_current_room = [&tabs](Messages &messages) {
+ int num_items = tabs[MESSAGES_TAB_INDEX].body->items.size();
+ bool scroll_to_end = (num_items == 0 || (num_items > 0 && tabs[MESSAGES_TAB_INDEX].body->get_selected_item() == num_items - 1));
+
+ BodyItem *selected_item = tabs[MESSAGES_TAB_INDEX].body->get_selected();
+ tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(messages_to_body_items(messages));
+ if(selected_item && !scroll_to_end) {
+ int selected_item_index = tabs[MESSAGES_TAB_INDEX].body->get_index_by_body_item(selected_item);
+ if(selected_item_index != -1)
+ tabs[MESSAGES_TAB_INDEX].body->set_selected_item(selected_item_index);
+ } else if(scroll_to_end) {
+ tabs[MESSAGES_TAB_INDEX].body->select_last_item();
+ }
+ };
+
+ auto add_new_rooms = [&tabs, &body_items_by_room, &current_room, &current_room_body_data, &room_name_text](Rooms &rooms) {
+ if(rooms.empty())
+ return;
+
+ for(size_t i = 0; i < rooms.size(); ++i) {
+ auto &room = rooms[i];
+ std::string room_name = room->name;
+ if(room_name.empty())
+ room_name = room->id;
+
+ auto body_item = BodyItem::create(std::move(room_name));
+ body_item->thumbnail_url = room->avatar_url;
+ body_item->userdata = room.get(); // Note: this has to be valid as long as the room list is valid!
+ tabs[ROOMS_TAB_INDEX].body->items.push_back(body_item);
+ body_items_by_room[room] = { body_item, true, 0 };
+ }
+
+ if(current_room)
+ return;
+
+ current_room = rooms[0];
+ auto room_body_item_it = body_items_by_room.find(current_room);
+ if(room_body_item_it != body_items_by_room.end()) {
+ current_room_body_data = &room_body_item_it->second;
+ room_name_text.setString(current_room_body_data->body_item->get_title());
+ }
+ };
+
+ auto get_room_by_ptr = [&body_items_by_room](RoomData *room_ptr) -> std::shared_ptr<RoomData> {
+ for(auto &[room, body_data] : body_items_by_room) {
+ if(room.get() == room_ptr)
+ return room;
+ }
+ return nullptr;
+ };
+
while (current_page == PageType::CHAT) {
sf::Int32 frame_time_ms = frame_timer.restart().asMilliseconds();
while (window.pollEvent(event)) {
@@ -3218,15 +3298,15 @@ namespace QuickMedia {
hit_top = false;
break;
}
- if(hit_top && !fetching_previous_messages_running && tabs[selected_tab].type == ChatTabType::MESSAGES) {
+ if(hit_top && !fetching_previous_messages_running && tabs[selected_tab].type == ChatTabType::MESSAGES && current_room) {
gradient_inc = 0;
fetching_previous_messages_running = true;
- previous_messages_future_room_id = current_room_id;
- previous_messages_future = std::async(std::launch::async, [this, &previous_messages_future_room_id]() {
- BodyItems result_items;
- if(matrix->get_previous_room_messages(previous_messages_future_room_id, result_items) != PluginResult::OK)
- fprintf(stderr, "Failed to get previous matrix messages in room: %s\n", previous_messages_future_room_id.c_str());
- return result_items;
+ previous_messages_future_room = current_room;
+ previous_messages_future = std::async(std::launch::async, [this, &previous_messages_future_room]() {
+ Messages messages;
+ if(matrix->get_previous_room_messages(previous_messages_future_room, messages) != PluginResult::OK)
+ fprintf(stderr, "Failed to get previous matrix messages in room: %s\n", previous_messages_future_room->id.c_str());
+ return messages;
});
}
} else if(event.key.code == sf::Keyboard::Down || event.key.code == sf::Keyboard::J) {
@@ -3242,20 +3322,20 @@ namespace QuickMedia {
selected_tab = std::max(0, selected_tab - 1);
read_marker_timer.restart();
redraw = true;
- if(typing) {
+ if(typing && current_room) {
fprintf(stderr, "Stopped typing\n");
typing = false;
- typing_futures.push_back(std::async(typing_async_func, false, current_room_id));
+ typing_futures.push_back(std::async(typing_async_func, false, current_room));
}
} else if((event.key.code == sf::Keyboard::Right || event.key.code == sf::Keyboard::L) && synced) {
tabs[selected_tab].body->clear_cache();
selected_tab = std::min((int)tabs.size() - 1, selected_tab + 1);
read_marker_timer.restart();
redraw = true;
- if(typing) {
+ if(typing && current_room) {
fprintf(stderr, "Stopped typing\n");
typing = false;
- typing_futures.push_back(std::async(typing_async_func, false, current_room_id));
+ typing_futures.push_back(std::async(typing_async_func, false, current_room));
}
}
@@ -3326,7 +3406,7 @@ namespace QuickMedia {
continue;
launch_url(selected_item->get_title());
}
- } else if(event.type == sf::Event::KeyReleased && chat_state == ChatState::NAVIGATING && tabs[selected_tab].type == ChatTabType::MESSAGES) {
+ } else if(event.type == sf::Event::KeyReleased && chat_state == ChatState::NAVIGATING && tabs[selected_tab].type == ChatTabType::MESSAGES && current_room) {
if(event.key.code == sf::Keyboard::U) {
new_page = PageType::FILE_MANAGER;
chat_input.set_editable(false);
@@ -3341,7 +3421,7 @@ namespace QuickMedia {
// TODO: Make asynchronous.
// TODO: Upload multiple files.
std::string err_msg;
- if(matrix->post_file(current_room_id, sf::Clipboard::getString(), err_msg) != PluginResult::OK) {
+ if(matrix->post_file(current_room, sf::Clipboard::getString(), err_msg) != PluginResult::OK) {
std::string desc = "Failed to upload media to room, error: " + err_msg;
show_notification("QuickMedia", desc.c_str(), Urgency::CRITICAL);
}
@@ -3382,13 +3462,13 @@ namespace QuickMedia {
show_notification("QuickMedia", "No message selected for editing");
}
}
-
+
if(event.key.code == sf::Keyboard::D) {
BodyItem *selected = tabs[selected_tab].body->get_selected();
if(selected) {
// TODO: Make asynchronous
std::string err_msg;
- if(matrix->delete_message(current_room_id, selected->userdata, err_msg) != PluginResult::OK) {
+ if(matrix->delete_message(current_room, selected->userdata, err_msg) != PluginResult::OK) {
// TODO: Show inline notification
show_notification("QuickMedia", "Failed to delete message, reason: " + err_msg, Urgency::CRITICAL);
}
@@ -3405,9 +3485,9 @@ namespace QuickMedia {
// TODO: Also show typing event when ctrl+v pasting?
if(event.text.unicode != 13) { // Return key
start_typing_timer.restart();
- if(!typing) {
+ if(!typing && current_room) {
fprintf(stderr, "Started typing\n");
- typing_futures.push_back(std::async(typing_async_func, true, current_room_id));
+ typing_futures.push_back(std::async(typing_async_func, true, current_room));
}
typing = true;
}
@@ -3416,10 +3496,10 @@ namespace QuickMedia {
chat_input.set_text("");
chat_state = ChatState::NAVIGATING;
currently_operating_on_item = nullptr;
- if(typing) {
+ if(typing && current_room) {
fprintf(stderr, "Stopped typing\n");
typing = false;
- typing_futures.push_back(std::async(typing_async_func, false, current_room_id));
+ typing_futures.push_back(std::async(typing_async_func, false, current_room));
}
}
//chat_input.on_event(event);
@@ -3428,21 +3508,23 @@ namespace QuickMedia {
BodyItem *selected_item = tabs[selected_tab].body->get_selected();
if(selected_item) {
tabs[selected_tab].body->clear_cache();
- current_room_id = selected_item->url;
+
+ current_room = get_room_by_ptr((RoomData*)selected_item->userdata);
+ assert(current_room);
selected_tab = MESSAGES_TAB_INDEX;
tabs[MESSAGES_TAB_INDEX].body->clear_items();
- BodyItems new_items;
- if(matrix->get_all_synced_room_messages(current_room_id, new_items) == PluginResult::OK) {
- tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(std::move(new_items));
+ Messages new_messages;
+ if(matrix->get_all_synced_room_messages(current_room, new_messages) == PluginResult::OK) {
+ tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(messages_to_body_items(new_messages));
tabs[MESSAGES_TAB_INDEX].body->select_last_item();
} else {
- std::string err_msg = "Failed to get messages in room: " + current_room_id;
+ std::string err_msg = "Failed to get messages in room: " + current_room->id;
show_notification("QuickMedia", err_msg, Urgency::CRITICAL);
}
- auto room_body_item_it = body_items_by_room_id.find(current_room_id);
- if(room_body_item_it != body_items_by_room_id.end()) {
+ auto room_body_item_it = body_items_by_room.find(current_room);
+ if(room_body_item_it != body_items_by_room.end()) {
current_room_body_data = &room_body_item_it->second;
room_name_text.setString(current_room_body_data->body_item->get_title());
room_avatar_thumbnail_data = std::make_shared<ThumbnailData>();
@@ -3458,28 +3540,30 @@ namespace QuickMedia {
case PageType::FILE_MANAGER: {
new_page = PageType::CHAT;
- auto file_manager_page = std::make_unique<FileManagerPage>(this);
- file_manager_page->set_current_directory(get_home_dir().data);
- auto file_manager_body = create_body();
- file_manager_page->get_files_in_directory(file_manager_body->items);
- std::vector<Tab> tabs;
- tabs.push_back(Tab{std::move(file_manager_body), std::move(file_manager_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
-
- selected_files.clear();
- page_loop(std::move(tabs));
-
- if(selected_files.empty()) {
- fprintf(stderr, "No files selected!\n");
- } else {
- // TODO: Make asynchronous.
- // TODO: Upload multiple files.
- std::string err_msg;
- if(matrix->post_file(current_room_id, selected_files[0], err_msg) != PluginResult::OK) {
- std::string desc = "Failed to upload media to room, error: " + err_msg;
- show_notification("QuickMedia", desc.c_str(), Urgency::CRITICAL);
+ if(current_room) {
+ auto file_manager_page = std::make_unique<FileManagerPage>(this);
+ file_manager_page->set_current_directory(get_home_dir().data);
+ auto file_manager_body = create_body();
+ file_manager_page->get_files_in_directory(file_manager_body->items);
+ std::vector<Tab> tabs;
+ tabs.push_back(Tab{std::move(file_manager_body), std::move(file_manager_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
+
+ selected_files.clear();
+ page_loop(std::move(tabs));
+
+ if(selected_files.empty()) {
+ fprintf(stderr, "No files selected!\n");
+ } else {
+ // TODO: Make asynchronous.
+ // TODO: Upload multiple files.
+ std::string err_msg;
+ if(matrix->post_file(current_room, selected_files[0], err_msg) != PluginResult::OK) {
+ std::string desc = "Failed to upload media to room, error: " + err_msg;
+ show_notification("QuickMedia", desc.c_str(), Urgency::CRITICAL);
+ }
}
+ redraw = true;
}
- redraw = true;
break;
}
case PageType::CHAT_LOGIN: {
@@ -3502,10 +3586,10 @@ namespace QuickMedia {
break;
}
- if(typing && start_typing_timer.getElapsedTime().asSeconds() >= typing_timeout_seconds) {
+ if(typing && start_typing_timer.getElapsedTime().asSeconds() >= typing_timeout_seconds && current_room) {
fprintf(stderr, "Stopped typing\n");
typing = false;
- typing_futures.push_back(std::async(typing_async_func, false, current_room_id));
+ typing_futures.push_back(std::async(typing_async_func, false, current_room));
}
for(auto it = typing_futures.begin(); it != typing_futures.end(); ) {
@@ -3589,26 +3673,18 @@ namespace QuickMedia {
sync_min_time_ms = 50;
sync_running = true;
sync_timer.restart();
- sync_future_room_id = current_room_id;
- sync_future = std::async(std::launch::async, [this, &sync_future_room_id, synced]() {
+ sync_future = std::async(std::launch::async, [this, synced]() {
SyncFutureResult result;
if(matrix->sync(result.room_sync_messages) == PluginResult::OK) {
fprintf(stderr, "Synced matrix\n");
if(!synced) {
- if(matrix->get_joined_rooms(result.rooms_body_items) != PluginResult::OK) {
+ if(matrix->get_joined_rooms(result.rooms) != PluginResult::OK) {
show_notification("QuickMedia", "Failed to get a list of joined rooms", Urgency::CRITICAL);
current_page = PageType::EXIT;
return result;
}
}
-
- if(sync_future_room_id.empty() && !result.rooms_body_items.empty())
- sync_future_room_id = result.rooms_body_items[0]->url;
-
- if(matrix->get_new_room_messages(sync_future_room_id, result.body_items) != PluginResult::OK) {
- fprintf(stderr, "Failed to get new matrix messages in room: %s\n", sync_future_room_id.c_str());
- }
} else {
fprintf(stderr, "Failed to sync matrix\n");
}
@@ -3619,40 +3695,14 @@ namespace QuickMedia {
if(sync_future.valid() && sync_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
SyncFutureResult sync_result = sync_future.get();
- // Ignore finished sync if it happened in another room. When we navigate back to the room we will get the messages again
- if(sync_future_room_id == current_room_id || !synced) {
- int num_items = tabs[MESSAGES_TAB_INDEX].body->items.size();
- bool scroll_to_end = (num_items == 0 || (num_items > 0 && tabs[MESSAGES_TAB_INDEX].body->get_selected_item() == num_items - 1));
-
- BodyItem *selected_item = tabs[MESSAGES_TAB_INDEX].body->get_selected();
- tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(std::move(sync_result.body_items));
- if(selected_item && !scroll_to_end) {
- int selected_item_index = tabs[MESSAGES_TAB_INDEX].body->get_index_by_body_item(selected_item);
- if(selected_item_index != -1)
- tabs[MESSAGES_TAB_INDEX].body->set_selected_item(selected_item_index);
- } else if(scroll_to_end) {
- tabs[MESSAGES_TAB_INDEX].body->select_last_item();
- }
- }
- // Initial sync
- if(!synced) {
- tabs[ROOMS_TAB_INDEX].body->items = std::move(sync_result.rooms_body_items);
+ add_new_rooms(sync_result.rooms);
- for(auto body_item : tabs[ROOMS_TAB_INDEX].body->items) {
- body_items_by_room_id[body_item->url] = { body_item, true, 0 };
- }
+ auto room_messages_it = sync_result.room_sync_messages.find(current_room);
+ if(room_messages_it != sync_result.room_sync_messages.end())
+ add_new_messages_to_current_room(room_messages_it->second);
- // The room id should be saved in a file when changing viewed room.
- if(!tabs[ROOMS_TAB_INDEX].body->items.empty())
- current_room_id = tabs[ROOMS_TAB_INDEX].body->items[0]->url;
-
- auto room_body_item_it = body_items_by_room_id.find(current_room_id);
- if(room_body_item_it != body_items_by_room_id.end()) {
- current_room_body_data = &room_body_item_it->second;
- room_name_text.setString(current_room_body_data->body_item->get_title());
- }
- }
+ //modify_related_messages()
process_new_room_messages(sync_result.room_sync_messages, !synced);
sync_running = false;
@@ -3666,13 +3716,13 @@ namespace QuickMedia {
}
if(fetching_previous_messages_running && previous_messages_future.valid() && previous_messages_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
- BodyItems new_body_items = previous_messages_future.get();
- fprintf(stderr, "Finished fetching older messages, num new messages: %zu\n", new_body_items.size());
+ Messages new_messages = previous_messages_future.get();
+ fprintf(stderr, "Finished fetching older messages, num new messages: %zu\n", new_messages.size());
// Ignore finished fetch of messages if it happened in another room. When we navigate back to the room we will get the messages again
- size_t num_new_messages = new_body_items.size();
- if(previous_messages_future_room_id == current_room_id && num_new_messages > 0) {
+ size_t num_new_messages = new_messages.size();
+ if(previous_messages_future_room == current_room && num_new_messages > 0) {
BodyItem *selected_item = tabs[MESSAGES_TAB_INDEX].body->get_selected();
- tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(std::move(new_body_items));
+ tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(messages_to_body_items(new_messages));
if(selected_item) {
int selected_item_index = tabs[MESSAGES_TAB_INDEX].body->get_index_by_body_item(selected_item);
if(selected_item_index != -1)
@@ -3799,7 +3849,7 @@ namespace QuickMedia {
window.draw(loading_text);
}
- if(tabs[selected_tab].type == ChatTabType::MESSAGES) {
+ if(tabs[selected_tab].type == ChatTabType::MESSAGES && current_room) {
BodyItem *last_visible_item = tabs[selected_tab].body->get_last_fully_visible_item();
if(is_window_focused && chat_state != ChatState::URL_SELECTION && current_room_body_data && last_visible_item && !setting_read_marker && read_marker_timer.getElapsedTime().asMilliseconds() >= read_marker_timeout_ms) {
Message *message = (Message*)last_visible_item->userdata;
@@ -3809,8 +3859,9 @@ namespace QuickMedia {
current_room_body_data->last_read_message_timestamp = message->timestamp;
// TODO: What if the message is no longer valid?
setting_read_marker = true;
- set_read_marker_future = std::async(std::launch::async, [this, current_room_id, message]() mutable {
- if(matrix->set_read_marker(current_room_id, message) != PluginResult::OK) {
+ std::shared_ptr<RoomData> room = current_room;
+ set_read_marker_future = std::async(std::launch::async, [this, room, message]() mutable {
+ if(matrix->set_read_marker(room, message) != PluginResult::OK) {
fprintf(stderr, "Warning: failed to set read marker to %s\n", message->event_id.c_str());
}
});
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index 18a31a0..0866bac 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -53,30 +53,24 @@ namespace QuickMedia {
return user->read_marker_event_id;
}
- size_t RoomData::prepend_messages_reverse(std::vector<std::shared_ptr<Message>> new_messages) {
+ void RoomData::prepend_messages_reverse(std::vector<std::shared_ptr<Message>> new_messages) {
std::lock_guard<std::mutex> lock(room_mutex);
- size_t num_inserted = 0;
for(auto it = new_messages.begin(); it != new_messages.end(); ++it) {
if(message_by_event_id.find((*it)->event_id) == message_by_event_id.end()) {
message_by_event_id.insert(std::make_pair((*it)->event_id, *it));
messages.insert(messages.begin(), std::move(*it));
- ++num_inserted;
}
}
- return num_inserted;
}
- size_t RoomData::append_messages(std::vector<std::shared_ptr<Message>> new_messages) {
+ void RoomData::append_messages(std::vector<std::shared_ptr<Message>> new_messages) {
std::lock_guard<std::mutex> lock(room_mutex);
- size_t num_inserted = 0;
for(auto it = new_messages.begin(); it != new_messages.end(); ++it) {
if(message_by_event_id.find((*it)->event_id) == message_by_event_id.end()) {
message_by_event_id.insert(std::make_pair((*it)->event_id, *it));
messages.push_back(std::move(*it));
- ++num_inserted;
}
}
- return num_inserted;
}
std::shared_ptr<Message> RoomData::get_message_by_id(const std::string &id) {
@@ -141,7 +135,7 @@ namespace QuickMedia {
return PluginResult::OK;
}
- PluginResult Matrix::get_joined_rooms(BodyItems &result_items) {
+ PluginResult Matrix::get_joined_rooms(Rooms &rooms) {
std::vector<CommandArg> additional_args = {
{ "-H", "Authorization: Bearer " + access_token }
};
@@ -162,114 +156,28 @@ namespace QuickMedia {
continue;
std::string room_id_str = room_id_json.GetString();
- std::string room_name;
- std::string avatar_url;
-
auto room = get_room_by_id(room_id_str);
if(!room) {
room = std::make_shared<RoomData>();
room->id = room_id_json.GetString();
add_room(std::move(room));
- room_name = room_id_str;
fprintf(stderr, "Missing room %s from /sync, adding in joined_rooms\n", room_id_str.c_str());
- } else {
- room_name = room->name;
- if(room_name.empty())
- room_name = room_id_str;
- avatar_url = room->avatar_url;
}
- auto body_item = BodyItem::create(std::move(room_name));
- body_item->url = room_id_str;
- body_item->thumbnail_url = std::move(avatar_url);
- result_items.push_back(std::move(body_item));
- }
-
- return PluginResult::OK;
- }
-
- static void room_messages_to_body_items(const std::shared_ptr<Message> *messages, size_t num_messages, BodyItems &result_items) {
- for(size_t i = 0; i < num_messages; ++i) {
- auto body_item = BodyItem::create("");
- body_item->set_author(messages[i]->user->display_name);
- body_item->set_description(messages[i]->body);
- body_item->set_timestamp(messages[i]->timestamp);
- if(!messages[i]->thumbnail_url.empty())
- body_item->thumbnail_url = messages[i]->thumbnail_url;
- else if(!messages[i]->url.empty() && messages[i]->type == MessageType::IMAGE)
- body_item->thumbnail_url = messages[i]->url;
- else
- body_item->thumbnail_url = messages[i]->user->avatar_url;
- // TODO: Show image thumbnail inline instead of url to image and showing it as the thumbnail of the body item
- body_item->url = messages[i]->url;
- body_item->author_color = messages[i]->user->display_name_color;
- body_item->userdata = (void*)messages[i].get(); // Note: messages[i] has to be valid as long as body_item is used!
- result_items.push_back(std::move(body_item));
- }
- }
-
- // TODO: Merge common code with |get_new_room_messages|
- PluginResult Matrix::get_all_synced_room_messages(const std::string &room_id, BodyItems &result_items) {
- auto room = get_room_by_id(room_id);
- if(!room) {
- fprintf(stderr, "Error: no such room: %s\n", room_id.c_str());
- return PluginResult::ERR;
+ rooms.push_back(room);
}
- // TODO: Thread safe?
- /*
- if(!room->initial_fetch_finished) {
- PluginResult result = get_previous_room_messages(room);
- if(result == PluginResult::OK) {
- room->initial_fetch_finished = true;
- } else {
- fprintf(stderr, "Initial sync failed for room: %s\n", room_id.c_str());
- return result;
- }
- }
- */
-
- room->acquire_room_lock();
- room_messages_to_body_items(room->get_messages_thread_unsafe().data(), room->get_messages_thread_unsafe().size(), result_items);
- room->last_read_index = room->get_messages_thread_unsafe().size();
- room->release_room_lock();
return PluginResult::OK;
}
- PluginResult Matrix::get_new_room_messages(const std::string &room_id, BodyItems &result_items) {
- auto room = get_room_by_id(room_id);
- if(!room) {
- fprintf(stderr, "Error: no such room: %s\n", room_id.c_str());
- return PluginResult::ERR;
- }
-
- /*
- if(!room->initial_fetch_finished) {
- PluginResult result = get_previous_room_messages(room);
- if(result == PluginResult::OK) {
- room->initial_fetch_finished = true;
- } else {
- fprintf(stderr, "Initial sync failed for room: %s\n", room_id.c_str());
- return result;
- }
- }
- */
-
+ PluginResult Matrix::get_all_synced_room_messages(std::shared_ptr<RoomData> room, Messages &messages) {
room->acquire_room_lock();
- size_t num_new_messages = room->get_messages_thread_unsafe().size() - room->last_read_index;
- room_messages_to_body_items(room->get_messages_thread_unsafe().data() + room->last_read_index, num_new_messages, result_items);
- room->last_read_index = room->get_messages_thread_unsafe().size();
+ messages = room->get_messages_thread_unsafe();
room->release_room_lock();
return PluginResult::OK;
}
- PluginResult Matrix::get_previous_room_messages(const std::string &room_id, BodyItems &result_items) {
- auto room = get_room_by_id(room_id);
- if(!room) {
- fprintf(stderr, "Error: no such room: %s\n", room_id.c_str());
- return PluginResult::ERR;
- }
-
+ PluginResult Matrix::get_previous_room_messages(std::shared_ptr<RoomData> room, Messages &messages) {
room->acquire_room_lock();
size_t num_messages_before = room->get_messages_thread_unsafe().size();
room->release_room_lock();
@@ -280,7 +188,7 @@ namespace QuickMedia {
room->acquire_room_lock();
size_t num_messages_after = room->get_messages_thread_unsafe().size();
size_t num_new_messages = num_messages_after - num_messages_before;
- room_messages_to_body_items(room->get_messages_thread_unsafe().data(), num_new_messages, result_items);
+ messages.insert(messages.end(), room->get_messages_thread_unsafe().begin(), room->get_messages_thread_unsafe().begin() + num_new_messages);
room->release_room_lock();
return PluginResult::OK;
}
@@ -536,20 +444,12 @@ namespace QuickMedia {
if(!events_json.IsArray())
return;
- std::vector<std::shared_ptr<Message>> *room_sync_messages = nullptr;
- if(room_messages)
- room_sync_messages = &(*room_messages)[room_data];
-
std::vector<std::shared_ptr<Message>> new_messages;
for(const rapidjson::Value &event_item_json : events_json.GetArray()) {
if(!event_item_json.IsObject())
continue;
- const rapidjson::Value &type_json = GetMember(event_item_json, "type");
- if(!type_json.IsString() || strcmp(type_json.GetString(), "m.room.message") != 0)
- continue;
-
const rapidjson::Value &sender_json = GetMember(event_item_json, "sender");
if(!sender_json.IsString())
continue;
@@ -562,12 +462,8 @@ namespace QuickMedia {
std::string event_id_str = event_id_json.GetString();
- const rapidjson::Value &content_json = GetMember(event_item_json, "content");
- if(!content_json.IsObject())
- continue;
-
- const rapidjson::Value &content_type = GetMember(content_json, "msgtype");
- if(!content_type.IsString())
+ const rapidjson::Value *content_json = &GetMember(event_item_json, "content");
+ if(!content_json->IsObject())
continue;
auto user = room_data->get_user_by_id(sender_json_str);
@@ -577,24 +473,71 @@ namespace QuickMedia {
continue;
}
- const rapidjson::Value &body_json = GetMember(content_json, "body");
- if(!body_json.IsString())
- continue;
-
time_t timestamp = 0;
const rapidjson::Value &origin_server_ts = GetMember(event_item_json, "origin_server_ts");
if(origin_server_ts.IsNumber())
timestamp = origin_server_ts.GetInt64();
- std::string replaces_event_id;
- const rapidjson::Value &relates_to_json = GetMember(content_json, "m.relates_to");
+ const rapidjson::Value &type_json = GetMember(event_item_json, "type");
+ if(!type_json.IsString())
+ continue;
+
+ RelatedEventType related_event_type = RelatedEventType::NONE;
+ std::string related_event_id;
+ const rapidjson::Value &relates_to_json = GetMember(*content_json, "m.relates_to");
if(relates_to_json.IsObject()) {
const rapidjson::Value &replaces_event_id_json = GetMember(relates_to_json, "event_id");
const rapidjson::Value &rel_type_json = GetMember(relates_to_json, "rel_type");
- if(replaces_event_id_json.IsString() && rel_type_json.IsString() && strcmp(rel_type_json.GetString(), "m.replace") == 0)
- replaces_event_id = replaces_event_id_json.GetString();
+ if(replaces_event_id_json.IsString() && rel_type_json.IsString() && strcmp(rel_type_json.GetString(), "m.replace") == 0) {
+ related_event_id = replaces_event_id_json.GetString();
+ related_event_type = RelatedEventType::EDIT;
+ } else {
+ const rapidjson::Value &in_reply_to_json = GetMember(relates_to_json, "m.in_reply_to");
+ if(in_reply_to_json.IsObject()) {
+ const rapidjson::Value &in_reply_to_event_id = GetMember(in_reply_to_json, "event_id");
+ if(in_reply_to_event_id.IsString()) {
+ related_event_id = in_reply_to_event_id.GetString();
+ related_event_type = RelatedEventType::REPLY;
+ }
+ }
+ }
+ }
+
+ const rapidjson::Value &new_content_json = GetMember(*content_json, "m.new_content");
+ if(new_content_json.IsObject())
+ content_json = &new_content_json;
+
+ const rapidjson::Value &content_type = GetMember(*content_json, "msgtype");
+ if(!content_type.IsString() || strcmp(type_json.GetString(), "m.room.redaction") == 0) {
+ auto message = std::make_shared<Message>();
+ message->type = MessageType::REDACTION;
+ message->user = user;
+ message->event_id = event_id_str;
+ message->body = "Message deleted";
+ message->timestamp = timestamp;
+ message->related_event_type = RelatedEventType::REDACTION;
+
+ const rapidjson::Value &reason_json = GetMember(*content_json, "reason");
+ if(reason_json.IsString()) {
+ message->body += ", reason: ";
+ message->body += reason_json.GetString();
+ }
+
+ const rapidjson::Value &redacts_json = GetMember(event_item_json, "redacts");
+ if(redacts_json.IsString())
+ message->related_event_id = redacts_json.GetString();
+
+ new_messages.push_back(message);
+ continue;
}
+ if(strcmp(type_json.GetString(), "m.room.message") != 0)
+ continue;
+
+ const rapidjson::Value &body_json = GetMember(*content_json, "body");
+ if(!body_json.IsString())
+ continue;
+
auto message = std::make_shared<Message>();
std::string prefix;
@@ -603,30 +546,30 @@ namespace QuickMedia {
if(strcmp(content_type.GetString(), "m.text") == 0) {
message->type = MessageType::TEXT;
} else if(strcmp(content_type.GetString(), "m.image") == 0) {
- const rapidjson::Value &url_json = GetMember(content_json, "url");
+ const rapidjson::Value &url_json = GetMember(*content_json, "url");
if(!url_json.IsString() || strncmp(url_json.GetString(), "mxc://", 6) != 0)
continue;
message->url = homeserver + "/_matrix/media/r0/download/" + (url_json.GetString() + 6);
- message->thumbnail_url = message_content_extract_thumbnail_url(content_json, homeserver);
+ message->thumbnail_url = message_content_extract_thumbnail_url(*content_json, homeserver);
message->type = MessageType::IMAGE;
} else if(strcmp(content_type.GetString(), "m.video") == 0) {
- const rapidjson::Value &url_json = GetMember(content_json, "url");
+ const rapidjson::Value &url_json = GetMember(*content_json, "url");
if(!url_json.IsString() || strncmp(url_json.GetString(), "mxc://", 6) != 0)
continue;
message->url = homeserver + "/_matrix/media/r0/download/" + (url_json.GetString() + 6);
- message->thumbnail_url = message_content_extract_thumbnail_url(content_json, homeserver);
+ message->thumbnail_url = message_content_extract_thumbnail_url(*content_json, homeserver);
message->type = MessageType::VIDEO;
} else if(strcmp(content_type.GetString(), "m.audio") == 0) {
- const rapidjson::Value &url_json = GetMember(content_json, "url");
+ const rapidjson::Value &url_json = GetMember(*content_json, "url");
if(!url_json.IsString() || strncmp(url_json.GetString(), "mxc://", 6) != 0)
continue;
message->url = homeserver + "/_matrix/media/r0/download/" + (url_json.GetString() + 6);
message->type = MessageType::AUDIO;
} else if(strcmp(content_type.GetString(), "m.file") == 0) {
- const rapidjson::Value &url_json = GetMember(content_json, "url");
+ const rapidjson::Value &url_json = GetMember(*content_json, "url");
if(!url_json.IsString() || strncmp(url_json.GetString(), "mxc://", 6) != 0)
continue;
@@ -639,12 +582,12 @@ namespace QuickMedia {
message->type = MessageType::TEXT;
prefix = "* NOTICE * ";
} else if(strcmp(content_type.GetString(), "m.location") == 0) { // TODO: show locations differently
- const rapidjson::Value &geo_uri_json = GetMember(content_json, "geo_uri");
+ const rapidjson::Value &geo_uri_json = GetMember(*content_json, "geo_uri");
if(geo_uri_json.IsString())
prefix = geo_uri_json.GetString() + std::string(" | ");
message->type = MessageType::TEXT;
- message->thumbnail_url = message_content_extract_thumbnail_url(content_json, homeserver);
+ message->thumbnail_url = message_content_extract_thumbnail_url(*content_json, homeserver);
} else {
continue;
}
@@ -652,22 +595,22 @@ namespace QuickMedia {
message->user = user;
message->event_id = event_id_str;
message->body = prefix + body_json.GetString();
- message->replaces_event_id = std::move(replaces_event_id);
+ message->related_event_id = std::move(related_event_id);
+ message->related_event_type = related_event_type;
// TODO: Is @room ok? shouldn't we also check if the user has permission to do @room? (only when notifications are limited to @mentions)
if(has_unread_notifications && !username.empty())
message->mentions_me = message_contains_user_mention(message->body, username) || message_contains_user_mention(message->body, "@room");
message->timestamp = timestamp;
new_messages.push_back(message);
- if(room_sync_messages)
- room_sync_messages->push_back(message);
}
+ // TODO: Add directly to this instead when set? otherwise add to new_messages
+ if(room_messages)
+ (*room_messages)[room_data] = new_messages;
+
// TODO: Loop and std::move instead? doesn't insert create copies?
if(message_dir == MessageDirection::BEFORE) {
- size_t num_inserted_messages = room_data->prepend_messages_reverse(std::move(new_messages));
- // TODO: Is this thread-safe?
- if(room_data->last_read_index != 0)
- room_data->last_read_index += num_inserted_messages;
+ room_data->prepend_messages_reverse(std::move(new_messages));
} else if(message_dir == MessageDirection::AFTER) {
room_data->append_messages(std::move(new_messages));
}
@@ -860,7 +803,7 @@ namespace QuickMedia {
return "m.file";
}
- PluginResult Matrix::post_message(const std::string &room_id, const std::string &body, const std::optional<UploadInfo> &file_info, const std::optional<UploadInfo> &thumbnail_info) {
+ PluginResult Matrix::post_message(std::shared_ptr<RoomData> room, const std::string &body, const std::optional<UploadInfo> &file_info, const std::optional<UploadInfo> &thumbnail_info) {
char random_characters[18];
if(!generate_random_characters(random_characters, sizeof(random_characters)))
return PluginResult::ERR;
@@ -940,7 +883,7 @@ namespace QuickMedia {
};
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());
+ 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());
rapidjson::Document json_root;
DownloadResult download_result = download_json(json_root, request_url, std::move(additional_args), true);
@@ -987,9 +930,7 @@ namespace QuickMedia {
std::string related_to_body;
switch(message->type) {
case MessageType::TEXT: {
- if(!message->replaces_event_id.empty() && strncmp(message->body.c_str(), " * ", 3) == 0)
- related_to_body = remove_reply_formatting(message->body.substr(3));
- else
+ if(message->related_event_type != RelatedEventType::NONE)
related_to_body = remove_reply_formatting(message->body);
break;
}
@@ -1005,6 +946,9 @@ namespace QuickMedia {
case MessageType::FILE:
related_to_body = "sent a file";
break;
+ case MessageType::REDACTION:
+ related_to_body = message->body;
+ break;
}
return related_to_body;
}
@@ -1027,13 +971,7 @@ namespace QuickMedia {
}
// TODO: Support greentext
- PluginResult Matrix::post_reply(const std::string &room_id, const std::string &body, void *relates_to) {
- auto room = get_room_by_id(room_id);
- if(!room) {
- fprintf(stderr, "Error: no such room: %s\n", room_id.c_str());
- return PluginResult::ERR;
- }
-
+ PluginResult Matrix::post_reply(std::shared_ptr<RoomData> room, const std::string &body, void *relates_to) {
// TODO: Store shared_ptr<Message> instead of raw pointer...
Message *relates_to_message_raw = (Message*)relates_to;
std::shared_ptr<Message> relates_to_message_shared = room->get_message_by_id(relates_to_message_raw->event_id);
@@ -1077,7 +1015,7 @@ namespace QuickMedia {
};
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());
+ 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());
rapidjson::Document json_root;
DownloadResult download_result = download_json(json_root, request_url, std::move(additional_args), true);
@@ -1094,13 +1032,7 @@ namespace QuickMedia {
return PluginResult::OK;
}
- PluginResult Matrix::post_edit(const std::string &room_id, const std::string &body, void *relates_to) {
- auto room = get_room_by_id(room_id);
- if(!room) {
- fprintf(stderr, "Error: no such room: %s\n", room_id.c_str());
- return PluginResult::ERR;
- }
-
+ PluginResult Matrix::post_edit(std::shared_ptr<RoomData> room, const std::string &body, void *relates_to) {
Message *relates_to_message_raw = (Message*)relates_to;
std::shared_ptr<Message> relates_to_message_shared = room->get_message_by_id(relates_to_message_raw->event_id);
std::shared_ptr<Message> relates_to_message_original = get_edited_message_original_message(room.get(), relates_to_message_shared);
@@ -1173,7 +1105,7 @@ namespace QuickMedia {
};
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());
+ 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());
rapidjson::Document json_root;
DownloadResult download_result = download_json(json_root, request_url, std::move(additional_args), true);
@@ -1193,10 +1125,10 @@ namespace QuickMedia {
// 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())
+ if(message->related_event_type != RelatedEventType::EDIT)
return message;
- auto replaced_message = room_data->get_message_by_id(message->replaces_event_id);
+ auto replaced_message = room_data->get_message_by_id(message->related_event_id);
if(!replaced_message) {
rapidjson::Document request_data(rapidjson::kObjectType);
request_data.AddMember("lazy_load_members", true, request_data.GetAllocator());
@@ -1237,13 +1169,16 @@ namespace QuickMedia {
if(!body_json.IsString())
return nullptr;
- std::string replaces_event_id;
+ RelatedEventType related_event_type = RelatedEventType::NONE;
+ std::string related_event_id;
const rapidjson::Value &relates_to_json = GetMember(content_json, "m.relates_to");
if(relates_to_json.IsObject()) {
const rapidjson::Value &event_id_json = GetMember(relates_to_json, "event_id");
const rapidjson::Value &rel_type_json = GetMember(relates_to_json, "rel_type");
- if(event_id_json.IsString() && rel_type_json.IsString() && strcmp(rel_type_json.GetString(), "m.replace") == 0)
- replaces_event_id = event_id_json.GetString();
+ if(event_id_json.IsString() && rel_type_json.IsString() && strcmp(rel_type_json.GetString(), "m.replace") == 0) {
+ related_event_id = event_id_json.GetString();
+ related_event_type = RelatedEventType::EDIT;
+ }
}
const rapidjson::Value &content_type = GetMember(content_json, "msgtype");
@@ -1252,7 +1187,8 @@ namespace QuickMedia {
auto new_message = std::make_shared<Message>();
new_message->event_id = event_id_json.GetString();
- new_message->replaces_event_id = std::move(replaces_event_id);
+ new_message->related_event_id = std::move(related_event_id);
+ new_message->related_event_type = related_event_type;
if(strcmp(content_type.GetString(), "m.text") == 0) {
new_message->type = MessageType::TEXT;
} else if(strcmp(content_type.GetString(), "m.image") == 0) {
@@ -1284,10 +1220,10 @@ namespace QuickMedia {
return filename;
}
- PluginResult Matrix::post_file(const std::string &room_id, const std::string &filepath, std::string &err_msg) {
+ PluginResult Matrix::post_file(std::shared_ptr<RoomData> room, const std::string &filepath, std::string &err_msg) {
UploadInfo file_info;
UploadInfo thumbnail_info;
- PluginResult upload_file_result = upload_file(room_id, filepath, file_info, thumbnail_info, err_msg);
+ PluginResult upload_file_result = upload_file(room, filepath, file_info, thumbnail_info, err_msg);
if(upload_file_result != PluginResult::OK)
return upload_file_result;
@@ -1297,10 +1233,10 @@ namespace QuickMedia {
thumbnail_info_opt = std::move(thumbnail_info);
const char *filename = file_get_filename(filepath);
- return post_message(room_id, filename, file_info_opt, thumbnail_info_opt);
+ return post_message(room, filename, file_info_opt, thumbnail_info_opt);
}
- PluginResult Matrix::upload_file(const std::string &room_id, const std::string &filepath, UploadInfo &file_info, UploadInfo &thumbnail_info, std::string &err_msg) {
+ PluginResult Matrix::upload_file(std::shared_ptr<RoomData> room, const std::string &filepath, UploadInfo &file_info, UploadInfo &thumbnail_info, std::string &err_msg) {
FileAnalyzer file_analyzer;
if(!file_analyzer.load_file(filepath.c_str())) {
err_msg = "Failed to load " + filepath;
@@ -1337,7 +1273,7 @@ namespace QuickMedia {
if(tmp_file != -1) {
if(video_get_first_frame(filepath.c_str(), tmp_filename)) {
UploadInfo upload_info_ignored; // Ignore because it wont be set anyways. Thumbnails dont have thumbnails.
- PluginResult upload_thumbnail_result = upload_file(room_id, tmp_filename, thumbnail_info, upload_info_ignored, err_msg);
+ PluginResult upload_thumbnail_result = upload_file(room, tmp_filename, thumbnail_info, upload_info_ignored, err_msg);
if(upload_thumbnail_result != PluginResult::OK) {
close(tmp_file);
remove(tmp_filename);
@@ -1489,7 +1425,7 @@ namespace QuickMedia {
return PluginResult::OK;
}
- PluginResult Matrix::delete_message(const std::string &room_id, void *message, std::string &err_msg){
+ PluginResult Matrix::delete_message(std::shared_ptr<RoomData> room, void *message, std::string &err_msg){
char random_characters[18];
if(!generate_random_characters(random_characters, sizeof(random_characters)))
return PluginResult::ERR;
@@ -1512,7 +1448,7 @@ namespace QuickMedia {
};
char url[512];
- snprintf(url, sizeof(url), "%s/_matrix/client/r0/rooms/%s/redact/%s/m%ld.%.*s", homeserver.c_str(), room_id.c_str(), message_typed->event_id.c_str(), time(NULL), (int)random_readable_chars.size(), random_readable_chars.c_str());
+ snprintf(url, sizeof(url), "%s/_matrix/client/r0/rooms/%s/redact/%s/m%ld.%.*s", homeserver.c_str(), room->id.c_str(), message_typed->event_id.c_str(), time(NULL), (int)random_readable_chars.size(), random_readable_chars.c_str());
rapidjson::Document json_root;
DownloadResult download_result = download_json(json_root, url, std::move(additional_args), true, &err_msg);
@@ -1595,7 +1531,7 @@ namespace QuickMedia {
return PluginResult::OK;
}
- PluginResult Matrix::on_start_typing(const std::string &room_id) {
+ PluginResult Matrix::on_start_typing(std::shared_ptr<RoomData> room) {
rapidjson::Document request_data(rapidjson::kObjectType);
request_data.AddMember("typing", true, request_data.GetAllocator());
request_data.AddMember("timeout", 30000, request_data.GetAllocator()); // 30 sec timeout
@@ -1612,13 +1548,13 @@ namespace QuickMedia {
};
std::string server_response;
- if(download_to_string(homeserver + "/_matrix/client/r0/rooms/" + room_id + "/typing/" + url_param_encode(user_id) , server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK)
+ if(download_to_string(homeserver + "/_matrix/client/r0/rooms/" + room->id + "/typing/" + url_param_encode(user_id) , server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK)
return PluginResult::NET_ERR;
return PluginResult::OK;
}
- PluginResult Matrix::on_stop_typing(const std::string &room_id) {
+ PluginResult Matrix::on_stop_typing(std::shared_ptr<RoomData> room) {
rapidjson::Document request_data(rapidjson::kObjectType);
request_data.AddMember("typing", false, request_data.GetAllocator());
@@ -1634,13 +1570,13 @@ namespace QuickMedia {
};
std::string server_response;
- if(download_to_string(homeserver + "/_matrix/client/r0/rooms/" + room_id + "/typing/" + url_param_encode(user_id), server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK)
+ if(download_to_string(homeserver + "/_matrix/client/r0/rooms/" + room->id + "/typing/" + url_param_encode(user_id), server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK)
return PluginResult::NET_ERR;
return PluginResult::OK;
}
- PluginResult Matrix::set_read_marker(const std::string &room_id, const Message *message) {
+ PluginResult Matrix::set_read_marker(std::shared_ptr<RoomData> room, const Message *message) {
rapidjson::Document request_data(rapidjson::kObjectType);
request_data.AddMember("m.fully_read", rapidjson::StringRef(message->event_id.c_str()), request_data.GetAllocator());
request_data.AddMember("m.read", rapidjson::StringRef(message->event_id.c_str()), request_data.GetAllocator());
@@ -1658,7 +1594,7 @@ namespace QuickMedia {
};
std::string server_response;
- if(download_to_string(homeserver + "/_matrix/client/r0/rooms/" + room_id + "/read_markers", server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK)
+ if(download_to_string(homeserver + "/_matrix/client/r0/rooms/" + room->id + "/read_markers", server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK)
return PluginResult::NET_ERR;
return PluginResult::OK;
@@ -1706,12 +1642,7 @@ namespace QuickMedia {
return PluginResult::OK;
}
- std::shared_ptr<UserInfo> Matrix::get_me(const std::string &room_id) {
- auto room = get_room_by_id(room_id);
- if(!room) {
- fprintf(stderr, "Error: no such room: %s\n", room_id.c_str());
- return nullptr;
- }
+ std::shared_ptr<UserInfo> Matrix::get_me(std::shared_ptr<RoomData> room) {
return room->get_user_by_id(user_id);
}