diff --git a/.gitignore b/.gitignore
index 1316742b3cd061754803991b0233865f78c9b37e..b8451a656514cbf0233c784684bb42a23fd28e1b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
 *.pro.user
 build_*/
 lib/qtlib/
+lib/AppImageUpdate/
+lib/AppImageUpdate-prebuilt/
diff --git a/app/app.pri b/app/app.pri
index 7e03a9c0fa9cc860f9a31358cc220eead6766d19..53ee440b9fd207041cdf79a18653e5b87957931a 100644
--- a/app/app.pri
+++ b/app/app.pri
@@ -11,7 +11,9 @@ HEADERS += \
     $${PWD}/src/handlers/confighandler.h \
     $${PWD}/src/handlers/systemhandler.h \
     $${PWD}/src/handlers/ocsapihandler.h \
-    $${PWD}/src/handlers/itemhandler.h
+    $${PWD}/src/handlers/itemhandler.h \
+    $${PWD}/src/handlers/updatehandler.h \
+    $${PWD}/src/handlers/desktopthemehandler.h
 
 SOURCES += \
     $${PWD}/src/main.cpp \
@@ -19,7 +21,9 @@ SOURCES += \
     $${PWD}/src/handlers/confighandler.cpp \
     $${PWD}/src/handlers/systemhandler.cpp \
     $${PWD}/src/handlers/ocsapihandler.cpp \
-    $${PWD}/src/handlers/itemhandler.cpp
+    $${PWD}/src/handlers/itemhandler.cpp \
+    $${PWD}/src/handlers/updatehandler.cpp \
+    $${PWD}/src/handlers/desktopthemehandler.cpp
 
 RESOURCES += $${PWD}/configs/configs.qrc
 
