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 /src | |
parent | cf28b9984b9661fbc64684cf046fa3256040ed1d (diff) |
Matrix: allow pressing enter on a message with a room alias to join the room
Diffstat (limited to 'src')
-rw-r--r-- | src/QuickMedia.cpp | 30 | ||||
-rw-r--r-- | src/plugins/Matrix.cpp | 83 |
2 files changed, 108 insertions, 5 deletions
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()) |