diff --git a/src/api/sqliteConnector.cpp b/src/api/sqliteConnector.cpp index 8b464c0..278d920 100644 --- a/src/api/sqliteConnector.cpp +++ b/src/api/sqliteConnector.cpp @@ -16,6 +16,8 @@ #include #include +#include + using std::string; SqliteConnector::SqliteConnector(const string &DBpath) : _dbpath(DBpath) @@ -259,6 +261,28 @@ void SqliteConnector::deleteChild(const string &path, const string &title) rs = sqlite3_reset(stmt); } +void SqliteConnector::deleteItemsNotBeginsWith(string beginPath) +{ + open(); + + // escape characters + beginPath = std::regex_replace(beginPath, std::regex("%"), "#%"); + beginPath = std::regex_replace(beginPath, std::regex("_"), "#_"); + beginPath = beginPath + "%"; + + int rs; + sqlite3_stmt *stmt = 0; + rs = sqlite3_prepare_v2(_db, "DELETE FROM 'metadata' WHERE path NOT LIKE ? ESCAPE '#'", -1, &stmt, 0); + rs = sqlite3_bind_text(stmt, 1, beginPath.c_str(), beginPath.length(), NULL); + + rs = sqlite3_step(stmt); + if (rs != SQLITE_DONE) + { + Log::writeErrorLog(std::string("An error ocurred trying to delete the items that begins with " + beginPath) + sqlite3_errmsg(_db) + std::string(" (Error Code: ") + std::to_string(rs) + ")"); + } + rs = sqlite3_clear_bindings(stmt); + rs = sqlite3_reset(stmt); +} bool SqliteConnector::resetHideState() { diff --git a/src/api/sqliteConnector.h b/src/api/sqliteConnector.h index d3f207d..f0bfe9f 100644 --- a/src/api/sqliteConnector.h +++ b/src/api/sqliteConnector.h @@ -32,7 +32,7 @@ public: bool open(); int getDbVersion(); - + void runMigration(int currentVersion); std::string getEtag(const std::string &path); @@ -47,6 +47,8 @@ public: void deleteChild(const std::string &path, const std::string &title); + void deleteItemsNotBeginsWith(std::string beginPath); + bool resetHideState(); bool saveItemsChildren(const std::vector &children); diff --git a/src/api/webDAV.cpp b/src/api/webDAV.cpp index 8565c2a..0f5d6f1 100644 --- a/src/api/webDAV.cpp +++ b/src/api/webDAV.cpp @@ -19,6 +19,7 @@ #include #include #include +#include using std::ifstream; using std::ofstream; @@ -27,6 +28,20 @@ using std::vector; namespace fs = std::experimental::filesystem; +std::string WebDAV::getRootPath(bool encode) { + string rootPath = Util::getConfig("ex_relativeRootPath", "/"); + if (rootPath == "") + rootPath += "/"; + + string rtc = NEXTCLOUD_ROOT_PATH + Util::getConfig("UUID", "") + rootPath; + if (encode) { + Util::encodeUrl(rtc); + rtc = std::regex_replace(rtc, std::regex("%2F"), "/"); + } + + return rtc; +} + WebDAV::WebDAV() { if (iv_access(NEXTCLOUD_PATH.c_str(), W_OK) != 0) @@ -184,7 +199,7 @@ vector WebDAV::getDataStructure(const string &pathUrl) tempItem.title = tempItem.title.substr(tempItem.title.find_last_of("/") + 1, tempItem.title.length()); Util::decodeUrl(tempItem.title); - string &pathDecoded = tempItem.path; + string pathDecoded = tempItem.path; Util::decodeUrl(pathDecoded); tempItem.hide = _fileHandler->getHideState(tempItem.type, prefix,(pathDecoded), tempItem.title); @@ -233,6 +248,7 @@ string WebDAV::propfind(const string &pathUrl) string readBuffer; CURLcode res; CURL *curl = curl_easy_init(); + Log::writeInfoLog("Path: " + pathUrl); if (curl) { @@ -274,7 +290,33 @@ string WebDAV::propfind(const string &pathUrl) switch (response_code) { case 404: - Message(ICON_ERROR, "Error", "The URL seems to be incorrect. You can look up the WebDav URL in the settings of the files webapp. ", 4000); + if (getRootPath().compare( NEXTCLOUD_ROOT_PATH + Util::getConfig("uuid", "")) != 0) { + if (propfind(NEXTCLOUD_ROOT_PATH + Util::getConfig("UUID", "")) != "") { + // Own root path defined + string output; + int dialogResult = DialogSynchro( + ICON_ERROR, + "Action", + output.append("The specified start folder does not seem to exist:\n").append(Util::getConfig("ex_relativeRootPath", "/")).append("\n\nWhat would you like to do?").c_str(), + "Reset start folder", "Close App", NULL + ); + switch (dialogResult) + { + case 1: + { + Util::accessConfig(Action::IWriteString, "ex_relativeRootPath", ""); + return propfind(NEXTCLOUD_ROOT_PATH + Util::getConfig("UUID", "")); + } + break; + case 2: + default: + CloseApp(); + break; + } + } + } else { + Message(ICON_ERROR, "Error", "The URL seems to be incorrect. You can look up the WebDav URL in the settings of the files webapp. ", 4000); + } break; case 401: Message(ICON_ERROR, "Error", "Username/password incorrect.", 4000); diff --git a/src/api/webDAV.h b/src/api/webDAV.h index f462b75..255c21f 100644 --- a/src/api/webDAV.h +++ b/src/api/webDAV.h @@ -38,6 +38,12 @@ class WebDAV std::vector getDataStructure(const std::string &pathUrl); + /** + * Returns the root path of the nextcloud server + * (e.g. /remote.php/dav/files/userName/startFolder/) + */ + static std::string getRootPath(bool encode = false); + /** * gets the dataStructure of the given URL and writes its WEBDAV items to the items vector * diff --git a/src/handler/eventHandler.cpp b/src/handler/eventHandler.cpp index 1d78cc5..74bf423 100644 --- a/src/handler/eventHandler.cpp +++ b/src/handler/eventHandler.cpp @@ -49,7 +49,7 @@ EventHandler::EventHandler() iv_mkdir(Util::accessConfig(Action::IReadString, "storageLocation",{}).c_str(), 0777); std::vector currentWebDAVItems; - string path = NEXTCLOUD_ROOT_PATH + Util::accessConfig(Action::IReadString,"UUID",{}) + '/'; + string path = WebDAV::getRootPath(true); currentWebDAVItems = _webDAV.getDataStructure(path); _menu = std::unique_ptr(new MainMenu("Nextcloud")); @@ -234,7 +234,7 @@ void EventHandler::mainMenuHandler(const int index) else { Util::accessConfig(Action::IWriteString, "storageLocation", _currentPath); - std::vector currentWebDAVItems = _webDAV.getDataStructure(NEXTCLOUD_ROOT_PATH + Util::accessConfig(Action::IReadString,"UUID",{}) + '/'); + std::vector currentWebDAVItems = _webDAV.getDataStructure(WebDAV::getRootPath(true)); if (currentWebDAVItems.empty()) { Message(ICON_ERROR, "Error", "Failed to get items. Please try again.", 1000); @@ -388,8 +388,14 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2) Util::accessConfig(Action::IWriteString, "ex_extensionList", _excludeFileView->getExtensionList()); Util::accessConfig(Action::IWriteString, "ex_pattern",_excludeFileView->getRegex()); Util::accessConfig(Action::IWriteString, "ex_folderPattern",_excludeFileView->getFolderRegex()); + Util::accessConfig(Action::IWriteString, "ex_relativeRootPath", _excludeFileView->getStartFolder()); Util::accessConfig(Action::IWriteInt, "ex_invertMatch", _excludeFileView->getInvertMatch()); + _sqllite.resetHideState(); + if (_excludeFileView->getStartFolder() != "") + { + _sqllite.deleteItemsNotBeginsWith(WebDAV::getRootPath(true)); + } _excludeFileView.reset(); ShowHourglassForce(); @@ -399,7 +405,7 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2) vector currentFolder = FileBrowser::getFileStructure(_currentPath,false,true); _fileView.reset(new FileView(_menu->getContentRect(), currentFolder,1)); } else { - std::vector currentWebDAVItems = _webDAV.getDataStructure(NEXTCLOUD_ROOT_PATH + Util::accessConfig(Action::IReadString,"UUID",{}) + '/'); + std::vector currentWebDAVItems = _webDAV.getDataStructure(WebDAV::getRootPath(true)); updateItems(currentWebDAVItems); drawWebDAVItems(currentWebDAVItems); } @@ -413,7 +419,7 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2) vector currentFolder = FileBrowser::getFileStructure(_currentPath,false,true); _fileView.reset(new FileView(_menu->getContentRect(), currentFolder,1)); } else { - std::vector currentWebDAVItems = _webDAV.getDataStructure(NEXTCLOUD_ROOT_PATH + Util::accessConfig(Action::IReadString,"UUID",{}) + '/'); + std::vector currentWebDAVItems = _webDAV.getDataStructure(WebDAV::getRootPath(true)); updateItems(currentWebDAVItems); drawWebDAVItems(currentWebDAVItems); } @@ -509,7 +515,6 @@ void EventHandler::openItem() void EventHandler::openFolder() { - std::vector currentWebDAVItems; switch ((_webDAVView->getCurrentEntry().state == FileState::ILOCAL) ? FileState::ILOCAL : _sqllite.getState(_webDAVView->getCurrentEntry().path)) diff --git a/src/handler/mainMenu.h b/src/handler/mainMenu.h index ecec3b2..369c6ac 100644 --- a/src/handler/mainMenu.h +++ b/src/handler/mainMenu.h @@ -55,7 +55,7 @@ private: char *_logout = strdup("Logout"); char *_chooseFolder = strdup("Create here"); char *_sortBy = strdup("Order items by"); - char *_excludeFiles = strdup("Exclude and hide files"); + char *_excludeFiles = strdup("Exclude and hide items"); char *_info = strdup("Info"); char *_exit = strdup("Close App"); diff --git a/src/ui/excludeFileView/excludeFileView.cpp b/src/ui/excludeFileView/excludeFileView.cpp index 8bcd088..af67186 100644 --- a/src/ui/excludeFileView/excludeFileView.cpp +++ b/src/ui/excludeFileView/excludeFileView.cpp @@ -22,6 +22,7 @@ ExcludeFileView::ExcludeFileView(const irect &contentRect): _contentRect(content _extensionList = Util::getConfig("ex_extensionList", ""); _regex = Util::getConfig("ex_pattern", ""); _folderRegex = Util::getConfig("ex_folderPattern", ""); + _startFolder = Util::getConfig("ex_relativeRootPath", ""); _invertMatch = Util::getConfig("ex_invertMatch",0); int contentHeight = contentRect.h / 2; @@ -54,20 +55,25 @@ ExcludeFileView::ExcludeFileView(const irect &contentRect): _contentRect(content DrawString(_folderRegexButton.x, _folderRegexButton.y, _folderRegex.c_str()); DrawRect(_folderRegexButton.x - 1, _folderRegexButton.y - 1, _folderRegexButton.w + 2, _folderRegexButton.h + 2, BLACK); - _invertMatchButton = iRect(_contentRect.w - 2 * checkBoxWidth, beginY + 6 * contents, checkBoxWidth, contents, ALIGN_CENTER); + _startFolderButton = iRect(beginX, beginY + 6 * contents, contentWidth, contents, ALIGN_CENTER); + DrawTextRect(_startFolderButton.x, _startFolderButton.y - _fontHeight - _fontHeight/3, _startFolderButton.w, _startFolderButton.h, "Start folder:", ALIGN_LEFT); + DrawString(_startFolderButton.x, _startFolderButton.y, _startFolder.c_str()); + DrawRect(_startFolderButton.x - 1, _startFolderButton.y - 1, _startFolderButton.w + 2, _startFolderButton.h + 2, BLACK); + + _invertMatchButton = iRect(_contentRect.w - 2 * checkBoxWidth, beginY + 8 * contents, checkBoxWidth, contents, ALIGN_CENTER); DrawTextRect(beginX, _invertMatchButton.y, contentWidth, _invertMatchButton.h, "Only include matching:", ALIGN_LEFT); DrawRect(_invertMatchButton.x - 1, _invertMatchButton.y - 1, _invertMatchButton.w + 2, _invertMatchButton.h + 2, BLACK); if (_invertMatch) { FillArea(_invertMatchButton.x - 1, _invertMatchButton.y - 1, _invertMatchButton.w + 2, _invertMatchButton.h + 2, BLACK); } - _saveButton = iRect(beginX, beginY + 8 * contents, contentWidth / 2 - 20, contents, ALIGN_CENTER); + _saveButton = iRect(beginX, beginY + 10 * contents, contentWidth / 2 - 20, contents, ALIGN_CENTER); FillAreaRect(&_saveButton, BLACK); SetFont(_font, WHITE); DrawTextRect2(&_saveButton, "Save"); PartialUpdate(_contentRect.x, _contentRect.y, _contentRect.w, _contentRect.h); - _cancelButton = iRect(beginX + contentWidth / 2, beginY + 8 * contents, contentWidth / 2 - 20, contents, ALIGN_CENTER); + _cancelButton = iRect(beginX + contentWidth / 2, beginY + 10 * contents, contentWidth / 2 - 20, contents, ALIGN_CENTER); FillAreaRect(&_cancelButton, BLACK); SetFont(_font, WHITE); DrawTextRect2(&_cancelButton, "Cancel"); @@ -111,6 +117,15 @@ int ExcludeFileView::excludeClicked(int x, int y) OpenKeyboard("/root/.*/test/", &_temp[0], EXCLUDE_FILE_KEYBOARD_STRING_LENGHT, KBD_NORMAL, &keyboardHandlerStatic); return 1; } + else if (IsInRect(x, y, &_startFolderButton)) + { + _target = ExcludeFileKeyboardTarget::ISTARTFOLDER; + if (!_startFolder.empty()) + _temp = _startFolder; + _temp.resize(EXCLUDE_FILE_KEYBOARD_STRING_LENGHT); + OpenKeyboard("/MyBooks/", &_temp[0], EXCLUDE_FILE_KEYBOARD_STRING_LENGHT, KBD_NORMAL, &keyboardHandlerStatic); + return 1; + } else if (IsInRect(x, y, &_invertMatchButton)) { _invertMatch = !_invertMatch; @@ -198,4 +213,18 @@ void ExcludeFileView::keyboardHandler(char *text) FillAreaRect(&_folderRegexButton, WHITE); DrawTextRect2(&_folderRegexButton, s.c_str()); } + else if (_target == ExcludeFileKeyboardTarget::ISTARTFOLDER) + { + _startFolder = s.c_str(); + if (_startFolder.length() > 1 && _startFolder != "/") { + if (_startFolder.substr(0, 1) != "/") { + _startFolder = "/" + _startFolder; + } + if (_startFolder.substr(_startFolder.length() - 1) != "/") { + _startFolder = _startFolder + "/"; + } + } + FillAreaRect(&_startFolderButton, WHITE); + DrawTextRect2(&_startFolderButton, _startFolder.c_str()); + } } diff --git a/src/ui/excludeFileView/excludeFileView.h b/src/ui/excludeFileView/excludeFileView.h index b3e10c6..57801ab 100644 --- a/src/ui/excludeFileView/excludeFileView.h +++ b/src/ui/excludeFileView/excludeFileView.h @@ -22,7 +22,8 @@ enum class ExcludeFileKeyboardTarget { IEXTENSIONS, IREGEX, - IFOLDERREGEX + IFOLDERREGEX, + ISTARTFOLDER, }; const int EXCLUDE_FILE_KEYBOARD_STRING_LENGHT = 90; @@ -51,6 +52,7 @@ public: std::string getExtensionList() { return _extensionList; }; std::string getRegex() { return _regex; }; std::string getFolderRegex() { return _folderRegex; }; + std::string getStartFolder() { return _startFolder; }; int getInvertMatch() { return _invertMatch; }; private: @@ -64,10 +66,12 @@ private: irect _regexButton; irect _invertMatchButton; irect _folderRegexButton; + irect _startFolderButton; ExcludeFileKeyboardTarget _target; std::string _extensionList; std::string _regex; std::string _folderRegex; + std::string _startFolder; bool _invertMatch = false; std::string _temp; diff --git a/src/ui/webDAVView/webDAVView.cpp b/src/ui/webDAVView/webDAVView.cpp index 67a7e51..c7476a2 100644 --- a/src/ui/webDAVView/webDAVView.cpp +++ b/src/ui/webDAVView/webDAVView.cpp @@ -41,7 +41,9 @@ WebDAVView::WebDAVView(const irect &contentRect, vector &itemsUnfilt std::vector::iterator begin; - if (items.at(0).path.compare(NEXTCLOUD_ROOT_PATH) == 0) + string rootPath = WebDAV::getRootPath(false); + string parentRootPath = rootPath.substr(0, rootPath.substr(0, rootPath.length() - 1).find_last_of("/") + 1); + if (items.at(0).path.compare(parentRootPath) == 0) { items.erase(items.begin()); begin = items.begin(); diff --git a/src/util/util.cpp b/src/util/util.cpp index 1939984..07f1895 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -100,6 +100,18 @@ void Util::decodeUrl(string &text) curl_easy_cleanup(curl); } +void Util::encodeUrl(string &text) +{ + char *buffer; + CURL *curl = curl_easy_init(); + + buffer = curl_easy_escape(curl, text.c_str(), 0); + text = buffer; + + curl_free(buffer); + curl_easy_cleanup(curl); +} + void kill_child(int sig) { //SIGKILL diff --git a/src/util/util.h b/src/util/util.h index 575dd8e..1996ce9 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -15,6 +15,8 @@ #include "log.h" #include +using std::string; + enum class Action { IWriteSecret, @@ -25,7 +27,7 @@ enum class Action IReadInt }; -const std::string CONFIG_PATH = CONFIG_FOLDER + "/nextcloud.cfg"; +const std::string CONFIG_PATH = "/mnt/ext1/system/config/nextcloud/nextcloud.cfg"; class Util { @@ -155,6 +157,13 @@ public: */ static void decodeUrl(std::string &text); + /** + * Encodes an URL + * + * @param text text that shall be converted + */ + static void encodeUrl(std::string &text); + /** * Updates the library of the Pocketbook *