changeset 11:7e2f14c7aba2

Split up downloader component and further implement it
author Andre Heinecke <aheinecke@intevation.de>
date Fri, 14 Feb 2014 11:20:15 +0000
parents fe39d93f1261
children 9121eea6d93f
files CMakeLists.txt ui/downloader.cpp ui/downloader_linux.cpp ui/downloader_win.cpp ui/mainwindow.cpp
diffstat 5 files changed, 281 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Thu Feb 13 14:43:15 2014 +0000
+++ b/CMakeLists.txt	Fri Feb 14 11:20:15 2014 +0000
@@ -20,6 +20,9 @@
 set(M13UI_SOURCES
     ${CMAKE_SOURCE_DIR}/ui/mainwindow.cpp
     ${CMAKE_SOURCE_DIR}/ui/certificatelist.cpp
+    ${CMAKE_SOURCE_DIR}/ui/downloader.cpp
+    ${CMAKE_SOURCE_DIR}/ui/downloader_win.cpp
+    ${CMAKE_SOURCE_DIR}/ui/downloader_linux.cpp
     ${CMAKE_SOURCE_DIR}/ui/listutil.c
 )
 
@@ -67,7 +70,8 @@
         -lQt5PlatformSupport -lQt5Gui -lcomdlg32 -loleaut32 -limm32 -lwinmm
         -lglu32 -lopengl32 -lgdi32 -ljpeg -lpng -lQt5Core -lole32 -luuid -lws2_32
         -ladvapi32 -lshell32 -luser32 -lkernel32 -lz -lsicuin -lsicuuc -lsicudt -lpcre16)
-   set(EXTRA_STATIC_LIBS Qt5::QWindowsIntegrationPlugin ${WINDOWS_EXTRA_LIBS})
+
+   set(EXTRA_STATIC_LIBS Qt5::QWindowsIntegrationPlugin ${WINDOWS_EXTRA_LIBS} -lwinhttp)
 
    set(HARDENING_FLAGS " ${HARDENING_FLAGS} -Wl,--dynamicbase -Wl,--nxcompat")
 endif()
--- a/ui/downloader.cpp	Thu Feb 13 14:43:15 2014 +0000
+++ b/ui/downloader.cpp	Fri Feb 14 11:20:15 2014 +0000
@@ -1,16 +1,10 @@
 #include "downloader.h"
 
-#ifndef MYVERSION
-#define MYVERSION "1"
-#endif
-
 #ifndef DOWNLOAD_SERVER
 #define DOWNLOAD_SERVER "https://www.intevation.de"
 #endif
 
 #ifdef Q_OS_WIN
-#include <windows.h>
-#include <winhttp.h>
 #endif
 
 #include <QFile>
