aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2023-03-11 23:12:25 +0100
committerdec05eba <dec05eba@protonmail.com>2023-03-11 23:12:25 +0100
commit118ea78d95a82d9f943180c8f976befc5d2dc97e (patch)
treec8daf5216042f35a0019edcfee44f343df864807 /src
parentcf28b9984b9661fbc64684cf046fa3256040ed1d (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.cpp30
-rw-r--r--src/plugins/Matrix.cpp83
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())