@@ -29,7 +33,6 @@ unix:!ios:!android {
     QT += dbus
 
     HEADERS += \
-        $${PWD}/src/handlers/desktopthemehandler.h \
         $${PWD}/src/desktopthemes/kdetheme.h \
         $${PWD}/src/desktopthemes/gnometheme.h \
         $${PWD}/src/desktopthemes/xfcetheme.h \
@@ -37,7 +40,6 @@ unix:!ios:!android {
         $${PWD}/src/desktopthemes/matetheme.h
 
     SOURCES += \
-        $${PWD}/src/handlers/desktopthemehandler.cpp \
         $${PWD}/src/desktopthemes/kdetheme.cpp \
         $${PWD}/src/desktopthemes/gnometheme.cpp \
         $${PWD}/src/desktopthemes/xfcetheme.cpp \
diff --git a/app/configs/application.json b/app/configs/application.json
index ad7d95946fbd93520bb1524f6d31da9a0ca75cc7..54fe50b69d8b9b3ea58445fbef0c7fdd323fb7ca 100644
--- a/app/configs/application.json
+++ b/app/configs/application.json
@@ -1,7 +1,7 @@
 {
     "id": "ocs-manager",
     "name": "ocs-manager",
-    "version": "0.4.4",
+    "version": "0.5.0",
     "organization": "Opendesktop.org",
     "domain": "org.opendesktop.ocs-manager",
     "icon": ":/desktop/ocs-manager.svg",
diff --git a/app/src/handlers/confighandler.cpp b/app/src/handlers/confighandler.cpp
index bcb3e744f50dacf5d8b2a3ceb9ca6d8f6a670bf7..6ccbf7d0e9dbbd16f819b744feaf24a1b0eb2019 100644
--- a/app/src/handlers/confighandler.cpp
+++ b/app/src/handlers/confighandler.cpp
@@ -31,6 +31,11 @@ QJsonObject ConfigHandler::getUsrConfigApplication() const
 
 bool ConfigHandler::setUsrConfigApplication(const QJsonObject &object) const
 {
+    /* object format
+    {
+        "update_checked_at": 1483658977219
+    }
+    */
     return usrConfig_.set("application", object);
 }
 
@@ -64,6 +69,16 @@ bool ConfigHandler::setUsrConfigInstalledItems(const QJsonObject &object) const
     return usrConfig_.set("installed_items", object);
 }
 
+QJsonObject ConfigHandler::getUsrConfigUpdateAvailableItems() const
+{
+    return usrConfig_.get("update_available_items");
+}
+
+bool ConfigHandler::setUsrConfigUpdateAvailableItems(const QJsonObject &object) const
+{
+    return usrConfig_.set("update_available_items", object);
+}
+
 bool ConfigHandler::setUsrConfigProvidersProvider(const QString &providerKey, const QJsonObject &object) const
 {
     /* object format
@@ -162,6 +177,26 @@ bool ConfigHandler::removeUsrConfigInstalledItemsItem(const QString &itemKey) co
     return setUsrConfigInstalledItems(installedItems);
 }
 
+bool ConfigHandler::setUsrConfigUpdateAvailableItemsItem(const QString &itemKey, const QJsonObject &object) const
+{
+    /* object format
+    {
+        "installed_item": "http://example.com/downloads/example.AppImage",
+        "update_method": "appimageupdate"
+    }
+    */
+    auto updateAvailableItems = getUsrConfigUpdateAvailableItems();
+    updateAvailableItems[itemKey] = object;
+    return setUsrConfigUpdateAvailableItems(updateAvailableItems);
+}
+
+bool ConfigHandler::removeUsrConfigUpdateAvailableItemsItem(const QString &itemKey) const
+{
+    auto updateAvailableItems = getUsrConfigUpdateAvailableItems();
+    updateAvailableItems.remove(itemKey);
+    return setUsrConfigUpdateAvailableItems(updateAvailableItems);
+}
+
 void ConfigHandler::importAppConfigApplication()
 {
     appConfigApplication_ = appConfig_.get("application");
diff --git a/app/src/handlers/confighandler.h b/app/src/handlers/confighandler.h
index bd44739d030aec2fe98cc653aed0e7c9f2632c12..a1531ffb94c8ce5387b18c2dc541a51818782c71 100644
--- a/app/src/handlers/confighandler.h
+++ b/app/src/handlers/confighandler.h
@@ -24,6 +24,8 @@ public slots:
     bool setUsrConfigCategories(const QJsonObject &object) const;
     QJsonObject getUsrConfigInstalledItems() const;
     bool setUsrConfigInstalledItems(const QJsonObject &object) const;
+    QJsonObject getUsrConfigUpdateAvailableItems() const;
+    bool setUsrConfigUpdateAvailableItems(const QJsonObject &object) const;
 
     bool setUsrConfigProvidersProvider(const QString &providerKey, const QJsonObject &object) const;
     bool removeUsrConfigProvidersProvider(const QString &providerKey) const;
@@ -32,6 +34,8 @@ public slots:
     bool setUsrConfigCategoriesInstallType(const QString &providerKey, const QString &categoryKey, const QString &installType) const;
     bool setUsrConfigInstalledItemsItem(const QString &itemKey, const QJsonObject &object) const;
     bool removeUsrConfigInstalledItemsItem(const QString &itemKey) const;
+    bool setUsrConfigUpdateAvailableItemsItem(const QString &itemKey, const QJsonObject &object) const;
+    bool removeUsrConfigUpdateAvailableItemsItem(const QString &itemKey) const;
 
 private:
     void importAppConfigApplication();
diff --git a/app/src/handlers/desktopthemehandler.cpp b/app/src/handlers/desktopthemehandler.cpp
index 20869ec8ac63d9f919df1a02ce6279852328d18a..01eaa22e2b9cc2cb12d09a863daba41bc2dc3244 100644
--- a/app/src/handlers/desktopthemehandler.cpp
+++ b/app/src/handlers/desktopthemehandler.cpp
@@ -96,9 +96,9 @@ bool DesktopThemeHandler::isApplicableType(const QString &installType) const
     return applicableTypes.contains(installType);
 }
 
-#ifdef QTLIB_UNIX
 bool DesktopThemeHandler::applyTheme(const QString &path, const QString &installType) const
 {
+#ifdef QTLIB_UNIX
     if (QFileInfo::exists(path) && isApplicableType(installType)) {
         auto desktop = desktopEnvironment();
 
@@ -196,7 +196,7 @@ bool DesktopThemeHandler::applyTheme(const QString &path, const QString &install
             }
         }
     }
+#endif
 
     return false;
 }
-#endif
diff --git a/app/src/handlers/desktopthemehandler.h b/app/src/handlers/desktopthemehandler.h
index 9ba1f4a06416c033d02c02246df7d248cd446659..73d77f101d97a44032f3be52b5a8ced04d63d2b9 100644
--- a/app/src/handlers/desktopthemehandler.h
+++ b/app/src/handlers/desktopthemehandler.h
@@ -12,8 +12,5 @@ public:
 public slots:
     QString desktopEnvironment() const;
     bool isApplicableType(const QString &installType) const;
-
-#ifdef QTLIB_UNIX
     bool applyTheme(const QString &path, const QString &installType) const;
-#endif
 };
