Warning, file /maui/mauikit-filebrowsing/src/code/syncing.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 #include "syncing.h" 0002 #include "fmstatic.h" 0003 0004 #include <QDir> 0005 #include <QEventLoop> 0006 #include <QFileInfo> 0007 #include <QTimer> 0008 #include <QDebug> 0009 0010 #include "WebDAVClient.hpp" 0011 #include "WebDAVItem.hpp" 0012 #include "WebDAVReply.hpp" 0013 0014 #include <KLocalizedString> 0015 0016 Syncing::Syncing(QObject *parent) : QObject(parent) 0017 { 0018 this->setCredentials(this->host, this->user, this->password); 0019 } 0020 0021 void Syncing::listContent(const QUrl &path, const QStringList &filters, const int &depth) 0022 { 0023 this->currentPath = path; 0024 0025 auto url = QUrl(path).path().replace(user, QStringLiteral("")); 0026 this->listDirOutputHandler(this->client->listDir(url, static_cast<ListDepthEnum>(depth)), filters); 0027 } 0028 0029 void Syncing::setCredentials(const QString &server, const QString &user, const QString &password) 0030 { 0031 this->host = server; 0032 this->user = user; 0033 this->password = password; 0034 0035 this->client = new WebDAVClient(this->host, this->user, this->password); 0036 } 0037 0038 void Syncing::listDirOutputHandler(WebDAVReply *reply, const QStringList &filters) 0039 { 0040 connect(reply, &WebDAVReply::listDirResponse, this, [=](QNetworkReply *, QList<WebDAVItem> items) { 0041 // qDebug() << "URL :" << listDirReply->url(); 0042 // qDebug() << "Received List of" << items.length() << "items"; 0043 // qDebug() << endl << "---------------------------------------"; 0044 FMH::MODEL_LIST list; 0045 for (WebDAVItem item : items) { 0046 const auto url = QUrl(item.getHref()).toString(); 0047 0048 QString path = QString(FMStatic::PATHTYPE_URI[FMStatic::PATHTYPE_KEY::CLOUD_PATH] + this->user + QStringLiteral("/")) + QString(url).replace(QStringLiteral("/remote.php/webdav/"), QStringLiteral("")); 0049 0050 auto displayName = item.getContentType().isEmpty() ? QString(url).replace(QStringLiteral("/remote.php/webdav/"), QStringLiteral("")).replace(QStringLiteral("/"), QStringLiteral("")) : QString(path).right(path.length() - path.lastIndexOf(QStringLiteral("/")) - 1); 0051 0052 // qDebug()<< "PATHS:" << path << this->currentPath; 0053 0054 if (QString(url).replace(QStringLiteral("/remote.php/webdav/"), QStringLiteral("")).isEmpty() || path == this->currentPath.toString()) 0055 continue; 0056 0057 // qDebug()<< "FILTERING "<< filters << QString(displayName).right(displayName.length() - displayName.lastIndexOf(".")); 0058 if (!filters.isEmpty() && !filters.contains(QStringLiteral("*") + QString(displayName).right(displayName.length() - displayName.lastIndexOf(QStringLiteral("."))))) 0059 continue; 0060 0061 list << FMH::MODEL {{FMH::MODEL_KEY::LABEL, displayName}, 0062 {FMH::MODEL_KEY::NAME, item.getDisplayName()}, 0063 {FMH::MODEL_KEY::DATE, item.getCreationDate().toString(Qt::TextDate)}, 0064 {FMH::MODEL_KEY::MODIFIED, item.getLastModified()}, 0065 {FMH::MODEL_KEY::MIME, item.getContentType().isEmpty() ? QStringLiteral("inode/directory") : item.getContentType()}, 0066 {FMH::MODEL_KEY::ICON, FMStatic::getIconName(QUrl(url))}, 0067 {FMH::MODEL_KEY::SIZE, QString::number(item.getContentLength())}, 0068 {FMH::MODEL_KEY::PATH, path}, 0069 {FMH::MODEL_KEY::URL, url}, 0070 {FMH::MODEL_KEY::THUMBNAIL, item.getContentType().isEmpty() ? url : this->getCacheFile(QUrl(url)).toString()}}; 0071 } 0072 Q_EMIT this->listReady(list, this->currentPath); 0073 }); 0074 connect(reply, &WebDAVReply::error, this, [=](QNetworkReply::NetworkError err) { 0075 // qDebug() << "ERROR" << err; 0076 this->emitError(err); 0077 }); 0078 } 0079 0080 QUrl Syncing::getCacheFile(const QUrl &path) 0081 { 0082 // const auto directory = FM::resolveUserCloudCachePath(this->host, this->user); 0083 const auto directory = QStringLiteral(""); 0084 const auto file = directory + path.toString().replace(QStringLiteral("remote.php/webdav/"), QStringLiteral("")); 0085 0086 qDebug() << "resolving file" << file; 0087 0088 if (FMH::fileExists(QUrl(file))) 0089 return QUrl(file); 0090 else 0091 return path; 0092 } 0093 0094 void Syncing::download(const QUrl &path) 0095 { 0096 QString url = QString(path.toString()).replace(QStringLiteral("remote.php/webdav/"), QStringLiteral("")); 0097 0098 WebDAVReply *reply = this->client->downloadFrom(url); 0099 qDebug() << "CURRENT CREDENTIALS" << this->host << this->user; 0100 connect(reply, &WebDAVReply::downloadResponse, this, [=](QNetworkReply *reply) 0101 { 0102 if (!reply->error()) 0103 { 0104 qDebug() << "\nDownload Success" 0105 << "\nURL :" << reply->url() << "\nSize :" << reply->size(); 0106 auto file = reply->readAll(); 0107 const auto directory = FMStatic::CloudCachePath + QStringLiteral("opendesktop/") + this->user; 0108 0109 QDir dir(directory); 0110 0111 if (!dir.exists()) 0112 dir.mkpath(QStringLiteral(".")); 0113 0114 this->saveTo(file, QUrl(directory + url)); 0115 } else { 0116 qDebug() << "ERROR(DOWNLOAD)" << reply->error() << reply->url() << url; 0117 Q_EMIT this->error(reply->errorString()); 0118 } 0119 }); 0120 0121 connect(reply, &WebDAVReply::downloadProgressResponse, this, [=](qint64 bytesReceived, qint64 bytesTotal) { 0122 int percent = ((float)bytesReceived / bytesTotal) * 100; 0123 0124 qDebug() << "\nReceived : " << bytesReceived << "\nTotal : " << bytesTotal << "\nPercent : " << percent; 0125 0126 Q_EMIT this->progress(percent); 0127 }); 0128 0129 connect(reply, &WebDAVReply::error, this, [=](QNetworkReply::NetworkError err) { 0130 qDebug() << "ERROR" << err; 0131 }); 0132 } 0133 0134 void Syncing::upload(const QUrl &path, const QUrl &filePath) 0135 { 0136 if (!FMH::fileExists(filePath)) 0137 return; 0138 0139 qDebug() << "Copy to cloud. File exists" << path << filePath; 0140 0141 this->mFile.setFileName(filePath.toString()); 0142 0143 if (this->mFile.open(QIODevice::ReadOnly)) { 0144 qDebug() << "Copy to cloud. File could be opened"; 0145 0146 WebDAVReply *reply = this->client->uploadTo(path.toString(), QFileInfo(filePath.toString()).fileName(), &this->mFile); 0147 0148 connect(reply, &WebDAVReply::uploadFinished, this, [=](QNetworkReply *reply) { 0149 if (!reply->error()) { 0150 qDebug() << "\nUpload Success" 0151 << "\nURL :" << reply->url() << "\nSize :" << reply->size(); 0152 0153 auto cachePath = this->saveToCache(filePath.toString(), path); 0154 0155 auto item = FMStatic::getFileInfoModel(QUrl(cachePath)); 0156 // item[FMH::MODEL_KEY::PATH] = this->currentPath+"/"+QFileInfo(filePath).fileName()+"/"; 0157 0158 Q_EMIT this->uploadReady(item, this->currentPath); 0159 } else { 0160 qDebug() << "ERROR(UPLOAD)" << reply->error(); 0161 Q_EMIT this->error(reply->errorString()); 0162 } 0163 0164 if (!this->uploadQueue.isEmpty()) { 0165 qDebug() << "UPLOAD QUEUE" << this->uploadQueue; 0166 this->upload(path, QUrl(this->uploadQueue.takeLast())); 0167 } 0168 }); 0169 0170 connect(reply, &WebDAVReply::error, this, [=](QNetworkReply::NetworkError err) { 0171 qDebug() << "ERROR" << err; 0172 this->emitError(err); 0173 }); 0174 } 0175 } 0176 0177 void Syncing::createDir(const QUrl &path, const QString &name) 0178 { 0179 WebDAVReply *reply = this->client->createDir(path.toString(), name); 0180 0181 connect(reply, &WebDAVReply::createDirFinished, this, [=](QNetworkReply *reply) { 0182 if (!reply->error()) { 0183 qDebug() << "\nDir Created" 0184 << "\nURL :" << reply->url(); 0185 FMH::MODEL dir = {{FMH::MODEL_KEY::LABEL, name}, 0186 {FMH::MODEL_KEY::DATE, QDateTime::currentDateTime().toString(Qt::TextDate)}, 0187 {FMH::MODEL_KEY::MIME, QStringLiteral("inode/directory")}, 0188 {FMH::MODEL_KEY::ICON, QStringLiteral("folder")}, 0189 {FMH::MODEL_KEY::PATH, this->currentPath.toString() + QStringLiteral("/") + name + QStringLiteral("/")}}; 0190 Q_EMIT this->dirCreated(dir, this->currentPath); 0191 } else { 0192 qDebug() << "ERROR(CREATE DIR)" << reply->error(); 0193 Q_EMIT this->error(reply->errorString()); 0194 } 0195 }); 0196 0197 connect(reply, &WebDAVReply::error, this, [=](QNetworkReply::NetworkError err) { 0198 qDebug() << "ERROR" << err; 0199 this->emitError(err); 0200 }); 0201 } 0202 0203 void Syncing::emitError(const QNetworkReply::NetworkError &err) 0204 { 0205 switch (err) { 0206 case QNetworkReply::AuthenticationRequiredError: 0207 Q_EMIT this->error(i18n("The remote server requires authentication to serve the content but the credentials provided were not accepted (if any)")); 0208 break; 0209 0210 case QNetworkReply::ConnectionRefusedError: 0211 Q_EMIT this->error(i18n("the remote server refused the connection (the server is not accepting requests")); 0212 break; 0213 0214 case QNetworkReply::RemoteHostClosedError: 0215 Q_EMIT this->error(i18n("the remote server closed the connection prematurely, before the entire reply was received and processed")); 0216 break; 0217 0218 case QNetworkReply::HostNotFoundError: 0219 Q_EMIT this->error(i18n("the remote host name was not found (invalid hostname)")); 0220 break; 0221 0222 case QNetworkReply::TimeoutError: 0223 Q_EMIT this->error(i18n("the connection to the remote server timed out")); 0224 break; 0225 0226 case QNetworkReply::OperationCanceledError: 0227 Q_EMIT this->error(i18n("the operation was canceled via calls to abort() or close() before it was finished.")); 0228 break; 0229 0230 case QNetworkReply::SslHandshakeFailedError: 0231 Q_EMIT this->error(i18n("the SSL/TLS handshake failed and the encrypted channel could not be established. The sslErrors() signal should have been emitted.")); 0232 break; 0233 0234 case QNetworkReply::TemporaryNetworkFailureError: 0235 Q_EMIT this->error( 0236 i18n("the connection was broken due to disconnection from the network, however the system has initiated roaming to another access point. The request should be resubmitted and will be processed as soon as the connection is re-established.")); 0237 break; 0238 0239 case QNetworkReply::NetworkSessionFailedError: 0240 Q_EMIT this->error(i18n("the connection was broken due to disconnection from the network or failure to start the network.")); 0241 break; 0242 0243 case QNetworkReply::BackgroundRequestNotAllowedError: 0244 Q_EMIT this->error(i18n("the background request is not currently allowed due to platform policy.")); 0245 break; 0246 0247 case QNetworkReply::TooManyRedirectsError: 0248 Q_EMIT this->error(i18n("while following redirects, the maximum limit was reached. The limit is by default set to 50 or as set by QNetworkRequest::setMaxRedirectsAllowed(). (This value was introduced in 5.6.)")); 0249 break; 0250 0251 case QNetworkReply::InsecureRedirectError: 0252 Q_EMIT this->error(i18n("while following redirects, the network access API detected a redirect from a encrypted protocol (https) to an unencrypted one (http).")); 0253 break; 0254 0255 case QNetworkReply::ProxyConnectionRefusedError: 0256 Q_EMIT this->error(i18n("the connection to the proxy server was refused (the proxy server is not accepting requests)")); 0257 break; 0258 0259 case QNetworkReply::ProxyConnectionClosedError: 0260 Q_EMIT this->error(i18n("the proxy server closed the connection prematurely, before the entire reply was received and processed")); 0261 break; 0262 0263 case QNetworkReply::ProxyNotFoundError: 0264 Q_EMIT this->error(i18n("the proxy host name was not found (invalid proxy hostname)")); 0265 break; 0266 0267 case QNetworkReply::ProxyTimeoutError: 0268 Q_EMIT this->error(i18n("the connection to the proxy timed out or the proxy did not reply in time to the request sent")); 0269 break; 0270 0271 case QNetworkReply::ProxyAuthenticationRequiredError: 0272 Q_EMIT this->error(i18n("the proxy requires authentication in order to honour the request but did not accept any credentials offered (if any)")); 0273 break; 0274 0275 case QNetworkReply::ContentAccessDenied: 0276 Q_EMIT this->error(i18n("the access to the remote content was denied (similar to HTTP error 403)")); 0277 break; 0278 0279 case QNetworkReply::ContentOperationNotPermittedError: 0280 Q_EMIT this->error(i18n("the operation requested on the remote content is not permitted")); 0281 break; 0282 0283 case QNetworkReply::ContentNotFoundError: 0284 Q_EMIT this->error(i18n("the remote content was not found at the server (similar to HTTP error 404)")); 0285 break; 0286 0287 case QNetworkReply::ContentReSendError: 0288 Q_EMIT this->error(i18n("the request needed to be sent again, but this failed for example because the upload data could not be read a second time.")); 0289 break; 0290 0291 case QNetworkReply::ServiceUnavailableError: 0292 Q_EMIT this->error(i18n("the server is unable to handle the request at this time.")); 0293 break; 0294 0295 default: 0296 Q_EMIT this->error(i18n("There was an unknown error with the remote server or your internet connection.")); 0297 } 0298 } 0299 0300 void Syncing::saveTo(const QByteArray &array, const QUrl &path) 0301 { 0302 QFile file(path.toLocalFile()); 0303 0304 if (!file.exists()) { 0305 QDir dir; 0306 uint cut = path.toString().length() - path.toString().lastIndexOf(QStringLiteral("/")) - 1; 0307 auto newPath = path.toString().right(cut); 0308 dir.mkdir(path.toString().replace(newPath, QStringLiteral(""))); 0309 qDebug() << newPath << cut; 0310 0311 } else 0312 file.remove(); 0313 0314 file.open(QIODevice::WriteOnly); 0315 file.write(array); 0316 file.close(); 0317 0318 Q_EMIT this->itemReady(FMStatic::getFileInfoModel(path), this->currentPath, this->signalType); 0319 // Q_EMIT this->itemReady(FMH::getFileInfoModel(path)); 0320 } 0321 0322 QString Syncing::saveToCache(const QString &file, const QUrl &where) 0323 { 0324 const auto directory = FMStatic::CloudCachePath + QStringLiteral("opendesktop/") + this->user + QStringLiteral("/") + where.toString(); 0325 0326 QDir dir(directory); 0327 0328 if (!dir.exists()) 0329 dir.mkpath(QStringLiteral(".")); 0330 0331 const auto newPath = directory + QStringLiteral("/") + QFileInfo(file).fileName(); 0332 0333 if (QFile::copy(file, newPath)) 0334 return newPath; 0335 0336 return QString(); 0337 } 0338 0339 void Syncing::resolveFile(const FMH::MODEL &item, const Syncing::SIGNAL_TYPE &signalType) 0340 { 0341 this->signalType = signalType; 0342 0343 const auto url = item[FMH::MODEL_KEY::URL]; 0344 const auto file = this->getCacheFile(QUrl(url)); 0345 0346 if (FMH::fileExists(file)) { 0347 const auto cacheFile = FMStatic::getFileInfoModel(file); 0348 0349 const auto dateCacheFile = QDateTime::fromString(cacheFile[FMH::MODEL_KEY::DATE], Qt::TextDate); 0350 const auto dateCloudFile = QDateTime::fromString(QString(item[FMH::MODEL_KEY::MODIFIED]).replace(QStringLiteral("GMT"), QStringLiteral("")).simplified(), QStringLiteral("ddd, dd MMM yyyy hh:mm:ss")); 0351 0352 qDebug() << "FILE EXISTS ON CACHE" << dateCacheFile << dateCloudFile << QString(item[FMH::MODEL_KEY::MODIFIED]).replace(QStringLiteral("GMT"), QStringLiteral("")).simplified() << file; 0353 0354 if (dateCloudFile > dateCacheFile) 0355 this->download(QUrl(url)); 0356 else 0357 Q_EMIT this->itemReady(cacheFile, this->currentPath, this->signalType); 0358 0359 } else 0360 this->download(QUrl(url)); 0361 } 0362 0363 void Syncing::setCopyTo(const QUrl &path) 0364 { 0365 if (this->copyTo == path) 0366 return; 0367 0368 this->copyTo = path; 0369 } 0370 0371 QUrl Syncing::getCopyTo() const 0372 { 0373 return this->copyTo; 0374 } 0375 0376 QString Syncing::getUser() const 0377 { 0378 return this->user; 0379 } 0380 0381 void Syncing::setUploadQueue(const QStringList &list) 0382 { 0383 this->uploadQueue = list; 0384 } 0385 0386 QString Syncing::localToAbstractCloudPath(const QString &url) 0387 { 0388 return QString(url).replace(FMStatic::CloudCachePath + QStringLiteral("opendesktop"), FMStatic::PATHTYPE_URI[FMStatic::PATHTYPE_KEY::CLOUD_PATH]); 0389 }