From b1b9ce2959a22bb495589c4be38c873ebb9801be Mon Sep 17 00:00:00 2001 From: J-D-K Date: Fri, 4 Jul 2025 15:04:13 -0400 Subject: [PATCH] Fix WebDav basepath/root --- include/remote/Storage.hpp | 6 ++++ source/remote/GoogleDrive.cpp | 3 ++ source/remote/Item.cpp | 2 ++ source/remote/Storage.cpp | 5 ++++ source/remote/WebDav.cpp | 56 +++++++++++++++++++++++++++++------ 5 files changed, 63 insertions(+), 9 deletions(-) diff --git a/include/remote/Storage.hpp b/include/remote/Storage.hpp index aeb5e0f..45c953e 100644 --- a/include/remote/Storage.hpp +++ b/include/remote/Storage.hpp @@ -84,6 +84,9 @@ namespace remote /// @brief Returns whether or not the remote storage type supports UTF-8 for names or requires path safe titles. bool supports_utf8() const; + /// @brief Returns the prefix for menus. + std::string_view get_prefix() const; + protected: /// @brief This is the size of the buffers used for snprintf'ing URLs together. static constexpr size_t SIZE_URL_BUFFER = 0x401; @@ -109,6 +112,9 @@ namespace remote /// @brief This is the main remote listing. Storage::List m_list; + /// @brief This is the prefix used for menus. + std::string m_prefix; + /// @brief Searches the list for a directory matching name and the current parent. /// @param name Name to search for. Storage::List::iterator find_directory_by_name(std::string_view name); diff --git a/source/remote/GoogleDrive.cpp b/source/remote/GoogleDrive.cpp index 198e5b4..e832732 100644 --- a/source/remote/GoogleDrive.cpp +++ b/source/remote/GoogleDrive.cpp @@ -50,6 +50,9 @@ remote::GoogleDrive::GoogleDrive() : Storage() // Google Drive doesn't really use directories, so UTF-8 is fine! m_utf8Paths = true; + // Google Drive menu prefix. + m_prefix = "[GD] "; + // Load the json file. json::Object clientJson = json::new_object(json_object_from_file, remote::PATH_GOOGLE_DRIVE_CONFIG.data()); if (!clientJson) diff --git a/source/remote/Item.cpp b/source/remote/Item.cpp index ce32cf1..a7b651f 100644 --- a/source/remote/Item.cpp +++ b/source/remote/Item.cpp @@ -1,5 +1,7 @@ #include "remote/Item.hpp" +#include "logger.hpp" + remote::Item::Item(std::string_view name, std::string_view id, std::string_view parent, size_t size, bool directory) : m_name(name), m_id(id), m_parent(parent), m_size(size), m_isDirectory(directory) {}; diff --git a/source/remote/Storage.cpp b/source/remote/Storage.cpp index 86ee19b..2901f7e 100644 --- a/source/remote/Storage.cpp +++ b/source/remote/Storage.cpp @@ -74,6 +74,11 @@ bool remote::Storage::supports_utf8() const return m_utf8Paths; } +std::string_view remote::Storage::get_prefix() const +{ + return m_prefix; +} + remote::Storage::List::iterator remote::Storage::find_directory_by_name(std::string_view name) { return std::find_if(m_list.begin(), m_list.end(), [name, this](const Item &item) { diff --git a/source/remote/WebDav.cpp b/source/remote/WebDav.cpp index e2ea76c..5c1f9cb 100644 --- a/source/remote/WebDav.cpp +++ b/source/remote/WebDav.cpp @@ -3,12 +3,13 @@ #include "curl/curl.hpp" #include "logger.hpp" #include "remote/remote.hpp" +#include "stringutil.hpp" #include namespace { const char *TAG_XML_HREF = "href"; -} +} // namespace // Declarations here. Definitions at bottom. /// @brief Gets a XML element by name. This is namespace agnostic. @@ -20,6 +21,12 @@ static tinyxml2::XMLElement *get_element_by_name(tinyxml2::XMLElement *parent, s /// @param tag Tag to get the name of. static std::string_view get_tag_begin(std::string_view tag); +/// @brief Slices and unescapes the directory or filename from the href. +/// @param handle Curl handle to use to unescape. +/// @param href HREF to slice. +/// @note This seemed like a better alternative than relying on servers having displayname. +static std::string slice_name_from_href(curl::Handle &handle, std::string_view href); + remote::WebDav::WebDav() : Storage() { static const char *STRING_CONFIG_READ_ERROR = "Error initializing WebDav: %s"; @@ -27,6 +34,9 @@ remote::WebDav::WebDav() : Storage() // WebDav has problems with these. m_utf8Paths = false; + // WebDav prefix for menus. + m_prefix = "[WD] "; + json::Object config = json::new_object(json_object_from_file, remote::PATH_WEBDAV_CONFIG.data()); if (!config) { @@ -52,7 +62,7 @@ remote::WebDav::WebDav() : Storage() { // The root is both in the beginning. I want this to work as closely as the original just not as poorly written // or thought out as the original JKSV dav code. - m_root = json_object_get_string(basepath); + m_root = stringutil::get_formatted_string("/%s/", json_object_get_string(basepath)); m_parent = m_root; } @@ -77,7 +87,6 @@ remote::WebDav::WebDav() : Storage() logger::log(STRING_CONFIG_READ_ERROR, "Error retrieving listing from WebDav server!"); return; } - m_isInitialized = true; } @@ -328,8 +337,11 @@ bool remote::WebDav::process_listing(std::string_view xml) tinyxml2::XMLElement *collection = get_element_by_name(resourceType, "collection"); if (collection) { - // JKSV doesn't expose folder names to the end user, so they are emplaced as-is. - m_list.emplace_back(href->GetText(), href->GetText(), parentLocation->GetText(), 0, true); + m_list.emplace_back(slice_name_from_href(m_curl, href->GetText()), + href->GetText(), + parentLocation->GetText(), + 0, + true); remote::URL nextUrl{m_origin}; nextUrl.append_path(href->GetText()); @@ -342,15 +354,14 @@ bool remote::WebDav::process_listing(std::string_view xml) } else { - tinyxml2::XMLElement *displayName = get_element_by_name(prop, "displayname"); tinyxml2::XMLElement *getContentLength = get_element_by_name(prop, "getcontentlength"); - if (!displayName || !getContentLength) + if (!getContentLength) { - logger::log(STRING_ERROR_PROCESSING_XML, "Missing needed tags for file!"); + logger::log(STRING_ERROR_PROCESSING_XML, "Missing needed data for file!"); continue; } - m_list.emplace_back(displayName->GetText(), + m_list.emplace_back(slice_name_from_href(m_curl, href->GetText()), href->GetText(), parentLocation->GetText(), std::strtoll(getContentLength->GetText(), NULL, 10), @@ -388,3 +399,30 @@ static std::string_view get_tag_begin(std::string_view tag) } return tag.substr(colon + 1); } + +static std::string slice_name_from_href(curl::Handle &handle, std::string_view href) +{ + std::string name{}; + + // This means we're working with a directory. + if (href.back() == '/') + { + size_t end = href.find_last_of('/'); + size_t begin = href.find_last_of('/', end - 1); + + // To do: Inspect this behavior better. + name = href.substr(begin + 1, (end - begin) - 1); + } + else + { + // File + size_t begin = href.find_last_of('/'); + name = href.substr(begin + 1); + } + + curl::unescape_string(handle, name, name); + + logger::log(name.c_str()); + + return name; +}