aheinecke@10: #include "downloader.h" aheinecke@10: aheinecke@10: #ifndef DOWNLOAD_SERVER aheinecke@10: #define DOWNLOAD_SERVER "https://www.intevation.de" aheinecke@10: #endif aheinecke@10: aheinecke@10: #include aheinecke@15: #include aheinecke@10: #include aheinecke@15: #include andre@32: #include andre@32: #include andre@32: #include andre@27: andre@27: #include andre@27: #include andre@27: #include andre@27: #include andre@27: #include andre@27: #include andre@27: andre@27: #define MAX_SW_SIZE 10485760 andre@27: #define MAX_LIST_SIZE 1048576 andre@32: andre@32: #define LIST_RESOURCE "/incoming/aheinecke/test" andre@32: #define SW_RESOURCE "/incoming/aheinecke/test" andre@32: aheinecke@10: aheinecke@15: Downloader::Downloader(QObject* parent, const QString& url, aheinecke@15: const QByteArray& certificate, aheinecke@15: const QDateTime& newestSW, aheinecke@45: const QDateTime& newestList, aheinecke@45: const QString& resourceSW, aheinecke@45: const QString& resourceList): aheinecke@12: QThread(parent), aheinecke@15: mLastModSW(newestSW), andre@27: mLastModList(newestList), aheinecke@45: mResourceSW(resourceSW), aheinecke@45: mResourceList(resourceList), aheinecke@45: mSSLConnection(url, certificate) aheinecke@10: { andre@27: } andre@27: andre@27: andre@27: Downloader::~Downloader() { aheinecke@10: } aheinecke@10: aheinecke@15: QString Downloader::getDataDirectory() aheinecke@10: { aheinecke@15: QString candidate = aheinecke@15: QStandardPaths::writableLocation(QStandardPaths::DataLocation); aheinecke@12: aheinecke@15: if (candidate.isEmpty()) { aheinecke@15: qDebug() << "Could not find writeable locaction for me"; aheinecke@15: return QString(); aheinecke@15: } aheinecke@15: aheinecke@15: QDir cDir(candidate); aheinecke@15: aheinecke@15: if (!cDir.exists()) { aheinecke@15: if (!cDir.mkpath(candidate)) { aheinecke@15: qDebug() << "Could not create path to: " << candidate; aheinecke@15: return QString(); aheinecke@15: } aheinecke@15: } aheinecke@15: return cDir.absolutePath(); aheinecke@10: } andre@27: andre@32: andre@32: QDateTime Downloader::getLastModifiedHeader(const QString &resource) { andre@32: int ret = -1; andre@32: QByteArray response; andre@32: QTextStream responseStream(&response); andre@32: QLocale cLocale = QLocale::c(); andre@32: QString headRequest = andre@32: QString::fromLatin1("HEAD %1 HTTP/1.1\r\n" andre@32: "Connection: Keep-Alive\r\n" andre@32: "\r\n\r\n").arg(resource); andre@32: aheinecke@45: ret = mSSLConnection.write(headRequest.toUtf8()); andre@32: if (ret != 0) { aheinecke@45: emit error (tr("Connection lost"), SSLConnection::ConnectionLost); andre@32: return QDateTime(); andre@32: } andre@32: aheinecke@45: response = mSSLConnection.read(1024); andre@32: andre@32: if (response.isNull()) { andre@32: qDebug() << "No response"; aheinecke@45: emit error (tr("Connection lost"), SSLConnection::ConnectionLost); andre@32: return QDateTime(); andre@32: } andre@32: andre@32: while (1) { andre@32: QString line = responseStream.readLine(); andre@32: if (line.isNull()) { andre@32: break; andre@32: } andre@32: if (line.startsWith("Last-Modified:")) { andre@32: QDateTime candidate = cLocale.toDateTime(line, "'Last-Modified: 'ddd, dd MMM yyyy HH:mm:ss' GMT'"); andre@32: qDebug() << "Parsed line : " << line << " to " << candidate; andre@32: if (candidate.isValid()) { andre@32: return candidate; andre@32: } andre@32: } andre@32: } andre@32: aheinecke@45: emit error (tr("Invalid response from the server"), SSLConnection::InvalidResponse); andre@32: return QDateTime(); andre@32: } andre@32: andre@32: bool Downloader::downloadFile(const QString &resource, andre@32: const QString &fileName, andre@32: size_t maxSize) andre@32: { andre@32: int ret = -1; andre@32: size_t bytesRead = 0; andre@32: QString getRequest = andre@32: QString::fromLatin1("GET %1 HTTP/1.1\r\n\r\n").arg(resource); andre@32: andre@32: QSaveFile outputFile(fileName); andre@32: aheinecke@45: ret = mSSLConnection.write(getRequest.toUtf8()); andre@32: andre@32: // Open / Create the file to write to. andre@32: if (!outputFile.open(QIODevice::WriteOnly)) { andre@32: qDebug() << "Failed to open file"; andre@32: return false; andre@32: } andre@32: andre@32: if (ret != 0) { aheinecke@45: emit error(tr("Connection lost"), SSLConnection::ConnectionLost); andre@32: return false; andre@32: } andre@32: andre@32: do { aheinecke@45: QByteArray response = mSSLConnection.read(8192); andre@32: if (response.isNull()) { andre@32: qDebug() << "Error reading response"; aheinecke@45: emit error(tr("Connection lost"), SSLConnection::ConnectionLost); andre@32: return false; andre@32: } andre@32: if (response.isEmpty()) { andre@32: /* We have read everything there is to read */ andre@32: break; andre@32: } andre@32: andre@32: outputFile.write(response); andre@32: bytesRead += response.size(); andre@32: } while (bytesRead < maxSize); andre@32: andre@32: return outputFile.commit(); andre@32: } andre@27: andre@27: void Downloader::run() { andre@27: int ret; andre@32: QDateTime remoteModList; andre@32: QDateTime remoteModSW; andre@27: aheinecke@45: if (!mSSLConnection.initialized()) { aheinecke@45: emit error(tr("Failed to initialize SSL Module."), SSLConnection::ErrUnknown); andre@27: return; andre@27: } andre@27: aheinecke@45: ret = mSSLConnection.connect(); andre@32: andre@27: if (ret != 0) { aheinecke@45: emit error(tr("Failed to connect."), aheinecke@45: mSSLConnection.getLastError()); andre@27: return; andre@27: } andre@27: andre@27: emit progress(tr("Connected"), 1, -1); andre@27: aheinecke@45: remoteModSW = getLastModifiedHeader(mResourceSW); aheinecke@45: remoteModList = getLastModifiedHeader(mResourceList); andre@32: andre@32: if (!remoteModSW.isValid() || !remoteModList.isValid()) { andre@32: qDebug() << "Could not read headers"; andre@32: return; andre@32: } andre@32: andre@32: if (!mLastModSW.isValid() || remoteModSW > mLastModSW) { andre@32: QString dataDirectory = getDataDirectory(); andre@32: andre@32: if (dataDirectory.isEmpty()) { andre@32: qDebug() << "Failed to get data directory"; andre@32: return; andre@32: } andre@32: andre@32: QString fileName = dataDirectory.append("/SW-") andre@32: .append(remoteModSW.toString("yyyymmddHHmmss")) andre@32: .append(".exe"); andre@32: andre@32: qDebug() << "fileName: " << fileName; andre@32: andre@32: if (!downloadFile(QString::fromLatin1(SW_RESOURCE), andre@32: fileName, MAX_SW_SIZE)) { andre@32: return; andre@32: } andre@32: andre@32: emit newSoftwareAvailable(fileName, remoteModSW); andre@32: } else if (!mLastModList.isValid() || remoteModList > mLastModList) { andre@32: QString dataDirectory = getDataDirectory(); andre@32: andre@32: if (dataDirectory.isEmpty()) { andre@32: qDebug() << "Failed to get data directory"; andre@32: return; andre@32: } andre@32: andre@32: QString fileName = dataDirectory.append("/list-") andre@32: .append(remoteModSW.toString("yyyymmddHHmmss")) andre@32: .append(".txt"); andre@32: andre@32: qDebug() << "fileName: " << fileName; andre@32: andre@32: if (!downloadFile(QString::fromLatin1(LIST_RESOURCE), andre@32: fileName, MAX_LIST_SIZE)) { andre@32: return; andre@32: } andre@32: andre@32: emit newListAvailable(fileName, remoteModList); andre@32: } andre@27: andre@27: emit progress(tr("Closing"), 1, -1); andre@27: }