diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100644 new mode 100755 index 5921e8c..f402e62 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,18 +48,19 @@ list(APPEND PB_LINK_DIRECTORIES "${TOOLCHAIN_PATH}/usr/arm-obreey-linux-gnueabi/ list(APPEND PB_LINK_DIRECTORIES "${TOOLCHAIN_PATH}/usr/arm-obreey-linux-gnueabi/sysroot/usr/local/lib") list(APPEND PB_INCLUDE_DIRECTORIES "${TOOLCHAIN_PATH}/usr/arm-obreey-linux-gnueabi/sysroot/usr/include") -set(SOURCES ${CMAKE_SOURCE_DIR}/src/main.cpp +set(SOURCES ${CMAKE_SOURCE_DIR}/src/main.cpp ${CMAKE_SOURCE_DIR}/src/handler/contextMenu.cpp - ${CMAKE_SOURCE_DIR}/src/handler/eventHandler.cpp - ${CMAKE_SOURCE_DIR}/src/handler/mainMenu.cpp - ${CMAKE_SOURCE_DIR}/src/util/nextcloud.cpp - ${CMAKE_SOURCE_DIR}/src/util/item.cpp - ${CMAKE_SOURCE_DIR}/src/ui/listView.cpp - ${CMAKE_SOURCE_DIR}/src/ui/listViewEntry.cpp - ${CMAKE_SOURCE_DIR}/src/ui/loginView.cpp - ${CMAKE_SOURCE_DIR}/src/util/util.cpp - ${CMAKE_SOURCE_DIR}/src/util/log.cpp - + ${CMAKE_SOURCE_DIR}/src/handler/eventHandler.cpp + ${CMAKE_SOURCE_DIR}/src/handler/mainMenu.cpp + ${CMAKE_SOURCE_DIR}/src/ui/listView/listView.cpp + ${CMAKE_SOURCE_DIR}/src/ui/listView/listViewEntry.cpp + ${CMAKE_SOURCE_DIR}/src/ui/webDAVView/webDAVView.cpp + ${CMAKE_SOURCE_DIR}/src/ui/webDAVView/webDAVViewEntry.cpp + ${CMAKE_SOURCE_DIR}/src/ui/loginView/loginView.cpp + ${CMAKE_SOURCE_DIR}/src/util/util.cpp + ${CMAKE_SOURCE_DIR}/src/util/log.cpp + ${CMAKE_SOURCE_DIR}/src/api/webDAV.cpp + ${CMAKE_SOURCE_DIR}/src/api/sqliteConnector.cpp ) add_executable(Nextcloud.app ${SOURCES}) @@ -71,9 +72,13 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/handler/ ${CMAKE_SOURCE_DIR}/src/util/ ${CMAKE_SOURCE_DIR}/src/ui/ + ${CMAKE_SOURCE_DIR}/src/ui/listView/ + ${CMAKE_SOURCE_DIR}/src/ui/webDAVView/ + ${CMAKE_SOURCE_DIR}/src/ui/loginView/ + ${CMAKE_SOURCE_DIR}/src/api/ ) -TARGET_LINK_LIBRARIES (Nextcloud.app PRIVATE inkview freetype curl) +TARGET_LINK_LIBRARIES (Nextcloud.app PRIVATE inkview freetype curl sqlite3) INSTALL (TARGETS Nextcloud.app) diff --git a/README.md b/README.md index 0739a6b..72eca44 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ A basic client to access an existing nextcloud instance via Pocketbook. * Remove files from local storage system * Show local files that are saved but no longer available in the cloud * Open epub, pdf, text, html, word and mobi with default ebook reader application -* Set Start folder to custom path * Offline Modus * Navigaten via keys and touch diff --git a/pb.sh b/pb.sh new file mode 100755 index 0000000..80966d0 --- /dev/null +++ b/pb.sh @@ -0,0 +1,89 @@ +#!/bin/bash + +LOGFILE="/mnt/Pocketbook/system/config/nextcloud/logfile.txt" +APPLOCATION="bin/Nextcloud.app" +APPDIR="/mnt/Pocketbook/applications/" + +############################################################ +# Help # +############################################################ +Help() +{ + # Display Help + echo "Functions to interact with the PB" + echo + echo "Syntax: pb [h|c|l|u]" + echo "options:" + echo "-h Print this Help." + echo "-c Copy the app to the appfolder" + echo "-l Show a logfile, if it exists" + echo "-u Unmount PB" + echo +} + +############################################################ +# MOUNT # +############################################################ +Mount() +{ +MOUNTPOINT=$(sudo blkid | awk '/PB632/ {print $1;}' | tr -d ':') +if [ -n "$MOUNTPOINT" ] +then + if mount | grep $MOUNTPOINT > /dev/null; then + echo "Already mounted." + else + sudo mount $MOUNTPOINT /mnt/Pocketbook + fi +else + echo "Could not find PB" +fi +} + +############################################################ +############################################################ +# Main program # +############################################################ +############################################################ +[ $# -eq 0 ] && Help +while getopts ":hclu" o; do + case $o in + h) #Display help + Help + exit;; + l) + Mount + if [ -f "$LOGFILE" ]; + then + less $LOGFILE; + while true; do + read -p "Do you want to delete log?" yn + case $yn in + [Yy]* ) sudo rm -r $LOGFILE; break;; + [Nn]* ) exit;; + * ) echo "Y/N";; + esac + done + else + echo "No log file found." + fi + ;; + c) + Mount + if [ -d "$APPDIR" ] + then + make + sudo cp $APPLOCATION $APPDIR + fi + ;; + u) + if mount | grep /mnt/Pocketbook > /dev/null; then + sudo umount /mnt/Pocketbook + echo "Pocketbook umounted" + else + echo "/mnt/Pocketbook not mounted." + fi + ;; + *) + echo "Invalid command. To see available commands add -h." + esac +done diff --git a/src/api/model.h b/src/api/model.h new file mode 100644 index 0000000..b8c6935 --- /dev/null +++ b/src/api/model.h @@ -0,0 +1,15 @@ +//------------------------------------------------------------------ +// model.h +// +// Author: JuanJakobo +// Date: 23.04.2021 +// Description: Base model +//------------------------------------------------------------------- + +#ifndef MODEL +#define MODEL + +struct Entry +{ +}; +#endif diff --git a/src/api/sqliteConnector.cpp b/src/api/sqliteConnector.cpp new file mode 100644 index 0000000..3c33bca --- /dev/null +++ b/src/api/sqliteConnector.cpp @@ -0,0 +1,186 @@ +//------------------------------------------------------------------ +// sqliteconnector.cpp +// +// Author: JuanJakobo +// Date: 18.07.2021 +// Description: +// +//------------------------------------------------------------------- + +#include "sqliteConnector.h" +#include "sqlite3.h" +#include "log.h" + +#include +#include +using std::string; + +SqliteConnector::SqliteConnector(const string &DBpath) : _dbpath(DBpath) +{ +} + +SqliteConnector::~SqliteConnector() +{ + sqlite3_close(_db); + Log::writeInfoLog("closed DB"); +} + +bool SqliteConnector::open() +{ + int rs; + + rs = sqlite3_open(_dbpath.c_str(), &_db); + + if (rs) + { + Log::writeErrorLog("Could not open DB at " + _dbpath); + return false; + } + + rs = sqlite3_exec(_db, "CREATE TABLE IF NOT EXISTS metadata (title VARCHAR, localPath VARCHAR, size VARCHAR, fileType VARCHAR, lasteditDate VARCHAR, type INT, state INT, etag VARCHAR, path VARCHAR, parentPath VARCHAR, key VARCHAR, PRIMARY KEY (key))", NULL, 0, NULL); + + return true; +} + +string SqliteConnector::getEtag(string path) +{ + open(); + + int rs; + sqlite3_stmt *stmt = 0; + std::vector items; + + + rs = sqlite3_prepare_v2(_db, "SELECT etag FROM 'metadata' WHERE path = ? LIMIT 1;", -1, &stmt, 0); + rs = sqlite3_bind_text(stmt, 1, path.c_str(), path.length(), NULL); + + //TODO erase while + while (sqlite3_step(stmt) == SQLITE_ROW) + { + path = reinterpret_cast(sqlite3_column_text(stmt, 0)); + } + + sqlite3_finalize(stmt); + sqlite3_close(_db); + return path; +} + +std::vector SqliteConnector::getItemsChildren(const string &parentPath) +{ + open(); + + int rs; + sqlite3_stmt *stmt = 0; + std::vector items; + + + rs = sqlite3_prepare_v2(_db, "SELECT title, localPath, path, size, etag, fileType, lastEditDate, type, state FROM 'metadata' WHERE parentPath = ?;", -1, &stmt, 0); + rs = sqlite3_bind_text(stmt, 1, parentPath.c_str(), parentPath.length(), NULL); + + while (sqlite3_step(stmt) == SQLITE_ROW) + { + + WebDAVItem temp; + + temp.title = reinterpret_cast(sqlite3_column_text(stmt, 0)); + temp.localPath = reinterpret_cast(sqlite3_column_text(stmt, 1)); + temp.path = reinterpret_cast(sqlite3_column_text(stmt, 2)); + temp.size = reinterpret_cast(sqlite3_column_text(stmt, 3)); + temp.etag = reinterpret_cast(sqlite3_column_text(stmt, 4)); + temp.fileType = reinterpret_cast(sqlite3_column_text(stmt, 5)); + temp.lastEditDate = reinterpret_cast(sqlite3_column_text(stmt, 6)); + temp.type = static_cast(sqlite3_column_int(stmt,7)); + temp.state = static_cast(sqlite3_column_int(stmt,8)); + + items.push_back(temp); + // + //TODO also for folders + /* + if (iv_access(tempItem.localPath.c_str(), W_OK) != 0) + tempItem.state = FileState::ICLOUD; + else + tempItem.state = FileState::ISYNCED; + */ + + } + + sqlite3_finalize(stmt); + sqlite3_close(_db); + return items; +} + +void SqliteConnector::deleteChildren(const string &parentPath) +{ + open(); + int rs; + sqlite3_stmt *stmt = 0; + Log::writeInfoLog(parentPath); + rs = sqlite3_prepare_v2(_db, "DELETE FROM 'metadata' WHERE parentPath like ?", -1, &stmt, 0); + rs = sqlite3_bind_text(stmt, 1, parentPath.c_str(), parentPath.length(), NULL); + + rs = sqlite3_step(stmt); + if (rs != SQLITE_DONE) + { + Log::writeErrorLog(std::string("An error ocurred trying to delete items of the path ") + sqlite3_errmsg(_db) + std::string(" (Error Code: ") + std::to_string(rs) + ")"); + } + rs = sqlite3_clear_bindings(stmt); + rs = sqlite3_reset(stmt); + +} + +//TODO for folder write to all below folder or do singles? +// void SqliteConnector::updateState(const WebDAVItem + +bool SqliteConnector::saveItemsChildren(const std::vector &items) +{ + open(); + int rs; + string key; + sqlite3_stmt *stmt = 0; + string parent = items.at(0).path; + + //Sqlite version to old... is 3.18, require 3.24 + //Log::writeInfoLog(sqlite3_libversion()); + //rs = sqlite3_prepare_v2(_db, "INSERT INTO 'metadata' (title, localPath, path, size, parentPath, etag, fileType, lastEditDate, type, state, key) VALUES (?,?,?,?,?,?,?,?,?,?,?) ON CONFLICT(key) DO UPDATE SET etag=?, size=?, lastEditDate=? WHERE metadata.etag <> ?;", -1, &stmt, 0); + deleteChildren(parent); + + + rs = sqlite3_prepare_v2(_db, "INSERT INTO 'metadata' (title, localPath, path, size, parentPath, etag, fileType, lastEditDate, type, state, key) VALUES (?,?,?,?,?,?,?,?,?,?,?);", -1, &stmt, 0); + rs = sqlite3_exec(_db, "BEGIN TRANSACTION;", NULL, NULL, NULL); + + for (auto item : items) + { + Log::writeInfoLog("item :" + item.title); + rs = sqlite3_bind_text(stmt, 1, item.title.c_str(), item.title.length(), NULL); + rs = sqlite3_bind_text(stmt, 2, item.localPath.c_str(), item.localPath.length(), NULL); + rs = sqlite3_bind_text(stmt, 3, item.path.c_str(), item.path.length(), NULL); + rs = sqlite3_bind_text(stmt, 4, item.size.c_str(), item.size.length(), NULL); + rs = sqlite3_bind_text(stmt, 5, parent.c_str(), parent.length(), NULL); + rs = sqlite3_bind_text(stmt, 6, item.etag.c_str(), item.etag.length(), NULL); + rs = sqlite3_bind_text(stmt, 7, item.fileType.c_str(), item.fileType.length(), NULL); + rs = sqlite3_bind_text(stmt, 8, item.lastEditDate.c_str(), item.lastEditDate.length(), NULL); + rs = sqlite3_bind_int(stmt, 9, item.type); + rs = sqlite3_bind_int(stmt, 10, item.state); + key = parent + item.title; + rs = sqlite3_bind_text(stmt, 11, key.c_str(),key.length(),NULL); + + rs = sqlite3_step(stmt); + if (rs == SQLITE_CONSTRAINT) + { + Log::writeInfoLog("item exists already: " + item.path); + } + else if (rs != SQLITE_DONE) + { + Log::writeErrorLog(std::string("error inserting into table ") + sqlite3_errmsg(_db) + std::string(" (Error Code: ") + std::to_string(rs) + ")"); + } + rs = sqlite3_clear_bindings(stmt); + rs = sqlite3_reset(stmt); + } + + sqlite3_exec(_db, "END TRANSACTION;", NULL, NULL, NULL); + + sqlite3_finalize(stmt); + sqlite3_close(_db); + + return true; +} diff --git a/src/api/sqliteConnector.h b/src/api/sqliteConnector.h new file mode 100644 index 0000000..a65d0ca --- /dev/null +++ b/src/api/sqliteConnector.h @@ -0,0 +1,44 @@ +//------------------------------------------------------------------ +// sqliteconnector.h +// +// Author: JuanJakobo +// Date: 18.07.2021 +// Description: +// +//------------------------------------------------------------------- + +#ifndef SQLITECONNECTOR +#define SQLITECONNECTOR + +#include "webDAVModel.h" +#include "sqlite3.h" + +#include +#include + +class SqliteConnector +{ +public: + /** + * + */ + SqliteConnector(const std::string &DBpath); + + ~SqliteConnector(); + + bool open(); + + std::string getEtag(std::string path); + + std::vector getItemsChildren(const std::string &parenthPath); + + void deleteChildren(const std::string &parentPath); + + bool saveItemsChildren(const std::vector &children); + +private: + std::string _dbpath; + sqlite3 *_db; +}; + +#endif diff --git a/src/api/webDAV.cpp b/src/api/webDAV.cpp new file mode 100644 index 0000000..75e9ba2 --- /dev/null +++ b/src/api/webDAV.cpp @@ -0,0 +1,465 @@ +// +//------------------------------------------------------------------ +// webdav.cpp +// +// Author: JuanJakobo +// Date: 06.07.2022 +// +//------------------------------------------------------------------- + +#include "webDAV.h" +#include "util.h" +#include "log.h" +#include "eventHandler.h" + +#include +#include +#include +#include +#include + +using std::ifstream; +using std::ofstream; +using std::string; +using std::vector; + + +WebDAV::WebDAV() +{ + + //TODO update on first login only start and create update button, update others just if etag changed + //save all to sqlite + + if (iv_access(NEXTCLOUD_PATH.c_str(), W_OK) != 0) + iv_mkdir(NEXTCLOUD_PATH.c_str(), 0777); + + if (iv_access(NEXTCLOUD_FILE_PATH.c_str(), W_OK) != 0) + iv_mkdir(NEXTCLOUD_FILE_PATH.c_str(), 0777); + + if (iv_access(CONFIG_PATH.c_str(), W_OK) == 0) + { + _username = Util::accessConfig(CONFIG_PATH,Action::IReadString,"username"); + _password = Util::accessConfig(CONFIG_PATH,Action::IReadSecret,"password"); + _url = Util::accessConfig(CONFIG_PATH, Action::IReadString, "url"); + } +} + + +//TODO pass in vector and change that one? +std::vector WebDAV::login(const string &Url, const string &Username, const string &Pass) +{ + string uuid; + std::size_t found = Url.find(NEXTCLOUD_ROOT_PATH); + + if (found != std::string::npos) + { + _url = Url.substr(0, found); + uuid = Url.substr(found + NEXTCLOUD_ROOT_PATH.length()); + } + else + { + _url = Url; + uuid = Username; + } + + auto tempPath = NEXTCLOUD_ROOT_PATH + uuid + "/"; + std::vector tempItems = getDataStructure(tempPath); + if (!tempItems.empty()) + { + if (iv_access(CONFIG_PATH.c_str(), W_OK) != 0) + iv_buildpath(CONFIG_PATH.c_str()); + Util::accessConfig(CONFIG_PATH, Action::IWriteString, "url", _url); + Util::accessConfig(CONFIG_PATH, Action::IWriteString, "username", Username); + Util::accessConfig(CONFIG_PATH, Action::IWriteString, "uuid", uuid); + Util::accessConfig(CONFIG_PATH, Action::IWriteSecret, "password", Pass); + } + return tempItems; +} + +void WebDAV::logout(bool deleteFiles) +{ + if (deleteFiles) + { + //string cmd = "rm -rf " + NEXTCLOUD_FILE_PATH + "/" + getUUID() + "/"; + //system(cmd.c_str()); + } + remove(CONFIG_PATH.c_str()); + remove((CONFIG_PATH + ".back.").c_str()); + + //_url.clear(); + //TODO where? + //tempItems.clear(); +} + +//TODO pas as reversne and no return +string WebDAV::getLocalPath(string path) +{ + Util::decodeUrl(path); + if (path.find(NEXTCLOUD_ROOT_PATH) != string::npos) + path = path.substr(NEXTCLOUD_ROOT_PATH.length()); + + return NEXTCLOUD_FILE_PATH + "/" + path; +} + +//TODO SQL CHeck before calling this function --> if is needed... +///TODO rename function +vector WebDAV::getDataStructure(const string &pathUrl) +{ + string xmlItem = propfind(pathUrl); + if(!xmlItem.empty()) + { + string beginItem = ""; + string endItem = ""; + vector tempItems; + WebDAVItem tempItem; + size_t begin = xmlItem.find(beginItem); + size_t end; + + while (begin != std::string::npos) + { + end = xmlItem.find(endItem); + //TODO use xml lib? + + //TODO fav is int? + //Log::writeInfoLog(Util::getXMLAttribute(xmlItem, "d:favorite")); + + tempItem.etag = Util::getXMLAttribute(xmlItem, "d:getetag"); + tempItem.path = Util::getXMLAttribute(xmlItem, "d:href"); + tempItem.lastEditDate = Util::getXMLAttribute(xmlItem, "d:getlastmodified"); + + double size = atof(Util::getXMLAttribute(xmlItem, "oc:size").c_str()); + if (size < 1024) + tempItem.size = "< 1 KB"; + else + { + double departBy; + double tempSize; + string unit; + + if (size < 1048576) + { + departBy = 1024; + unit = "KB"; + } + else if (size < 1073741824) + { + departBy = 1048576; + unit = "MB"; + } + else + { + departBy = 1073741824; + unit = "GB"; + } + tempSize = round((size / departBy) * 10.0) / 10.0; + std::ostringstream stringStream; + stringStream << tempSize; + tempItem.size = stringStream.str() + " " + unit; + } + + //replaces everthing in front of /remote.php as this is already part of the url + if(tempItem.path.find(NEXTCLOUD_START_PATH) != 0) + tempItem.path.erase(0,tempItem.path.find(NEXTCLOUD_START_PATH)); + + tempItem.title = tempItem.path; + tempItem.localPath = getLocalPath(tempItem.path); + + if (tempItem.path.back() == '/') + { + tempItem.localPath = tempItem.localPath.substr(0, tempItem.localPath.length() - 1); + tempItem.type = Itemtype::IFOLDER; + tempItem.title = tempItem.title.substr(0, tempItem.path.length() - 1); + //TODO set sync status of folders --> use sqlite? + } + else + { + tempItem.type = Itemtype::IFILE; + tempItem.fileType = Util::getXMLAttribute(xmlItem, "d:getcontenttype"); + + if (iv_access(tempItem.localPath.c_str(), W_OK) != 0) + tempItem.state = FileState::ICLOUD; + else + tempItem.state = FileState::ISYNCED; + } + + tempItem.title = tempItem.title.substr(tempItem.title.find_last_of("/") + 1, tempItem.title.length()); + Util::decodeUrl(tempItem.title); + + tempItems.push_back(tempItem); + xmlItem = xmlItem.substr(end + endItem.length()); + begin = xmlItem.find(beginItem); + } + + + //TODO doppelt + if (tempItems.empty()) + return {}; + + //resize item 1 + string header = tempItems.at(0).path; + header = header.substr(0, header.find_last_of("/")); + header = header.substr(0, header.find_last_of("/") + 1); + tempItems.at(0).path = header; + tempItems.at(0).title += "\nclick to go back"; + tempItems.at(0).lastEditDate = ""; + if (tempItems.at(0).path.compare(NEXTCLOUD_ROOT_PATH) == 0) + tempItems.erase(tempItems.begin()); + + string localPath = getLocalPath(pathUrl); + + //if the current folder does not exist locally, create it + if (iv_access(localPath.c_str(), W_OK) != 0) + iv_buildpath(localPath.c_str()); + + return tempItems; + } + return {}; + //TODO return empty items? +} +/* +void Nextcloud::downloadFolder(vector &tempItems, int itemID) +{ + + //TODO etag + BanSleep(2000); + + if (tempItems.at(itemID).getState() == FileState::ILOCAL) + { + UpdateProgressbar(("Removing local item " + tempItems.at(itemID).getLocalPath()).c_str(), 0); + tempItems.at(itemID).removeFile(); + if (_type == Itemtype::IFOLDER) + { + string cmd = "rm -rf " + _localPath + "/"; + system(cmd.c_str()); + return true; + } + + if (remove(_localPath.c_str()) != 0) + return false; + if (_state == FileState::ISYNCED || _state == FileState::IOUTSYNCED) + { + _state = FileState::ICLOUD; + } + else + { + //TODO applies if file is only local + //only show if person is inside this folder + Message(ICON_INFORMATION, "Warning", "The file will be shown until next folder update.", 1200); + } + return true; + return; + } + + //check files; where modified date --> modified date of structure + //first check cloud, then check local + + if (tempItems.at(itemID).getType() == Itemtype::IFOLDER) + { + //check etag + + //for folders + //1. check etag --> if is different, cloud has been updated --> need to dig in deeper here; + //2. if is the same, only check local file system and dont show folder anymore + string temp = tempItems.at(itemID).getPath(); + Log::writeInfoLog("Path to look for " + temp); + vector tempItems = getDataStructure(temp); + + //first item of the vector is the root path itself + for (size_t i = 1; i < tempItems.size(); i++) + { + Log::writeInfoLog("Item: " + tempItems.at(i).getPath()); + downloadFolder(tempItems, i); + } + } + else + { + //for files + //1. check etag --> if is differnt, cloud has been updated + //2. check modification date and file size locally --> if is different, local has been updated + + //3. if both --> create conflict + //4. if first, renew file --> reset etag + //5. if second --> upload the local file; test if it has not been update in the cloud + Log::writeInfoLog("started download of " + tempItems.at(itemID).getPath() + " to " + tempItems.at(itemID).getLocalPath()); + get(tempItems, itemID); + } + + return; +} + +void Nextcloud::download(int itemID) +{ + if (!Util::connectToNetwork()) + { + Message(ICON_WARNING, "Warning", "Can not connect to the Internet. Switching to offline modus.", 2000); + _workOffline = true; + return; + } + + this->downloadFolder(tempItems, itemID); + + UpdateProgressbar("Download completed", 100); +} +*/ + + +string WebDAV::propfind(const string &pathUrl) +{ + //TODO catch here pathUrl is empty! + if (pathUrl.empty()) + return ""; + + //where to test this?? + //include error messsages + if(_username.empty() || _password.empty()) + return ""; + + //string localPath = getLocalPath(pathUrl); + + if (!Util::connectToNetwork()) + { + Message(ICON_WARNING, "Warning", "Cannot connect to the internet. Switching to offline modus. To work online turn on online modus in the menu.", 2000); + return ""; + } + // + //get etag from current and then send request with FT_ENC_TAG + //need path url and also the etag + + //can handle multiple etags --> * if exists + +*/ + + + string readBuffer; + CURLcode res; + CURL *curl = curl_easy_init(); + + if (curl) + { + string post = _username + ":" + _password; + Log::writeInfoLog(_url + pathUrl); + + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, "Depth: 1"); + curl_easy_setopt(curl, CURLOPT_URL, (_url + pathUrl).c_str()); + curl_easy_setopt(curl, CURLOPT_USERPWD, post.c_str()); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PROPFIND"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Util::writeCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "<\?xml version=\"1.0\" encoding=\"UTF-8\"\?> \ + \ + \ + \ + \ + \ + \ + "); + + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + + if (res == CURLE_OK) + { + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + + switch (response_code) + { + case 404: + Message(ICON_ERROR, "Error", "The URL seems to be incorrect. You can look up the WebDav URL in the files app under settings. ", 4000); + break; + case 401: + Message(ICON_ERROR, "Error", "Username/password incorrect.", 4000); + break; + case 207: + return readBuffer; + break; + default: + Message(ICON_ERROR, "Error", ("An unknown error occured. Switching to offline modus. To work online turn on online modus in the menu. (Curl Response Code " + std::to_string(response_code) + ")").c_str(), 4000); + //TODO change default msg + } + } + else + { + string response = std::string("An error occured. (") + curl_easy_strerror(res) + " (Curl Error Code: " + std::to_string(res) + ")). Please try again."; + Log::writeErrorLog(response); + Message(ICON_ERROR, "Error", response.c_str(), 4000); + } + } + return ""; +} + +/* +void WebDAV::get(vector &tempItems, int itemID) +{ + //CHECK id + if (tempItems.at(itemID).getState() == FileState::ISYNCED) + { + UpdateProgressbar(("The newest version of file " + tempItems.at(itemID).getLocalPath() + " is already downloaded.").c_str(), 0); + return; + } + + if (tempItems.at(itemID).getPath().empty()) + { + Message(ICON_ERROR, "Error", "Download path is not set, therefore cannot download the file.", 2000); + return; + } + + UpdateProgressbar(("Starting Download of " + tempItems.at(itemID).getLocalPath()).c_str(), 0); + CURLcode res; + CURL *curl = curl_easy_init(); + + if (curl) + { + string post = this->getUsername() + std::string(":") + this->getPassword(); + + FILE *fp; + fp = iv_fopen(tempItems.at(itemID).getLocalPath().c_str(), "wb"); + + curl_easy_setopt(curl, CURLOPT_URL, (_url + tempItems.at(itemID).getPath()).c_str()); + curl_easy_setopt(curl, CURLOPT_USERPWD, post.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Util::writeData); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, Util::progress_callback); + //in case that cacert is available use it + if (iv_access(CACERT_PATH.c_str(), W_OK) == 0) + curl_easy_setopt(curl, CURLOPT_CAINFO, CACERT_PATH.c_str()); + else + Log::writeErrorLog("could not find cacert"); + //Follow redirects + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + iv_fclose(fp); + + if (res == CURLE_OK) + { + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + + switch (response_code) + { + case 200: + Log::writeInfoLog("finished download of " + tempItems.at(itemID).getPath() + " to " + tempItems.at(itemID).getLocalPath()); + tempItems.at(itemID).setState(FileState::ISYNCED); + break; + case 401: + Message(ICON_ERROR, "Error", "Username/password incorrect.", 2000); + break; + default: + Message(ICON_ERROR, "Error", ("An unknown error occured. (Curl Response Code " + std::to_string(response_code) + ")").c_str(), 2000); + break; + } + } + else + { + string response = std::string("An error occured. (") + curl_easy_strerror(res) + " (Curl Error Code: " + std::to_string(res) + ")). Please try again."; + if(res == 60) + response = "Seems as if you are using Let's Encrypt Certs. Please follow the guide on Github (https://github.com/JuanJakobo/Pocketbook-Nextcloud-Client) to use a custom Cert Store on PB."; + Message(ICON_ERROR, "Error", response.c_str(), 4000); + } + } +} +*/ diff --git a/src/api/webDAV.h b/src/api/webDAV.h new file mode 100644 index 0000000..74dcff1 --- /dev/null +++ b/src/api/webDAV.h @@ -0,0 +1,59 @@ +//------------------------------------------------------------------ +// webdav.h +// +// Author: JuanJakobo +// Date: 06.07.2022 +// Description: Interface to the webdav API +// +//------------------------------------------------------------------- + +#ifndef WEBDAV +#define WEBDAV + +#include "webDAVModel.h" + +#include +#include + +//TODO rename +const std::string NEXTCLOUD_FILE_PATH = "/mnt/ext1/nextcloud"; +const std::string NEXTCLOUD_ROOT_PATH = "/remote.php/dav/files/"; +const std::string NEXTCLOUD_START_PATH = "/remote.php/"; +const std::string CACERT_PATH = "/mnt/ext1/applications/cacert.pem"; +const std::string NEXTCLOUD_PATH = "/mnt/ext1/system/config/nextcloud"; + +class WebDAV +{ + public: + /** + * Creates a new pocket object containing token to access the api + * + */ + WebDAV(); + + std::vector login(const std::string &Url, const std::string &Username, const std::string &Pass); + + void logout(bool deleteFiles = false); + + std::string getLocalPath(std::string path); + + std::vector getDataStructure(const std::string &pathUrl); + + + /** + * gets the dataStructure of the given URL and writes its WEBDAV items to the items vector + * + * @param pathUrl URL to get the dataStructure of + * @param Username the username of the Nextcloud instance + * @param Pass the pass of the Nextcloud instance + * @return vector of Items + */ + std::string propfind(const std::string &pathUrl); + + private: + std::string _username; + std::string _password; + std::string _url; + +}; +#endif diff --git a/src/api/webDAVModel.h b/src/api/webDAVModel.h new file mode 100644 index 0000000..394d0cd --- /dev/null +++ b/src/api/webDAVModel.h @@ -0,0 +1,42 @@ +//------------------------------------------------------------------ +// webDAVItem.h +// +// Author: JuanJakobo +// Date: 07.07.2022 +// Description: +//------------------------------------------------------------------- + +#ifndef WEBDAVITEM +#define WEBDAVITEM + +#include "model.h" + +#include + +enum Itemtype +{ + IFILE, + IFOLDER +}; + +enum FileState +{ + ICLOUD, + ISYNCED, + IOUTSYNCED, + ILOCAL +}; + +struct WebDAVItem : Entry{ + std::string etag; + std::string path; + std::string title; + std::string localPath; + FileState state{FileState::ICLOUD}; + Itemtype type; + std::string lastEditDate{"Error"}; + std::string size; + std::string fileType; +}; + +#endif diff --git a/src/handler/contextMenu.cpp b/src/handler/contextMenu.cpp index 0fdef3c..b2cd4e7 100644 --- a/src/handler/contextMenu.cpp +++ b/src/handler/contextMenu.cpp @@ -38,4 +38,4 @@ int ContextMenu::createMenu(int y, FileState itemstate, iv_menuhandler handler) OpenMenu(contextMenu, 0, ScreenWidth(),y, handler); return 1; -} \ No newline at end of file +} diff --git a/src/handler/contextMenu.h b/src/handler/contextMenu.h index 3607ad8..d1e2ec8 100644 --- a/src/handler/contextMenu.h +++ b/src/handler/contextMenu.h @@ -10,7 +10,7 @@ #define CONTEXT_MENU #include "inkview.h" -#include "item.h" +#include "webDAVModel.h" #include @@ -23,10 +23,10 @@ public: /** * Shows the menu on the screen, lets the user choose menu options and then redirects the handler to the caller - * - * @param y y-coordinate of the item + * + * @param y y-coordinate of the item * @param FileState status of the item for that the menu is created - * @param handler which action does the menu buttons start + * @param handler which action does the menu buttons start * @return int returns if the event was handled */ int createMenu(int y, FileState itemstate, iv_menuhandler handler); @@ -37,4 +37,4 @@ private: char *_sync = strdup("Sync"); char *_remove = strdup("Remove"); }; -#endif \ No newline at end of file +#endif diff --git a/src/handler/eventHandler.cpp b/src/handler/eventHandler.cpp index 29e345e..58de8a8 100644 --- a/src/handler/eventHandler.cpp +++ b/src/handler/eventHandler.cpp @@ -10,14 +10,17 @@ #include "eventHandler.h" #include "mainMenu.h" #include "contextMenu.h" -#include "listView.h" +#include "webDAVView.h" #include "util.h" #include "log.h" +#include "webDAV.h" +#include "webDAVModel.h" #include #include using std::string; +using std::vector; std::unique_ptr EventHandler::_eventHandlerStatic; @@ -27,26 +30,62 @@ EventHandler::EventHandler() _eventHandlerStatic = std::unique_ptr(this); _loginView = nullptr; - _listView = nullptr; + _webDAVView = nullptr; + vector fromDB; + std::vector currentWebDAVItems; - if (iv_access(NEXTCLOUD_CONFIG_PATH.c_str(), W_OK) == 0) + if (iv_access(CONFIG_PATH.c_str(), W_OK) == 0) { - if (_nextcloud.login()) + //menubar + //explanation on first login? + //TODO here mark folders that are unsynced? + //compare both datasets, if fromDB etag is different, mark as unsycned + string tempPath = NEXTCLOUD_ROOT_PATH + Util::accessConfig(CONFIG_PATH, Action::IReadString,"UUID"); + currentWebDAVItems = _webDAV.getDataStructure(tempPath); + fromDB = _sqllite.getItemsChildren(tempPath); + } + //TODO here or father below? + _menu = std::unique_ptr(new MainMenu("Nextcloud")); + + if(currentWebDAVItems.empty()) + { + //use from DB + //this one is always required --> if does not work -> say to the user that it did not work, to sync use + /* + vector Nextcloud::getOfflineStructure(const string &pathUrl) + { + if (pathUrl.compare(NEXTCLOUD_ROOT_PATH + getUUID() + "/") == 0) + { + Message(ICON_ERROR, "Error", "The root structure is not available offline. Please try again to login.", 2000); + logout(); + } + */ + Message(ICON_ERROR, "Error", "Could not login, please try again.", 1200); + if(fromDB.empty()) { - _listView = std::unique_ptr(new ListView(_menu.getContentRect(), _nextcloud.getItems())); - FullUpdate(); - return; - } - else - { - Message(ICON_ERROR, "Error", "Could not login, please try again.", 1200); - _nextcloud.logout(); + int dialogResult = DialogSynchro(ICON_QUESTION, "Action", "Could not login and there is no DB available to restore information. What would you like to do?", "Logout", "Close App", NULL); + switch (dialogResult) + { + case 1: + { + _webDAV.logout(); + _loginView = std::unique_ptr(new LoginView(_menu->getContentRect())); + FullUpdate(); + } + break; + case 2: + default: + CloseApp(); + break; + } } } - - _loginView = std::unique_ptr(new LoginView(_menu.getContentRect())); - - FullUpdate(); + else + { + _webDAVView = std::unique_ptr(new WebDAVView(_menu->getContentRect(), _currentWebDAVItems,1)); + _sqllite.saveItemsChildren(_currentWebDAVItems); + FullUpdate(); + } } int EventHandler::eventDistributor(const int type, const int par1, const int par2) @@ -68,63 +107,39 @@ void EventHandler::mainMenuHandler(const int index) { switch (index) { - //offlineModus + //TODO actualize current folder case 101: { - if (_nextcloud.isWorkOffline()) - { - if (Util::connectToNetwork()) - { - _nextcloud.switchWorkOffline(); - } - else - { - Message(ICON_WARNING, "Warning", "Could not connect to the internet.", 1200); - } - } - else - { - _nextcloud.switchWorkOffline(); - } - - break; - } - //Make startfolder - case 102: - { - _nextcloud.setStartFolder(_tempPath); - Message(ICON_INFORMATION, "Info", ("On the next startup the folder" + _tempPath + " will be shown.").c_str(), 1200); - break; } //Logout - case 103: + case 102: { int dialogResult = DialogSynchro(ICON_QUESTION, "Action", "Do you want to delete local files?", "Yes", "No", "Cancel"); switch (dialogResult) { case 1: - _nextcloud.logout(true); + _webDAV.logout(true); break; case 3: return; default: - _nextcloud.logout(); + _webDAV.logout(); break; } - _listView.release(); - _loginView = std::unique_ptr(new LoginView(_menu.getContentRect())); + _webDAVView.release(); + _loginView = std::unique_ptr(new LoginView(_menu->getContentRect())); FullUpdate(); break; } //Info - case 104: + case 103: { Message(ICON_INFORMATION, "Information", "Version 0.73 \n For support please open a ticket at https://github.com/JuanJakobo/Pocketbook-Nextcloud-Client/issues", 1200); break; } //Exit - case 105: + case 104: CloseApp(); break; default: @@ -146,7 +161,7 @@ void EventHandler::contextMenuHandler(const int index) //Open case 101: { - if (_nextcloud.getItems().at(_tempItemID).getType() == Itemtype::IFOLDER) + if (_webDAVView->getCurrentEntry().type == Itemtype::IFOLDER) { openFolder(); } @@ -167,22 +182,29 @@ void EventHandler::contextMenuHandler(const int index) case 103: { OpenProgressbar(1, "Removing...", "Removing Files.", 0, NULL); + /* + Log::writeInfoLog("removing file " + _items.at(itemID).getPath()); + if (!_items.at(itemID).removeFile()) + return false; + + return true; + */ + /* if (_nextcloud.removeItem(_tempItemID)) { updatePBLibrary(); CloseProgressbar(); - _listView->drawEntry(_tempItemID); + _webDAVView->reDrawCurrentEntry(); } else - { - CloseProgressbar(); - Message(ICON_WARNING, "Warning", "Could not delete the file, please try again.", 1200); - } + */ + CloseProgressbar(); + Message(ICON_WARNING, "Warning", "Could not delete the file, please try again.", 1200); break; } default: { - _listView->invertEntryColor(_tempItemID); + _webDAVView->invertCurrentEntryColor(); break; } @@ -195,42 +217,36 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2) //long press to open up context menu if (type == EVT_POINTERLONG) { - if (_listView != nullptr) + if (_webDAVView != nullptr) { - _tempItemID = _listView->listClicked(par1, par2); - _listView->invertEntryColor(_tempItemID); - if (_tempItemID != -1) + _webDAVView->checkIfEntryClicked(par1, par2); + _webDAVView->invertCurrentEntryColor(); + if (_webDAVView->getCurrentEntry().title.compare("...") != 0) { - if (_nextcloud.getItems().at(_tempItemID).getTitle().compare("...") != 0) - { - _contextMenu = std::unique_ptr(new ContextMenu()); - _contextMenu->createMenu(par2, _nextcloud.getItems().at(_tempItemID).getState(), EventHandler::contextMenuHandlerStatic); - } + _contextMenu = std::unique_ptr(new ContextMenu()); + _contextMenu->createMenu(par2, _webDAVView->getCurrentEntry().state, EventHandler::contextMenuHandlerStatic); } } } else if (type == EVT_POINTERUP) { - //menu is clicked - if (IsInRect(par1, par2, _menu.getMenuButtonRect()) == 1) + if (IsInRect(par1, par2, &_menu->getMenuButtonRect()) == 1) { - return _menu.createMenu(_nextcloud.isLoggedIn(), _nextcloud.isWorkOffline(), EventHandler::mainMenuHandlerStatic); + return _menu->createMenu((_webDAVView != nullptr), EventHandler::mainMenuHandlerStatic); } - //if listView is shown - else if (_listView != nullptr) + else if (_webDAVView != nullptr) { - _tempItemID = _listView->listClicked(par1, par2); - if (_tempItemID != -1) + if(_webDAVView->checkIfEntryClicked(par1, par2)) { - _listView->invertEntryColor(_tempItemID); + _webDAVView->invertCurrentEntryColor(); - if (_nextcloud.getItems().at(_tempItemID).getType() == Itemtype::IFOLDER) + if (_webDAVView->getCurrentEntry().type == Itemtype::IFOLDER) { openFolder(); } else { - if (_nextcloud.getItems().at(_tempItemID).getState() == FileState::ISYNCED || (_nextcloud.isWorkOffline() && _nextcloud.getItems().at(_tempItemID).getState() == FileState::IOUTSYNCED)) + if (_webDAVView->getCurrentEntry().state != FileState::ICLOUD) { openItem(); } @@ -250,17 +266,17 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2) { ShowHourglassForce(); - if (_nextcloud.login(_loginView->getURL(), _loginView->getUsername(), _loginView->getPassword())) + std::vector currentWebDAVItems = _webDAV.login(_loginView->getURL(), _loginView->getUsername(), _loginView->getPassword()); + if(currentWebDAVItems.empty()) { - _listView = std::unique_ptr(new ListView(_menu.getContentRect(), _nextcloud.getItems())); - _loginView.reset(); - - FullUpdate(); + HideHourglass(); + Log::writeErrorLog("login failed."); } else { - HideHourglass(); - Log::writeLog("login failed."); + _webDAVView = std::make_unique(WebDAVView(_menu->getContentRect(), currentWebDAVItems,1)); + _loginView.reset(); + FullUpdate(); } return 0; } @@ -271,60 +287,96 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2) void EventHandler::updatePBLibrary() { - if (_nextcloud.getItems().at(_tempItemID).getType() == Itemtype::IFOLDER) + if (_webDAVView->getCurrentEntry().type == Itemtype::IFOLDER) { Util::updatePBLibrary(15); } else { - if (_nextcloud.getItems().at(_tempItemID).isBook()) + //if (_nextcloud.getItems().at(_tempItemID).isBook()) + /* + * is needed twice! + if (_fileType.find("application/epub+zip") != string::npos || + _fileType.find("application/pdf") != string::npos || + _fileType.find("application/octet-stream") != string::npos || + _fileType.find("text/plain") != string::npos || + _fileType.find("text/html") != string::npos || + _fileType.find("text/rtf") != string::npos || + _fileType.find("application/msword") != string::npos || + _fileType.find("application/x-mobipocket-ebook") != string::npos || + _fileType.find("application/vnd.openxmlformats-officedocument.wordprocessingml.document") != string::npos || + _fileType.find("application/x-fictionbook+xml") != string::npos) Util::updatePBLibrary(5); + */ } } void EventHandler::startDownload() { - if (_nextcloud.isWorkOffline()) - { - int dialogResult = DialogSynchro(ICON_QUESTION, "Action", "You are in offline modus. Go back online?", "Yes", "No", "Cancel"); - if (dialogResult == 2 || dialogResult == 3) - return; // 1; - _nextcloud.switchWorkOffline(); - } OpenProgressbar(1, "Downloading...", "Checking network connection", 0, NULL); try { - _nextcloud.download(_tempItemID); + //_nextcloud.download(_tempItemID); } catch (const std::exception &e) { - Log::writeLog(e.what()); + Log::writeErrorLog(e.what()); Message(ICON_ERROR, "Error", "Something has gone wrong. Please check the logs. (/system/config/nextcloud/)", 1200); } updatePBLibrary(); CloseProgressbar(); - _listView->drawEntry(_tempItemID); + _webDAVView->reDrawCurrentEntry(); } void EventHandler::openItem() { - _listView->invertEntryColor(_tempItemID); - _nextcloud.getItems().at(_tempItemID).open(); + _webDAVView->invertCurrentEntryColor(); + /* + if (_state == FileState::ICLOUD) + { + Message(ICON_ERROR, "File not found.", "Could not find file.", 1000); + } + else if(isBook()) + { + + OpenBook(_localPath.c_str(), "", 0); + } + else + { + Message(ICON_INFORMATION, "Warning", "The filetype is currently not supported.", 1200); + } + */ + //webDAVView->getCurrentEntry + //_nextcloud.getItems().at(_tempItemID).open(); } void EventHandler::openFolder() { - FillAreaRect(_menu.getContentRect(), WHITE); ShowHourglassForce(); + //_nextcloud.setItems(_nextcloud.getDataStructure(_tempPath)); + //TODO if folder is unsynced sync + std::vector currentWebDAVItems = _webDAV.getDataStructure(_webDAVView->getCurrentEntry().path); + if(currentWebDAVItems.empty()) + { + Log::writeErrorLog("items empty"); + HideHourglass(); + _webDAVView->invertCurrentEntryColor(); + } + else + { + Log::writeInfoLog("got new items"); + _sqllite.saveItemsChildren(currentWebDAVItems); - _tempPath = _nextcloud.getItems().at(_tempItemID).getPath(); - if (!_tempPath.empty()) - _nextcloud.setItems(_nextcloud.getDataStructure(_tempPath)); - _listView.release(); - _listView = std::unique_ptr(new ListView(_menu.getContentRect(), _nextcloud.getItems())); - _listView->drawHeader(_tempPath.substr(NEXTCLOUD_ROOT_PATH.length())); - PartialUpdate(_menu.getContentRect()->x, _menu.getContentRect()->y, _menu.getContentRect()->w, _menu.getContentRect()->h); + //if folder is synced, get only from DB + //vector fromDB = _sqllite.getItemsChildren(_tempPath); + //get etags from DB, if etag for path is unchanged, stays the same, same for foldersjj + FillAreaRect(&_menu->getContentRect(), WHITE); + _webDAVView.release(); + _webDAVView = std::unique_ptr(new WebDAVView(_menu->getContentRect(), _currentWebDAVItems,1)); + //_sqllite.saveItemsChildren(_nextcloud.getItems()); + PartialUpdate(_menu->getContentRect().x, _menu->getContentRect().y, _menu->getContentRect().w, _menu->getContentRect().h); + } } int EventHandler::keyHandler(const int type, const int par1, const int par2) @@ -334,19 +386,19 @@ int EventHandler::keyHandler(const int type, const int par1, const int par2) //menu button if (par1 == 23) { - _listView->firstPage(); + _webDAVView->firstPage(); } - else if (_listView != nullptr) + else if (_webDAVView != nullptr) { //left button if (par1 == 24) { - _listView->prevPage(); + _webDAVView->prevPage(); } //right button else if (par1 == 25) { - _listView->nextPage(); + _webDAVView->nextPage(); } } else @@ -358,3 +410,82 @@ int EventHandler::keyHandler(const int type, const int par1, const int par2) return 1; } + + +/* +void Nextcloud::getLocalFileStructure(vector &tempItems, const string &localPath) +{ + //get local files, https://stackoverflow.com/questions/306533/how-do-i-get-a-list-of-files-in-a-directory-in-c + DIR *dir; + class dirent *ent; + class stat st; + + dir = opendir(localPath.c_str()); + while ((ent = readdir(dir)) != NULL) + { + const string fileName = ent->d_name; + const string fullFileName = localPath + fileName; + + if (fileName[0] == '.') + continue; + + if (stat(fullFileName.c_str(), &st) == -1) + continue; + + const bool isDirectory = (st.st_mode & S_IFDIR) != 0; + + bool found = false; + //looks if files have been modified + for (unsigned int i = 1; i < tempItems.size(); i++) + { + if (tempItems.at(i).getLocalPath().compare(fullFileName) == 0) + { + //do via etag and not outsync ! + if (!isDirectory) + { + //check if was changed on the cloud and here and then update... + //if etag ist different and last modifcated changed local --> create conflict + //compare by etag + //get last modification date and compare; if is different upload this + + std::ifstream in(fullFileName, std::ifstream::binary | std::ifstream::ate); + Log::writeInfoLog(tempItems.at(i).getTitle()); + Log::writeInfoLog(std::to_string(in.tellg())); + + Log::writeInfoLog(std::to_string(tempItems.at(i).getSize())); + if (in.tellg() != tempItems.at(i).getSize()) + { + tempItems.at(i).setState(FileState::IOUTSYNCED); + } + } + found = true; + break; + } + } + if (!found) + { + if (isDirectory) + { + //create new dir in cloud + tempItems.push_back(Item(fullFileName, FileState::ILOCAL, Itemtype::IFOLDER)); + Item::Item(const string &localPath, FileState state, Itemtype type) : _localPath(localPath), _state(state), _type(type) + { + _title = _localPath; + _title = _title.substr(_title.find_last_of("/") + 1, _title.length()); + Util::decodeUrl(_title); + } + } + else + { + //put to coud + tempItems.push_back(Item(fullFileName, FileState::ILOCAL, Itemtype::IFILE)); + } + } + } + closedir(dir); +} + + + +*/ + diff --git a/src/handler/eventHandler.h b/src/handler/eventHandler.h index ad3480a..269bfc7 100644 --- a/src/handler/eventHandler.h +++ b/src/handler/eventHandler.h @@ -11,25 +11,29 @@ #include "contextMenu.h" #include "mainMenu.h" -#include "nextcloud.h" -#include "listView.h" +#include "webDAV.h" +#include "webDAVView.h" #include "loginView.h" +#include "sqliteConnector.h" #include -const std::string LOG_PATH = "/mnt/ext1/system/config/nextcloud"; +const std::string CONFIG_FOLDER = "/mnt/ext1/system/config/nextcloud"; +const std::string CONFIG_PATH = CONFIG_FOLDER + "/nextcloud.cfg"; +//TODO use folder of nextcloud conifg temp +const std::string DB_PATH = CONFIG_FOLDER + "/data.db"; class EventHandler { public: /** - * Defines fonds, sets global Event Handler and starts new content + * Defines fonds, sets global Event Handler and starts new content */ EventHandler(); /** * Handles events and redirects them - * + * * @param type event type * @param par1 first argument of the event * @param par2 second argument of the event @@ -39,38 +43,38 @@ public: private: static std::unique_ptr _eventHandlerStatic; - std::unique_ptr _listView; + std::unique_ptr _webDAVView; std::unique_ptr _loginView; std::unique_ptr _contextMenu; - MainMenu _menu = MainMenu("Nextcloud"); - Nextcloud _nextcloud = Nextcloud(); - std::string _tempPath; - int _tempItemID; + std::unique_ptr _menu; + + WebDAV _webDAV = WebDAV(); + SqliteConnector _sqllite = SqliteConnector(DB_PATH); /** * Function needed to call C function, redirects to real function - * + * * @param index int of the menu that is set */ static void mainMenuHandlerStatic(const int index); /** * Handles menu events and redirects them - * + * * @param index int of the menu that is set */ void mainMenuHandler(const int index); /** * Function needed to call C function, redirects to real function - * + * * @param index int of the menu that is set */ static void contextMenuHandlerStatic(const int index); /** * Handlescontext menu events and redirects them - * + * * @param index int of the menu that is set */ @@ -78,7 +82,7 @@ private: /** * Handles pointer Events - * + * * @param type event type * @param par1 first argument of the event * @param par2 second argument of the event @@ -88,13 +92,13 @@ private: /** * Updates PB Library - * + * */ void updatePBLibrary(); /** * Starts the download of an item - * + * */ void startDownload(); @@ -113,7 +117,7 @@ private: /** * Handles key Events - * + * * @param type event type * @param par1 first argument of the event (is the key) * @param par2 second argument of the event diff --git a/src/handler/mainMenu.cpp b/src/handler/mainMenu.cpp index 5d01df8..8e7c279 100644 --- a/src/handler/mainMenu.cpp +++ b/src/handler/mainMenu.cpp @@ -15,10 +15,9 @@ using std::string; MainMenu::MainMenu(const string &name) { - //Define panel size _panelMenuHeight = ScreenHeight() / 18; - _panelMenuBeginY = 0; _mainMenuWidth = ScreenWidth() / 3; + _panelMenuBeginY = 0; _panelMenuBeginX = ScreenWidth() - _mainMenuWidth; _menuButtonRect = iRect(_mainMenuWidth * 2, _panelMenuBeginY, _mainMenuWidth, _panelMenuHeight, ALIGN_RIGHT); @@ -30,18 +29,17 @@ MainMenu::MainMenu(const string &name) DrawTextRect2(&_menuButtonRect, "Menu"); DrawLine(0, _panelMenuHeight - 1, ScreenWidth(), _panelMenuHeight - 1, BLACK); - _contentRect = iRect(0, _panelMenuHeight, ScreenWidth(), (ScreenHeight() - PanelHeight() - _panelMenuHeight), 0); + _contentRect = iRect(0, _panelMenuHeight, ScreenWidth(), (ScreenHeight() - _panelMenuHeight), 0); - SetHardTimer("PANELUPDATE", panelHandlerStatic, 110000); - DrawPanel(NULL, "", NULL, -1); + SetPanelType(0); + PartialUpdate(0, _panelMenuBeginY, ScreenWidth(), _panelMenuHeight); } MainMenu::~MainMenu() { CloseFont(_menuFont); - free(_text); + free(_syncFolder); free(_menu); - free(_makeStartfolder); free(_logout); free(_info); free(_exit); @@ -53,27 +51,20 @@ void MainMenu::panelHandlerStatic() SetHardTimer("PANELUPDATE", panelHandlerStatic, 110000); } -int MainMenu::createMenu(bool loggedIn, bool workOffline, iv_menuhandler handler) +int MainMenu::createMenu(bool loggedIn, iv_menuhandler handler) { - string text = "Work offline"; - if (workOffline) - text = "Work online"; - - _text = strdup(text.c_str()); - imenu mainMenu[] = { {ITEM_HEADER, 0, _menu, NULL}, //show logged in - {loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 101, _text, NULL}, - {loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 102, _makeStartfolder, NULL}, - {loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 103, _logout, NULL}, + {loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 101, _syncFolder, NULL}, + {loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 102, _logout, NULL}, //show always - {ITEM_ACTIVE, 104, _info, NULL}, - {ITEM_ACTIVE, 105, _exit, NULL}, + {ITEM_ACTIVE, 103, _info, NULL}, + {ITEM_ACTIVE, 104, _exit, NULL}, {0, 0, NULL, NULL}}; OpenMenu(mainMenu, 0, _panelMenuBeginX, _panelMenuBeginY, handler); return 1; -} \ No newline at end of file +} diff --git a/src/handler/mainMenu.h b/src/handler/mainMenu.h index 15b4c06..b5ba01f 100644 --- a/src/handler/mainMenu.h +++ b/src/handler/mainMenu.h @@ -17,25 +17,25 @@ class MainMenu { public: /** - * Defines fonds, sets global Event Handler and starts new content - * + * Defines fonds, sets global Event Handler and starts new content + * * @param name name of the application */ MainMenu(const std::string &name); ~MainMenu(); - irect *getContentRect() { return &_contentRect; }; - irect *getMenuButtonRect() { return &_menuButtonRect; }; + irect &getContentRect() { return _contentRect; }; + irect &getMenuButtonRect() { return _menuButtonRect; }; /** * Shows the menu on the screen, lets the user choose menu options and then redirects the handler to the caller - * + * * @param loogedIn the status if the user is logged in - * @param handler handles the clicks on the menu + * @param handler handles the clicks on the menu * @return int returns if the event was handled */ - int createMenu(bool loggedIn, bool workOffline, iv_menuhandler handler); + int createMenu(bool loggedIn, iv_menuhandler handler); private: ifont *_menuFont; @@ -49,9 +49,8 @@ private: imenu _mainMenu; irect _contentRect; - char *_text; char *_menu = strdup("Menu"); - char *_makeStartfolder = strdup("Make startfolder"); + char *_syncFolder = strdup("Actualize folder"); char *_logout = strdup("Logout"); char *_info = strdup("Info"); char *_exit = strdup("Close App"); @@ -61,4 +60,4 @@ private: */ static void panelHandlerStatic(); }; -#endif \ No newline at end of file +#endif diff --git a/src/ui/fileModel.h b/src/ui/fileModel.h new file mode 100644 index 0000000..4ea5d57 --- /dev/null +++ b/src/ui/fileModel.h @@ -0,0 +1,28 @@ +//------------------------------------------------------------------ +// fileModel.h +// +// Author: JuanJakobo +// Date: 23.04.2021 +// Description: +//------------------------------------------------------------------- + +#ifndef FILEMODEL +#define FILEMODEL + +//#include "model.h" + +#include + +enum Type +{ + FOLDER, + FIL +}; + +struct File : Entry{ + std::string name; + std::string path; + Type type; +}; + +#endif diff --git a/src/ui/fileView/fileView.cpp b/src/ui/fileView/fileView.cpp new file mode 100644 index 0000000..89b2639 --- /dev/null +++ b/src/ui/fileView/fileView.cpp @@ -0,0 +1,44 @@ +//------------------------------------------------------------------ +// fileView.cpp +// +// Author: JuanJakobo +// Date: 08.09.2021 +// +//------------------------------------------------------------------- + +#include "fileView.h" +#include "fileViewEntry.h" +#include "fileModel.h" + +#include +#include + +using std::vector; + +FileView::FileView(const irect &contentRect, const vector &files, int page) : ListView(contentRect, page) +{ + auto pageHeight = 0; + auto contentHeight = _contentRect->h - _footerHeight; + auto entrycount = files.size(); + + _entries.reserve(entrycount); + + auto i = 0; + while (i < entrycount) + { + auto entrySize = TextRectHeight(contentRect->w, files.at(i).name.c_str(), 0) + 2.5 * _entryFontHeight; + if ((pageHeight + entrySize) > contentHeight) + { + pageHeight = 0; + _page++; + } + irect rect = iRect(_contentRect->x, _contentRect->y + pageHeight, _contentRect->w, entrySize, 0); + + _entries.emplace_back(std::unique_ptr(new FileViewEntry(_page, rect, files.at(i)))); + + i++; + pageHeight = pageHeight + entrySize; + } + draw(); +} + diff --git a/src/ui/fileView/fileView.h b/src/ui/fileView/fileView.h new file mode 100644 index 0000000..abb00e3 --- /dev/null +++ b/src/ui/fileView/fileView.h @@ -0,0 +1,35 @@ +//------------------------------------------------------------------ +// fileView.h +// +// Author: JuanJakobo +// Date: 08.09.2021 +// Description: An UI class to display items in a listview +//------------------------------------------------------------------- + +#ifndef FILEVIEW +#define FILEVIEW + +#include "fileModel.h" +#include "listView.h" +#include "fileViewEntry.h" + +#include +#include + +class FileView final : public ListView +{ +public: + /** + * Displays a list view + * + * @param ContentRect area of the screen where the list view is placed + * @param Items items that shall be shown in the listview + * @param page page that is shown, default is 1 + */ + FileView(const irect &contentRect, const std::vector &files, int page = 1); + + File &getCurrentEntry() { return getEntry(_selectedEntry); }; + + File &getEntry(int entryID) { return std::dynamic_pointer_cast(_entries.at(entryID))->get(); }; +}; +#endif diff --git a/src/ui/fileView/fileViewEntry.cpp b/src/ui/fileView/fileViewEntry.cpp new file mode 100644 index 0000000..f2da96c --- /dev/null +++ b/src/ui/fileView/fileViewEntry.cpp @@ -0,0 +1,35 @@ +//------------------------------------------------------------------ +// fileViewEntry.cpp +// +// Author: JuanJakobo +// Date: 08.09.2021 +// +//------------------------------------------------------------------- + +#include "fileViewEntry.h" +#include "fileModel.h" + +#include + +FileViewEntry::FileViewEntry(int page, const irect &position, const File &entry) : ListViewEntry(page, position), _entry(entry) +{ +} + +void FileViewEntry::draw(const ifont *entryFont, const ifont *entryFontBold, int fontHeight) +{ + SetFont(entryFontBold, BLACK); + int heightOfTitle = TextRectHeight(_position.w, _entry.name.c_str(), 0); + DrawTextRect(_position.x, _position.y, _position.w, heightOfTitle, _entry.name.c_str(), ALIGN_LEFT); + + SetFont(entryFont, BLACK); + + //DrawTextRect(_position.x, _position.y + heightOfTitle, _position.w, fontHeight, _entry.name.c_str(), ALIGN_LEFT); + DrawTextRect(_position.x, _position.y + heightOfTitle + fontHeight, _position.w, fontHeight, _entry.path.c_str(), ALIGN_LEFT); + std::string type = "File"; + if(_entry.type == Type::FOLDER) + type = "Folder"; + DrawTextRect(_position.x, _position.y + heightOfTitle + fontHeight, _position.w, fontHeight, type.c_str(), ALIGN_RIGHT); + + int line = (_position.y + _position.h) - 1; + DrawLine(0, line, ScreenWidth(), line, BLACK); +} diff --git a/src/ui/fileView/fileViewEntry.h b/src/ui/fileView/fileViewEntry.h new file mode 100644 index 0000000..dd0785d --- /dev/null +++ b/src/ui/fileView/fileViewEntry.h @@ -0,0 +1,41 @@ +//------------------------------------------------------------------ +// fileViewEntry.h +// +// Author: JuanJakobo +// Date: 08.09.2021 +// Description: +//------------------------------------------------------------------- + +#ifndef FILEVIEWENTRY +#define FILEVIEWENTRY + +#include "listViewEntry.h" +#include "fileModel.h" + +class FileViewEntry : public ListViewEntry +{ +public: + /** + * Creates an FileViewEntry + * + * @param Page site of the listView the Entry is shown + * @param Rect area of the screen the item is positioned + * @param entry entry that shall be drawn + */ + FileViewEntry(int page, const irect &position, const File &entry); + + /** + * draws the FileViewEntry to the screen + * + * @param entryFont font for the entry itself + * @param entryFontBold bold font for the header + * @param fontHeight height of the font + */ + void draw(const ifont *entryFont, const ifont *entryFontBold, int fontHeight) override; + + File &get() { return _entry; }; + +private: + File _entry; +}; +#endif diff --git a/src/ui/listView.cpp b/src/ui/listView.cpp deleted file mode 100644 index a431236..0000000 --- a/src/ui/listView.cpp +++ /dev/null @@ -1,186 +0,0 @@ -//------------------------------------------------------------------ -// listView.cpp -// -// Author: JuanJakobo -// Date: 04.08.2020 -// -//------------------------------------------------------------------- - -#include "inkview.h" -#include "item.h" -#include "util.h" -#include "listView.h" -#include "listViewEntry.h" - -#include -#include -#include - -using std::string; -using std::vector; - -ListView::ListView(const irect *contentRect, const vector &items) : _contentRect(contentRect), _items(&items) -{ - FillAreaRect(_contentRect, WHITE); - - _entries.clear(); - - int entrySize = _contentRect->h / (_itemCount + 1); - - _headerHeight = 0.25 * entrySize; - _footerHeight = 0.75 * entrySize; - - _headerFontHeight = 0.8 * _headerHeight; - _footerFontHeight = 0.3 * _footerHeight; - _entryFontHeight = 0.2 * entrySize; - - _headerFont = OpenFont("LiberationMono", _headerFontHeight, FONT_STD); - _footerFont = OpenFont("LiberationMono", _footerFontHeight, FONT_STD); - _entryFont = OpenFont("LiberationMono", _entryFontHeight, FONT_STD); - _entryFontBold = OpenFont("LiberationMono-Bold", _entryFontHeight, FONT_BOLD); - - _page = 1; - _shownPage = _page; - - auto i = _items->size(); - auto z = 0; - - _entries.reserve(i); - - while (i > 0) - { - if (z >= _itemCount) - { - _page++; - z = 0; - } - - irect rect = iRect(_contentRect->x, z * entrySize + _headerHeight + _contentRect->y, _contentRect->w, entrySize, 0); - this->_entries.emplace_back(_page, rect); - i--; - z++; - } - - _pageIcon = iRect(_contentRect->w - 100, _contentRect->h + _contentRect->y - _footerHeight, 100, _footerHeight, ALIGN_CENTER); - - _firstPageButton = iRect(_contentRect->x, _contentRect->h + _contentRect->y - _footerHeight, 130, _footerHeight, ALIGN_CENTER); - _prevPageButton = iRect(_contentRect->x + 150, _contentRect->h + _contentRect->y - _footerHeight, 130, _footerHeight, ALIGN_CENTER); - _nextPageButton = iRect(_contentRect->x + 300, _contentRect->h + _contentRect->y - _footerHeight, 130, _footerHeight, ALIGN_CENTER); - _lastPageButton = iRect(_contentRect->x + 450, _contentRect->h + _contentRect->y - _footerHeight, 130, _footerHeight, ALIGN_CENTER); - - drawEntries(); - drawFooter(); -} - -ListView::~ListView() -{ - CloseFont(_entryFont); - CloseFont(_entryFontBold); - CloseFont(_headerFont); - CloseFont(_footerFont); -} - -void ListView::drawHeader(string headerText) -{ - SetFont(_headerFont, BLACK); - Util::decodeUrl(headerText); - DrawTextRect(_contentRect->x, _contentRect->y, _contentRect->w, _headerHeight - 1, headerText.c_str(), ALIGN_LEFT); - - int line = (_contentRect->y + _headerHeight) - 2; - DrawLine(0, line, ScreenWidth(), line, BLACK); -} - -void ListView::drawEntry(int itemID) -{ - FillAreaRect(_entries[itemID].getPosition(), WHITE); - _entries[itemID].draw(_items->at(itemID), _entryFont, _entryFontBold, _entryFontHeight); - updateEntry(itemID); -} - -void ListView::invertEntryColor(int itemID) -{ - InvertAreaBW(_entries[itemID].getPosition()->x, _entries[itemID].getPosition()->y, _entries[itemID].getPosition()->w, _entries[itemID].getPosition()->h); - updateEntry(itemID); -} - -void ListView::drawEntries() -{ - for (unsigned int i = 0; i < _entries.size(); i++) - { - if (_entries[i].getPage() == _shownPage) - _entries[i].draw(_items->at(i), _entryFont, _entryFontBold, _entryFontHeight); - } -} - -int ListView::listClicked(int x, int y) -{ - if (IsInRect(x, y, &_firstPageButton)) - { - firstPage(); - } - else if (IsInRect(x, y, &_nextPageButton)) - { - nextPage(); - } - else if (IsInRect(x, y, &_prevPageButton)) - { - prevPage(); - } - else if (IsInRect(x, y, &_lastPageButton)) - { - actualizePage(_page); - } - else - { - for (unsigned int i = 0; i < _entries.size(); i++) - { - if (_entries[i].getPage() == _shownPage && IsInRect(x, y, _entries[i].getPosition()) == 1) - { - return i; - } - } - } - return -1; -} - -void ListView::drawFooter() -{ - SetFont(_footerFont, WHITE); - string footer = std::to_string(_shownPage) + "/" + std::to_string(_page); - FillAreaRect(&_pageIcon, BLACK); - - DrawTextRect2(&_pageIcon, footer.c_str()); - FillAreaRect(&_firstPageButton, BLACK); - DrawTextRect2(&_firstPageButton, "First"); - FillAreaRect(&_prevPageButton, BLACK); - DrawTextRect2(&_prevPageButton, "Prev"); - FillAreaRect(&_nextPageButton, BLACK); - DrawTextRect2(&_nextPageButton, "Next"); - FillAreaRect(&_lastPageButton, BLACK); - DrawTextRect2(&_lastPageButton, "Last"); -} - -void ListView::updateEntry(int itemID) -{ - PartialUpdate(_entries[itemID].getPosition()->x, _entries[itemID].getPosition()->y, _entries[itemID].getPosition()->w, _entries[itemID].getPosition()->h); -} - -void ListView::actualizePage(int pageToShown) -{ - if (pageToShown > _page) - { - Message(ICON_INFORMATION, "Info", "You have reached the last page, to return to the first, please click \"first.\"", 1200); - } - else if (pageToShown < 1) - { - Message(ICON_INFORMATION, "Info", "You are already on the first page.", 1200); - } - else - { - _shownPage = pageToShown; - FillArea(_contentRect->x, _contentRect->y + _headerHeight, _contentRect->w, _contentRect->h, WHITE); - drawEntries(); - drawFooter(); - PartialUpdate(_contentRect->x, _contentRect->y + _headerHeight, _contentRect->w, _contentRect->h); - } -} \ No newline at end of file diff --git a/src/ui/listView/listView.cpp b/src/ui/listView/listView.cpp new file mode 100644 index 0000000..34aeb81 --- /dev/null +++ b/src/ui/listView/listView.cpp @@ -0,0 +1,155 @@ +//------------------------------------------------------------------ +// listView.cpp +// +// Author: JuanJakobo +// Date: 04.08.2020 +// +//------------------------------------------------------------------- + +#include "inkview.h" +#include "listView.h" +#include "listViewEntry.h" + +#include +#include + +using std::string; +using std::vector; + +ListView::ListView(const irect &contentRect, int page) : _contentRect(contentRect), _shownPage(page) +{ + _entries.clear(); + + _footerHeight = _contentRect.h / 15; + _footerFontHeight = 0.3 * _footerHeight; + _entryFontHeight = contentRect.h/45; + + _footerFont = OpenFont("LiberationMono", _footerFontHeight, 1); + _entryFont = OpenFont("LiberationMono", _entryFontHeight, 1); + _entryFontBold = OpenFont("LiberationMono-Bold", _entryFontHeight, 1); + + SetFont(_entryFont, BLACK); + + int footerWidth = contentRect.w/20; + + _pageIcon = iRect(_contentRect.w - footerWidth*2, _contentRect.h + _contentRect.y - _footerHeight, contentRect.w/10, _footerHeight, ALIGN_CENTER); + + _firstPageButton = iRect(_contentRect.x, _contentRect.h + _contentRect.y - _footerHeight, contentRect.w/8, _footerHeight, ALIGN_CENTER); + + _prevPageButton = iRect(_contentRect.x + footerWidth*3, _contentRect.h + _contentRect.y - _footerHeight, contentRect.w/8, _footerHeight, ALIGN_CENTER); + + _nextPageButton = iRect(_contentRect.x + footerWidth*6, _contentRect.h + _contentRect.y - _footerHeight, contentRect.w/8, _footerHeight, ALIGN_CENTER); + + _lastPageButton = iRect(_contentRect.x + footerWidth*9, _contentRect.h + _contentRect.y - _footerHeight, contentRect.w/8, _footerHeight, ALIGN_CENTER); +} + +ListView::~ListView() +{ + CloseFont(_entryFont); + CloseFont(_entryFontBold); + CloseFont(_footerFont); +} + +void ListView::draw() +{ + FillAreaRect(&_contentRect, WHITE); + drawEntries(); + drawFooter(); + PartialUpdate(_contentRect.x, _contentRect.y, _contentRect.w, _contentRect.h); +} + +void ListView::reDrawCurrentEntry() +{ + FillAreaRect(&_entries.at(_selectedEntry)->getPosition(), WHITE); + _entries.at(_selectedEntry)->draw(_entryFont, _entryFontBold, _entryFontHeight); + updateEntry(_selectedEntry); +} + +void ListView::invertCurrentEntryColor() +{ + InvertAreaBW(_entries.at(_selectedEntry)->getPosition().x, _entries.at(_selectedEntry)->getPosition().y, _entries.at(_selectedEntry)->getPosition().w, _entries.at(_selectedEntry)->getPosition().h); + updateEntry(_selectedEntry); +} + +void ListView::drawEntries() +{ + for (unsigned int i = 0; i < _entries.size(); i++) + { + if (_entries.at(i)->getPage() == _shownPage) + _entries.at(i)->draw(_entryFont, _entryFontBold, _entryFontHeight); + } +} + +bool ListView::checkIfEntryClicked(int x, int y) +{ + if (IsInRect(x, y, &_firstPageButton)) + { + firstPage(); + } + else if (IsInRect(x, y, &_nextPageButton)) + { + nextPage(); + } + else if (IsInRect(x, y, &_prevPageButton)) + { + prevPage(); + } + else if (IsInRect(x, y, &_lastPageButton)) + { + actualizePage(_page); + } + else + { + for (unsigned int i = 0; i < _entries.size(); i++) + { + if (_entries.at(i)->getPage() == _shownPage && IsInRect(x, y, &_entries.at(i)->getPosition()) == 1) + { + _selectedEntry = i; + return true; + } + } + } + return false; +} + +void ListView::drawFooter() +{ + SetFont(_footerFont, WHITE); + string footer = std::to_string(_shownPage) + "/" + std::to_string(_page); + FillAreaRect(&_pageIcon, BLACK); + + DrawTextRect2(&_pageIcon, footer.c_str()); + FillAreaRect(&_firstPageButton, BLACK); + DrawTextRect2(&_firstPageButton, "First"); + FillAreaRect(&_prevPageButton, BLACK); + DrawTextRect2(&_prevPageButton, "Prev"); + FillAreaRect(&_nextPageButton, BLACK); + DrawTextRect2(&_nextPageButton, "Next"); + FillAreaRect(&_lastPageButton, BLACK); + DrawTextRect2(&_lastPageButton, "Last"); +} + +void ListView::updateEntry(int entryID) +{ + PartialUpdate(_entries.at(entryID)->getPosition().x, _entries.at(entryID)->getPosition().y, _entries.at(entryID)->getPosition().w, _entries.at(entryID)->getPosition().h); +} + +void ListView::actualizePage(int pageToShow) +{ + if (pageToShow > _page) + { + Message(ICON_INFORMATION, "Info", "You have reached the last page, to return to the first, please click \"first.\"", 1200); + } + else if (pageToShow < 1) + { + Message(ICON_INFORMATION, "Info", "You are already on the first page.", 1200); + } + else + { + _shownPage = pageToShow; + FillArea(_contentRect.x, _contentRect.y, _contentRect.w, _contentRect.h, WHITE); + drawEntries(); + drawFooter(); + PartialUpdate(_contentRect.x, _contentRect.y, _contentRect.w, _contentRect.h); + } +} diff --git a/src/ui/listView.h b/src/ui/listView/listView.h similarity index 58% rename from src/ui/listView.h rename to src/ui/listView/listView.h index 98bb6c1..c3bdde5 100644 --- a/src/ui/listView.h +++ b/src/ui/listView/listView.h @@ -10,10 +10,9 @@ #define LISTVIEW #include "inkview.h" -#include "item.h" #include "listViewEntry.h" +#include "model.h" -#include #include #include @@ -21,41 +20,16 @@ class ListView { public: /** - * Displays a list view - * + * Displays a list view + * * @param ContentRect area of the screen where the list view is placed * @param Items items that shall be shown in the listview */ - ListView(const irect *contentRect, const std::vector &items); + ListView(const irect &contentRect, int page); - ~ListView(); + virtual ~ListView(); - /** - * Draws the header - * - * @param headerText the text that shall be displayed in the header - * - */ - void drawHeader(std::string headerText); - - /** - * Draws an single entry to the screen - * - * @param itemID the id of the item that shall be drawn - */ - void drawEntry(int itemID); - - /** - * inverts the color of an entry - * - * @param itemID the id of the item that shall be inverted - */ - void invertEntryColor(int itemID); - - /** - * Iterates through the items and sends them to the listViewEntry Class for drawing - */ - void drawEntries(); + int getShownPage(){return _shownPage;}; /** * Navigates to the next page @@ -72,54 +46,74 @@ public: */ void firstPage() { this->actualizePage(1); }; + /** + * Draws an single entry to the screen + */ + void reDrawCurrentEntry(); + + /** + * inverts the color of the currently selected entry + */ + void invertCurrentEntryColor(); + /** * Checkes if the listview has been clicked and either changes the page or returns item ID - * + * * @param x x-coordinate * @param y y-coordinate - * @return int Item ID that has been clicked, -1 if no Item was clicked + * @return true if was clicked */ - int listClicked(int x, int y); + bool checkIfEntryClicked(int x, int y); -private: + int getCurrentEntryItertator() const {return _selectedEntry;}; + + /** + * Clears the screen and draws entries and footer + * + */ + void draw(); + +protected: int _footerHeight; - int _headerHeight; - int _headerFontHeight; int _footerFontHeight; int _entryFontHeight; - const irect *_contentRect; - std::unique_ptr> _items; - std::vector _entries; - ifont *_headerFont; + const irect _contentRect; + std::vector> _entries; ifont *_footerFont; ifont *_entryFont; ifont *_entryFontBold; - int _page; + int _page = 1; int _shownPage; irect _pageIcon; irect _nextPageButton; irect _prevPageButton; irect _firstPageButton; irect _lastPageButton; - int _itemCount = 7; + int _selectedEntry; + /** - * Draws the footer including a page changer + * Iterates through the items and sends them to the listViewEntry Class for drawing + */ + void drawEntries(); + + /** + * Draws the footer including a page changer */ void drawFooter(); /** - * updates an entry - * - * @param itemID the id of the item that shall be inverted + * updates an entry + * + * @param entryID the id of the item that shall be inverted */ - void updateEntry(int itemID); + void updateEntry(int entryID); /** * Navigates to the selected page - * - * @param pageToShown page that shall be shown + * + * @param pageToShow page that shall be shown */ - void actualizePage(int pageToShown); + void actualizePage(int pageToShow); }; -#endif \ No newline at end of file +#endif diff --git a/src/ui/listView/listViewEntry.cpp b/src/ui/listView/listViewEntry.cpp new file mode 100644 index 0000000..4421b14 --- /dev/null +++ b/src/ui/listView/listViewEntry.cpp @@ -0,0 +1,14 @@ +//------------------------------------------------------------------ +// hnCommentViewEntry.cpp +// +// Author: JuanJakobo +// Date: 04.08.2020 +// +//------------------------------------------------------------------- + +#include "inkview.h" +#include "listViewEntry.h" + +ListViewEntry::ListViewEntry(int page, const irect &rect) : _page(page), _position(rect) +{ +} \ No newline at end of file diff --git a/src/ui/listViewEntry.h b/src/ui/listView/listViewEntry.h similarity index 68% rename from src/ui/listViewEntry.h rename to src/ui/listView/listViewEntry.h index b35e5ec..3da49a3 100644 --- a/src/ui/listViewEntry.h +++ b/src/ui/listView/listViewEntry.h @@ -10,34 +10,35 @@ #define LISTVIEWENTRY #include "inkview.h" -#include "item.h" +#include "model.h" class ListViewEntry { public: /** - * Creates an ListViewEntry - * + * Creates an ListViewEntry + * * @param Page site of the listView the Entry is shown * @param Rect area of the screen the item is positioned */ - ListViewEntry(int page, irect position); + ListViewEntry(int page, const irect &position); - irect *getPosition() { return &_position; } + virtual ~ListViewEntry(){}; + + irect &getPosition() { return _position; } int getPage() const { return _page; } /** * draws the listViewEntry to the screen - * - * @param item item that shall be drawn + * * @param entryFont font for the entry itself * @param entryFontBold bold font for the header - * @param fontHeight height of the font + * @param fontHeight height of the font */ - void draw(const Item &item, ifont *entryFont, ifont *entryFontBold, int fontHeight); + virtual void draw(const ifont *entryFont, const ifont *entryFontBold, int fontHeight) = 0; -private: +protected: int _page; irect _position; }; -#endif \ No newline at end of file +#endif diff --git a/src/ui/listViewEntry.cpp b/src/ui/listViewEntry.cpp deleted file mode 100644 index ad2cd33..0000000 --- a/src/ui/listViewEntry.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//------------------------------------------------------------------ -// listViewEntry.cpp -// -// Author: JuanJakobo -// Date: 04.08.2020 -// -//------------------------------------------------------------------- - -#include "inkview.h" -#include "item.h" -#include "listViewEntry.h" -#include "util.h" - -ListViewEntry::ListViewEntry(int page, irect rect) : _page(page), _position(rect) -{ -} - -void ListViewEntry::draw(const Item &item, ifont *entryFont, ifont *entryFontBold, int fontHeight) -{ - SetFont(entryFontBold, BLACK); - DrawTextRect(_position.x, _position.y, _position.w, fontHeight, item.getTitle().c_str(), ALIGN_LEFT); - - SetFont(entryFont, BLACK); - - if (item.getState() == FileState::ILOCAL) - { - DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, "Local", ALIGN_RIGHT); - } - else - { - if (item.getType() == IFILE) - { - DrawTextRect(_position.x, _position.y + fontHeight, _position.w, fontHeight, item.getFiletype().c_str(), ALIGN_LEFT); - - if (item.getState() == FileState::ISYNCED) - { - DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, "Synced", ALIGN_RIGHT); - } - else if(item.getState() == FileState::IOUTSYNCED) - { - DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, "Out of sync", ALIGN_RIGHT); - } - else - { - DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, "Click to Download", ALIGN_RIGHT); - } - } - else - { - if (item.getState() == FileState::ISYNCED) - { - DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, "Folder synced", ALIGN_RIGHT); - } - } - - DrawTextRect(_position.x, _position.y + 2 * fontHeight, _position.w, fontHeight, item.getLastEditDate().c_str(), ALIGN_LEFT); - DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, item.getSizeString().c_str(), ALIGN_LEFT); - } - - int line = (_position.y + _position.h) - 1; - DrawLine(0, line, ScreenWidth(), line, BLACK); -} \ No newline at end of file diff --git a/src/ui/loginView.cpp b/src/ui/loginView/loginView.cpp similarity index 91% rename from src/ui/loginView.cpp rename to src/ui/loginView/loginView.cpp index fbce289..428607c 100644 --- a/src/ui/loginView.cpp +++ b/src/ui/loginView/loginView.cpp @@ -14,17 +14,17 @@ using std::string; -LoginView *LoginView::_loginViewStatic; +std::unique_ptr LoginView::_loginViewStatic; -LoginView::LoginView(const irect *contentRect) : _contentRect(contentRect) +LoginView::LoginView(const irect &contentRect) : _contentRect(contentRect) { - _loginViewStatic = this; + _loginViewStatic = std::unique_ptr(this); - int contentHeight = contentRect->h / 2; - int contentWidth = _contentRect->w * 0.9; + int contentHeight = contentRect.h / 2; + int contentWidth = _contentRect.w * 0.9; int beginY = 0.4 * contentHeight; - int beginX = (_contentRect->w - contentWidth) / 2; + int beginX = (_contentRect.w - contentWidth) / 2; int contents = contentHeight / 7; @@ -32,7 +32,7 @@ LoginView::LoginView(const irect *contentRect) : _contentRect(contentRect) _loginFont = OpenFont("LiberationMono", _loginFontHeight, FONT_STD); SetFont(_loginFont, BLACK); - FillAreaRect(_contentRect, WHITE); + FillAreaRect(&_contentRect, WHITE); _urlButton = iRect(beginX, beginY, contentWidth, contents, ALIGN_CENTER); DrawTextRect(_urlButton.x, _urlButton.y - _loginFontHeight - _loginFontHeight/2, _urlButton.w, _urlButton.h, "Server address:", ALIGN_LEFT); @@ -142,4 +142,4 @@ void LoginView::keyboardHandler(char *text) DrawTextRect2(&_passwordButton, pass.c_str()); } -} \ No newline at end of file +} diff --git a/src/ui/loginView.h b/src/ui/loginView/loginView.h similarity index 85% rename from src/ui/loginView.h rename to src/ui/loginView/loginView.h index 9c21c97..0f54568 100644 --- a/src/ui/loginView.h +++ b/src/ui/loginView/loginView.h @@ -12,6 +12,7 @@ #include "inkview.h" #include +#include enum KeyboardTarget { @@ -26,17 +27,17 @@ class LoginView { public: /** - * Draws the loginView includin URL, Username and Password buttons inside the contentRect - * + * Draws the loginView includin URL, Username and Password buttons inside the contentRect + * * @param contentRect area where the loginscreen shall be drawn */ - LoginView(const irect *contentRect); + LoginView(const irect &contentRect); ~LoginView(); /** * Checks which part of the loginscreen is shown and reacts accordingly - * + * * @param x x-coordinate * @param y y-coordinate * @return int if event has been handled. Returns 2 if login has been clicked and all items are set @@ -48,10 +49,10 @@ public: std::string getURL() { return _url; }; private: - static LoginView *_loginViewStatic; + static std::unique_ptr _loginViewStatic; int _loginFontHeight; ifont *_loginFont; - const irect *_contentRect; + const irect _contentRect; irect _urlButton; irect _loginButton; irect _usernameButton; @@ -64,17 +65,17 @@ private: /** * Functions needed to call C function, handles the keyboard - * + * * @param text text that has been typed in by the user */ static void keyboardHandlerStatic(char *text); /** * Called by the static method and saves and writes the input from the user to the screen - * - * @param text text that has been typed in by the user - */ + * + * @param text text that has been typed in by the user + */ void keyboardHandler(char *text); }; -#endif \ No newline at end of file +#endif diff --git a/src/ui/webDAVView/webDAVView.cpp b/src/ui/webDAVView/webDAVView.cpp new file mode 100644 index 0000000..fd42cab --- /dev/null +++ b/src/ui/webDAVView/webDAVView.cpp @@ -0,0 +1,62 @@ +//------------------------------------------------------------------ +// webDAVView.cpp +// +// Author: JuanJakobo +// Date: 08.09.2021 +// +//------------------------------------------------------------------- + +#include "webDAVView.h" +#include "webDAVModel.h" +#include "webDAV.h" + +#include +#include + +using std::vector; + +WebDAVView::WebDAVView(const irect &contentRect, vector &items, int page) : ListView(contentRect, page) +{ + auto pageHeight = 0; + auto contentHeight = _contentRect.h - _footerHeight; + auto entrycount = items.size(); + + _entries.reserve(entrycount); + + //resize item 1 + std::string header = items.at(0).path; + header = header.substr(0, header.find_last_of("/")); + header = header.substr(0, header.find_last_of("/") + 1); + items.at(0).path = header; + items.at(0).title += "\nclick to go back"; + items.at(0).lastEditDate = ""; + if (items.at(0).path.compare(NEXTCLOUD_ROOT_PATH) == 0) + items.erase(items.begin()); + + for(auto item : items) + { + auto entrySize = TextRectHeight(contentRect.w, item.title.c_str(), 0); + + if(item.type == IFILE) + entrySize += _entryFontHeight; + + if(item.title.find("click to go back") != std::string::npos) + entrySize += 0.5 * _entryFontHeight; + else + entrySize += 2.5 * _entryFontHeight; + + + if ((pageHeight + entrySize) > contentHeight) + { + pageHeight = 0; + _page++; + } + irect rect = iRect(_contentRect.x, _contentRect.y + pageHeight, _contentRect.w, entrySize, 0); + + _entries.emplace_back(std::unique_ptr(new WebDAVViewEntry(_page, rect, item))); + + pageHeight = pageHeight + entrySize; + } + draw(); +} + diff --git a/src/ui/webDAVView/webDAVView.h b/src/ui/webDAVView/webDAVView.h new file mode 100644 index 0000000..4317e98 --- /dev/null +++ b/src/ui/webDAVView/webDAVView.h @@ -0,0 +1,35 @@ +//------------------------------------------------------------------ +// webDAVView.h +// +// Author: JuanJakobo +// Date: 08.09.2021 +// Description: An UI class to display items in a listview +//------------------------------------------------------------------- + +#ifndef WEBDAVVIEW +#define WEBDAVVIEW + +#include "webDAVModel.h" +#include "listView.h" +#include "webDAVViewEntry.h" + +#include +#include + +class WebDAVView final : public ListView +{ +public: + /** + * Displays a list view + * + * @param ContentRect area of the screen where the list view is placed + * @param Items items that shall be shown in the listview + * @param page page that is shown, default is 1 + */ + WebDAVView(const irect &contentRect, std::vector &items, int page = 1); + + WebDAVItem &getCurrentEntry() { return getEntry(_selectedEntry); }; + + WebDAVItem &getEntry(int entryID) { return std::dynamic_pointer_cast(_entries.at(entryID))->get(); }; +}; +#endif diff --git a/src/ui/webDAVView/webDAVViewEntry.cpp b/src/ui/webDAVView/webDAVViewEntry.cpp new file mode 100644 index 0000000..8b74344 --- /dev/null +++ b/src/ui/webDAVView/webDAVViewEntry.cpp @@ -0,0 +1,72 @@ +//------------------------------------------------------------------ +// WebDAVViewEntry.cpp +// +// Author: JuanJakobo +// Date: 08.09.2021 +// +//------------------------------------------------------------------- + +#include "webDAVViewEntry.h" +#include "webDAVModel.h" + +#include + +WebDAVViewEntry::WebDAVViewEntry(int page, const irect &position, const WebDAVItem &entry) : ListViewEntry(page, position), _entry(entry) +{ +} + +void WebDAVViewEntry::draw(const ifont *entryFont, const ifont *entryFontBold, int fontHeight) +{ + + SetFont(entryFontBold, BLACK); + int heightOfTitle = TextRectHeight(_position.w, _entry.title.c_str(), 0); + if(_entry.title.find("click to go back") != std::string::npos) + DrawTextRect(_position.x, _position.y, _position.w, heightOfTitle, _entry.title.c_str(), ALIGN_CENTER); + else + { + DrawTextRect(_position.x, _position.y, _position.w, heightOfTitle, _entry.title.c_str(), ALIGN_LEFT); + + SetFont(entryFont, BLACK); + + + if (_entry.state == FileState::ILOCAL) + { + DrawTextRect(_position.x, _position.y + heightOfTitle + 2 * fontHeight, _position.w, fontHeight, "Local", ALIGN_RIGHT); + } + else + { + if (_entry.type == IFILE) + { + DrawTextRect(_position.x, _position.y + heightOfTitle, _position.w, fontHeight, _entry.fileType.c_str(), ALIGN_LEFT); + + switch(_entry.state) + { + case FileState::ISYNCED: + DrawTextRect(_position.x, _position.y + heightOfTitle + 2 * fontHeight, _position.w, fontHeight, "Synced", ALIGN_RIGHT); + break; + case FileState::IOUTSYNCED: + DrawTextRect(_position.x, _position.y + heightOfTitle + 2 * fontHeight, _position.w, fontHeight, "Out of sync", ALIGN_RIGHT); + break; + default: + DrawTextRect(_position.x, _position.y + heightOfTitle + 2 * fontHeight, _position.w, fontHeight, "Click to Download", ALIGN_RIGHT); + } + + DrawTextRect(_position.x, _position.y + heightOfTitle + fontHeight, _position.w, fontHeight, _entry.lastEditDate.c_str(), ALIGN_LEFT); + DrawTextRect(_position.x, _position.y + heightOfTitle + 2 * fontHeight, _position.w, fontHeight, _entry.size.c_str(), ALIGN_LEFT); + } + else + { + if (_entry.state == FileState::ISYNCED) + { + DrawTextRect(_position.x, _position.y + heightOfTitle + fontHeight, _position.w, fontHeight, "Folder synced", ALIGN_RIGHT); + } + DrawTextRect(_position.x, _position.y + heightOfTitle, _position.w, fontHeight, _entry.lastEditDate.c_str(), ALIGN_LEFT); + DrawTextRect(_position.x, _position.y + heightOfTitle + fontHeight, _position.w, fontHeight, _entry.size.c_str(), ALIGN_LEFT); + } + + } + + } + int line = (_position.y + _position.h) - 1; + DrawLine(0, line, ScreenWidth(), line, BLACK); +} diff --git a/src/ui/webDAVView/webDAVViewEntry.h b/src/ui/webDAVView/webDAVViewEntry.h new file mode 100644 index 0000000..e2ef40e --- /dev/null +++ b/src/ui/webDAVView/webDAVViewEntry.h @@ -0,0 +1,41 @@ +//------------------------------------------------------------------ +// webDAVViewEntry.h +// +// Author: JuanJakobo +// Date: 08.09.2021 +// Description: +//------------------------------------------------------------------- + +#ifndef WEBDAVVIEWENTRY +#define WEBDAVVIEWENTRY + +#include "listViewEntry.h" +#include "webDAVModel.h" + +class WebDAVViewEntry : public ListViewEntry +{ +public: + /** + * Creates an WebDAVViewEntry + * + * @param Page site of the listView the Entry is shown + * @param Rect area of the screen the item is positioned + * @param entry entry that shall be drawn + */ + WebDAVViewEntry(int page, const irect &position, const WebDAVItem &entry); + + /** + * draws the WebDAVViewEntry to the screen + * + * @param entryFont font for the entry itself + * @param entryFontBold bold font for the header + * @param fontHeight height of the font + */ + void draw(const ifont *entryFont, const ifont *entryFontBold, int fontHeight) override; + + WebDAVItem &get() { return _entry; }; + +private: + WebDAVItem _entry; +}; +#endif diff --git a/src/util/item.cpp b/src/util/item.cpp deleted file mode 100644 index 8c12223..0000000 --- a/src/util/item.cpp +++ /dev/null @@ -1,168 +0,0 @@ -//------------------------------------------------------------------ -// item.cpp -// -// Author: JuanJakobo -// Date: 04.08.2020 -// -//------------------------------------------------------------------- - -#include "item.h" -#include "inkview.h" -#include "util.h" -#include "nextcloud.h" -#include "log.h" - -#include -#include -#include - -using namespace std; - -Item::Item(const string &xmlItem) -{ - _path = Util::getXMLAttribute(xmlItem, "d:href"); - - //replaces everthing in front of /remote.php as this is already part of the url - Log::writeLog("path before transformation " + _path); - if(_path.find(NEXTCLOUD_START_PATH) != 0) - { - _path.erase(0,_path.find(NEXTCLOUD_START_PATH)); - Log::writeLog("path after transformation " + _path); - } - - _lastEditDate = Util::getXMLAttribute(xmlItem, "d:getlastmodified"); - _title = _path; - _localPath = Nextcloud::getLocalPath(_path); - - if (_path.back() == '/') - { - _localPath = _localPath.substr(0, _localPath.length() - 1); - _type = Itemtype::IFOLDER; - _title = _title.substr(0, _path.length() - 1); - _size = atof(Util::getXMLAttribute(xmlItem, "d:quota-used-bytes").c_str()); - } - else - { - _type = Itemtype::IFILE; - _size = atof(Util::getXMLAttribute(xmlItem, "d:getcontentlength").c_str()); - _fileType = Util::getXMLAttribute(xmlItem, "d:getcontenttype"); - - if (iv_access(_localPath.c_str(), W_OK) != 0) - { - _state = FileState::ICLOUD; - } - else - { - _state = FileState::ISYNCED; - } - } - - _title = _title.substr(_title.find_last_of("/") + 1, _title.length()); - Util::decodeUrl(_title); -} - -Item::Item(const string &localPath, FileState state, Itemtype type) : _localPath(localPath), _state(state), _type(type) -{ - _title = _localPath; - _title = _title.substr(_title.find_last_of("/") + 1, _title.length()); - Util::decodeUrl(_title); -} - -bool Item::isBook() const -{ - if (_fileType.find("application/epub+zip") != string::npos || - _fileType.find("application/pdf") != string::npos || - _fileType.find("application/octet-stream") != string::npos || - _fileType.find("text/plain") != string::npos || - _fileType.find("text/html") != string::npos || - _fileType.find("text/rtf") != string::npos || - _fileType.find("application/msword") != string::npos || - _fileType.find("application/x-mobipocket-ebook") != string::npos || - _fileType.find("application/vnd.openxmlformats-officedocument.wordprocessingml.document") != string::npos || - _fileType.find("application/x-fictionbook+xml") != string::npos) - return true; - return false; -} - -void Item::open() const -{ - if (_state == FileState::ICLOUD) - { - Message(ICON_ERROR, "File not found.", "Could not find file.", 1000); - } - else if(isBook()) - { - - OpenBook(_localPath.c_str(), "", 0); - } - /* - else if (_fileType.find("audio/mpeg") != string::npos || - _fileType.find("audio/ogg") != string::npos || - _fileType.find("audio/mp4") != string::npos || - _fileType.find("audio/m4b") != string::npos) - { - PlayFile(_localPath.c_str()); - OpenPlayer(); - } - else if (_fileType.find("image/jpeg") != string::npos) - { - Message(3, "Info", "Opening image", 600); - } - */ - else - { - Message(ICON_INFORMATION, "Warning", "The filetype is currently not supported.", 1200); - } -} - -bool Item::removeFile() -{ - if (_type == Itemtype::IFOLDER) - { - string cmd = "rm -rf " + _localPath + "/"; - system(cmd.c_str()); - return true; - } - - if (remove(_localPath.c_str()) != 0) - return false; - if (_state == FileState::ISYNCED || _state == FileState::IOUTSYNCED) - { - _state = FileState::ICLOUD; - } - else - { - Message(ICON_INFORMATION, "Warning", "The file will be shown until next folder update.", 1200); - } - return true; -} - -string Item::getSizeString() const -{ - - if (_size < 1024) - return "< 1 KB"; - - double departBy; - double tempSize; - string unit; - - if (_size < 1048576) - { - departBy = 1024; - unit = "KB"; - } - else if (_size < 1073741824) - { - departBy = 1048576; - unit = "MB"; - } - else - { - departBy = 1073741824; - unit = "GB"; - } - - tempSize = round((_size / departBy) * 10.0) / 10.0; - return std::to_string(tempSize) + " " + unit; -} \ No newline at end of file diff --git a/src/util/item.h b/src/util/item.h deleted file mode 100644 index e41a6f0..0000000 --- a/src/util/item.h +++ /dev/null @@ -1,100 +0,0 @@ -//------------------------------------------------------------------ -// item.h -// -// Author: JuanJakobo -// Date: 04.08.2020 -// Description: Describes an WEBDAV item -//------------------------------------------------------------------- - -#ifndef ITEM -#define ITEM - -#include "inkview.h" - -#include - -enum Itemtype -{ - IFILE, - IFOLDER -}; - -enum FileState -{ - ICLOUD, - ISYNCED, - IOUTSYNCED, - ILOCAL -}; - -class Item -{ -public: - /** - * Creates an item by receiving the xml from nextcloud and parses it into an object - * - * @param xmlItem result of the nextcloud request - */ - Item(const std::string &xmlItem); - - /** - * Creates a new item by receiving localPath from the pocketbook - * - * @param localPath path where the file is placed - * @param state state of the file - * @param type type of the item (folder/file) - */ - Item(const std::string &localPath, FileState state, Itemtype type); - - - /** - * Checks if item is a book - */ - bool isBook() const; - - /** - * Tries to open the item by checking the file format and then executes the fitting action - */ - void open() const; - - bool removeFile(); - - void setPath(const std::string &path) { _path = path; }; - std::string getPath() const { return _path; }; - - std::string getLocalPath() const { return _localPath; }; - - Itemtype getType() const { return _type; }; - - void setTitle(const std::string &title) { _title = title; }; - std::string getTitle() const { return _title; }; - - void setState(FileState state) { _state = state; }; - FileState getState() const { return _state; }; - - std::string getLastEditDate() const { return _lastEditDate; }; - void setLastEditDate(const std::string &date) { _lastEditDate = date; }; - - double getSize() const { return _size; }; - std::string getSizeString() const; - - std::string getFiletype() const { return _fileType; }; - -private: - std::string _path; - std::string _title; - std::string _localPath; - FileState _state{FileState::ICLOUD}; - Itemtype _type; - std::string _lastEditDate{"Error"}; - double _size; - std::string _fileType; - - /** - * Converts the size to an easier readble format - * - * @param tempSize Size of the item in bytes - */ - void setSize(double tempSize); -}; -#endif \ No newline at end of file diff --git a/src/util/log.cpp b/src/util/log.cpp index 0105bca..169f239 100644 --- a/src/util/log.cpp +++ b/src/util/log.cpp @@ -12,9 +12,19 @@ #include #include +void Log::writeInfoLog(const std::string &text) +{ + writeLog("Info:" + text); +} + +void Log::writeErrorLog(const std::string &text) +{ + writeLog("Error:" + text); +} + void Log::writeLog(const std::string &text) { - std::ofstream log(LOG_PATH + std::string("/logfile.txt"), std::ios_base::app | std::ios_base::out); + std::ofstream log(CONFIG_FOLDER + std::string("/logfile.txt"), std::ios_base::app | std::ios_base::out); time_t rawtime; struct tm *timeinfo; @@ -25,7 +35,7 @@ void Log::writeLog(const std::string &text) strftime(buffer, sizeof(buffer), "%d/%b/%Y:%H:%M:%S %z", timeinfo); - log << buffer << ":" << text << "\n"; + log << buffer << ':' << text << "\n"; log.close(); -} \ No newline at end of file +} diff --git a/src/util/log.h b/src/util/log.h index ce63924..910c499 100644 --- a/src/util/log.h +++ b/src/util/log.h @@ -17,13 +17,27 @@ class Log { public: /** - * Writes a log entry to the log file - * + * Writes a error log entry to the log file + * * @param text that shall be written to the log */ - static void writeLog(const std::string &text); + static void writeErrorLog(const std::string &text); + + /** + * Writes a info log entry to the log file + * + * @param text that shall be written to the log + */ + static void writeInfoLog(const std::string &text); private: Log() {} + + /** + * Writes a log entry to the log file + * + * @param text that shall be written to the log + */ + static void writeLog(const std::string &text); }; -#endif \ No newline at end of file +#endif diff --git a/src/util/nextcloud.cpp b/src/util/nextcloud.cpp deleted file mode 100644 index 3732461..0000000 --- a/src/util/nextcloud.cpp +++ /dev/null @@ -1,503 +0,0 @@ -//------------------------------------------------------------------ -// nextcloud.cpp -// -// Author: JuanJakobo -// Date: 04.08.2020 -// -//------------------------------------------------------------------- - -#include "inkview.h" -#include "nextcloud.h" -#include "util.h" -#include "item.h" -#include "log.h" - -#include -#include -#include -#include - -using std::ifstream; -using std::ofstream; -using std::string; -using std::vector; - -Nextcloud::Nextcloud() -{ - - if (iv_access(NEXTCLOUD_PATH.c_str(), W_OK) != 0) - iv_mkdir(NEXTCLOUD_PATH.c_str(), 0777); - - if (iv_access(NEXTCLOUD_FILE_PATH.c_str(), W_OK) != 0) - iv_mkdir(NEXTCLOUD_FILE_PATH.c_str(), 0777); -//create database - -} - -bool Nextcloud::setItems(const vector &tempItems) -{ - - if (tempItems.empty()) - return false; - - if (!_items.empty()) - _items.clear(); - - _items = tempItems; - - //resize item 1 - string header = _items.at(0).getPath(); - header = header.substr(0, header.find_last_of("/")); - header = header.substr(0, header.find_last_of("/") + 1); - _items.at(0).setPath(header); - _items.at(0).setTitle("..."); - _items.at(0).setLastEditDate(""); - if (_items.at(0).getPath().compare(NEXTCLOUD_ROOT_PATH) == 0) - _items.erase(_items.begin()); - - return true; -} - -bool Nextcloud::login() -{ - string tempPath = getStartFolder(); - - if (tempPath.empty()) - tempPath = NEXTCLOUD_ROOT_PATH + this->getUUID() + "/"; - - if (setItems(getDataStructure(tempPath))) - { - _loggedIn = true; - return true; - } - - return false; -} - -bool Nextcloud::login(const string &Url, const string &Username, const string &Pass) -{ - string uuid; - std::size_t found = Url.find(NEXTCLOUD_ROOT_PATH); - - if (found != std::string::npos) - { - _url = Url.substr(0, found); - uuid = Url.substr(found + NEXTCLOUD_ROOT_PATH.length()); - } - else - { - _url = Url; - uuid = Username; - } - - string tempPath = NEXTCLOUD_ROOT_PATH + uuid + "/"; - if (setItems(getDataStructure(tempPath, Username, Pass))) - { - Log::writeLog("Got items"); - - if (iv_access(NEXTCLOUD_CONFIG_PATH.c_str(), W_OK) != 0) - iv_buildpath(NEXTCLOUD_CONFIG_PATH.c_str()); - this->setUsername(Username); - this->setUUID(uuid); - this->setPassword(Pass); - this->setURL(_url); - this->setStartFolder(tempPath); - _loggedIn = true; - return true; - } - return false; -} - -void Nextcloud::logout(bool deleteFiles) -{ - if (deleteFiles) - { - string cmd = "rm -rf " + NEXTCLOUD_FILE_PATH + "/" + getUUID() + "/"; - system(cmd.c_str()); - } - remove(NEXTCLOUD_CONFIG_PATH.c_str()); - remove((NEXTCLOUD_CONFIG_PATH + ".back.").c_str()); - - _url.clear(); - _items.clear(); - _workOffline = false; - _loggedIn = false; -} - -void Nextcloud::downloadItem(vector &tempItems, int itemID) -{ - if (tempItems.at(itemID).getState() == FileState::ISYNCED) - { - UpdateProgressbar(("The newest version of file " + tempItems.at(itemID).getLocalPath() + " is already downloaded.").c_str(), 0); - return; - } - - if (tempItems.at(itemID).getPath().empty()) - { - Message(ICON_ERROR, "Error", "Download path is not set, therefore cannot download the file.", 2000); - return; - } - - UpdateProgressbar(("Starting Download of " + tempItems.at(itemID).getLocalPath()).c_str(), 0); - CURLcode res; - CURL *curl = curl_easy_init(); - - if (curl) - { - string post = this->getUsername() + std::string(":") + this->getPassword(); - - FILE *fp; - fp = iv_fopen(tempItems.at(itemID).getLocalPath().c_str(), "wb"); - - curl_easy_setopt(curl, CURLOPT_URL, (_url + tempItems.at(itemID).getPath()).c_str()); - curl_easy_setopt(curl, CURLOPT_USERPWD, post.c_str()); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Util::writeData); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false); - curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, Util::progress_callback); - //in case that cacert is available use it - if (iv_access(CACERT_PATH.c_str(), W_OK) == 0) - curl_easy_setopt(curl, CURLOPT_CAINFO, CACERT_PATH.c_str()); - else - Log::writeLog("could not find cacert"); - //Follow redirects - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); - res = curl_easy_perform(curl); - curl_easy_cleanup(curl); - iv_fclose(fp); - - if (res == CURLE_OK) - { - long response_code; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); - - switch (response_code) - { - case 200: - Log::writeLog("finished download of " + tempItems.at(itemID).getPath() + " to " + tempItems.at(itemID).getLocalPath()); - tempItems.at(itemID).setState(FileState::ISYNCED); - break; - case 401: - Message(ICON_ERROR, "Error", "Username/password incorrect.", 2000); - break; - default: - Message(ICON_ERROR, "Error", ("An unknown error occured. (Curl Response Code " + std::to_string(response_code) + ")").c_str(), 2000); - break; - } - } - else - { - string response = std::string("An error occured. (") + curl_easy_strerror(res) + " (Curl Error Code: " + std::to_string(res) + ")). Please try again."; - if(res == 60) - response = "Seems as if you are using Let's Encrypt Certs. Please follow the guide on Github (https://github.com/JuanJakobo/Pocketbook-Nextcloud-Client) to use a custom Cert Store on PB."; - Message(ICON_ERROR, "Error", response.c_str(), 4000); - } - } -} - -void Nextcloud::downloadFolder(vector &tempItems, int itemID) -{ - BanSleep(2000); - - if (tempItems.at(itemID).getState() == FileState::ILOCAL) - { - UpdateProgressbar(("Removing local item " + tempItems.at(itemID).getLocalPath()).c_str(), 0); - tempItems.at(itemID).removeFile(); - return; - } - - if (tempItems.at(itemID).getType() == Itemtype::IFOLDER) - { - string temp = tempItems.at(itemID).getPath(); - Log::writeLog("Path to look for " + temp); - vector tempItems = getDataStructure(temp); - - //first item of the vector is the root path itself - for (size_t i = 1; i < tempItems.size(); i++) - { - Log::writeLog("Item: " + tempItems.at(i).getPath()); - downloadFolder(tempItems, i); - } - } - else - { - Log::writeLog("started download of " + tempItems.at(itemID).getPath() + " to " + tempItems.at(itemID).getLocalPath()); - downloadItem(tempItems, itemID); - } - - return; -} - -void Nextcloud::download(int itemID) -{ - if (!Util::connectToNetwork()) - { - Message(ICON_WARNING, "Warning", "Can not connect to the Internet. Switching to offline modus.", 2000); - _workOffline = true; - return; - } - - this->downloadFolder(_items, itemID); - - UpdateProgressbar("Download completed", 100); -} - -bool Nextcloud::removeItem(int itemID) -{ - Log::writeLog("removing file " + _items.at(itemID).getPath()); - if (!_items.at(itemID).removeFile()) - return false; - - return true; -} - -vector Nextcloud::getDataStructure(string &pathUrl) -{ - return getDataStructure(pathUrl, this->getUsername(), this->getPassword()); -} - -vector Nextcloud::getDataStructure(const string &pathUrl, const string &Username, const string &Pass) -{ - if (_workOffline) - return getOfflineStructure(pathUrl); - - if (!Util::connectToNetwork()) - { - Message(ICON_WARNING, "Warning", "Cannot connect to the internet. Switching to offline modus. To work online turn on online modus in the menu.", 2000); - _workOffline = true; - return getOfflineStructure(pathUrl); - } - - if (_url.empty()) - _url = this->getUrl(); - - if (Username.empty() || Pass.empty()) - { - Message(ICON_ERROR, "Error", "Username/password not set.", 2000); - return {}; - } - - Log::writeLog("Starting download of DataStructure"); - Log::writeLog(_url + pathUrl); - - string readBuffer; - CURLcode res; - CURL *curl = curl_easy_init(); - - if (curl) - { - string post = Username + ":" + Pass; - - struct curl_slist *headers = NULL; - headers = curl_slist_append(headers, "Depth: 1"); - curl_easy_setopt(curl, CURLOPT_URL, (_url + pathUrl).c_str()); - curl_easy_setopt(curl, CURLOPT_USERPWD, post.c_str()); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PROPFIND"); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Util::writeCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); - - if (iv_access(CACERT_PATH.c_str(), R_OK) == 0) - curl_easy_setopt(curl, CURLOPT_CAINFO, CACERT_PATH.c_str()); - else - Log::writeLog("could not find cacert"); - - res = curl_easy_perform(curl); - curl_easy_cleanup(curl); - - if (res == CURLE_OK) - { - long response_code; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); - - switch (response_code) - { - case 404: - Message(ICON_ERROR, "Error", "The URL seems to be incorrect. You can look up the WebDav URL in the files app under settings. ", 4000); - break; - case 401: - Message(ICON_ERROR, "Error", "Username/password incorrect.", 4000); - break; - case 207: - { - string localPath = this->getLocalPath(pathUrl); - - //create items_ - vector tempItems = readInXML(readBuffer); - if (tempItems.empty()) - return {}; - - if (iv_access(localPath.c_str(), W_OK) != 0) - { - //if the current folder does not exist locally, create it - iv_buildpath(localPath.c_str()); - } - else - { - //get items from local path - if (iv_access(localPath.c_str(), R_OK) != 0) - { - Log::writeLog("Local structure of " + localPath + " found."); - } - - getLocalFileStructure(tempItems, localPath); - } - - //update the .structure file acording to items in the folder - localPath = localPath + NEXTCLOUD_STRUCTURE_EXTENSION; - - //save xml to make the structure available offline - ofstream outFile(localPath); - if (outFile) - { - outFile << readBuffer; - Log::writeLog("Saved local copy of tree structure to " + localPath); - } - else - { - Log::writeLog(localPath + " Couldnt save copy of tree structure locally."); - } - - outFile.close(); - return tempItems; - } - default: - Message(ICON_ERROR, "Error", ("An unknown error occured. Switching to offline modus. To work online turn on online modus in the menu. (Curl Response Code " + std::to_string(response_code) + ")").c_str(), 4000); - _workOffline = true; - return getOfflineStructure(pathUrl); - } - } - else - { - string response = std::string("An error occured. (") + curl_easy_strerror(res) + " (Curl Error Code: " + std::to_string(res) + ")). Please try again."; - if(res == 60) - response = "Seems as if you are using Let's Encrypt Certs. Please follow the guide on Github (https://github.com/JuanJakobo/Pocketbook-Nextcloud-Client) to use a custom Cert Store on PB."; - Message(ICON_ERROR, "Error", response.c_str(), 4000); - } - } - return {}; -} - -//TODO Do generic? -//use boost xml -vector Nextcloud::readInXML(string xml) -{ - size_t begin; - size_t end; - string beginItem = ""; - string endItem = ""; - vector tempItems; - - begin = xml.find(beginItem); - - while (begin != std::string::npos) - { - end = xml.find(endItem); - - tempItems.push_back(xml.substr(begin, end)); - - xml = xml.substr(end + endItem.length()); - - begin = xml.find(beginItem); - } - - return tempItems; -} - -string Nextcloud::getLocalPath(string path) -{ - Util::decodeUrl(path); - if (path.find(NEXTCLOUD_ROOT_PATH) != string::npos) - path = path.substr(NEXTCLOUD_ROOT_PATH.length()); - - return NEXTCLOUD_FILE_PATH + "/" + path; -} - -vector Nextcloud::getOfflineStructure(const string &pathUrl) -{ - string localPath = this->getLocalPath(pathUrl) + NEXTCLOUD_STRUCTURE_EXTENSION; - if (iv_access(localPath.c_str(), W_OK) == 0) - { - ifstream inFile(localPath); - std::stringstream buffer; - buffer << inFile.rdbuf(); - - vector tempItems = readInXML(buffer.str()); - - if (tempItems.empty()) - return {}; - - getLocalFileStructure(tempItems, this->getLocalPath(pathUrl)); - return tempItems; - } - else - { - if (pathUrl.compare(NEXTCLOUD_ROOT_PATH + getUUID() + "/") == 0) - { - Message(ICON_ERROR, "Error", "The root structure is not available offline. Please try again to login.", 2000); - logout(); - } - else - { - //Structure is not available offline, stay at the tree - Message(ICON_ERROR, "Error", "The selected structure is not available offline.", 2000); - } - } - return {}; -} - -void Nextcloud::getLocalFileStructure(vector &tempItems, const string &localPath) -{ - //get local files, https://stackoverflow.com/questions/306533/how-do-i-get-a-list-of-files-in-a-directory-in-c - DIR *dir; - class dirent *ent; - class stat st; - - dir = opendir(localPath.c_str()); - while ((ent = readdir(dir)) != NULL) - { - const string fileName = ent->d_name; - const string fullFileName = localPath + fileName; - - if (fileName[0] == '.') - continue; - - if (stat(fullFileName.c_str(), &st) == -1) - continue; - - const bool isDirectory = (st.st_mode & S_IFDIR) != 0; - - bool found = false; - for (unsigned int i = 1; i < tempItems.size(); i++) - { - if (tempItems.at(i).getLocalPath().compare(fullFileName) == 0) - { - if (!isDirectory) - { - std::ifstream in(fullFileName, std::ifstream::binary | std::ifstream::ate); - Log::writeLog(tempItems.at(i).getTitle()); - Log::writeLog(std::to_string(in.tellg())); - Log::writeLog(std::to_string(tempItems.at(i).getSize())); - if (in.tellg() != tempItems.at(i).getSize()) - { - tempItems.at(i).setState(FileState::IOUTSYNCED); - } - } - found = true; - break; - } - } - if (!found) - { - if (isDirectory) - { - tempItems.push_back(Item(fullFileName, FileState::ILOCAL, Itemtype::IFOLDER)); - } - else - { - tempItems.push_back(Item(fullFileName, FileState::ILOCAL, Itemtype::IFILE)); - } - } - } - closedir(dir); -} diff --git a/src/util/nextcloud.h b/src/util/nextcloud.h deleted file mode 100644 index 5cbd046..0000000 --- a/src/util/nextcloud.h +++ /dev/null @@ -1,172 +0,0 @@ -//------------------------------------------------------------------ -// nextcloud.h -// -// Author: JuanJakobo -// Date: 04.08.2020 -// Description: Handles the userdata and issues, login and download of data structure for nextcloud WEBDAV -// -//------------------------------------------------------------------- - -#ifndef NEXTCLOUD -#define NEXTCLOUD - -#include "inkview.h" -#include "util.h" -#include "item.h" - -#include -#include -#include - -const std::string NEXTCLOUD_PATH = "/mnt/ext1/system/config/nextcloud"; -const std::string NEXTCLOUD_CONFIG_PATH = NEXTCLOUD_PATH + "/nextcloud.cfg"; -const std::string NEXTCLOUD_FILE_PATH = "/mnt/ext1/nextcloud"; -const std::string NEXTCLOUD_ROOT_PATH = "/remote.php/dav/files/"; -const std::string NEXTCLOUD_STRUCTURE_EXTENSION = ".structure"; -const std::string NEXTCLOUD_START_PATH = "/remote.php/"; -const std::string CACERT_PATH = "/mnt/ext1/applications/cacert.pem"; - -class Nextcloud -{ -public: - explicit Nextcloud(); - //TODO public? - void setURL(const std::string &Url) { Util::accessConfig(Action::IWriteString, "url", Url); }; - void setUsername(const std::string &Username) { Util::accessConfig(Action::IWriteString, "username", Username); }; - void setUUID(const std::string &UUID) { Util::accessConfig(Action::IWriteString, "UUID", UUID); }; - void setPassword(const std::string &Pass) { Util::accessConfig(Action::IWriteSecret, "password", Pass); }; - void setStartFolder(const std::string &Path) { Util::accessConfig(Action::IReadString, "startFolder", Path); }; - - std::string getUsername() { return Util::accessConfig(Action::IReadString, "username"); }; - - bool setItems(const std::vector &tempItems); - - const std::vector &getItems() const { return _items; }; - bool isLoggedIn() const { return _loggedIn; }; - bool isWorkOffline() const { return _workOffline; }; - void switchWorkOffline() { _workOffline = !_workOffline; }; - - /** - * Handles login by receiving userdat from config - * - * @return true - login succeeded, false - login failed - */ - bool login(); - - /** - * Handles first login to nextcloud, if sucessfull saves userdata - * - * @param Username the username of the Nextcloud instance - * @param Pass the pass of the Nextcloud instance - * @return true - login succeeded, false - login failed - */ - bool login(const std::string &Url, const std::string &Username, const std::string &Pass); - - /** - * Deletes the config files and deletes are temp files - * @param deleteFiles default false, true - local files are deleted, false local files are kept - */ - void logout(bool deleteFiles = false); - - /** - * Downloads a certain item from the Nextcloud and saves it locally - * @param tempItems set of items where the item is in - * @param itemID id of the item - */ - void downloadItem(std::vector &tempItems, int itemID); - - /** - * Downloads a certain folder from the Nextcloud and saves it locally - * @param tempItems set of items where the item is in - * @param itemID id of the item - */ - void downloadFolder(std::vector &tempItems, int itemId); - - /** - * Checks the network connection and starts the download of the certain itemId - * - * @param itemID id of the item that shall be downloaded - */ - void download(int itemID); - - /** - * Removes the item - * - * @param itemID id of the item that shall be removed - * @return bool true - success, false - failure - */ - bool removeItem(int itemID); - - /** - * gets the dataStructure of the given URL and writes its WEBDAV items to the items vector, reads Userdata from configfile - * - * @param pathUrl URL to get the dataStructure of - * @return vector of items - */ - std::vector getDataStructure(std::string &pathUrl); - - /** - * formats the pathUrl to a local path - * - * @param path online path - * @return local path - */ - static std::string getLocalPath(std::string path); - - /** - * checks the local storage checks if the items are locally available - * - * @param tempItems items that shall be compared - * @param localPath path that has to be checked - */ - void getLocalFileStructure(std::vector &tempItems, const std::string &localPath); - -private: - std::vector _items; - bool _loggedIn{false}; - std::string _url; - std::string _username; - std::string _password; - bool _workOffline{false}; - - /** - * gets the dataStructure of the given URL and writes its WEBDAV items to the items vector - * - * @param pathUrl URL to get the dataStructure of - * @param Username the username of the Nextcloud instance - * @param Pass the pass of the Nextcloud instance - * @return vector of Items - */ - std::vector getDataStructure(const std::string &pathUrl, const std::string &Username, const std::string &Pass); - - std::string getUrl() { return Util::accessConfig(Action::IReadString, "url"); }; - std::string getUUID() { return Util::accessConfig(Action::IReadString, "UUID"); }; - std::string getPassword() { return Util::accessConfig(Action::IReadSecret, "password"); }; - std::string getStartFolder() { return Util::accessConfig(Action::IReadString, "startFolder"); }; - - /** - * Handles the end of the game dialog and lets the user - * choose inbetween starting a new game or closing the app - * - * @param Button id of the button that was pressed - * @return void - */ - static void DialogHandlerStatic(int Button); - - /** - * Reads in the xml and creates a vector of items of it - * - * @param xml xml formatted result from curl call - * @return vector the items that have been read from the xml - */ - std::vector readInXML(std::string xml); - - /** - * Checks if a .structure file exists and if that is the case return a vector of items - * @param pathUrl path that shall be checked - * @return return the items for the structure if available offline - */ - std::vector getOfflineStructure(const std::string &pathUrl); -}; - -#endif \ No newline at end of file diff --git a/src/util/util.cpp b/src/util/util.cpp index a1745c6..f4df641 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -8,7 +8,6 @@ #include "util.h" #include "inkview.h" #include "log.h" -#include "nextcloud.h" #include #include @@ -54,12 +53,10 @@ bool Util::connectToNetwork() return false; } -//make template? - -string Util::accessConfig(const Action &action, const string &name, const string &value) +string Util::accessConfig(const string &path, const Action &action, const string &name, const string &value) { iconfigedit *temp = nullptr; - iconfig *config = OpenConfig(NEXTCLOUD_CONFIG_PATH.c_str(), temp); + iconfig *config = OpenConfig(path.c_str(), temp); string returnValue; switch (action) @@ -157,4 +154,4 @@ void Util::updatePBLibrary(int seconds) execlp(cmd.c_str(), cmd.c_str(), (char *)NULL); exit(1); } -} \ No newline at end of file +} diff --git a/src/util/util.h b/src/util/util.h index 2819930..7be4085 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -26,28 +26,28 @@ class Util public: /** * Handles the return of curl command - * + * */ static size_t writeCallback(void *contents, size_t size, size_t nmemb, void *userp); /** * Saves the return of curl command - * + * */ static size_t writeData(void *ptr, size_t size, size_t nmemb, FILE *stream); /** * Checks if a network connection can be established - * + * * @return true - network access succeeded, false - network access failed */ static bool connectToNetwork(); - //TODO Doku - static std::string accessConfig(const Action &action, const std::string &name, const std::string &value = std::string()); + static std::string accessConfig(const std::string &path, const Action &action, const std::string &name, const std::string &value = std::string()); + /** * Returns an integer representing the download progress - * + * */ static int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); @@ -58,18 +58,18 @@ public: /** * Decodes an URL - * + * * @param text text that shall be converted */ static void decodeUrl(std::string &text); - /** - * Updates the library of the Pocketbook - * - */ + /** + * Updates the library of the Pocketbook + * + */ static void updatePBLibrary(int seconds); private: Util() {} }; -#endif \ No newline at end of file +#endif