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 }