replace nextcloud and item classes
parent
e87ddf534b
commit
8531df2c0a
|
@ -52,8 +52,6 @@ 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/listView.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/listView/listViewEntry.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ui/webDAVView/webDAVView.cpp
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Author: JuanJakobo
|
||||
// Date: 23.04.2021
|
||||
// Description:
|
||||
// Description: Base model
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
#ifndef MODEL
|
||||
|
|
|
@ -10,10 +10,13 @@
|
|||
#include "webDAV.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "eventHandler.h"
|
||||
|
||||
#include <string>
|
||||
#include <curl/curl.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <math.h>
|
||||
|
||||
using std::ifstream;
|
||||
using std::ofstream;
|
||||
|
@ -27,24 +30,84 @@ WebDAV::WebDAV()
|
|||
//TODO update on first login only start and create update button, update others just if etag changed
|
||||
//save all to sqlite
|
||||
|
||||
Log::writeInfoLog(NEXTCLOUD_PATH);
|
||||
if (iv_access(NEXTCLOUD_PATH.c_str(), W_OK) != 0)
|
||||
iv_mkdir(NEXTCLOUD_PATH.c_str(), 0777);
|
||||
|
||||
Log::writeInfoLog(NEXTCLOUD_FILE_PATH);
|
||||
if (iv_access(NEXTCLOUD_FILE_PATH.c_str(), W_OK) != 0)
|
||||
iv_mkdir(NEXTCLOUD_FILE_PATH.c_str(), 0777);
|
||||
|
||||
Log::writeInfoLog(CONFIG_PATH);
|
||||
if (iv_access(CONFIG_PATH.c_str(), W_OK) == 0)
|
||||
{
|
||||
_username = Util::accessConfig(Action::IReadString,"username");
|
||||
_password = Util::accessConfig(Action::IReadSecret,"password");
|
||||
_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 is just getDatastructure?
|
||||
bool Nextcloud::login()
|
||||
{
|
||||
string tempPath = getStartFolder();
|
||||
|
||||
if (tempPath.empty())
|
||||
tempPath = NEXTCLOUD_ROOT_PATH + this->getUUID() + "/";
|
||||
|
||||
if (setItems(getDataStructure(tempPath)))
|
||||
{
|
||||
_loggedIn = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(_username.empty())
|
||||
Log::writeErrorLog("username not set");
|
||||
//test login
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
//TODO pass in vector and change that one?
|
||||
std::vector<WebDAVItem> 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<WebDAVItem> 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);
|
||||
Util::accessConfig(CONFIG_PATH, Action::IWriteString, "startFolder", tempPath);
|
||||
}
|
||||
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?
|
||||
//_items.clear();
|
||||
}
|
||||
|
||||
//TODO pas as reversne and no return
|
||||
|
@ -61,6 +124,18 @@ string WebDAV::getLocalPath(string path)
|
|||
///TODO rename function
|
||||
vector<WebDAVItem> WebDAV::getDataStructure(const string &pathUrl)
|
||||
{
|
||||
/*
|
||||
*TODO resize item one and make clickable, what to do with the start?
|
||||
//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());
|
||||
*/
|
||||
string xmlItem = propfind(pathUrl);
|
||||
if(!xmlItem.empty())
|
||||
{
|
||||
|
@ -82,7 +157,37 @@ vector<WebDAVItem> WebDAV::getDataStructure(const string &pathUrl)
|
|||
tempItem.etag = Util::getXMLAttribute(xmlItem, "d:getetag");
|
||||
tempItem.path = Util::getXMLAttribute(xmlItem, "d:href");
|
||||
tempItem.lastEditDate = Util::getXMLAttribute(xmlItem, "d:getlastmodified");
|
||||
tempItem.size = atof(Util::getXMLAttribute(xmlItem, "oc:size").c_str());
|
||||
|
||||
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));
|
||||
|
@ -132,25 +237,119 @@ vector<WebDAVItem> WebDAV::getDataStructure(const string &pathUrl)
|
|||
return {};
|
||||
//TODO return empty items?
|
||||
}
|
||||
/*
|
||||
void Nextcloud::downloadFolder(vector<Item> &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<Item> 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(_items, itemID);
|
||||
|
||||
UpdateProgressbar("Download completed", 100);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
string WebDAV::propfind(const string &pathUrl)
|
||||
{
|
||||
/*
|
||||
string localPath = getLocalPath(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);
|
||||
_workOffline = true;
|
||||
return getOfflineStructure(pathUrl);
|
||||
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
|
||||
|
||||
if (_url.empty())
|
||||
_url = this->getUrl();
|
||||
//can handle multiple etags --> * if exists
|
||||
|
||||
*/
|
||||
|
||||
auto _url = Util::accessConfig(Action::IReadString, "url");
|
||||
|
||||
string readBuffer;
|
||||
CURLcode res;
|
||||
|
@ -159,12 +358,11 @@ string WebDAV::propfind(const string &pathUrl)
|
|||
if (curl)
|
||||
{
|
||||
string post = _username + ":" + _password;
|
||||
Log::writeInfoLog(post);
|
||||
Log::writeInfoLog(_url + NEXTCLOUD_ROOT_PATH + pathUrl);
|
||||
Log::writeInfoLog(_url + pathUrl);
|
||||
|
||||
struct curl_slist *headers = NULL;
|
||||
headers = curl_slist_append(headers, "Depth: 1");
|
||||
curl_easy_setopt(curl, CURLOPT_URL, (_url + NEXTCLOUD_ROOT_PATH + pathUrl).c_str());
|
||||
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");
|
||||
|
@ -212,3 +410,77 @@ string WebDAV::propfind(const string &pathUrl)
|
|||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
void WebDAV::get(vector<Item> &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);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -11,17 +11,16 @@
|
|||
#define WEBDAV
|
||||
|
||||
#include "webDAVModel.h"
|
||||
#include "eventHandler.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
const std::string CONFIG_PATH = CONFIG_FOLDER + "/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";
|
||||
//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
|
||||
{
|
||||
|
@ -32,6 +31,10 @@ class WebDAV
|
|||
*/
|
||||
WebDAV();
|
||||
|
||||
std::vector<WebDAVItem> 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<WebDAVItem> getDataStructure(const std::string &pathUrl);
|
||||
|
@ -45,12 +48,12 @@ class WebDAV
|
|||
* @param Pass the pass of the Nextcloud instance
|
||||
* @return vector of Items
|
||||
*/
|
||||
//TODO return xml argument?h
|
||||
std::string propfind(const std::string &pathUrl);
|
||||
|
||||
private:
|
||||
std::string _username;
|
||||
std::string _password;
|
||||
std::string _url;
|
||||
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include "contextMenu.h"
|
||||
#include "mainMenu.h"
|
||||
#include "nextcloud.h"
|
||||
#include "webDAVView.h"
|
||||
#include "loginView.h"
|
||||
#include "sqliteConnector.h"
|
||||
|
@ -19,6 +18,7 @@
|
|||
#include <memory>
|
||||
|
||||
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";
|
||||
|
||||
|
|
|
@ -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 <math.h>
|
||||
#include <string>
|
||||
#include <curl/curl.h>
|
||||
|
||||
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;
|
||||
}
|
100
src/util/item.h
100
src/util/item.h
|
@ -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 <string>
|
||||
|
||||
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
|
|
@ -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 <string>
|
||||
#include <curl/curl.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
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<Item> &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<Item> &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<Item> &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<Item> 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<Item> Nextcloud::getDataStructure(string &pathUrl)
|
||||
{
|
||||
return getDataStructure(pathUrl, this->getUsername(), this->getPassword());
|
||||
}
|
||||
|
||||
vector<Item> 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<Item> 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<Item> Nextcloud::readInXML(string xml)
|
||||
{
|
||||
size_t begin;
|
||||
size_t end;
|
||||
string beginItem = "<d:response>";
|
||||
string endItem = "</d:response>";
|
||||
vector<Item> 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<Item> 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<Item> 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<Item> &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);
|
||||
}
|
|
@ -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 <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
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<Item> &tempItems);
|
||||
|
||||
const std::vector<Item> &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<Item> &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<Item> &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<Item> 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<Item> &tempItems, const std::string &localPath);
|
||||
|
||||
private:
|
||||
std::vector<Item> _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<Item> 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<Item> the items that have been read from the xml
|
||||
*/
|
||||
std::vector<Item> 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<Item> getOfflineStructure(const std::string &pathUrl);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue