diff options
author | dec05eba <dec05eba@protonmail.com> | 2023-03-11 23:12:25 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2023-03-11 23:12:25 +0100 |
commit | 118ea78d95a82d9f943180c8f976befc5d2dc97e (patch) | |
tree | c8daf5216042f35a0019edcfee44f343df864807 | |
parent | cf28b9984b9661fbc64684cf046fa3256040ed1d (diff) |
Matrix: allow pressing enter on a message with a room alias to join the room
-rw-r--r-- | TODO | 5 | ||||
-rw-r--r-- | plugins/Matrix.hpp | 1 | ||||
-rw-r--r-- | src/QuickMedia.cpp | 30 | ||||
-rw-r--r-- | src/plugins/Matrix.cpp | 83 | ||||
-rw-r--r-- | tests/main.cpp | 20 |
5 files changed, 132 insertions, 7 deletions
@@ -33,7 +33,7 @@ Update 4chan thread in real time, just like 4chan-x. Add url preview for matrix (using matrix api, fallback to client url preview (using our own url preview project) if disabled by the homeserver). IMPORTANT: Cleanup old messages in matrix (from matrix plugin), and instead either save them to disk or refetch them from server when going up to read old messages. (High memory usage, high disk space) Do not try to reload/redownload thumbnail that fails to download after its cleared when its no longer visible on screen and then becomes visible. -Show google recaptcha on youtube when search/play fails, which can happen when using tor. +Show google recaptcha on youtube when search/play fails, which can happen when using tor. Also required for readm (which was removed because of that). Show notifications when we receive a message in a matrix room even if we are not mentioned. This happens when we have set to receive notifications for all messages. If there are multiple users with the same name in a matrix room, then display the user id beside the displayname. Show 4chan warnings as warnings instead of ban when posting a message (show the warning message) and then post the message. @@ -256,4 +256,5 @@ Fully support all emoji, including the minimally-qualified ones. Sometimes twemo Support NicoNicoDouga and BiliBili (user request). Support arabic/hebrew text. Use Text class for all text rendering. Add command to change avatar/username/etc globally/per room in matrix. -Fix youtube information page missing info, show more youtube info in search results.
\ No newline at end of file +Fix youtube information page missing info, show more youtube info in search results. +Implement m.room.canonical_alias.
\ No newline at end of file diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp index 4e3309f..0eb8766 100644 --- a/plugins/Matrix.hpp +++ b/plugins/Matrix.hpp @@ -35,6 +35,7 @@ namespace QuickMedia { std::string extract_user_name_from_user_id(const std::string &user_id); // Returns empty string on error std::string extract_user_name_from_email(const std::string &email); + std::vector<std::string> matrix_extract_room_ids(const std::string &str); struct MatrixChatBodyDecryptJob { enum class DecryptState { diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index fb96dfb..5bdbdb1 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -6064,11 +6064,12 @@ namespace QuickMedia { if(text.empty()) { return false; } else { - TaskResult task_result = run_task_with_loading_screen([this, text{std::move(text)}] { + TaskResult task_result = run_task_with_loading_screen([this, &text] { return matrix->join_room(text) == PluginResult::OK; }); if(task_result == TaskResult::TRUE) { + show_notification("QuickMedia", "You joined " + text, Urgency::NORMAL); chat_input.set_editable(false); chat_state = ChatState::NAVIGATING; return true; @@ -6701,18 +6702,29 @@ namespace QuickMedia { } } + std::vector<std::string> room_ids = matrix_extract_room_ids(selected->get_description()); + // TODO: If content type is a file, show file-manager prompt where it should be saved and asynchronously save it instead std::vector<std::string> urls = ranges_get_strings(selected->get_description(), extract_urls(selected->get_description())); - if(urls.size() == 1) { + if(urls.size() == 1 && room_ids.empty()) { launch_url(urls[0]); return true; - } else if(urls.size() > 1) { + } else if(!urls.empty() || !room_ids.empty()) { chat_state = ChatState::URL_SELECTION; url_selection_body.clear_items(); + for(const std::string &url : urls) { auto body_item = BodyItem::create(url); + body_item->url = url; + url_selection_body.append_item(std::move(body_item)); + } + + for(const std::string &room_id : room_ids) { + auto body_item = BodyItem::create("Join " + room_id); + body_item->url = room_id; url_selection_body.append_item(std::move(body_item)); } + return true; } return false; @@ -7285,7 +7297,17 @@ namespace QuickMedia { BodyItem *selected_item = url_selection_body.get_selected(); if(!selected_item) continue; - launch_url(selected_item->get_title()); + + if(!selected_item->url.empty() && (selected_item->url[0] == '#' || selected_item->url[0] == '!')) { + TaskResult task_result = run_task_with_loading_screen([this, selected_item] { + return matrix->join_room(selected_item->url) == PluginResult::OK; + }); + + if(task_result == TaskResult::TRUE) + show_notification("QuickMedia", "You joined " + selected_item->url, Urgency::NORMAL); + } else { + launch_url(selected_item->get_title()); + } } } else if(event.type == mgl::Event::KeyPressed && chat_state == ChatState::REPLYING) { if(selected_tab == MESSAGES_TAB_INDEX) { diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index 062d16a..d847719 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -3464,6 +3464,74 @@ namespace QuickMedia { return email.substr(0, index); } + // Not 100% correct on the server name part, but good enough + static std::string_view extract_matrix_identifier(const char *str, size_t size) { + if(size == 0) + return {}; + + size_t index = 0; + switch(str[index]) { + case '@': + case '!': + case '$': + case '+': + case '#': + break; + default: + return {}; + } + + ++index; + const size_t local_part_start = index; + bool found_colon = false; + // Parse local part + for(; index < size; ++index) { + char c = str[index]; + if((c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '=' || c == '_' || c == '/') { + + } else if(c == ':') { + found_colon = true; + break; + } + } + + if(!found_colon || index - local_part_start == 0) + return {}; + + ++index; + const size_t server_part_start = index; + // Parse server name + for(; index < size; ++index) { + char c = str[index]; + if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.' || c == ':' || c == '[' || c == ']') { + + } else { + break; + } + } + + if(index - server_part_start == 0) + return {}; + + return { str, index }; + } + + std::vector<std::string> matrix_extract_room_ids(const std::string &str) { + std::vector<std::string> result; + size_t index = 0; + while(index < str.size()) { + std::string_view room_id = extract_matrix_identifier(str.data() + index, str.size() - index); + // TODO: Support ! room id joining. It doesn't work right now. Seems like matrix itself doesn't support that + if(room_id.empty() || (room_id[0] != '#'/* && room_id[0] != '!'*/)) { + ++index; + } else { + index += room_id.size(); + result.emplace_back(room_id.data(), room_id.size()); + } + } + return result; + } + static std::string combine_user_display_names_for_room_name(std::vector<std::shared_ptr<UserInfo>> &user_info, const std::string &fallback_user_id) { std::string result; if(user_info.size() == 0) @@ -5446,8 +5514,21 @@ namespace QuickMedia { return true; } + static std::string room_id_extract_server_name(const std::string &room_id) { + size_t index = room_id.find(':'); + if(index == std::string::npos) + return ""; + else + return room_id.substr(index + 1); + } + PluginResult Matrix::join_room(const std::string &room_id_or_name) { assert(delegate); + + std::string url = homeserver + "/_matrix/client/r0/join/" + url_param_encode(room_id_or_name); + if(!room_id_or_name.empty() && room_id_or_name[0] == '!') + url += "?via=" + url_param_encode(room_id_extract_server_name(room_id_or_name)); + std::vector<CommandArg> additional_args = { { "-X", "POST" }, { "-H", "content-type: application/json" }, @@ -5457,7 +5538,7 @@ namespace QuickMedia { rapidjson::Document json_root; std::string err_msg; - DownloadResult download_result = download_json(json_root, homeserver + "/_matrix/client/r0/join/" + url_param_encode(room_id_or_name), std::move(additional_args), true, &err_msg); + DownloadResult download_result = download_json(json_root, url, std::move(additional_args), true, &err_msg); if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result); if(!json_root.IsObject()) diff --git a/tests/main.cpp b/tests/main.cpp index 0eae9ba..bfece6e 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -121,5 +121,25 @@ int main() { assert_equals(extract_user_name_from_email("@dec05eba:domain.com"), ""); assert_equals(extract_user_name_from_email("dec05eba"), ""); + auto room_ids = matrix_extract_room_ids("hello #sneed:matrix.org world #feed:midov.pl"); + assert_equals(room_ids.size(), 2); + assert_equals(room_ids[0], "#sneed:matrix.org"); + assert_equals(room_ids[1], "#feed:midov.pl"); + + room_ids = matrix_extract_room_ids("#sneed:matrix.org"); + assert_equals(room_ids.size(), 1); + assert_equals(room_ids[0], "#sneed:matrix.org"); + + room_ids = matrix_extract_room_ids("#sneedmatrix.org"); + assert_equals(room_ids.size(), 0); + + room_ids = matrix_extract_room_ids("!sneed:matrix.org"); + assert_equals(room_ids.size(), 0); + //assert_equals(room_ids.size(), 1); + //assert_equals(room_ids[0], "!sneed:matrix.org"); + + room_ids = matrix_extract_room_ids("@sneed:matrix.org"); + assert_equals(room_ids.size(), 0); + return 0; } |