diff --git a/app/src/main.cpp b/app/src/main.cpp
index a702c0219fd173d6a2ed3b00740b59896e85e86f..e6c228c2964fb470b73bea8df5603877082b6eb1 100644
--- a/app/src/main.cpp
+++ b/app/src/main.cpp
@@ -8,9 +8,6 @@
 #include <QDebug>
 
 #include "handlers/confighandler.h"
-//#include "handlers/systemhandler.h"
-//#include "handlers/ocshandler.h"
-//#include "handlers/itemhandler.h"
 #include "websockets/websocketserver.h"
 
 int main(int argc, char *argv[])
@@ -18,7 +15,7 @@ int main(int argc, char *argv[])
     // Init
     QCoreApplication app(argc, argv);
 
-    ConfigHandler *configHandler = new ConfigHandler(&app);
+    ConfigHandler *configHandler = new ConfigHandler();
     QJsonObject appConfigApplication = configHandler->getAppConfigApplication();
 
     app.setApplicationName(appConfigApplication["name"].toString());
@@ -48,7 +45,7 @@ int main(int argc, char *argv[])
     int port = clParser.value(clOptionPort).toInt();
 
     // Setup websocket server
-    WebSocketServer *wsServer = new WebSocketServer(appConfigApplication["id"].toString(), port, &app);
+    WebSocketServer *wsServer = new WebSocketServer(configHandler, appConfigApplication["id"].toString(), port, &app);
     QObject::connect(wsServer, &WebSocketServer::stopped, &app, &QCoreApplication::quit);
 
     if (wsServer->start()) {
diff --git a/app/src/websockets/websocketserver.cpp b/app/src/websockets/websocketserver.cpp
index 5e00aa5f3492fda62848f2cbba58a29178aa5bba..2ea26278c066e03b02e45edfb1f15b4ef3062227 100644
--- a/app/src/websockets/websocketserver.cpp
+++ b/app/src/websockets/websocketserver.cpp
@@ -6,12 +6,30 @@
 
 #include "qtlib_json.h"
 
-WebSocketServer::WebSocketServer(const QString &serverName, quint16 serverPort, QObject *parent)
-    : QObject(parent), serverName_(serverName), serverPort_(serverPort)
+#include "handlers/confighandler.h"
+#include "handlers/systemhandler.h"
+#include "handlers/ocshandler.h"
+#include "handlers/itemhandler.h"
+
+WebSocketServer::WebSocketServer(ConfigHandler *configHandler, const QString &serverName, quint16 serverPort, QObject *parent)
+    : QObject(parent), configHandler_(configHandler), serverName_(serverName), serverPort_(serverPort)
 {
     wsServer_ = new QWebSocketServer(serverName_, QWebSocketServer::NonSecureMode, this);
     connect(wsServer_, &QWebSocketServer::newConnection, this, &WebSocketServer::wsNewConnection);
     connect(wsServer_, &QWebSocketServer::closed, this, &WebSocketServer::stopped);
+
+    configHandler_->setParent(this);
+    systemHandler_ = new SystemHandler(this);
+    ocsHandler_ = new OcsHandler(configHandler_, this);
+    itemHandler_ = new ItemHandler(configHandler_, this);
+    connect(itemHandler_, &ItemHandler::metadataSetChanged, this, &WebSocketServer::itemMetadataSetChanged);
+    connect(itemHandler_, &ItemHandler::downloadStarted, this, &WebSocketServer::itemDownloadStarted);
+    connect(itemHandler_, &ItemHandler::downloadFinished, this, &WebSocketServer::itemDownloadFinished);
+    connect(itemHandler_, &ItemHandler::downloadProgress, this, &WebSocketServer::itemDownloadProgress);
+    connect(itemHandler_, &ItemHandler::installStarted, this, &WebSocketServer::itemInstallStarted);
+    connect(itemHandler_, &ItemHandler::installFinished, this, &WebSocketServer::itemInstallFinished);
+    connect(itemHandler_, &ItemHandler::uninstallStarted, this, &WebSocketServer::itemUninstallStarted);
+    connect(itemHandler_, &ItemHandler::uninstallFinished, this, &WebSocketServer::itemUninstallFinished);
 }
 
 WebSocketServer::~WebSocketServer()
@@ -75,8 +93,9 @@ void WebSocketServer::wsTextMessageReceived(const QString &message)
     QWebSocket *wsClient = qobject_cast<QWebSocket *>(sender());
     if (wsClient) {
         qtlib::Json json(message.toUtf8());
-        if (json.isValid()) {
-            callFunction(json.toObject(), wsClient);
+        if (json.isObject()) {
+            QJsonObject object = json.toObject();
+            receiveMessage(object["id"].toString(), object["func"].toString(), object["data"].toArray());
         }
     }
 }
@@ -86,47 +105,222 @@ void WebSocketServer::wsBinaryMessageReceived(const QByteArray &message)
     QWebSocket *wsClient = qobject_cast<QWebSocket *>(sender());
     if (wsClient) {
         qtlib::Json json(message);
-        if (json.isValid()) {
-            callFunction(json.toObject(), wsClient);
+        if (json.isObject()) {
+            QJsonObject object = json.toObject();
+            receiveMessage(object["id"].toString(), object["func"].toString(), object["data"].toArray());
         }
     }
 }
 
-void WebSocketServer::callFunction(const QJsonObject &request, QWebSocket *wsClient)
+void WebSocketServer::itemMetadataSetChanged()
+{
+    QJsonArray data;
+    sendMessage("", "ItemHandler::metadataSetChanged", data);
+}
+
+void WebSocketServer::itemDownloadStarted(QJsonObject result)
+{
+    QJsonArray data;
+    data[0] = result;
+    sendMessage("", "ItemHandler::downloadStarted", data);
+}
+
+void WebSocketServer::itemDownloadFinished(QJsonObject result)
+{
+    QJsonArray data;
+    data[0] = result;
+    sendMessage("", "ItemHandler::downloadFinished", data);
+}
+
+void WebSocketServer::itemDownloadProgress(QString id, qint64 bytesReceived, qint64 bytesTotal)
+{
+    QJsonArray data;
+    data[0] = id;
+    data[1] = bytesReceived;
+    data[2] = bytesTotal;
+    sendMessage("", "ItemHandler::downloadProgress", data);
+}
+
+void WebSocketServer::itemInstallStarted(QJsonObject result)
+{
+    QJsonArray data;
+    data[0] = result;
+    sendMessage("", "ItemHandler::installStarted", data);
+}
+
+void WebSocketServer::itemInstallFinished(QJsonObject result)
+{
+    QJsonArray data;
+    data[0] = result;
+    sendMessage("", "ItemHandler::installFinished", data);
+}
+
+void WebSocketServer::itemUninstallStarted(QJsonObject result)
+{
+    QJsonArray data;
+    data[0] = result;
+    sendMessage("", "ItemHandler::uninstallStarted", data);
+}
+
+void WebSocketServer::itemUninstallFinished(QJsonObject result)
 {
-    /* request object format
+    QJsonArray data;
+    data[0] = result;
+    sendMessage("", "ItemHandler::uninstallFinished", data);
+}
+
+void WebSocketServer::receiveMessage(const QString &id, const QString &func, const QJsonArray &data)
+{
+    /* message object format
     {
         "id": "example",
-        "call": "functionName",
-        "args": {
-            "arg1": "value",
-            "arg2": 2,
-            "arg3": true
-        }
+        "func": "functionName",
+        "data": ["value", 2, true]
     }
     */
 
-    /* response object format
+    QJsonArray resultData;
+
+    // WebSocketServer
+    if (func == "WebSocketServer::stop") {
+        stop();
+    }
+    else if (func == "WebSocketServer::isError") {
+        resultData[0] = isError();
+    }
+    else if (func == "WebSocketServer::errorString") {
+        resultData[0] = errorString();
+    }
+    else if (func == "WebSocketServer::serverUrl") {
+        resultData[0] = serverUrl().toString();
+    }
+    // ConfigHandler
+    else if (func == "ConfigHandler::getAppConfigApplication") {
+        resultData[0] = configHandler_->getAppConfigApplication();
+    }
+    else if (func == "ConfigHandler::getAppConfigInstallTypes") {
+        resultData[0] = configHandler_->getAppConfigInstallTypes();
+    }
+    else if (func == "ConfigHandler::getUsrConfigApplication") {
+        resultData[0] = configHandler_->getUsrConfigApplication();
+    }
+    else if (func == "ConfigHandler::setUsrConfigApplication") {
+        resultData[0] = configHandler_->setUsrConfigApplication(data[0].toObject());
+    }
+    else if (func == "ConfigHandler::getUsrConfigProviders") {
+        resultData[0] = configHandler_->getUsrConfigProviders();
+    }
+    else if (func == "ConfigHandler::setUsrConfigProviders") {
+        resultData[0] = configHandler_->setUsrConfigProviders(data[0].toObject());
+    }
+    else if (func == "ConfigHandler::getUsrConfigCategories") {
+        resultData[0] = configHandler_->getUsrConfigCategories();
+    }
+    else if (func == "ConfigHandler::setUsrConfigCategories") {
+        resultData[0] = configHandler_->setUsrConfigCategories(data[0].toObject());
+    }
+    else if (func == "ConfigHandler::getUsrConfigInstalledItems") {
+        resultData[0] = configHandler_->getUsrConfigInstalledItems();
+    }
+    else if (func == "ConfigHandler::setUsrConfigInstalledItems") {
+        resultData[0] = configHandler_->setUsrConfigInstalledItems(data[0].toObject());
+    }
+    else if (func == "ConfigHandler::setUsrConfigProvidersProvider") {
+        resultData[0] = configHandler_->setUsrConfigProvidersProvider(data[0].toString(), data[1].toObject());
+    }
+    else if (func == "ConfigHandler::removeUsrConfigProvidersProvider") {
+        resultData[0] = configHandler_->removeUsrConfigProvidersProvider(data[0].toString());
+    }
+    else if (func == "ConfigHandler::setUsrConfigCategoriesProvider") {
+        resultData[0] = configHandler_->setUsrConfigCategoriesProvider(data[0].toString(), data[1].toObject());
+    }
+    else if (func == "ConfigHandler::removeUsrConfigCategoriesProvider") {
+        resultData[0] = configHandler_->removeUsrConfigCategoriesProvider(data[0].toString());
+    }
+    else if (func == "ConfigHandler::setUsrConfigCategoriesInstallType") {
+        resultData[0] = configHandler_->setUsrConfigCategoriesInstallType(data[0].toString(), data[1].toString(), data[2].toString());
+    }
+    else if (func == "ConfigHandler::setUsrConfigInstalledItemsItem") {
+        resultData[0] = configHandler_->setUsrConfigInstalledItemsItem(data[0].toString(), data[1].toObject());
+    }
+    else if (func == "ConfigHandler::removeUsrConfigInstalledItemsItem") {
+        resultData[0] = configHandler_->removeUsrConfigInstalledItemsItem(data[0].toString());
+    }
+    // SystemHandler
+    else if (func == "SystemHandler::isUnix") {
+        resultData[0] = systemHandler_->isUnix();
+    }
+    else if (func == "SystemHandler::desktopEnvironment") {
+        resultData[0] = systemHandler_->desktopEnvironment();
+    }
+    else if (func == "SystemHandler::isApplicableType") {
+        resultData[0] = systemHandler_->isApplicableType(data[0].toString());
+    }
+    else if (func == "SystemHandler::applyFile") {
+        resultData[0] = false;
+#ifdef QTLIB_UNIX
+        resultData[0] = systemHandler_->applyFile(data[0].toString(), data[1].toString());
+#endif
+    }
+    // OcsHandler
+    else if (func == "OcsHandler::addProviders") {
+        resultData[0] = ocsHandler_->addProviders(data[0].toString());
+    }
+    else if (func == "OcsHandler::removeProvider") {
+        resultData[0] = ocsHandler_->removeProvider(data[0].toString());
+    }
+    else if (func == "OcsHandler::updateAllCategories") {
+        resultData[0] = ocsHandler_->updateAllCategories(data[0].toBool());
+    }
+    else if (func == "OcsHandler::updateCategories") {
+        resultData[0] = ocsHandler_->updateCategories(data[0].toString(), data[1].toBool());
+    }
+    else if (func == "OcsHandler::getContents") {
+        resultData[0] = ocsHandler_->getContents(data[0].toString(), data[1].toString(),
+                data[2].toString(), data[3].toString(),
+                data[4].toString(), data[5].toString(), data[6].toInt(), data[7].toInt());
+    }
+    else if (func == "OcsHandler::getContent") {
+        resultData[0] = ocsHandler_->getContent(data[0].toString(), data[1].toString());
+    }
+    // ItemHandler
+    else if (func == "ItemHandler::metadataSet") {
+        resultData[0] = itemHandler_->metadataSet();
+    }
+    else if (func == "ItemHandler::download") {
+        itemHandler_->download(data[0].toString(), data[1].toString(), data[2].toString(), data[3].toString());
+    }
+    else if (func == "ItemHandler::uninstall") {
+        itemHandler_->uninstall(data[0].toString());
+    }
+    // Not supported
+    else {
+        return;
+    }
+
+    sendMessage(id, func, resultData);
+}
+
+void WebSocketServer::sendMessage(const QString &id, const QString &func, const QJsonArray &data)
+{
+    /* message object format
     {
         "id": "example",
-        "result": {}
+        "func": "functionName",
+        "data": ["value", 2, true]
     }
     */
 
-    QString id = request["id"].toString();
-    QString call = request["call"].toString();
-    QJsonObject args = request["args"].toObject();
+    QJsonObject object;
+    object["id"] = id;
+    object["func"] = func;
+    object["data"] = data;
 
-    QJsonObject response;
-    response["id"] = id;
+    QByteArray binaryMessage = qtlib::Json(object).toJson();
+    QString textMessage = QString::fromUtf8(binaryMessage);
 
-    if (call == "WebSocketServer::stop") {
-        stop();
+    foreach (QWebSocket *wsClient, wsClients_) {
+        wsClient->sendTextMessage(textMessage);
+        //wsClient->sendBinaryMessage(binaryMessage);
     }
-    else if (call == "WebSocketServer::serverUrl") {
-        response["result"] = serverUrl().toString();
-    }
-
-    wsClient->sendTextMessage(QString(qtlib::Json(response).toJson()));
-    //wsClient->sendBinaryMessage(qtlib::Json(response).toJson());
 }
diff --git a/app/src/websockets/websocketserver.h b/app/src/websockets/websocketserver.h
index 899d5dc9d9c7cf2bab69fe1c96a0632521583e91..698bd5c2b1fdd2794d35bfe501ff864ff2494ba7 100644
--- a/app/src/websockets/websocketserver.h
+++ b/app/src/websockets/websocketserver.h
@@ -2,37 +2,59 @@
 
 #include <QObject>
 #include <QUrl>
-//#include <QJsonObject>
+#include <QJsonObject>
+#include <QJsonArray>
 
 class QWebSocketServer;
 class QWebSocket;
 
+class ConfigHandler;
+class SystemHandler;
+class OcsHandler;
+class ItemHandler;
+
 class WebSocketServer : public QObject
 {
     Q_OBJECT
 
 public:
-    explicit WebSocketServer(const QString &serverName, quint16 serverPort = 0, QObject *parent = 0);
+    explicit WebSocketServer(ConfigHandler *configHandler, const QString &serverName = "WebSocketServer", quint16 serverPort = 0, QObject *parent = 0);
     ~WebSocketServer();
 
+signals:
+    void started();
+    void stopped();
+
+public slots:
     bool start();
     void stop();
     bool isError();
     QString errorString();
     QUrl serverUrl();
 
-signals:
-    void started();
-    void stopped();
-
 private slots:
     void wsNewConnection();
     void wsDisconnected();
     void wsTextMessageReceived(const QString &message);
     void wsBinaryMessageReceived(const QByteArray &message);
 
+    void itemMetadataSetChanged();
+    void itemDownloadStarted(QJsonObject result);
+    void itemDownloadFinished(QJsonObject result);
+    void itemDownloadProgress(QString id, qint64 bytesReceived, qint64 bytesTotal);
+    void itemInstallStarted(QJsonObject result);
+    void itemInstallFinished(QJsonObject result);
+    void itemUninstallStarted(QJsonObject result);
+    void itemUninstallFinished(QJsonObject result);
+
 private:
-    void callFunction(const QJsonObject &request, QWebSocket *wsClient);
+    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_;
+    OcsHandler *ocsHandler_;
+    ItemHandler *itemHandler_;
 
     QString serverName_;
     quint16 serverPort_;