diff --git a/app/src/handlers/updatehandler.cpp b/app/src/handlers/updatehandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8728458194615d4e7395f1bf74ba14b5d52138fc
--- /dev/null
+++ b/app/src/handlers/updatehandler.cpp
@@ -0,0 +1,190 @@
+#include "updatehandler.h"
+
+#include <QStringList>
+#include <QJsonValue>
+#include <QJsonArray>
+#include <QJsonObject>
+#include <QDateTime>
+#include <QThread>
+#include <QDebug>
+
+#ifdef QTLIB_UNIX
+#include "appimage/update.h"
+#endif
+
+#include "qtlib_file.h"
+
+#include "handlers/confighandler.h"
+
+UpdateHandler::UpdateHandler(ConfigHandler *configHandler, QObject *parent)
+    : QObject(parent), configHandler_(configHandler)
+{}
+
+void UpdateHandler::checkAll()
+{
+    emit checkAllStarted();
+
+    // Resets data
+    QJsonObject updateAvailableItems;
+    configHandler_->setUsrConfigUpdateAvailableItems(updateAvailableItems);
+
+    auto installedItems = configHandler_->getUsrConfigInstalledItems();
+
+    if (installedItems.isEmpty()) {
+        emit checkAllFinished();
+        return;
+    }
+
+    for (const auto &itemKey : installedItems.keys()) {
+        auto installedItem = installedItems[itemKey].toObject();
+        auto filename = installedItem["filename"].toString();
+        auto installType = installedItem["install_type"].toString();
+
+        qtlib::File file;
+#ifdef QTLIB_UNIX
+        file.setPath(configHandler_->getAppConfigInstallTypes()[installType].toObject()["destination"].toString() + "/" + filename);
+#else
+        file.setPath(configHandler_->getAppConfigInstallTypes()[installType].toObject()["generic_destination"].toString() + "/" + filename);
+#endif
+
+        QString updateMethod = "";
+
+        if (installType == "bin") {
+#ifdef QTLIB_UNIX
+            if (file.path().endsWith(".appimage", Qt::CaseInsensitive)) {
+                if (checkAppImage(file.path())) {
+                    updateMethod = "appimageupdate";
+                }
+                //else if (checkAppImageWithOcsApi(itemKey)) {
+                //    updateMethod = "appimageupdatewithocsapi";
+                //}
+            }
+#endif
+        }
+
+        if (!updateMethod.isEmpty()) {
+            QJsonObject updateAvailableItem;
+            updateAvailableItem["installed_item"] = itemKey;
+            updateAvailableItem["update_method"] = updateMethod;
+            // Use installed item's key as unique key to the update available item
+            configHandler_->setUsrConfigUpdateAvailableItemsItem(itemKey, updateAvailableItem);
+        }
+    }
+
+    auto application = configHandler_->getUsrConfigApplication();
+    application["update_checked_at"] = QDateTime::currentMSecsSinceEpoch();
+    configHandler_->setUsrConfigApplication(application);
+
+    emit checkAllFinished();
+}
+
+void UpdateHandler::update(const QString &itemKey)
+{
+    auto updateAvailableItems = configHandler_->getUsrConfigUpdateAvailableItems();
+
+    if (!updateAvailableItems.contains(itemKey)) {
+        return;
+    }
+
+    auto updateMethod = updateAvailableItems[itemKey].toObject()["update_method"].toString();
+
+#ifdef QTLIB_UNIX
+    if (updateMethod == "appimageupdate") {
+        updateAppImage(itemKey);
+    }
+    //else if (updateMethod == "appimageupdatewithocsapi") {
+    //    updateAppImageWithOcsApi(itemKey);
+    //}
+#endif
+}
+
+#ifdef QTLIB_UNIX
+QString UpdateHandler::describeAppImage(const QString &path) const
+{
+    appimage::update::Updater appImageUpdater(path.toStdString());
+    QString updateInformation;
+    std::string description;
+    if (appImageUpdater.describeAppImage(description)) {
+        updateInformation = QString::fromStdString(description);
+    }
+    return updateInformation;
+}
+
+bool UpdateHandler::checkAppImage(const QString &path) const
+{
+    appimage::update::Updater appImageUpdater(path.toStdString());
+    bool updateAvailable;
+    if (appImageUpdater.checkForChanges(updateAvailable)) {
+        return updateAvailable;
+    }
+    return false;
+}
+
+void UpdateHandler::updateAppImage(const QString &itemKey)
+{
+    auto updateAvailableItem = configHandler_->getUsrConfigUpdateAvailableItems()[itemKey].toObject();
+    auto installedItemKey = updateAvailableItem["installed_item"].toString();
+    auto installedItems = configHandler_->getUsrConfigInstalledItems();
+
+    if (!installedItems.contains(installedItemKey)) {
+        return;
+    }
+
+    auto installedItem = installedItems[installedItemKey].toObject();
+    auto filename = installedItem["filename"].toString();
+    auto installType = installedItem["install_type"].toString();
+
+    qtlib::File file(configHandler_->getAppConfigInstallTypes()[installType].toObject()["destination"].toString() + "/" + filename);
+
+    auto newFilename = filename;
+    auto updateInformation = describeAppImage(file.path());
+    for (const auto &info : updateInformation.split("\n")) {
+        if (info.endsWith(".zsync", Qt::CaseInsensitive)) {
+            newFilename = info.split("|").last().split("/").last().replace(".zsync", "", Qt::CaseInsensitive);
+            break;
+        }
+    }
+
+    appimage::update::Updater appImageUpdater(file.path().toStdString(), false);
+
+    if (!appImageUpdater.start()) {
+        return;
+    }
+
+    emit updateStarted(itemKey);
+
+    while (!appImageUpdater.isDone()) {
+        QThread::msleep(100);
+        double progress;
+        if (appImageUpdater.progress(progress)) {
+            emit updateProgress(itemKey, progress * 100);
+        }
+    }
+
+    if (appImageUpdater.hasError()) {
+        std::string nextMessage;
+        while (appImageUpdater.nextStatusMessage(nextMessage)) {
+            qWarning() << QString::fromStdString(nextMessage);
+        }
+
+        emit updateFinished(itemKey);
+        return;
+    }
+
+    installedItem["filename"] = newFilename;
+    QJsonArray files;
+    files.append(QJsonValue(newFilename));
+    installedItem["files"] = files;
+    installedItem["installed_at"] = QDateTime::currentMSecsSinceEpoch();
+
+    configHandler_->setUsrConfigInstalledItemsItem(installedItemKey, installedItem);
+
+    if (newFilename != filename) {
+        file.remove();
+    }
+
+    configHandler_->removeUsrConfigUpdateAvailableItemsItem(itemKey);
+
+    emit updateFinished(itemKey);
+}
+#endif
diff --git a/app/src/handlers/updatehandler.h b/app/src/handlers/updatehandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..7c6e851a4275bcfce8a8324c6e977398c9a148bb
--- /dev/null
+++ b/app/src/handlers/updatehandler.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <QObject>
+
+class ConfigHandler;
+
+class UpdateHandler : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit UpdateHandler(ConfigHandler *configHandler, QObject *parent = nullptr);
+
+signals:
+    void checkAllStarted();
+    void checkAllFinished();
+    void updateStarted(QString itemKey);
+    void updateFinished(QString itemKey);
+    void updateProgress(QString itemKey, int progress);
+
+public slots:
+    void checkAll();
+    void update(const QString &itemKey);
+
+private:
+#ifdef QTLIB_UNIX
+    QString describeAppImage(const QString &path) const;
+    bool checkAppImage(const QString &path) const;
+    void updateAppImage(const QString &itemKey);
+#endif
+
+    ConfigHandler *configHandler_;
+};
diff --git a/app/src/main.cpp b/app/src/main.cpp
index 6bb8c551c402f010114bfd5d6fbf94503449f6bd..8dca2326d7a819830d57a0aff714f57922c17f18 100644
--- a/app/src/main.cpp
+++ b/app/src/main.cpp
@@ -51,7 +51,7 @@ int main(int argc, char *argv[])
     QObject::connect(wsServer, &WebSocketServer::stopped, &app, &QGuiApplication::quit);
 
     if (wsServer->start()) {
-        qDebug() << "Websocket server started at:" << wsServer->serverUrl().toString();
+        qInfo() << "Websocket server started at:" << wsServer->serverUrl().toString();
     }
     else {
         qCritical() << "Failed to start websocket server:" << wsServer->errorString();
diff --git a/app/src/websockets/websocketserver.cpp b/app/src/websockets/websocketserver.cpp
index 45c4b60b1f3e1ee1601144e2d23d36336839f5fa..0380f6f7f6789b58e71040282a3e81e74f33ac2f 100644
--- a/app/src/websockets/websocketserver.cpp
+++ b/app/src/websockets/websocketserver.cpp
@@ -8,9 +8,10 @@
 
 #include "handlers/confighandler.h"
 #include "handlers/systemhandler.h"
-#include "handlers/desktopthemehandler.h"
 #include "handlers/ocsapihandler.h"
 #include "handlers/itemhandler.h"
+#include "handlers/updatehandler.h"
+#include "handlers/desktopthemehandler.h"
 
 WebSocketServer::WebSocketServer(ConfigHandler *configHandler, const QString &serverName, quint16 serverPort, QObject *parent)
     : QObject(parent), configHandler_(configHandler), serverName_(serverName), serverPort_(serverPort)
@@ -22,9 +23,10 @@ WebSocketServer::WebSocketServer(ConfigHandler *configHandler, const QString &se
 
     configHandler_->setParent(this);
     systemHandler_ = new SystemHandler(this);
-    desktopThemeHandler_ = new DesktopThemeHandler(this);
     ocsApiHandler_ = new OcsApiHandler(configHandler_, this);
     itemHandler_ = new ItemHandler(configHandler_, this);
+    updateHandler_ = new UpdateHandler(configHandler_, this);
+    desktopThemeHandler_ = new DesktopThemeHandler(this);
 
     connect(itemHandler_, &ItemHandler::metadataSetChanged, this, &WebSocketServer::itemMetadataSetChanged);
     connect(itemHandler_, &ItemHandler::downloadStarted, this, &WebSocketServer::itemDownloadStarted);
@@ -36,6 +38,12 @@ WebSocketServer::WebSocketServer(ConfigHandler *configHandler, const QString &se
     connect(itemHandler_, &ItemHandler::installFinished, this, &WebSocketServer::itemInstallFinished);
     connect(itemHandler_, &ItemHandler::uninstallStarted, this, &WebSocketServer::itemUninstallStarted);
     connect(itemHandler_, &ItemHandler::uninstallFinished, this, &WebSocketServer::itemUninstallFinished);
+
+    connect(updateHandler_, &UpdateHandler::checkAllStarted, this, &WebSocketServer::updateCheckAllStarted);
+    connect(updateHandler_, &UpdateHandler::checkAllFinished, this, &WebSocketServer::updateCheckAllFinished);
+    connect(updateHandler_, &UpdateHandler::updateStarted, this, &WebSocketServer::updateUpdateStarted);
+    connect(updateHandler_, &UpdateHandler::updateFinished, this, &WebSocketServer::updateUpdateFinished);
+    connect(updateHandler_, &UpdateHandler::updateProgress, this, &WebSocketServer::updateUpdateProgress);
 }
 
 WebSocketServer::~WebSocketServer()
@@ -191,6 +199,40 @@ void WebSocketServer::itemUninstallFinished(QJsonObject result)
     sendMessage("", "ItemHandler::uninstallFinished", data);
 }
 
+void WebSocketServer::updateCheckAllStarted()
+{
+    QJsonArray data;
+    sendMessage("", "UpdateHandler::checkAllStarted", data);
+}
+
+void WebSocketServer::updateCheckAllFinished()
+{
+    QJsonArray data;
+    sendMessage("", "UpdateHandler::checkAllFinished", data);
+}
+
+void WebSocketServer::updateUpdateStarted(QString itemKey)
+{
+    QJsonArray data;
+    data.append(itemKey);
+    sendMessage("", "UpdateHandler::updateStarted", data);
+}
+
+void WebSocketServer::updateUpdateFinished(QString itemKey)
+{
+    QJsonArray data;
+    data.append(itemKey);
+    sendMessage("", "UpdateHandler::updateFinished", data);
+}
+
+void WebSocketServer::updateUpdateProgress(QString itemKey, int progress)
+{
+    QJsonArray data;
+    data.append(itemKey);
+    data.append(progress);
+    sendMessage("", "UpdateHandler::updateProgress", data);
+}
+
 void WebSocketServer::receiveMessage(const QString &id, const QString &func, const QJsonArray &data)
 {
     /* message object format
@@ -247,6 +289,12 @@ void WebSocketServer::receiveMessage(const QString &id, const QString &func, con
     else if (func == "ConfigHandler::setUsrConfigInstalledItems") {
         resultData.append(configHandler_->setUsrConfigInstalledItems(data.at(0).toObject()));
     }
+    else if (func == "ConfigHandler::getUsrConfigUpdateAvailableItems") {
+        resultData.append(configHandler_->getUsrConfigUpdateAvailableItems());
+    }
+    else if (func == "ConfigHandler::setUsrConfigUpdateAvailableItems") {
+        resultData.append(configHandler_->setUsrConfigUpdateAvailableItems(data.at(0).toObject()));
+    }
     else if (func == "ConfigHandler::setUsrConfigProvidersProvider") {
         resultData.append(configHandler_->setUsrConfigProvidersProvider(data.at(0).toString(), data.at(1).toObject()));
     }
@@ -268,6 +316,12 @@ void WebSocketServer::receiveMessage(const QString &id, const QString &func, con
     else if (func == "ConfigHandler::removeUsrConfigInstalledItemsItem") {
         resultData.append(configHandler_->removeUsrConfigInstalledItemsItem(data.at(0).toString()));
     }
+    else if (func == "ConfigHandler::setUsrConfigUpdateAvailableItemsItem") {
+        resultData.append(configHandler_->setUsrConfigUpdateAvailableItemsItem(data.at(0).toString(), data.at(1).toObject()));
+    }
+    else if (func == "ConfigHandler::removeUsrConfigUpdateAvailableItemsItem") {
+        resultData.append(configHandler_->removeUsrConfigUpdateAvailableItemsItem(data.at(0).toString()));
+    }
     // SystemHandler
     else if (func == "SystemHandler::isUnix") {
         resultData.append(systemHandler_->isUnix());
@@ -278,20 +332,6 @@ void WebSocketServer::receiveMessage(const QString &id, const QString &func, con
     else if (func == "SystemHandler::openUrl") {
         resultData.append(systemHandler_->openUrl(data.at(0).toString()));
     }
-    // DesktopThemeHandler
-    else if (func == "DesktopThemeHandler::desktopEnvironment") {
-        resultData.append(desktopThemeHandler_->desktopEnvironment());
-    }
-    else if (func == "DesktopThemeHandler::isApplicableType") {
-        resultData.append(desktopThemeHandler_->isApplicableType(data.at(0).toString()));
-    }
-    else if (func == "DesktopThemeHandler::applyTheme") {
-#ifdef QTLIB_UNIX
-        resultData.append(desktopThemeHandler_->applyTheme(data.at(0).toString(), data.at(1).toString()));
-#else
-        resultData.append(false);
-#endif
-    }
     // OcsApiHandler
     else if (func == "OcsApiHandler::addProviders") {
         resultData.append(ocsApiHandler_->addProviders(data.at(0).toString()));
@@ -327,6 +367,23 @@ void WebSocketServer::receiveMessage(const QString &id, const QString &func, con
     else if (func == "ItemHandler::uninstall") {
         itemHandler_->uninstall(data.at(0).toString());
     }
+    // UpdateHandler
+    else if (func == "UpdateHandler::checkAll") {
+        updateHandler_->checkAll();
+    }
+    else if (func == "UpdateHandler::update") {
+        updateHandler_->update(data.at(0).toString());
+    }
+    // DesktopThemeHandler
+    else if (func == "DesktopThemeHandler::desktopEnvironment") {
+        resultData.append(desktopThemeHandler_->desktopEnvironment());
+    }
+    else if (func == "DesktopThemeHandler::isApplicableType") {
+        resultData.append(desktopThemeHandler_->isApplicableType(data.at(0).toString()));
+    }
+    else if (func == "DesktopThemeHandler::applyTheme") {
+        resultData.append(desktopThemeHandler_->applyTheme(data.at(0).toString(), data.at(1).toString()));
+    }
     // Not supported
     else {
         return;
diff --git a/app/src/websockets/websocketserver.h b/app/src/websockets/websocketserver.h
index 66edab50cecefde77a54e4d3da791fd7b814c31e..d017743bc2bf5737ba784e8cba81a641f332be09 100644
--- a/app/src/websockets/websocketserver.h
+++ b/app/src/websockets/websocketserver.h
@@ -10,9 +10,10 @@ class QWebSocket;
 
 class ConfigHandler;
 class SystemHandler;
-class DesktopThemeHandler;
 class OcsApiHandler;
 class ItemHandler;
+class UpdateHandler;
+class DesktopThemeHandler;
 
 class WebSocketServer : public QObject
 {
@@ -50,15 +51,22 @@ private slots:
     void itemUninstallStarted(QJsonObject result);
     void itemUninstallFinished(QJsonObject result);
 
+    void updateCheckAllStarted();
+    void updateCheckAllFinished();
+    void updateUpdateStarted(QString itemKey);
+    void updateUpdateFinished(QString itemKey);
+    void updateUpdateProgress(QString itemKey, int progress);
+
 private:
     void receiveMessage(const QString &id, const QString &func, const QJsonArray &data);
     void sendMessage(const QString &id, const QString &func, const QJsonArray &data);
 
     ConfigHandler *configHandler_;
     SystemHandler *systemHandler_;
-    DesktopThemeHandler *desktopThemeHandler_;
     OcsApiHandler *ocsApiHandler_;
     ItemHandler *itemHandler_;
+    UpdateHandler *updateHandler_;
+    DesktopThemeHandler *desktopThemeHandler_;
 
     QString serverName_;
     quint16 serverPort_;
diff --git a/lib/lib.pri b/lib/lib.pri
index 5343ea67e320f54da6851de3969e590c456d432d..78f96fbeb5c3dd5ee234b9dc11b1e07585e3554d 100644
--- a/lib/lib.pri
+++ b/lib/lib.pri
@@ -1 +1,25 @@
 include($${PWD}/qtlib/qtlib.pri)
+
+unix:!ios:!android {
+    INCLUDEPATH += $${PWD}/AppImageUpdate/include
+
+    DEPENDPATH += $${PWD}/AppImageUpdate/include
+
+    LIBS += \
+        -L$${PWD}/AppImageUpdate-prebuilt/src/ -lappimageupdate \
+        -L$${PWD}/AppImageUpdate-prebuilt/lib/zsync2/src/ -lzsync2 \
+        -L$${PWD}/AppImageUpdate-prebuilt/lib/zsync2/lib/libzsync/ -lzsync \
+        -L$${PWD}/AppImageUpdate-prebuilt/lib/zsync2/lib/librcksum/ -lrcksum \
+        -L$${PWD}/AppImageUpdate-prebuilt/lib/zsync2/lib/zlib/ -lz \
+        -L$${PWD}/AppImageUpdate-prebuilt/lib/ -lcpr
+
+    PRE_TARGETDEPS += \
+        $${PWD}/AppImageUpdate-prebuilt/src/libappimageupdate.a \
+        $${PWD}/AppImageUpdate-prebuilt/lib/zsync2/src/libzsync2.a \
+        $${PWD}/AppImageUpdate-prebuilt/lib/zsync2/lib/libzsync/libzsync.a \
+        $${PWD}/AppImageUpdate-prebuilt/lib/zsync2/lib/librcksum/librcksum.a \
+        $${PWD}/AppImageUpdate-prebuilt/lib/zsync2/lib/zlib/libz.a \
+        $${PWD}/AppImageUpdate-prebuilt/lib/libcpr.a
+
+    LIBS += -lcurl
+}
diff --git a/pkg/appimage/appimage.sh b/pkg/appimage/appimage.sh
index 17871c8d904ff5fea383b20cb975095690fa2125..513273c85d81d465724593399799dd463aa6a74d 100644
--- a/pkg/appimage/appimage.sh
+++ b/pkg/appimage/appimage.sh
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 PKGNAME='ocs-manager'
-PKGVER='0.4.4'
+PKGVER='0.5.0'
 PKGREL='1'
 
 curl -L -o linuxdeployqt "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage"
diff --git a/scripts/build-docker.sh b/scripts/build-docker.sh
index 9cfb2a04fbefcb2325e8234534b7f4b2beb7eda0..7e448b8bfdb30bde4290a32b47b922c4cd1d87aa 100644
--- a/scripts/build-docker.sh
+++ b/scripts/build-docker.sh
@@ -36,10 +36,12 @@ build_flatpak() {
 build_appimage() {
     # docker-image: ubuntu:17.10
     apt update -qq
+    apt -y install curl git
+
     apt -y install build-essential qt5-default libqt5websockets5-dev
+    apt -y install cmake libssl-dev libcurl4-gnutls-dev libxpm-dev
+
     apt -y install libssl1.0.0 zlib1g
-    apt -y install git
-    apt -y install curl
 
     useradd -m ${PKGUSER}
     export HOME="/home/${PKGUSER}"
diff --git a/scripts/import.sh b/scripts/import.sh
index 64f9385d803786dcee097c4e88ccbc97a7cd50d2..3b494b9a231cc36f67c758a2bcb37ef4e3fc01e0 100644
--- a/scripts/import.sh
+++ b/scripts/import.sh
@@ -5,3 +5,15 @@ PROJDIR="$(cd "$(dirname "${0}")/../" && pwd)"
 if [ ! -d "${PROJDIR}/lib/qtlib" ]; then
     git clone https://github.com/akiraohgaki/qtlib.git -b release-0.2.1 --single-branch --depth=1 "${PROJDIR}/lib/qtlib"
 fi
+
+if [ ! -d "${PROJDIR}/lib/AppImageUpdate" ]; then
+    git clone https://github.com/AppImage/AppImageUpdate.git -b continuous --single-branch --depth=1 "${PROJDIR}/lib/AppImageUpdate"
+    git -C "${PROJDIR}/lib/AppImageUpdate" submodule update --init --recursive #--depth=1
+fi
+
+if [ ! -d "${PROJDIR}/lib/AppImageUpdate-prebuilt" ]; then
+    mkdir "${PROJDIR}/lib/AppImageUpdate-prebuilt"
+    cd "${PROJDIR}/lib/AppImageUpdate-prebuilt"
+    cmake "${PROJDIR}/lib/AppImageUpdate" -DUSE_SYSTEM_CURL=ON -DBUILD_CPR_TESTS=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo
+    make libappimageupdate
+fi