aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/DownloadUtils.hpp2
-rw-r--r--plugins/FileManager.hpp1
-rw-r--r--plugins/Matrix.hpp1
-rw-r--r--src/DownloadUtils.cpp6
-rw-r--r--src/QuickMedia.cpp76
-rw-r--r--src/SearchBar.cpp8
-rw-r--r--src/plugins/Matrix.cpp82
7 files changed, 87 insertions, 89 deletions
diff --git a/include/DownloadUtils.hpp b/include/DownloadUtils.hpp
index 6af53ac..8f26bfc 100644
--- a/include/DownloadUtils.hpp
+++ b/include/DownloadUtils.hpp
@@ -20,7 +20,7 @@ namespace QuickMedia {
std::string value;
};
- DownloadResult download_to_string(const std::string &url, std::string &result, const std::vector<CommandArg> &additional_args, bool use_tor, bool use_browser_useragent = false);
+ DownloadResult download_to_string(const std::string &url, std::string &result, const std::vector<CommandArg> &additional_args, bool use_tor, bool use_browser_useragent = false, bool fail_on_error = true);
DownloadResult download_to_string_cache(const std::string &url, std::string &result, const std::vector<CommandArg> &additional_args, bool use_tor, bool use_browser_useragent = false);
std::vector<CommandArg> create_command_args_from_form_data(const std::vector<FormData> &form_data);
} \ No newline at end of file
diff --git a/plugins/FileManager.hpp b/plugins/FileManager.hpp
index d5d7088..f13184b 100644
--- a/plugins/FileManager.hpp
+++ b/plugins/FileManager.hpp
@@ -7,6 +7,7 @@ namespace QuickMedia {
class FileManager : public Plugin {
public:
FileManager();
+ virtual ~FileManager() = default;
PluginResult get_files_in_directory(BodyItems &result_items);
bool set_current_directory(const std::string &path);
bool set_child_directory(const std::string &filename);
diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp
index 760d543..97ba3cc 100644
--- a/plugins/Matrix.hpp
+++ b/plugins/Matrix.hpp
@@ -55,6 +55,7 @@ namespace QuickMedia {
class Matrix : public Plugin {
public:
Matrix();
+ virtual ~Matrix() = default;
bool search_is_filter() override { return true; }
bool search_suggestions_has_thumbnails() const override { return true; }
bool search_results_has_thumbnails() const override { return false; }
diff --git a/src/DownloadUtils.cpp b/src/DownloadUtils.cpp
index b7636d8..e748198 100644
--- a/src/DownloadUtils.cpp
+++ b/src/DownloadUtils.cpp
@@ -16,12 +16,14 @@ static const char *useragent_str = "user-agent: Mozilla/5.0 (X11; Linux x86_64)
namespace QuickMedia {
// TODO: Add timeout
- DownloadResult download_to_string(const std::string &url, std::string &result, const std::vector<CommandArg> &additional_args, bool use_tor, bool use_browser_useragent) {
+ DownloadResult download_to_string(const std::string &url, std::string &result, const std::vector<CommandArg> &additional_args, bool use_tor, bool use_browser_useragent, bool fail_on_error) {
sf::Clock timer;
std::vector<const char*> args;
if(use_tor)
args.push_back("torsocks");
- args.insert(args.end(), { "curl", "-f", "-H", "Accept-Language: en-US,en;q=0.5", "-H", "Connection: keep-alive", "--compressed", "-s", "-L" });
+ args.insert(args.end(), { "curl", "-H", "Accept-Language: en-US,en;q=0.5", "-H", "Connection: keep-alive", "--compressed", "-s", "-L" });
+ if(fail_on_error)
+ args.push_back("-f");
for(const CommandArg &arg : additional_args) {
args.push_back(arg.option.c_str());
args.push_back(arg.value.c_str());
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index c2c0004..e07c30a 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -3172,7 +3172,6 @@ namespace QuickMedia {
// so you dont have to retype a post that was in the middle of being posted when returning.
}
- // TODO: Provide a way to logout
void Program::chat_login_page() {
assert(current_plugin->name == "matrix");
@@ -3351,9 +3350,11 @@ namespace QuickMedia {
// TODO: Filer for rooms and settings
chat_input.onTextUpdateCallback = nullptr;
+ Page new_page = Page::CHAT;
+
// TODO: Show post message immediately, instead of waiting for sync. Otherwise it can take a while until we receive the message,
// which happens when uploading an image.
- chat_input.onTextSubmitCallback = [this, matrix, &tabs, &selected_tab, &current_room_id](const std::string &text) -> bool {
+ chat_input.onTextSubmitCallback = [matrix, &tabs, &selected_tab, &current_room_id, &new_page](const std::string &text) -> bool {
if(tabs[selected_tab].type == ChatTabType::MESSAGES) {
if(text.empty())
return false;
@@ -3362,37 +3363,10 @@ namespace QuickMedia {
std::string command = text;
strip(command);
if(command == "/upload") {
- if(!file_manager)
- file_manager = new FileManager();
- page_stack.push(Page::CHAT);
- current_page = Page::FILE_MANAGER;
- file_manager_page();
- if(selected_files.empty()) {
- fprintf(stderr, "No files selected!\n");
- return true;
- } else {
- // TODO: Make asynchronous.
- // TODO: Upload multiple files.
- if(matrix->post_file(current_room_id, selected_files[0]) != PluginResult::OK) {
- show_notification("QuickMedia", "Failed to upload image to room", Urgency::CRITICAL);
- return false;
- } else {
- return true;
- }
- }
+ new_page = Page::FILE_MANAGER;
+ return true;
} else if(command == "/logout") {
- matrix->logout();
- tabs[MESSAGES_TAB_INDEX].body->clear_thumbnails();
- // TODO: Instead of doing this, exit this current function and navigate to chat login page instead.
- // This doesn't currently work because at the end of this function there are futures that need to wait
- // and one of them is /sync, which has a timeout of 30 seconds. That timeout has to be killed somehow.
- delete current_plugin;
- current_plugin = new Matrix();
- current_page = Page::CHAT_LOGIN;
- chat_login_page();
- if(current_page == Page::CHAT)
- chat_page();
- exit(0);
+ new_page = Page::CHAT_LOGIN;
return true;
} else {
fprintf(stderr, "Error: invalid command: %s, expected /upload\n", command.c_str());
@@ -3567,6 +3541,44 @@ namespace QuickMedia {
}
}
+ switch(new_page) {
+ case Page::FILE_MANAGER: {
+ new_page = Page::CHAT;
+ if(!file_manager)
+ file_manager = new FileManager();
+ page_stack.push(Page::CHAT);
+ current_page = Page::FILE_MANAGER;
+ file_manager_page();
+ if(selected_files.empty()) {
+ fprintf(stderr, "No files selected!\n");
+ } else {
+ // TODO: Make asynchronous.
+ // TODO: Upload multiple files.
+ if(matrix->post_file(current_room_id, selected_files[0]) != PluginResult::OK)
+ show_notification("QuickMedia", "Failed to upload image to room", Urgency::CRITICAL);
+ }
+ break;
+ }
+ case Page::CHAT_LOGIN: {
+ new_page = Page::CHAT;
+ matrix->logout();
+ tabs[MESSAGES_TAB_INDEX].body->clear_thumbnails();
+ // TODO: Instead of doing this, exit this current function and navigate to chat login page instead.
+ // This doesn't currently work because at the end of this function there are futures that need to wait
+ // and one of them is /sync, which has a timeout of 30 seconds. That timeout has to be killed somehow.
+ //delete current_plugin;
+ //current_plugin = new Matrix();
+ current_page = Page::CHAT_LOGIN;
+ chat_login_page();
+ if(current_page == Page::CHAT)
+ chat_page();
+ exit(0);
+ break;
+ }
+ default:
+ break;
+ }
+
if(typing && start_typing_timer.getElapsedTime().asSeconds() >= typing_timeout_seconds) {
fprintf(stderr, "Stopped typing\n");
typing = false;
diff --git a/src/SearchBar.cpp b/src/SearchBar.cpp
index e646546..419ca38 100644
--- a/src/SearchBar.cpp
+++ b/src/SearchBar.cpp
@@ -161,8 +161,12 @@ namespace QuickMedia {
}
} else if(codepoint == 13) { // Return
bool clear_search = true;
- if(onTextSubmitCallback)
- clear_search = onTextSubmitCallback(show_placeholder ? "" : text.getString());
+ if(onTextSubmitCallback) {
+ if(show_placeholder)
+ clear_search = onTextSubmitCallback("");
+ else
+ clear_search = onTextSubmitCallback(text.getString());
+ }
if(clear_search)
clear();
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index 8b819a2..d709f73 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -54,7 +54,7 @@ namespace QuickMedia {
char url[512];
if(next_batch.empty())
- snprintf(url, sizeof(url), "%s/_matrix/client/r0/sync?timeout=0", homeserver.c_str());
+ snprintf(url, sizeof(url), "%s/_matrix/client/r0/sync?timeout=0&full_state=true", homeserver.c_str());
else
snprintf(url, sizeof(url), "%s/_matrix/client/r0/sync?timeout=30000&since=%s", homeserver.c_str(), next_batch.c_str());
@@ -831,38 +831,6 @@ namespace QuickMedia {
return post_message(room_id, filename, content_uri_json.asString(), MessageType::IMAGE, &message_info);
}
- static std::string parse_login_error_response(std::string json_str) {
- if(json_str.empty())
- return "Unknown error";
-
- 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(&json_str[0], &json_str[json_str.size()], &json_root, &json_errors)) {
- fprintf(stderr, "Matrix login response parse error: %s\n", json_errors.c_str());
- return json_str;
- }
-
- if(!json_root.isObject())
- return json_str;
-
- const Json::Value &errcode_json = json_root["errcode"];
- // Yes, matrix is retarded and returns M_NOT_JSON error code when username/password is incorrect
- if(errcode_json.isString() && strcmp(errcode_json.asCString(), "M_NOT_JSON") == 0)
- return "Incorrect username or password";
-
- return json_str;
- }
-
- // Returns empty string on error
- static std::string extract_homeserver_from_user_id(const std::string &user_id) {
- size_t index = user_id.find(':');
- if(index == std::string::npos)
- return "";
- return user_id.substr(index + 1);
- }
-
PluginResult Matrix::login(const std::string &username, const std::string &password, const std::string &homeserver, std::string &err_msg) {
// TODO: this is deprecated but not all homeservers have the new version.
// When this is removed from future version then switch to the new login method (identifier object with the username).
@@ -882,8 +850,8 @@ namespace QuickMedia {
};
std::string server_response;
- if(download_to_string(homeserver + "/_matrix/client/r0/login", server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK) {
- err_msg = parse_login_error_response(std::move(server_response));
+ if(download_to_string(homeserver + "/_matrix/client/r0/login", server_response, std::move(additional_args), use_tor, true, false) != DownloadResult::OK) {
+ err_msg = std::move(server_response);
return PluginResult::NET_ERR;
}
@@ -904,6 +872,12 @@ namespace QuickMedia {
return PluginResult::ERR;
}
+ const Json::Value &error = json_root["error"];
+ if(error.isString()) {
+ err_msg = error.asString();
+ return PluginResult::ERR;
+ }
+
const Json::Value &user_id_json = json_root["user_id"];
if(!user_id_json.isString()) {
err_msg = "Failed to parse matrix login response";
@@ -916,17 +890,13 @@ namespace QuickMedia {
return PluginResult::ERR;
}
- std::string user_id = user_id_json.asString();
+ // Use the user-provided homeserver instead of the one the server tells us about, otherwise this wont work with a proxy
+ // such as pantalaimon
+ json_root["homeserver"] = homeserver;
- std::string homeserver_response = extract_homeserver_from_user_id(user_id);
- if(homeserver_response.empty()) {
- err_msg = "Missing homeserver in user id, user id: " + user_id;
- return PluginResult::ERR;
- }
-
- this->user_id = std::move(user_id);
+ this->user_id = user_id_json.asString();
this->access_token = access_token_json.asString();
- this->homeserver = "https://" + std::move(homeserver_response);
+ this->homeserver = homeserver;
// TODO: Handle well_known field. The spec says clients SHOULD handle it if its provided
@@ -956,6 +926,13 @@ namespace QuickMedia {
if(download_to_string(homeserver + "/_matrix/client/r0/logout", server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK)
return PluginResult::NET_ERR;
+ // Make sure all fields are reset here!
+ room_data_by_id.clear();
+ user_id.clear();
+ access_token.clear();
+ homeserver.clear();
+ next_batch.clear();
+
return PluginResult::OK;
}
@@ -991,29 +968,30 @@ namespace QuickMedia {
return PluginResult::ERR;
}
- std::string user_id = user_id_json.asString();
- std::string access_token = access_token_json.asString();
-
- std::string homeserver = extract_homeserver_from_user_id(user_id);
- if(homeserver.empty()) {
- fprintf(stderr, "Missing homeserver in user id, user id: %s\n", user_id.c_str());
+ const Json::Value &homeserver_json = json_root["homeserver"];
+ if(!homeserver_json.isString()) {
+ fprintf(stderr, "Failed to parse matrix cached session response\n");
return PluginResult::ERR;
}
+ std::string user_id = user_id_json.asString();
+ std::string access_token = access_token_json.asString();
+ std::string homeserver = homeserver_json.asString();
+
std::vector<CommandArg> additional_args = {
{ "-H", "Authorization: Bearer " + access_token }
};
std::string server_response;
// We want to make any request to the server that can verify that our token is still valid, doesn't matter which call
- if(download_to_string("https://" + homeserver + "/_matrix/client/r0/account/whoami", server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK) {
+ if(download_to_string(homeserver + "/_matrix/client/r0/account/whoami", server_response, std::move(additional_args), use_tor, true) != DownloadResult::OK) {
fprintf(stderr, "Matrix whoami response: %s\n", server_response.c_str());
return PluginResult::NET_ERR;
}
this->user_id = std::move(user_id);
this->access_token = std::move(access_token);
- this->homeserver = "https://" + homeserver;
+ this->homeserver = std::move(homeserver);
return PluginResult::OK;
}