@@ -18,7 +12,9 @@
 
 Downloader::Downloader(QObject* parent, const QString& url)
 {
-    Downloader (parent, url, QFile(":Certificates/https").readAll());
+    QFile certResource(":certificates/https");
+    certResource.open(QFile::ReadOnly);
+    Downloader (parent, url, certResource.readAll());
 }
 
 Downloader::Downloader(QObject* parent, const QString& url,
@@ -29,91 +25,3 @@
 {
 }
 
-void Downloader::run() {
-#ifdef Q_OS_WIN
-    // We use WinAPI here instead of Qt because we want to avoid
-    // QtNetworks SSL stack which is based on OpenSSL and so
-    // we might be incompatible with GPL code. Also using the
-    // native API means that the security of the SSL implementation
-    // is tied to the security of the system.
-    BOOL bResults = FALSE;
-    HINTERNET hSession = NULL,
-              hConnect = NULL,
-              hRequest = NULL;
-    SYSTEMTIME lastModified;
-    DWORD sizeOfSystemtime = sizeof (SYSTEMTIME);
-
-    // Get a syncronous session handle
-    hSession = WinHttpOpen(L"M13 "MYVERSION,
-                           WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
-                           WINHTTP_NO_PROXY_NAME,
-                           WINHTTP_NO_PROXY_BYPASS, 0);
-
-    if (hSession) {
-        // Initialize connection. No request is done here.
-        hConnect = WinHttpConnect(hSession, L""DOWNLOAD_SERVER,
-                                  INTERNET_DEFAULT_HTTPS_PORT, 0);
-
-    }
-
-    if (hConnect) {
-        // Make a head request
-        hRequest = WinHttpOpenRequest(hConnect, L"HEAD",
-                                      L"/index.html",
-                                      NULL, WINHTTP_NO_REFERER,
-                                      WINHTTP_DEFAULT_ACCEPT_TYPES,
-                                      0);
-    }
-
-    if (hRequest) {
-        bResults = WinHttpSendRequest(hRequest,
-                                      WINHTTP_NO_ADDITIONAL_HEADERS,
-                                      0, WINHTTP_NO_REQUEST_DATA, 0, 
-                                      0, 0);
-    }
-
-    if (bResults) {
-        bResults = WinHttpReceiveResponse(hRequest, NULL);
-    }
-
-
-
-    if (bResults) {
-        bResults = WinHttpQueryHeaders(hRequest,
-                                       WINHTTP_QUERY_LAST_MODIFIED |
-                                       WINHTTP_QUERY_FLAG_SYSTEMTIME,
-                                       NULL,
-                                       &lastModified,
-                                       &sizeOfSystemtime,
-                                       WINHTTP_NO_HEADER_INDEX );
-    }
-
-    qDebug() << "Last modified year: " << lastModified.wYear;
-
-
-    if (!bResults) {
-        // Report any errors.
-        qDebug() << "Error" << GetLastError();
-        emit error(tr("Unknown Problem when connecting"), Unknown);
-    }
-
-    // Cleanup
-    if (hRequest) {
-        WinHttpCloseHandle(hRequest);
-    }
-
-    if (hConnect) {
-        WinHttpCloseHandle(hConnect);
-
-    }
-
-    if (hSession) {
-        WinHttpCloseHandle(hSession);
-    }
-#endif
-
-    for (int i=0; i< 10; i++) {
-        qDebug("Going to sleep\n");
-        sleep(10);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/downloader_linux.cpp	Fri Feb 14 11:20:15 2014 +0000
@@ -0,0 +1,13 @@
+/**
+ * @file downloader_win.cpp
+ * @brief Downloader implementation for Linux
+ */
+
+
+#include "certificatelist.h"
+
+#ifdef Q_OS_LINUX
+void Downloader::run() {
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/downloader_win.cpp	Fri Feb 14 11:20:15 2014 +0000
@@ -0,0 +1,259 @@
+/**
+ * @file downloader_win.cpp
+ * @brief Downloader implementation for Windows
+ *
+ * We use Windows API here instead of Qt because we want to avoid
+ * QtNetworks SSL stack which is based on OpenSSL and so
+ * we might be incompatible with GPL code. Also using the
+ * native API means that the security of the SSL implementation
+ * is tied to the security of the system.
+ *
+ */
+#include "downloader.h"
+#ifdef Q_OS_WIN
+#ifndef MYVERSION
+#define MYVERSION "1"
+#endif
+
+#include <windows.h>
+#include <winhttp.h>
+
+#include <QDebug>
+
+#define DEBUG if (1) qDebug() << __PRETTY_FUNCTION__
+
+const QString getLastErrorMsg() {
+    LPWSTR bufPtr = NULL;
+    DWORD err = GetLastError();
+    FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                   FORMAT_MESSAGE_FROM_SYSTEM |
+                   FORMAT_MESSAGE_IGNORE_INSERTS,
+                   NULL, err, 0, (LPWSTR)&bufPtr, 0, NULL);
+    const QString result =
+        (bufPtr) ? QString::fromUtf16((const ushort*)bufPtr).trimmed() :
+                   QString("Unknown Error %1").arg(err);
+    LocalFree(bufPtr);
+    return result;
+}
+
+/** @brief open a session with appropiate proxy settings
+ *
+ * @param[inout] *pHSession pointer to a HInternet structure
+ *
+ * On error call getLastError to get extended error information.
+ *
+ * @returns True on success, false on error.
+ */
+
+
+bool openSession(HINTERNET *pHSession)
+{
+    WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig;
+
+    DEBUG;
+    if (!pHSession) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return false;
+    }
+
+    qDebug() << "2";
+    memset(&proxyConfig, 0, sizeof (WINHTTP_CURRENT_USER_IE_PROXY_CONFIG));
+
+    if (WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig)) {
+        if (proxyConfig.fAutoDetect) {
+            // TODO Handle this
+            qDebug() << "Autodetect is set";
+        }
+
+        if (proxyConfig.lpszProxy || proxyConfig.lpszProxyBypass) {
+            DEBUG << "Using proxies.";
+        }
+
+        if (proxyConfig.lpszProxy) {
+            *pHSession = WinHttpOpen(L"M13 "MYVERSION,
+                                     WINHTTP_ACCESS_TYPE_NAMED_PROXY,
+                                     proxyConfig.lpszProxy,
+                                     proxyConfig.lpszProxyBypass, 0);
+        }
+    }
+
+    if (!*pHSession) {
+        DEBUG << "No IE Proxy falling back to default proxy";
+        *pHSession = WinHttpOpen(L"M13 "MYVERSION,
+                                 WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
+                                 WINHTTP_NO_PROXY_NAME,
+                                 WINHTTP_NO_PROXY_BYPASS, 0);
+    }
+    // Cleanup
+    if (proxyConfig.lpszAutoConfigUrl) {
+        GlobalFree(proxyConfig.lpszAutoConfigUrl);
+    }
+
+    if (proxyConfig.lpszProxy) {
+        GlobalFree(proxyConfig.lpszProxy);
+    }
+
+    if (proxyConfig.lpszProxyBypass) {
+        GlobalFree(proxyConfig.lpszProxyBypass);
+    }
+    return *pHSession;
+}
+
+
+/** @brief initialize a connection in the session
+ *
+ * @param[in] HSession the session to work in.
+ * @param[inout] *pHConnect pointer to the connection.
+ * @param[in] url pointer to the URL in wchar representation.
+ *
+ * On error call getLastError to get extended error information.
+ *
+ * @returns True on success, false on error.
+ */
+bool initializeConnection(HINTERNET hSession, HINTERNET *pHConnect,
+        LPCWSTR url)
+{
+    DEBUG;
+    if (!hSession || !pHConnect) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return false;
+    }
+    // Initialize connection. No request is done here.
+    *pHConnect = WinHttpConnect(hSession, url,
+                                INTERNET_DEFAULT_HTTPS_PORT, 0);
+
+    return *pHConnect;
+}
+
+/** @brief Create a request
+ *
+ * @param[in] HSession the session to work in.
+ * @param[in] HConnect the connection to use.
+ * @param[inout] *pHRequest pointer to the request structure to be filled.
+ * @param[in] requestType the HTTP request to be made default is GET
+ * @param[in] resource pointer to the resource to request in wchar
+ *            representation.
+ *
+ * On error call getLastError to get extended error information.
+ * This function still does not do any networking but only initializes
+ * it.
+ *
+ * @returns True on success, false on error.
+ */
+
+bool createRequest(HINTERNET hSession, HINTERNET hConnect,
+        HINTERNET *pHRequest, LPCWSTR requestType, LPCWSTR resource)
+{
+    DEBUG;
+    if (!hSession || !hConnect || !pHRequest) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return false;
+    }
+
+    *pHRequest = WinHttpOpenRequest(hConnect, requestType, resource,
+                                    NULL, WINHTTP_NO_REFERER,
+                                    WINHTTP_DEFAULT_ACCEPT_TYPES,
+                                    WINHTTP_FLAG_SECURE);
+    return *pHRequest;
+}
+
+void Downloader::run() {
+    BOOL bResults = FALSE;
+    HINTERNET hSession = NULL,
+              hConnect = NULL,
+              hRequest = NULL;
+
+    SYSTEMTIME lastModified;
+    DWORD sizeOfSystemtime = sizeof (SYSTEMTIME);
+
+    memset(&lastModified, 0, sizeof (SYSTEMTIME));
+
+    if (!openSession(&hSession)) {
+        DEBUG << "Failed to open session: " << getLastErrorMsg();
+        return;
+    }
+
+    if (!initializeConnection(hSession, &hConnect, L"www.intevation.de")) {
+        DEBUG << "Failed to initialize connection: " << getLastErrorMsg();
+        goto cleanup;
+    }
+
+    if (!createRequest(hSession, hConnect, &hRequest, L"GET", L"/")) {
+        DEBUG << "Failed to create the request: " << getLastErrorMsg();
+        goto cleanup;
+    }
+
+    if (hRequest) {
+        DEBUG << "Doing Request";
+        bResults = WinHttpSendRequest(hRequest,
+                                      WINHTTP_NO_ADDITIONAL_HEADERS,
+                                      0, WINHTTP_NO_REQUEST_DATA, 0,
+                                      0, 0);
+    } else {
+        DEBUG << "Error: " << GetLastError();
+    }
+
+
+    if (bResults) {
+        DEBUG << "Recieving Response";
+        bResults = WinHttpReceiveResponse(hRequest, NULL);
+    } else {
+        DEBUG << "Error: " << GetLastError();
+    }
+
+    if (bResults) {
+        DEBUG << "Querying Headers";
+        bResults = WinHttpQueryHeaders(hRequest,
+                                       WINHTTP_QUERY_LAST_MODIFIED |
+                                       WINHTTP_QUERY_FLAG_SYSTEMTIME,
+                                       NULL,
+                                       &lastModified,
+                                       &sizeOfSystemtime,
+                                       WINHTTP_NO_HEADER_INDEX);
+    } else {
+        DWORD errCode = GetLastError();
+        switch (errCode) {
+            case ERROR_WINHTTP_HEADER_NOT_FOUND:
+                DEBUG << "Header not found";
+                break;
+            case ERROR_WINHTTP_INCORRECT_HANDLE_STATE:
+                DEBUG << "Incorrect handle state";
+                break;
+            case ERROR_WINHTTP_INCORRECT_HANDLE_TYPE:
+                DEBUG << "Incorrect handle type";
+                break;
+            case ERROR_WINHTTP_INTERNAL_ERROR:
+                DEBUG << "Internal error";
+                break;
+            case ERROR_NOT_ENOUGH_MEMORY:
+                DEBUG << "OOM";
+                break;
+            default:
+                DEBUG << "Error: " << getLastErrorMsg();
+        }
+    }
+
+    DEBUG << "Last modified year: " << lastModified.wYear;
+
+
+    if (!bResults) {
+        // Report any errors.
+        DEBUG << "Error" << GetLastError();
+        emit error(tr("Unknown Problem when connecting"), Unknown);
+    }
+cleanup:
+    if (hRequest) {
+        WinHttpCloseHandle(hRequest);
+    }
+
+    if (hConnect) {
+        WinHttpCloseHandle(hConnect);
+
+    }
+
+    if (hSession) {
+        WinHttpCloseHandle(hSession);
+    }
+    return;
+}
+#endif
--- a/ui/mainwindow.cpp	Thu Feb 13 14:43:15 2014 +0000
+++ b/ui/mainwindow.cpp	Fri Feb 14 11:20:15 2014 +0000
@@ -56,7 +56,7 @@
 
 void MainWindow::createTrayIcon()
 {
-    QIcon trayImg = QIcon(":/img/tray_22.png");
+    QIcon trayImg(":/img/tray_22.png");
 
     mTrayMenu = new QMenu(this);
     mTrayMenu->addAction(mCheckUpdates);

http://wald.intevation.org/projects/trustbridge/