Mercurial > trustbridge
view ui/downloader.cpp @ 285:f23e0ccd5d14
Fix call to windows process.
This now uses the correct parameters, emits the signals
correctly as errors and waits for the process to finish instead
of relying on NOASYNC which did not work for runas and also
made it impossible to get the return code
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Wed, 02 Apr 2014 13:45:57 +0000 |
parents | 63b79d135631 |
children | 17e1c8f37d72 |
line wrap: on
line source
#include "downloader.h" #ifndef DOWNLOAD_SERVER #define DOWNLOAD_SERVER "https://www.intevation.de" #endif #include <QFile> #include <QDir> #include <QDebug> #include <QStandardPaths> #include <QLocale> #include <QSaveFile> #include <polarssl/net.h> #include <polarssl/ssl.h> #include <polarssl/entropy.h> #include <polarssl/ctr_drbg.h> #include <polarssl/error.h> #include <polarssl/certs.h> #define MAX_SW_SIZE 10485760 #define MAX_LIST_SIZE 1048576 Downloader::Downloader(QObject* parent, const QString& url, const QByteArray& certificate, const QDateTime& newestSW, const QDateTime& newestList, const QString& resourceSW, const QString& resourceList): QThread(parent), mLastModSW(newestSW), mLastModList(newestList), mResourceSW(resourceSW), mResourceList(resourceList), mSSLConnection(url, certificate) { } Downloader::~Downloader() { } QString Downloader::getDataDirectory() { QString candidate = QStandardPaths::writableLocation(QStandardPaths::DataLocation); if (candidate.isEmpty()) { qDebug() << "Could not find writeable locaction for me"; return QString(); } QDir cDir(candidate); if (!cDir.exists()) { if (!cDir.mkpath(candidate)) { qDebug() << "Could not create path to: " << candidate; return QString(); } } return cDir.absolutePath(); } QMap<QString, QString> Downloader::parseHeaders(QByteArray *data) { int bodyStart = data->indexOf("\r\n\r\n"); QMap<QString, QString> retval; QByteArray headers; QString response(*data); if (bodyStart == -1) { qDebug() << "Could not find header end."; emit error(tr("Invalid response"), SSLConnection::InvalidResponse); return retval; } /* Take the headers with one additional line break */ headers = data->left(bodyStart + 2); /* Chop off the head */ foreach (const QString& line, response.split("\r\n")) { int sepPos = -1; sepPos = line.indexOf(": "); if (sepPos == -1) { continue; } QString key = line.left(sepPos); QString value = line.right(line.size() - sepPos - 2); retval.insert(key, value); } *data = data->right(data->size() - bodyStart - 4); return retval; } QDateTime Downloader::getLastModifiedHeader(const QString &resource) { int ret = -1; QByteArray response; QLocale cLocale = QLocale::c(); QMap<QString, QString> headers; QString headRequest = QString::fromLatin1("HEAD %1 HTTP/1.0\r\n\r\n").arg(resource); ret = mSSLConnection.write(headRequest.toUtf8()); if (ret != 0) { emit error (tr("Connection lost"), SSLConnection::ConnectionLost); return QDateTime(); } response = mSSLConnection.read(1024); if (response.isNull()) { qDebug() << "No response"; emit error (tr("Connection lost"), SSLConnection::ConnectionLost); return QDateTime(); } headers = parseHeaders(&response); const QString lastModified = headers.value("Last-Modified"); qDebug() << "Headers: " << headers; if (!lastModified.isEmpty()) { QDateTime candidate = cLocale.toDateTime(lastModified, "ddd, dd MMM yyyy HH:mm:ss' GMT'"); if (candidate.isValid()) { return candidate; } } emit error (tr("Invalid response from the server"), SSLConnection::InvalidResponse); qDebug() << "Response from server was: " << response; return QDateTime(); } bool Downloader::downloadFile(const QString &resource, const QString &fileName, size_t maxSize) { int ret = -1; size_t bytesRead = 0; QString getRequest = QString::fromLatin1("GET %1 HTTP/1.0\r\n\r\n").arg(resource); QSaveFile outputFile(fileName); ret = mSSLConnection.write(getRequest.toUtf8()); // Open / Create the file to write to. if (!outputFile.open(QIODevice::WriteOnly)) { qDebug() << "Failed to open file"; return false; } if (ret != 0) { emit error(tr("Connection lost"), SSLConnection::ConnectionLost); return false; } bool inBody = false; QMap <QString, QString> headers; do { /* Read the response in 8KiB chunks */ int responseSize = 0; QByteArray response = mSSLConnection.read(8192); if (response.isNull()) { qDebug() << "Error reading response"; emit error(tr("Connection lost"), SSLConnection::ConnectionLost); return false; } responseSize = response.size(); if (!inBody) { headers = parseHeaders(&response); inBody = true; } outputFile.write(response); bytesRead += responseSize; if (responseSize < 8192) { /* Nothing more to read */ break; } /* TODO Emit progress */ } while (bytesRead < maxSize); return outputFile.commit(); } void Downloader::run() { int ret; QDateTime remoteModList; QDateTime remoteModSW; if (!mSSLConnection.initialized()) { emit error(tr("Failed to initialize SSL Module."), SSLConnection::ErrUnknown); return; } ret = mSSLConnection.connect(); if (ret != 0) { emit error(tr("Failed to connect."), mSSLConnection.getLastError()); return; } emit progress(tr("Connected"), 1, -1); remoteModSW = getLastModifiedHeader(mResourceSW); remoteModList = getLastModifiedHeader(mResourceList); if (!remoteModSW.isValid() || !remoteModList.isValid()) { qDebug() << "Could not parse headers"; return; } if (!mLastModSW.isValid() || remoteModSW > mLastModSW) { QString dataDirectory = getDataDirectory(); if (dataDirectory.isEmpty()) { qDebug() << "Failed to get data directory"; return; } QString fileName = dataDirectory.append("/SW-") .append(remoteModSW.toString("yyyymmddHHmmss")) .append(".exe"); qDebug() << "fileName: " << fileName; if (!downloadFile(mResourceSW, fileName, MAX_SW_SIZE)) { return; } emit newSoftwareAvailable(fileName, remoteModSW); } else if (!mLastModList.isValid() || remoteModList > mLastModList) { QString dataDirectory = getDataDirectory(); if (dataDirectory.isEmpty()) { qDebug() << "Failed to get data directory"; return; } QString fileName = dataDirectory.append("/list-") .append(remoteModSW.toString("yyyymmddHHmmss")) .append(".txt"); qDebug() << "fileName: " << fileName; if (!downloadFile(mResourceList, fileName, MAX_LIST_SIZE)) { return; } emit newListAvailable(fileName, remoteModList); } emit progress(tr("Closing"), 1, -1); }