diff --git a/.gitignore b/.gitignore
index 69e668d4f250ecf7ae2ecb5df2d22cd48f184776..1316742b3cd061754803991b0233865f78c9b37e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 *.pro.user
-pkg/build/
+build_*/
+lib/qtlib/
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 5eb62c7afd53e26d20750f5a6c4229f0d241f497..0000000000000000000000000000000000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-language: cpp
-sudo: required
-dist: trusty
-
-before_install:
-  - sudo add-apt-repository -y ppa:beineri/opt-qt57-trusty
-  - sudo apt-get update -qq
-
-install:
-  - sudo apt-get -y install build-essential fuse zsync desktop-file-utils
-  - sudo apt-get -y install qt57base qt57svg qt57declarative qt57quickcontrols
-  # Replace linuxdeployqt download URL to official download URL when the stable version released
-  - curl -L -o linuxdeployqt https://dl.dropboxusercontent.com/u/150776/temp/linuxdeployqt-799f704-x86-64.appimage
-  - sudo install -m 755 -p linuxdeployqt /usr/local/bin/linuxdeployqt
-  - rm linuxdeployqt
-
-before_script:
-  - sudo modprobe fuse
-  - source /opt/qt57/bin/qt57-env.sh
-
-script:
-  - sh ./pkg/build.sh appimage
-
-after_script:
-  - appimage_file="$(ls ./pkg/build/*.AppImage)"
-  - [ -f "${appimage_file}" ] && curl -T "${appimage_file}" "https://transfer.sh/${appimage_file}"
diff --git a/README.md b/README.md
index f58d1072ac3a2989ff769f335491e8db18182a34..258e5ba672167b8b52051cfe8e2ff6e4e5a02c02 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# xdgurl
+# ocs-url
 
-An install helper program for desktop stuff.
+An install helper program for items served on OpenCollaborationServices (OCS).
 
 Copyright: 2016-2017, Akira Ohgaki
 
@@ -10,6 +10,6 @@ Download Linux package from:
 
 https://www.linux-apps.com/p/1136805/
 
-And please check the xdgurl wiki for more information.
+And please check the ocs-url wiki for more information.
 
-https://github.com/xdgurl/xdgurl/wiki
+https://github.com/ocs-url/ocs-url/wiki
diff --git a/app/app.pri b/app/app.pri
new file mode 100644
index 0000000000000000000000000000000000000000..0a0cd1ec320382fbc250d00a5ba1f6bf139b5be3
--- /dev/null
+++ b/app/app.pri
@@ -0,0 +1,22 @@
+QT += \
+    core \
+    gui \
+    qml \
+    quick \
+    svg
+
+HEADERS += \
+    $${PWD}/src/handlers/confighandler.h \
+    $${PWD}/src/handlers/ocsurlhandler.h
+
+SOURCES += \
+    $${PWD}/src/main.cpp \
+    $${PWD}/src/handlers/confighandler.cpp \
+    $${PWD}/src/handlers/ocsurlhandler.cpp
+
+RESOURCES += \
+    $${PWD}/configs/configs.qrc \
+    $${PWD}/images/images.qrc \
+    $${PWD}/qml/qml.qrc
+
+INCLUDEPATH += $${PWD}/src
diff --git a/app/configs/application.json b/app/configs/application.json
new file mode 100644
index 0000000000000000000000000000000000000000..8b09a76c2e8093e5c0270019ca838c0901df425b
--- /dev/null
+++ b/app/configs/application.json
@@ -0,0 +1,13 @@
+{
+    "id": "ocs-url",
+    "name": "ocs-url",
+    "version": "3.0.0",
+    "organization": "ocs-url",
+    "domain": "com.ocs-url.ocs-url",
+    "icon": ":/desktop/ocs-url.svg",
+    "description": "An install helper program for items served on OpenCollaborationServices (OCS).",
+    "license": "GPL-3+",
+    "author": "Akira Ohgaki",
+    "contact": "akiraohgaki@gmail.com",
+    "homepage": "https://github.com/ocs-url/ocs-url"
+}
diff --git a/src/app/configs/configs.qrc b/app/configs/configs.qrc
similarity index 54%
rename from src/app/configs/configs.qrc
rename to app/configs/configs.qrc
index a27f28af5718bcfb48d18dd500717897c9b6e84d..496e259d7a5937ae4a51fa761a76b84b33a05daf 100644
--- a/src/app/configs/configs.qrc
+++ b/app/configs/configs.qrc
@@ -1,7 +1,7 @@
 <RCC>
     <qresource prefix="/configs">
         <file>application.json</file>
-        <file>destinations.json</file>
-        <file>destinations_alias.json</file>
+        <file>install_types.json</file>
+        <file>install_types_alias.json</file>
     </qresource>
 </RCC>
diff --git a/app/configs/install_types.json b/app/configs/install_types.json
new file mode 100644
index 0000000000000000000000000000000000000000..335de22350e81310a3820d1f0d79e6a5aea33037
--- /dev/null
+++ b/app/configs/install_types.json
@@ -0,0 +1,192 @@
+{
+    "bin": {
+        "name": "Softwares",
+        "destination": "$HOME/.local/bin",
+        "generic_destination": "$APP_DATA/bin"
+    },
+    "downloads": {
+        "name": "Downloads",
+        "destination": "$HOME/Downloads",
+        "generic_destination": "$APP_DATA/downloads"
+    },
+    "documents": {
+        "name": "Documents",
+        "destination": "$HOME/Documents",
+        "generic_destination": "$APP_DATA/documents"
+    },
+    "pictures": {
+        "name": "Pictures",
+        "destination": "$HOME/Pictures",
+        "generic_destination": "$APP_DATA/pictures"
+    },
+    "music": {
+        "name": "Music",
+        "destination": "$HOME/Music",
+        "generic_destination": "$APP_DATA/music"
+    },
+    "videos": {
+        "name": "Videos",
+        "destination": "$HOME/Videos",
+        "generic_destination": "$APP_DATA/videos"
+    },
+    "wallpapers": {
+        "name": "Wallpapers",
+        "destination": "$XDG_DATA_HOME/wallpapers",
+        "generic_destination": "$APP_DATA/wallpapers"
+    },
+    "fonts": {
+        "name": "Fonts",
+        "destination": "$HOME/.fonts",
+        "generic_destination": "$APP_DATA/fonts"
+    },
+    "cursors": {
+        "name": "Cursors",
+        "destination": "$HOME/.icons",
+        "generic_destination": "$APP_DATA/cursors"
+    },
+    "icons": {
+        "name": "Icons",
+        "destination": "$XDG_DATA_HOME/icons",
+        "generic_destination": "$APP_DATA/icons"
+    },
+    "emoticons": {
+        "name": "Emoticons",
+        "destination": "$XDG_DATA_HOME/emoticons",
+        "generic_destination": "$APP_DATA/emoticons"
+    },
+    "themes": {
+        "name": "Desktop Themes",
+        "destination": "$HOME/.themes",
+        "generic_destination": "$APP_DATA/themes"
+    },
+    "emerald_themes": {
+        "name": "Emerald Themes",
+        "destination": "$HOME/.emerald/themes",
+        "generic_destination": "$APP_DATA/emerald_themes"
+    },
+    "enlightenment_themes": {
+        "name": "Enlightenment Themes",
+        "destination": "$HOME/.e/e/themes",
+        "generic_destination": "$APP_DATA/enlightenment_themes"
+    },
+    "enlightenment_backgrounds": {
+        "name": "Enlightenment Backgrounds",
+        "destination": "$HOME/.e/e/backgrounds",
+        "generic_destination": "$APP_DATA/enlightenment_backgrounds"
+    },
+    "fluxbox_styles": {
+        "name": "Fluxbox Styles",
+        "destination": "$HOME/.fluxbox/styles",
+        "generic_destination": "$APP_DATA/fluxbox_styles"
+    },
+    "pekwm_themes": {
+        "name": "PekWM Themes",
+        "destination": "$HOME/.pekwm/themes",
+        "generic_destination": "$APP_DATA/pekwm_themes"
+    },
+    "icewm_themes": {
+        "name": "IceWM Themes",
+        "destination": "$HOME/.icewm/themes",
+        "generic_destination": "$APP_DATA/icewm_themes"
+    },
+    "plasma_plasmoids": {
+        "name": "Plasma Plasmoids",
+        "destination": "$XDG_DATA_HOME/plasma/plasmoids",
+        "generic_destination": "$APP_DATA/plasma_plasmoids"
+    },
+    "plasma_look_and_feel": {
+        "name": "Plasma Look and Feel",
+        "destination": "$XDG_DATA_HOME/plasma/look-and-feel",
+        "generic_destination": "$APP_DATA/plasma_look_and_feel"
+    },
+    "plasma_desktopthemes": {
+        "name": "Plasma Desktop Themes",
+        "destination": "$XDG_DATA_HOME/plasma/desktoptheme",
+        "generic_destination": "$APP_DATA/plasma_desktopthemes"
+    },
+    "kwin_effects": {
+        "name": "KWin Effects",
+        "destination": "$XDG_DATA_HOME/kwin/effects",
+        "generic_destination": "$APP_DATA/kwin_effects"
+    },
+    "kwin_scripts": {
+        "name": "KWin Scripts",
+        "destination": "$XDG_DATA_HOME/kwin/scripts",
+        "generic_destination": "$APP_DATA/kwin_scripts"
+    },
+    "kwin_tabbox": {
+        "name": "KWin Window Switcher",
+        "destination": "$XDG_DATA_HOME/kwin/tabbox",
+        "generic_destination": "$APP_DATA/kwin_tabbox"
+    },
+    "aurorae_themes": {
+        "name": "Aurorae Themes",
+        "destination": "$XDG_DATA_HOME/aurorae/themes",
+        "generic_destination": "$APP_DATA/aurorae_themes"
+    },
+    "dekorator_themes": {
+        "name": "deKorator Themes",
+        "destination": "$XDG_DATA_HOME/deKorator/themes",
+        "generic_destination": "$APP_DATA/dekorator_themes"
+    },
+    "qtcurve": {
+        "name": "QtCurve Themes",
+        "destination": "$XDG_DATA_HOME/QtCurve",
+        "generic_destination": "$APP_DATA/qtcurve"
+    },
+    "color_schemes": {
+        "name": "KDE Color Schemes",
+        "destination": "$XDG_DATA_HOME/color-schemes",
+        "generic_destination": "$APP_DATA/color_schemes"
+    },
+    "gnome_shell_extensions": {
+        "name": "Gnome Shell Extensions",
+        "destination": "$XDG_DATA_HOME/gnome-shell/extensions",
+        "generic_destination": "$APP_DATA/gnome_shell_extensions"
+    },
+    "cinnamon_applets": {
+        "name": "Cinnamon Applets",
+        "destination": "$XDG_DATA_HOME/cinnamon/applets",
+        "generic_destination": "$APP_DATA/cinnamon_applets"
+    },
+    "cinnamon_desklets": {
+        "name": "Cinnamon Desklets",
+        "destination": "$XDG_DATA_HOME/cinnamon/desklets",
+        "generic_destination": "$APP_DATA/cinnamon_desklets"
+    },
+    "cinnamon_extensions": {
+        "name": "Cinnamon Extensions",
+        "destination": "$XDG_DATA_HOME/cinnamon/extensions",
+        "generic_destination": "$APP_DATA/cinnamon_extensions"
+    },
+    "nautilus_scripts": {
+        "name": "Nautilus Scripts",
+        "destination": "$XDG_DATA_HOME/nautilus/scripts",
+        "generic_destination": "$APP_DATA/nautilus_scripts"
+    },
+    "amarok_scripts": {
+        "name": "Amarok Scripts",
+        "destination": "$KDEHOME/share/apps/amarok/scripts",
+        "generic_destination": "$APP_DATA/amarok_scripts"
+    },
+    "yakuake_skins": {
+        "name": "Yakuake Skins",
+        "destination": "$KDEHOME/share/apps/yakuake/skins",
+        "generic_destination": "$APP_DATA/yakuake_skins"
+    },
+    "cairo_clock_themes": {
+        "name": "Cairo-Clock Themes",
+        "destination": "$HOME/.cairo-clock/themes",
+        "generic_destination": "$APP_DATA/cairo_clock_themes"
+    },
+    "books": {
+        "name": "Books",
+        "destination": "$APP_DATA/books",
+        "generic_destination": "$APP_DATA/books"
+    },
+    "comics": {
+        "name": "Comics",
+        "destination": "$APP_DATA/comics",
+        "generic_destination": "$APP_DATA/comics"
+    }
+}
diff --git a/app/configs/install_types_alias.json b/app/configs/install_types_alias.json
new file mode 100644
index 0000000000000000000000000000000000000000..d67bb8bdd3d57e9ca16d759627fb6e2babed23ea
--- /dev/null
+++ b/app/configs/install_types_alias.json
@@ -0,0 +1,62 @@
+{
+    "gnome_shell_themes": {
+        "base": "themes",
+        "name": "Gnome Shell Themes"
+    },
+    "cinnamon_themes": {
+        "base": "themes",
+        "name": "Cinnamon Themes"
+    },
+    "gtk2_themes": {
+        "base": "themes",
+        "name": "GTK2 Themes"
+    },
+    "gtk3_themes": {
+        "base": "themes",
+        "name": "GTK3 Themes"
+    },
+    "metacity_themes": {
+        "base": "themes",
+        "name": "Metacity Themes"
+    },
+    "xfwm4_themes": {
+        "base": "themes",
+        "name": "XFWM4 Themes"
+    },
+    "openbox_themes": {
+        "base": "themes",
+        "name": "Openbox Themes"
+    },
+    "kvantum_themes": {
+        "base": "themes",
+        "name": "Kvantum Themes"
+    },
+    "compiz_themes": {
+        "base": "emerald_themes",
+        "name": "Compiz Themes"
+    },
+    "beryl_themes": {
+        "base": "emerald_themes",
+        "name": "Beryl Themes"
+    },
+    "plasma4_plasmoids": {
+        "base": "plasma_plasmoids",
+        "name": "Plasma4 Plasmoids"
+    },
+    "plasma5_plasmoids": {
+        "base": "plasma_plasmoids",
+        "name": "Plasma5 Plasmoids"
+    },
+    "plasma5_look_and_feel": {
+        "base": "plasma_look_and_feel",
+        "name": "Plasma5 Look and Feel"
+    },
+    "plasma5_desktopthemes": {
+        "base": "plasma_desktopthemes",
+        "name": "Plasma5 Desktop Themes"
+    },
+    "plasma_color_schemes": {
+        "base": "color_schemes",
+        "name": "Plasma Color Schemes"
+    }
+}
diff --git a/app/images/icons/dialog-information.svg b/app/images/icons/dialog-information.svg
new file mode 100644
index 0000000000000000000000000000000000000000..308bd4effd3bf6645e3d32ece1ba870ae9407643
--- /dev/null
+++ b/app/images/icons/dialog-information.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="128" height="128" viewBox="0, 0, 128, 128">
+  <g id="icon">
+    <path d="M64,8 C33.072,8 8,33.072 8,64 C8,94.928 33.072,120 64,120 C94.928,120 120,94.928 120,64 C120,33.072 94.928,8 64,8 z M64,24 C68.418,24 72,27.582 72,32 C72,36.418 68.418,40 64,40 C59.582,40 56,36.418 56,32 C56,27.582 59.582,24 64,24 z M48,48 L72,48 L72,96 L80,96 L80,104 L48,104 L48,96 L56,96 L56,56 L48,56 L48,48 z" fill="#000000" id="dialog-information"/>
+  </g>
+</svg>
diff --git a/app/images/icons/dialog-warning.svg b/app/images/icons/dialog-warning.svg
new file mode 100644
index 0000000000000000000000000000000000000000..3227b79aea5172ed3c13f5497f1ff5d3097c1349
--- /dev/null
+++ b/app/images/icons/dialog-warning.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="128" height="128" viewBox="0, 0, 128, 128">
+  <g id="icon">
+    <path d="M64,16 L8,112 L120,112 L64,16 z M56,48 L72,48 L72,80 L56,80 L56,48 z M64,88 C68.418,88 72,91.582 72,96 C72,100.418 68.418,104 64,104 C59.582,104 56,100.418 56,96 C56,91.582 59.582,88 64,88 z" fill="#000000" id="dialog-warning"/>
+  </g>
+</svg>
diff --git a/app/images/icons/emblem-default.svg b/app/images/icons/emblem-default.svg
new file mode 100644
index 0000000000000000000000000000000000000000..0c29d9a675fbdad3873a7c5c5cbeb379c7c91d86
--- /dev/null
+++ b/app/images/icons/emblem-default.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="128" height="128" viewBox="0, 0, 128, 128">
+  <g id="icon">
+    <path d="M64,8 C33.072,8 8,33.072 8,64 C8,94.928 33.072,120 64,120 C94.928,120 120,94.928 120,64 C120,33.072 94.928,8 64,8 z M80,32 L104,32 L56,104 L32,80 L32,56 L56,80 L80,32 z" fill="#000000" id="emblem-default"/>
+  </g>
+</svg>
diff --git a/app/images/icons/emblem-downloads.svg b/app/images/icons/emblem-downloads.svg
new file mode 100644
index 0000000000000000000000000000000000000000..dafc2dbce4da6d8f48b0273fefd9769130f6779f
--- /dev/null
+++ b/app/images/icons/emblem-downloads.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="128" height="128" viewBox="0, 0, 128, 128">
+  <g id="icon">
+    <path d="M40,8 L40,48 L16,48 L64,96 L112,48 L88,48 L88,8 L40,8 z M8,72 L8,120 L120,120 L120,72 L104,72 L104,104 L24,104 L24,72 L8,72 z" fill="#000000" id="emblem-downloads"/>
+  </g>
+</svg>
diff --git a/app/images/images.qrc b/app/images/images.qrc
new file mode 100644
index 0000000000000000000000000000000000000000..892ca1d82a513bc32268d6e6f70d06a6f062b61f
--- /dev/null
+++ b/app/images/images.qrc
@@ -0,0 +1,8 @@
+<RCC>
+    <qresource prefix="/images">
+        <file>icons/dialog-information.svg</file>
+        <file>icons/dialog-warning.svg</file>
+        <file>icons/emblem-default.svg</file>
+        <file>icons/emblem-downloads.svg</file>
+    </qresource>
+</RCC>
diff --git a/app/qml/main.qml b/app/qml/main.qml
new file mode 100644
index 0000000000000000000000000000000000000000..98753362ec0ecf1a266bebf2560ce40f239ee073
--- /dev/null
+++ b/app/qml/main.qml
@@ -0,0 +1,167 @@
+import QtQuick 2.0
+import QtQuick.Layouts 1.0
+import QtQuick.Controls 1.0
+
+import "ui" as Ui
+
+import "scripts/Utility.js" as Utility
+
+ApplicationWindow {
+    id: app
+
+    title: configHandler.getAppConfigApplication().name
+
+    visible: true
+    width: 400
+    minimumWidth: width
+    maximumWidth: width
+    height: 200
+    minimumHeight: height
+    maximumHeight: height
+
+    function init() {
+        var metadata = ocsUrlHandler.metadata();
+
+        var primaryMessages = {
+            "success_download": qsTr("Download successfull"),
+            "success_install": qsTr("Installation successfull"),
+            "error_validation": qsTr("Validation error"),
+            "error_network": qsTr("Network error"),
+            "error_save": qsTr("Saving file failed"),
+            "error_install": qsTr("Installation failed")
+        };
+
+        ocsUrlHandler.started.connect(function() {
+            confirmDialog.close();
+            progressDialog.open();
+        });
+
+        ocsUrlHandler.finishedWithSuccess.connect(function(result) {
+            progressDialog.close();
+            infoDialog.primaryText = primaryMessages[result.status];
+            infoDialog.informativeText = metadata.filename;
+            infoDialog.detailedText = result.message;
+            infoDialog.open();
+        });
+
+        ocsUrlHandler.finishedWithError.connect(function(result) {
+            progressDialog.close();
+            errorDialog.primaryText = primaryMessages[result.status];
+            errorDialog.informativeText = metadata.filename;
+            errorDialog.detailedText = result.message;
+            errorDialog.open();
+        });
+
+        ocsUrlHandler.downloadProgress.connect(function(id, bytesReceived, bytesTotal) {
+            progressDialog.primaryText = qsTr("Downloading");
+            progressDialog.informativeText = metadata.filename;
+            progressDialog.detailedContentLoader.item.progressBar = bytesReceived / bytesTotal;
+            progressDialog.detailedContentLoader.item.progressText
+                    = Utility.convertByteToHumanReadable(bytesReceived)
+                    + " / " + Utility.convertByteToHumanReadable(bytesTotal);
+        });
+
+        if (ocsUrlHandler.isValid()) {
+            if (metadata.command === "download") {
+                confirmDialog.primaryText = qsTr("Do you want to download?");
+            }
+            else if (metadata.command === "install") {
+                confirmDialog.primaryText = qsTr("Do you want to install?");
+            }
+            confirmDialog.informativeText = metadata.filename;
+            confirmDialog.detailedText
+                    = qsTr("URL") + ": " + metadata.url + "\n"
+                    + qsTr("File") + ": " + metadata.filename + "\n"
+                    + qsTr("Type") + ": " + configHandler.getAppConfigInstallTypes()[metadata.type].name;
+            confirmDialog.open();
+        }
+        else {
+            errorDialog.primaryText = primaryMessages["error_validation"];
+            errorDialog.detailedText = qsTr("Invalid OCS-URL");
+            errorDialog.open();
+        }
+    }
+
+    function fixWindowSize(dialog) {
+        if (dialog.visible) {
+            app.height = dialog.implicitHeight + (dialog.anchors.margins * 2);
+        }
+    }
+
+    Ui.Dialog {
+        id: confirmDialog
+        icon: "qrc:/images/icons/dialog-information.svg"
+        actionButton.text: qsTr("Details")
+        actionButton.onClicked: toggleDetails()
+        acceptButton.text: qsTr("OK")
+        acceptButton.onClicked: ocsUrlHandler.process()
+        rejectButton.text: qsTr("Cancel")
+        rejectButton.onClicked: Qt.quit()
+        onVisibleChanged: app.fixWindowSize(confirmDialog)
+        onImplicitHeightChanged: app.fixWindowSize(confirmDialog)
+    }
+
+    Ui.Dialog {
+        id: infoDialog
+        icon: "qrc:/images/icons/emblem-default.svg"
+        actionButton.text: qsTr("Details")
+        actionButton.onClicked: toggleDetails()
+        acceptButton.text: qsTr("Open")
+        acceptButton.onClicked: {
+            ocsUrlHandler.openDestination();
+            Qt.quit();
+        }
+        rejectButton.text: qsTr("Close")
+        rejectButton.onClicked: Qt.quit()
+        onVisibleChanged: app.fixWindowSize(infoDialog)
+        onImplicitHeightChanged: app.fixWindowSize(infoDialog)
+    }
+
+    Ui.Dialog {
+        id: errorDialog
+        icon: "qrc:/images/icons/dialog-warning.svg"
+        actionButton.text: qsTr("Details")
+        actionButton.onClicked: toggleDetails()
+        rejectButton.text: qsTr("Close")
+        rejectButton.onClicked: Qt.quit()
+        onVisibleChanged: app.fixWindowSize(errorDialog)
+        onImplicitHeightChanged: app.fixWindowSize(errorDialog)
+    }
+
+    Component {
+        id: progressComponent
+        ColumnLayout {
+            property alias progressBar: progressBar.value
+            property alias progressText: progressText.text
+            anchors.fill: parent
+            spacing: 4
+            ProgressBar {
+                id: progressBar
+                minimumValue: 0
+                maximumValue: 1
+                value: 0
+                Layout.fillWidth: true
+            }
+            Label {
+                id: progressText
+                text: ""
+                Layout.alignment: Qt.AlignRight
+            }
+        }
+    }
+
+    Ui.Dialog {
+        id: progressDialog
+        icon: "qrc:/images/icons/emblem-downloads.svg"
+        detailsVisible: true
+        detailedContentLoader.sourceComponent: progressComponent
+        rejectButton.text: qsTr("Cancel")
+        rejectButton.onClicked: Qt.quit()
+        onVisibleChanged: app.fixWindowSize(progressDialog)
+        onImplicitHeightChanged: app.fixWindowSize(progressDialog)
+    }
+
+    Component.onCompleted: {
+        app.init();
+    }
+}
diff --git a/src/app/qml/qml.qrc b/app/qml/qml.qrc
similarity index 78%
rename from src/app/qml/qml.qrc
rename to app/qml/qml.qrc
index 640e9f07108d13e701a9470cb50262b1ce40e70b..f0579e64390605af3ebc388c11d1887e1286a54c 100644
--- a/src/app/qml/qml.qrc
+++ b/app/qml/qml.qrc
@@ -1,6 +1,7 @@
 <RCC>
     <qresource prefix="/qml">
         <file>main.qml</file>
+        <file>ui/Dialog.qml</file>
         <file>scripts/Utility.js</file>
     </qresource>
 </RCC>
diff --git a/src/app/qml/scripts/Utility.js b/app/qml/scripts/Utility.js
similarity index 100%
rename from src/app/qml/scripts/Utility.js
rename to app/qml/scripts/Utility.js
diff --git a/app/qml/ui/Dialog.qml b/app/qml/ui/Dialog.qml
new file mode 100644
index 0000000000000000000000000000000000000000..b5f239fac85974ca7314ffacfdf3628180b2cefa
--- /dev/null
+++ b/app/qml/ui/Dialog.qml
@@ -0,0 +1,113 @@
+import QtQuick 2.0
+import QtQuick.Layouts 1.0
+import QtQuick.Controls 1.0
+
+ColumnLayout {
+    id: dialog
+
+    visible: false
+    anchors.fill: parent
+    anchors.margins: 12
+    spacing: 12
+
+    property alias icon: icon.source
+    property alias primaryText: primaryText.text
+    property alias informativeText: informativeText.text
+
+    property alias detailsVisible: details.visible
+    property alias detailedText: detailedText.text
+    property alias detailedContentLoader: detailedContentLoader
+
+    property alias actionButton: actionButton
+    property alias acceptButton: acceptButton
+    property alias rejectButton: rejectButton
+
+    function open() {
+        dialog.visible = true;
+    }
+
+    function close() {
+        dialog.visible = false;
+    }
+
+    function toggleDetails() {
+        details.visible = details.visible ? false : true;
+    }
+
+    RowLayout {
+        Layout.fillWidth: true
+        spacing: 12
+        Image {
+            id: icon
+            source: ""
+            visible: source.toString() ? true : false
+            Layout.preferredWidth: 48
+            Layout.preferredHeight: 48
+            sourceSize.width: 128
+            sourceSize.height: 128
+        }
+        ColumnLayout {
+            Layout.fillWidth: true
+            spacing: 4
+            Label {
+                id: primaryText
+                text: ""
+                visible: text ? true : false
+                Layout.fillWidth: true
+                wrapMode: Text.WrapAnywhere
+                font.bold: true
+                font.pixelSize: 14
+            }
+            Label {
+                id: informativeText
+                text: ""
+                visible: text ? true : false
+                Layout.fillWidth: true
+                wrapMode: Text.WrapAnywhere
+            }
+        }
+    }
+
+    ColumnLayout {
+        id: details
+        visible: false
+        Layout.fillWidth: true
+        Layout.fillHeight: true
+        spacing: 12
+        Label {
+            id: detailedText
+            text: ""
+            visible: text ? true : false
+            Layout.fillWidth: true
+            wrapMode: Text.WrapAnywhere
+        }
+        Loader {
+            id: detailedContentLoader
+            visible: (source.toString() || sourceComponent) ? true : false
+            Layout.fillWidth: true
+        }
+    }
+
+    RowLayout {
+        Layout.fillWidth: true
+        spacing: 4
+        Button {
+            id: actionButton
+            text: ""
+            visible: text ? true : false
+        }
+        Item {
+            Layout.fillWidth: true
+        }
+        Button {
+            id: acceptButton
+            text: ""
+            visible: text ? true : false
+        }
+        Button {
+            id: rejectButton
+            text: ""
+            visible: text ? true : false
+        }
+    }
+}
diff --git a/app/src/handlers/confighandler.cpp b/app/src/handlers/confighandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bc75e9faefc87d384f2ad19cd14ac38b580570e0
--- /dev/null
+++ b/app/src/handlers/confighandler.cpp
@@ -0,0 +1,63 @@
+#include "confighandler.h"
+
+#include <QStringList>
+
+#include "qtlib_dir.h"
+
+ConfigHandler::ConfigHandler(QObject *parent)
+    : QObject(parent)
+{
+    appConfig_ = qtlib::Config(":/configs");
+}
+
+QJsonObject ConfigHandler::getAppConfigApplication()
+{
+    if (appConfigApplication_.isEmpty()) {
+        appConfigApplication_ = appConfig_.get("application");
+    }
+    return appConfigApplication_;
+}
+
+QJsonObject ConfigHandler::getAppConfigInstallTypes()
+{
+    if (appConfigInstallTypes_.isEmpty()) {
+        QJsonObject installTypes = appConfig_.get("install_types");
+        foreach (const QString &key, installTypes.keys()) {
+            QJsonObject installtype = installTypes[key].toObject();
+            installtype["destination"] = convertPathString(installtype["destination"].toString());
+            installtype["generic_destination"] = convertPathString(installtype["generic_destination"].toString());
+            installTypes[key] = installtype;
+        }
+        QJsonObject installTypesAlias = appConfig_.get("install_types_alias");
+        foreach (const QString &key, installTypesAlias.keys()) {
+            QJsonObject installTypeAlias = installTypesAlias[key].toObject();
+            QString baseKey = installTypeAlias["base"].toString();
+            if (installTypes.contains(baseKey)) {
+                QJsonObject installType = installTypes[baseKey].toObject();
+                installType["base"] = baseKey;
+                installType["name"] = installTypeAlias["name"].toString();
+                installTypes[key] = installType;
+            }
+        }
+        appConfigInstallTypes_ = installTypes;
+    }
+    return appConfigInstallTypes_;
+}
+
+QString ConfigHandler::convertPathString(const QString &path)
+{
+    QString newPath = path;
+    if (newPath.contains("$HOME")) {
+        newPath.replace("$HOME", qtlib::Dir::homePath());
+    }
+    else if (newPath.contains("$XDG_DATA_HOME")) {
+        newPath.replace("$XDG_DATA_HOME", qtlib::Dir::genericDataPath());
+    }
+    else if (newPath.contains("$KDEHOME")) {
+        newPath.replace("$KDEHOME", qtlib::Dir::kdehomePath());
+    }
+    else if (newPath.contains("$APP_DATA")) {
+        newPath.replace("$APP_DATA", qtlib::Dir::genericDataPath() + "/" + getAppConfigApplication()["id"].toString());
+    }
+    return newPath;
+}
diff --git a/app/src/handlers/confighandler.h b/app/src/handlers/confighandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..247afc85f936d325f4477afe8bf907a22403eb44
--- /dev/null
+++ b/app/src/handlers/confighandler.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <QObject>
+#include <QJsonObject>
+
+#include "qtlib_config.h"
+
+class ConfigHandler : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit ConfigHandler(QObject *parent = 0);
+
+public slots:
+    QJsonObject getAppConfigApplication();
+    QJsonObject getAppConfigInstallTypes();
+
+private:
+    QString convertPathString(const QString &path);
+
+    qtlib::Config appConfig_;
+    QJsonObject appConfigApplication_;
+    QJsonObject appConfigInstallTypes_;
+};
diff --git a/src/app/handlers/xdgurlhandler.cpp b/app/src/handlers/ocsurlhandler.cpp
similarity index 60%
rename from src/app/handlers/xdgurlhandler.cpp
rename to app/src/handlers/ocsurlhandler.cpp
index 91533ca0b3dadda8e573f8c66e9ad61191dee0b8..3527d7b7387b715d1fe92f04bd30356f1c26ff7a 100644
--- a/src/app/handlers/xdgurlhandler.cpp
+++ b/app/src/handlers/ocsurlhandler.cpp
@@ -1,4 +1,4 @@
-#include "xdgurlhandler.h"
+#include "ocsurlhandler.h"
 
 #include <QUrlQuery>
 #include <QDesktopServices>
@@ -8,45 +8,46 @@
 #include "qtlib_networkresource.h"
 #include "qtlib_package.h"
 
-XdgUrlHandler::XdgUrlHandler(const QString &xdgUrl, const qtlib::Config &config, QObject *parent)
-    : QObject(parent), xdgUrl_(xdgUrl), config_(config)
+#include "handlers/confighandler.h"
+
+OcsUrlHandler::OcsUrlHandler(const QString &ocsUrl, ConfigHandler *configHandler, QObject *parent)
+    : QObject(parent), ocsUrl_(ocsUrl), configHandler_(configHandler)
 {
     parse();
-    loadDestinations();
 }
 
-QString XdgUrlHandler::xdgUrl() const
+QString OcsUrlHandler::ocsUrl() const
 {
-    return xdgUrl_;
+    return ocsUrl_;
 }
 
-QJsonObject XdgUrlHandler::metadata() const
+QJsonObject OcsUrlHandler::metadata() const
 {
     return metadata_;
 }
 
-void XdgUrlHandler::process()
+void OcsUrlHandler::process()
 {
-    // xdgs scheme is a reserved name, so the process of xdgs
-    // is the same process of the xdg scheme currently.
+    // ocss scheme is a reserved name, so the process of ocss
+    // is the same process of the ocs scheme currently.
 
     if (!isValid()) {
         QJsonObject result;
         result["status"] = QString("error_validation");
-        result["message"] = QString("Invalid XDG-URL " + xdgUrl_);
+        result["message"] = tr("Invalid OCS-URL");
         emit finishedWithError(result);
         return;
     }
 
     QString url = metadata_["url"].toString();
     qtlib::NetworkResource *resource = new qtlib::NetworkResource(url, QUrl(url), true, this);
-    connect(resource, &qtlib::NetworkResource::downloadProgress, this, &XdgUrlHandler::downloadProgress);
-    connect(resource, &qtlib::NetworkResource::finished, this, &XdgUrlHandler::networkResourceFinished);
+    connect(resource, &qtlib::NetworkResource::downloadProgress, this, &OcsUrlHandler::downloadProgress);
+    connect(resource, &qtlib::NetworkResource::finished, this, &OcsUrlHandler::networkResourceFinished);
     resource->get();
     emit started();
 }
 
-bool XdgUrlHandler::isValid()
+bool OcsUrlHandler::isValid()
 {
     QString scheme = metadata_["scheme"].toString();
     QString command = metadata_["command"].toString();
@@ -54,23 +55,24 @@ bool XdgUrlHandler::isValid()
     QString type = metadata_["type"].toString();
     QString filename = metadata_["filename"].toString();
 
-    if ((scheme == "xdg" || scheme == "xdgs")
+    // Still support xdg and xdgs schemes for backward compatibility
+    if ((scheme == "ocs" || scheme == "ocss" || scheme == "xdg" || scheme == "xdgs")
             && (command == "download" || command == "install")
             && QUrl(url).isValid()
-            && destinations_.contains(type)
+            && configHandler_->getAppConfigInstallTypes().contains(type)
             && !filename.isEmpty()) {
         return true;
     }
     return false;
 }
 
-void XdgUrlHandler::openDestination()
+void OcsUrlHandler::openDestination()
 {
     QString type = metadata_["type"].toString();
-    QDesktopServices::openUrl(QUrl("file://" + destinations_[type].toString()));
+    QDesktopServices::openUrl(QUrl("file://" + configHandler_->getAppConfigInstallTypes()[type].toObject()["destination"].toString()));
 }
 
-void XdgUrlHandler::networkResourceFinished(qtlib::NetworkResource *resource)
+void OcsUrlHandler::networkResourceFinished(qtlib::NetworkResource *resource)
 {
     if (!resource->isFinishedWithNoError()) {
         QJsonObject result;
@@ -89,12 +91,12 @@ void XdgUrlHandler::networkResourceFinished(qtlib::NetworkResource *resource)
     }
 }
 
-void XdgUrlHandler::parse()
+void OcsUrlHandler::parse()
 {
-    QUrl url(xdgUrl_);
+    QUrl url(ocsUrl_);
     QUrlQuery query(url);
 
-    metadata_["scheme"] = QString("xdg");
+    metadata_["scheme"] = QString("ocs");
     metadata_["command"] = QString("download");
     metadata_["url"] = QString("");
     metadata_["type"] = QString("downloads");
@@ -125,65 +127,31 @@ void XdgUrlHandler::parse()
     }
 }
 
-void XdgUrlHandler::loadDestinations()
-{
-    QJsonObject configDestinations = config_.get("destinations");
-    QJsonObject configDestinationsAlias = config_.get("destinations_alias");
-
-    foreach (const QString &key, configDestinations.keys()) {
-        destinations_[key] = convertPathString(configDestinations[key].toString());
-    }
-
-    foreach (const QString &key, configDestinationsAlias.keys()) {
-        QString value = configDestinationsAlias[key].toString();
-        if (destinations_.contains(value)) {
-            destinations_[key] = destinations_.value(value);
-        }
-    }
-}
-
-QString XdgUrlHandler::convertPathString(const QString &path)
-{
-    QString newPath = path;
-
-    if (newPath.contains("$HOME")) {
-        newPath.replace("$HOME", qtlib::Dir::homePath());
-    }
-    else if (newPath.contains("$XDG_DATA_HOME")) {
-        newPath.replace("$XDG_DATA_HOME", qtlib::Dir::genericDataPath());
-    }
-    else if (newPath.contains("$KDEHOME")) {
-        newPath.replace("$KDEHOME", qtlib::Dir::kdehomePath());
-    }
-
-    return newPath;
-}
-
-void XdgUrlHandler::saveDownloadedFile(qtlib::NetworkResource *resource)
+void OcsUrlHandler::saveDownloadedFile(qtlib::NetworkResource *resource)
 {
     QJsonObject result;
 
     QString type = metadata_["type"].toString();
-    qtlib::Dir destDir(destinations_[type].toString());
+    qtlib::Dir destDir(configHandler_->getAppConfigInstallTypes()[type].toObject()["destination"].toString());
     destDir.make();
     qtlib::File destFile(destDir.path() + "/" + metadata_["filename"].toString());
 
     if (!resource->saveData(destFile.path())) {
         result["status"] = QString("error_save");
-        result["message"] = QString("Failed to save data as " + destFile.path());
+        result["message"] = tr("Failed to save data");
         emit finishedWithError(result);
         resource->deleteLater();
         return;
     }
 
     result["status"] = QString("success_download");
-    result["message"] = QString("The file has been stored into " + destDir.path());
+    result["message"] = tr("The file has been downloaded");
     emit finishedWithSuccess(result);
 
     resource->deleteLater();
 }
 
-void XdgUrlHandler::installDownloadedFile(qtlib::NetworkResource *resource)
+void OcsUrlHandler::installDownloadedFile(qtlib::NetworkResource *resource)
 {
     QJsonObject result;
 
@@ -191,7 +159,7 @@ void XdgUrlHandler::installDownloadedFile(qtlib::NetworkResource *resource)
 
     if (!resource->saveData(tempFile.path())) {
         result["status"] = QString("error_save");
-        result["message"] = QString("Failed to save data as " + tempFile.path());
+        result["message"] = tr("Failed to save data");
         emit finishedWithError(result);
         resource->deleteLater();
         return;
@@ -199,47 +167,47 @@ void XdgUrlHandler::installDownloadedFile(qtlib::NetworkResource *resource)
 
     qtlib::Package package(tempFile.path());
     QString type = metadata_["type"].toString();
-    qtlib::Dir destDir(destinations_[type].toString());
+    qtlib::Dir destDir(configHandler_->getAppConfigInstallTypes()[type].toObject()["destination"].toString());
     destDir.make();
     qtlib::File destFile(destDir.path() + "/" + metadata_["filename"].toString());
 
     if (type == "bin"
             && package.installAsProgram(destFile.path())) {
-        result["message"] = QString("The file has been installed into " + destDir.path());
+        result["message"] = tr("The file has been installed as program");
     }
     else if ((type == "plasma_plasmoids" || type == "plasma4_plasmoids" || type == "plasma5_plasmoids")
              && package.installAsPlasmapkg("plasmoid")) {
-        result["message"] = QString("The plasmoid has been installed");
+        result["message"] = tr("The plasmoid has been installed");
     }
     else if ((type == "plasma_look_and_feel" || type == "plasma5_look_and_feel")
              && package.installAsPlasmapkg("lookandfeel")) {
-        result["message"] = QString("The plasma look and feel has been installed");
+        result["message"] = tr("The plasma look and feel has been installed");
     }
     else if ((type == "plasma_desktopthemes" || type == "plasma5_desktopthemes")
              && package.installAsPlasmapkg("theme")) {
-        result["message"] = QString("The plasma desktop theme has been installed");
+        result["message"] = tr("The plasma desktop theme has been installed");
     }
     else if (type == "kwin_effects"
              && package.installAsPlasmapkg("kwineffect")) {
-        result["message"] = QString("The KWin effect has been installed");
+        result["message"] = tr("The KWin effect has been installed");
     }
     else if (type == "kwin_scripts"
              && package.installAsPlasmapkg("kwinscript")) {
-        result["message"] = QString("The KWin script has been installed");
+        result["message"] = tr("The KWin script has been installed");
     }
     else if (type == "kwin_tabbox"
              && package.installAsPlasmapkg("windowswitcher")) {
-        result["message"] = QString("The KWin window switcher has been installed");
+        result["message"] = tr("The KWin window switcher has been installed");
     }
     else if (package.installAsArchive(destDir.path())) {
-        result["message"] = QString("The archive file has been extracted into " + destDir.path());
+        result["message"] = tr("The archive file has been extracted");
     }
     else if (package.installAsFile(destFile.path())) {
-        result["message"] = QString("The file has been installed into " + destDir.path());
+        result["message"] = tr("The file has been installed");
     }
     else {
         result["status"] = QString("error_install");
-        result["message"] = QString("Failed to installation");
+        result["message"] = tr("Failed to installation");
         emit finishedWithError(result);
         tempFile.remove();
         return;
diff --git a/src/app/handlers/xdgurlhandler.h b/app/src/handlers/ocsurlhandler.h
similarity index 67%
rename from src/app/handlers/xdgurlhandler.h
rename to app/src/handlers/ocsurlhandler.h
index 6abc30b79b760f7093da5e438946f0a98a2f0373..8c3f99da2d60069181862017af66386a97dfd797 100644
--- a/src/app/handlers/xdgurlhandler.h
+++ b/app/src/handlers/ocsurlhandler.h
@@ -3,18 +3,18 @@
 #include <QObject>
 #include <QJsonObject>
 
-#include "qtlib_config.h"
-
 namespace qtlib {
 class NetworkResource;
 }
 
-class XdgUrlHandler : public QObject
+class ConfigHandler;
+
+class OcsUrlHandler : public QObject
 {
     Q_OBJECT
 
 public:
-    explicit XdgUrlHandler(const QString &xdgUrl, const qtlib::Config &config, QObject *parent = 0);
+    explicit OcsUrlHandler(const QString &ocsUrl, ConfigHandler *configHandler, QObject *parent = 0);
 
 signals:
     void started();
@@ -23,7 +23,7 @@ signals:
     void downloadProgress(QString id, qint64 bytesReceived, qint64 bytesTotal);
 
 public slots:
-    QString xdgUrl() const;
+    QString ocsUrl() const;
     QJsonObject metadata() const;
 
     void process();
@@ -35,13 +35,10 @@ private slots:
 
 private:
     void parse();
-    void loadDestinations();
-    QString convertPathString(const QString &path);
     void saveDownloadedFile(qtlib::NetworkResource *resource);
     void installDownloadedFile(qtlib::NetworkResource *resource);
 
-    QString xdgUrl_;
-    qtlib::Config config_;
+    QString ocsUrl_;
+    ConfigHandler *configHandler_;
     QJsonObject metadata_;
-    QJsonObject destinations_;
 };
diff --git a/app/src/main.cpp b/app/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3acb73c3b6296be24473469ddd9023d843d17859
--- /dev/null
+++ b/app/src/main.cpp
@@ -0,0 +1,61 @@
+#include <QString>
+#include <QStringList>
+#include <QUrl>
+#include <QJsonObject>
+#include <QTranslator>
+#include <QLocale>
+#include <QCommandLineParser>
+#include <QApplication>
+#include <QIcon>
+#include <QQmlApplicationEngine>
+#include <QQmlContext>
+
+#include "handlers/confighandler.h"
+#include "handlers/ocsurlhandler.h"
+
+int main(int argc, char *argv[])
+{
+    // Init
+    QApplication app(argc, argv);
+
+    ConfigHandler *configHandler = new ConfigHandler();
+    QJsonObject appConfigApplication = configHandler->getAppConfigApplication();
+
+    app.setApplicationName(appConfigApplication["name"].toString());
+    app.setApplicationVersion(appConfigApplication["version"].toString());
+    app.setOrganizationName(appConfigApplication["organization"].toString());
+    app.setOrganizationDomain(appConfigApplication["domain"].toString());
+    app.setWindowIcon(QIcon::fromTheme(appConfigApplication["id"].toString(), QIcon(appConfigApplication["icon"].toString())));
+
+    // Setup translator
+    QTranslator translator;
+    if (translator.load(QLocale(), "messages", ".", ":/i18n")) {
+        app.installTranslator(&translator);
+    }
+
+    // Setup CLI
+    QCommandLineParser clParser;
+    clParser.setApplicationDescription(appConfigApplication["description"].toString());
+    clParser.addHelpOption();
+    clParser.addVersionOption();
+    clParser.addPositionalArgument("OCS-URL", "OCS-URL that starts with ocs://");
+    clParser.process(app);
+
+    QStringList args = clParser.positionalArguments();
+
+    if (args.size() != 1) {
+        clParser.showHelp(1);
+    }
+
+    QString ocsUrl = args.at(0);
+
+    // Setup QML
+    QQmlApplicationEngine qmlAppEngine;
+    QQmlContext *qmlContext = qmlAppEngine.rootContext();
+    configHandler->setParent(&qmlAppEngine);
+    qmlContext->setContextProperty("configHandler", configHandler);
+    qmlContext->setContextProperty("ocsUrlHandler", new OcsUrlHandler(ocsUrl, configHandler, &qmlAppEngine));
+    qmlAppEngine.load(QUrl("qrc:/qml/main.qml"));
+
+    return app.exec();
+}
diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml
new file mode 100644
index 0000000000000000000000000000000000000000..739213c255e1a294c4e85f67098c752ea3c75a60
--- /dev/null
+++ b/bitbucket-pipelines.yml
@@ -0,0 +1,78 @@
+pipelines:
+  branches:
+    master:
+      - step:
+          image: ubuntu:14.04
+          script:
+            - apt update -qq
+            - apt -y install sudo git curl
+            - apt -y install build-essential qt5-default libqt5svg5-dev qtdeclarative5-dev
+            - apt -y install devscripts debhelper fakeroot
+            - useradd -m pkgbuilder
+            - export HOME=/home/pkgbuilder
+            - chown -R pkgbuilder:pkgbuilder $(pwd)
+            - sudo -u pkgbuilder sh scripts/build.sh ubuntu
+  custom:
+    build-ubuntu:
+      - step:
+          image: ubuntu:14.04
+          script:
+            - apt update -qq
+            - apt -y install sudo git curl
+            - apt -y install build-essential qt5-default libqt5svg5-dev qtdeclarative5-dev
+            - apt -y install devscripts debhelper fakeroot
+            - useradd -m pkgbuilder
+            - export HOME=/home/pkgbuilder
+            - chown -R pkgbuilder:pkgbuilder $(pwd)
+            - sudo -u pkgbuilder sh scripts/build.sh ubuntu
+    build-fedora:
+      - step:
+          image: fedora:20
+          script:
+            # dnf >= fedora:22
+            - yum -y install sudo git curl
+            - yum -y install make automake gcc gcc-c++ libtool qt5-qtbase-devel qt5-qtsvg-devel qt5-qtdeclarative-devel
+            - yum -y install rpm-build
+            - useradd -m pkgbuilder
+            - export HOME=/home/pkgbuilder
+            - chown -R pkgbuilder:pkgbuilder $(pwd)
+            - sudo -u pkgbuilder sh scripts/build.sh fedora
+    build-archlinux:
+      - step:
+          image: finalduty/archlinux:latest
+          script:
+            - pacman -Syu --noconfirm
+            - pacman -S --noconfirm sudo git curl
+            - pacman -S --noconfirm base-devel qt5-base qt5-svg qt5-declarative qt5-quickcontrols
+            - useradd -m pkgbuilder
+            - export HOME=/home/pkgbuilder
+            - chown -R pkgbuilder:pkgbuilder $(pwd)
+            - sudo -u pkgbuilder sh scripts/build.sh archlinux
+    build-snap:
+      - step:
+          image: ubuntu:16.04
+          script:
+            - apt update -qq
+            - apt -y install sudo git curl
+            - apt -y install build-essential qt5-default libqt5svg5-dev qtdeclarative5-dev
+            - apt -y install snapcraft
+            - useradd -m pkgbuilder
+            - export HOME=/home/pkgbuilder
+            - chown -R pkgbuilder:pkgbuilder $(pwd)
+            - sudo -u pkgbuilder sh scripts/build.sh snap
+    build-appimage:
+      - step:
+          image: ubuntu:14.04
+          script:
+            # Require docker run with --cap-add SYS_ADMIN --device /dev/fuse
+            - echo 'appimage build is disabled currently'
+            - exit 1
+            - apt update -qq
+            - apt -y install sudo git curl
+            - apt -y install build-essential qt5-default libqt5svg5-dev qtdeclarative5-dev
+            - apt -y install fuse zsync desktop-file-utils
+            #- modprobe fuse
+            - useradd -m pkgbuilder
+            - export HOME=/home/pkgbuilder
+            - chown -R pkgbuilder:pkgbuilder $(pwd)
+            - sudo -u pkgbuilder sh scripts/build.sh appimage
diff --git a/deployment.pri b/deployment.pri
index a2a7b028b669e1895c1c220b451eebec0f22bf26..4e9bd388fcc47f4b32fed33ea3491ea492ceb5f8 100644
--- a/deployment.pri
+++ b/deployment.pri
@@ -3,7 +3,7 @@ unix:!ios:!android {
         PREFIX = /usr/local
     }
 
-    SRCDIR = $${PWD}/src
+    SRCDIR = $${PWD}
     BINDIR = $${PREFIX}/bin
     DATADIR = $${PREFIX}/share
 
diff --git a/desktop/desktop.pri b/desktop/desktop.pri
new file mode 100644
index 0000000000000000000000000000000000000000..0c1a8062e68d0287a37cb2761a6f2b15dad685ed
--- /dev/null
+++ b/desktop/desktop.pri
@@ -0,0 +1,3 @@
+RESOURCES += $${PWD}/desktop.qrc
+
+DISTFILES += $${PWD}/ocs-url.desktop
diff --git a/src/desktop/desktop.qrc b/desktop/desktop.qrc
similarity index 65%
rename from src/desktop/desktop.qrc
rename to desktop/desktop.qrc
index 2e0475004292b32a2a8c875f6fcbb03092c91fc4..61a8e10308f03346c57c709c3b9e0a380a8b79a1 100644
--- a/src/desktop/desktop.qrc
+++ b/desktop/desktop.qrc
@@ -1,5 +1,5 @@
 <RCC>
     <qresource prefix="/desktop">
-        <file>xdgurl.svg</file>
+        <file>ocs-url.svg</file>
     </qresource>
 </RCC>
diff --git a/desktop/ocs-url.desktop b/desktop/ocs-url.desktop
new file mode 100644
index 0000000000000000000000000000000000000000..9f41684b00e845c044647dd453caad61181874a3
--- /dev/null
+++ b/desktop/ocs-url.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=ocs-url
+Exec=ocs-url %u
+Icon=ocs-url
+Type=Application
+Terminal=false
+NoDisplay=true
+Categories=Network;Utility;
+MimeType=x-scheme-handler/ocs;x-scheme-handler/ocss;x-scheme-handler/xdg;x-scheme-handler/xdgs;
diff --git a/desktop/ocs-url.svg b/desktop/ocs-url.svg
new file mode 100644
index 0000000000000000000000000000000000000000..befab89cf7c80c503cd1b9e8fc23693e73cb98ab
--- /dev/null
+++ b/desktop/ocs-url.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="1000" height="1000" viewBox="0, 0, 1000, 1000">
+  <g id="icon">
+    <g id="background">
+      <path d="M975,500 C975,762.335 762.335,975 500,975 C237.665,975 25,762.335 25,500 C25,237.665 237.665,25 500,25 C762.335,25 975,237.665 975,500 z" fill="#19A2FF" id="background-2"/>
+      <path d="M950,500 C950,748.528 748.528,950 500,950 C251.472,950 50,748.528 50,500 C50,251.472 251.472,50 500,50 C748.528,50 950,251.472 950,500 z" fill="#53B2FF" id="background-1"/>
+    </g>
+    <g id="ocs-url">
+      <path d="M902.992,380.107 L924.992,380.107 L830.653,670.28 L808.653,670.28 z" fill="#FFFFFF" id="slash-2"/>
+      <path d="M852.992,380.107 L874.992,380.107 L780.653,670.28 L758.653,670.28 z" fill="#FFFFFF" id="slash-1"/>
+      <path d="M739.533,556.848 L775.533,556.848 L775.533,592.848 L739.533,592.848 z" fill="#FFFFFF" id="colon-2"/>
+      <path d="M739.505,457.85 L775.505,457.85 L775.505,493.85 L739.505,493.85 z" fill="#FFFFFF" id="colon-1"/>
+      <path d="M619.548,389.93 Q581.46,389.931 559.59,399.494 Q537.719,409.057 526.825,425.772 Q515.931,442.487 515.931,461.281 Q515.931,489.888 537.22,508.349 Q558.342,526.811 607.906,537.954 Q638.175,544.607 646.491,552.091 Q654.807,559.576 654.807,569.055 Q654.807,579.035 646.076,586.602 Q637.343,594.17 621.211,594.169 Q599.589,594.17 587.947,579.367 Q580.795,570.22 578.467,552.756 L506.784,557.247 Q509.943,594.17 533.893,618.12 Q557.843,642.07 620.047,642.069 Q655.472,642.07 678.757,631.84 Q702.041,621.612 715.014,601.82 Q727.987,582.029 727.987,558.577 Q727.987,538.619 718.258,522.486 Q708.528,506.354 687.156,495.459 Q665.784,484.566 616.388,473.921 Q596.429,469.764 591.108,464.94 Q585.618,460.283 585.619,454.462 Q585.618,446.479 592.272,440.907 Q598.924,435.336 612.063,435.335 Q628.03,435.336 637.094,442.819 Q646.158,450.304 648.986,466.77 L720.005,462.611 Q715.347,424.691 690.815,407.31 Q666.283,389.931 619.548,389.93 z" fill="#FFFFFF" id="s"/>
+      <path d="M449.767,389.931 Q424.743,389.931 401.937,399.275 Q379.13,408.62 361.867,425.249 Q344.604,441.879 334.31,464.844 Q324.015,487.809 324.015,515.366 Q324.015,542.925 334.468,566.206 Q344.921,589.488 362.184,606.434 Q379.447,623.381 402.095,632.724 Q424.743,642.069 449.451,642.069 Q461.487,642.069 473.841,639.693 Q486.194,637.318 500.448,632.249 L506.784,630.032 L506.784,556.544 Q483.027,581.886 453.252,581.885 Q439.631,581.886 427.911,576.817 Q416.191,571.75 407.48,562.88 Q398.769,554.011 393.86,541.974 Q388.95,529.938 388.95,515.683 Q388.95,501.746 393.86,489.709 Q398.769,477.673 407.322,468.961 Q415.874,460.251 427.753,455.182 Q439.631,450.115 453.568,450.114 Q485.244,450.115 506.784,476.405 L506.784,402.284 Q491.579,395.95 477.8,392.94 Q464.021,389.931 449.767,389.931 z" fill="#FFFFFF" id="c"/>
+      <path d="M223.997,389.93 Q252.822,389.932 277.212,399.591 Q301.602,409.254 319.183,426.357 Q336.762,443.463 346.582,466.427 Q356.401,489.393 356.402,515.999 Q356.401,542.608 346.582,565.572 Q336.762,588.538 319.183,605.641 Q301.602,622.748 277.212,632.407 Q252.822,642.07 223.997,642.068 Q194.855,642.07 170.624,632.407 Q146.392,622.748 128.97,605.641 Q111.548,588.538 101.729,565.572 Q91.91,542.608 91.91,515.999 Q91.91,489.393 101.729,466.427 Q111.548,443.463 128.97,426.357 Q146.392,409.254 170.624,399.591 Q194.855,389.932 223.997,389.93 z M223.997,450.114 Q210.377,450.115 198.182,455.024 Q185.986,459.935 176.801,468.803 Q167.614,477.673 162.23,489.709 Q156.845,501.747 156.845,515.999 Q156.845,530.255 162.23,542.29 Q167.614,554.328 176.801,563.196 Q185.986,572.067 198.182,576.975 Q210.377,581.886 223.997,581.885 Q237.618,581.886 249.813,576.975 Q262.008,572.067 271.352,563.196 Q280.697,554.328 286.082,542.29 Q291.466,530.255 291.466,515.999 Q291.466,501.747 286.082,489.709 Q280.697,477.673 271.352,468.803 Q262.008,459.935 249.813,455.024 Q237.618,450.115 223.997,450.114 z" fill="#FFFFFF" id="o"/>
+    </g>
+  </g>
+</svg>
diff --git a/i18n/i18n.pri b/i18n/i18n.pri
new file mode 100644
index 0000000000000000000000000000000000000000..31b3fcf015d808de7fd1fb6b0118bb263b3859bf
--- /dev/null
+++ b/i18n/i18n.pri
@@ -0,0 +1 @@
+RESOURCES += $${PWD}/i18n.qrc
diff --git a/i18n/i18n.pro b/i18n/i18n.pro
new file mode 100644
index 0000000000000000000000000000000000000000..69dbabbda28aed392a3bef2b8912e0bb971e3eac
--- /dev/null
+++ b/i18n/i18n.pro
@@ -0,0 +1,7 @@
+SOURCES += $$system(find ../app -type f -name "*.cpp" -or -name "*.qml" -or -name "*.js")
+
+TRANSLATIONS += \
+    messages.ts \
+    messages.en_US.ts
+
+include(i18n.pri)
diff --git a/i18n/i18n.qrc b/i18n/i18n.qrc
new file mode 100644
index 0000000000000000000000000000000000000000..196056e88cd16b582c2230e134a580b74746714b
--- /dev/null
+++ b/i18n/i18n.qrc
@@ -0,0 +1,6 @@
+<RCC>
+    <qresource prefix="/i18n">
+        <file>messages.qm</file>
+        <file>messages.en_US.qm</file>
+    </qresource>
+</RCC>
diff --git a/i18n/messages.en_US.qm b/i18n/messages.en_US.qm
new file mode 100644
index 0000000000000000000000000000000000000000..9dad8dffceb9623e88f8b96d9cd0caf25574c6fa
Binary files /dev/null and b/i18n/messages.en_US.qm differ
diff --git a/i18n/messages.en_US.ts b/i18n/messages.en_US.ts
new file mode 100644
index 0000000000000000000000000000000000000000..03aaebb4f3b17512eead28b3ca74779ec73128c4
--- /dev/null
+++ b/i18n/messages.en_US.ts
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="en_US">
+<context>
+    <name>OcsUrlHandler</name>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="37"/>
+        <source>Invalid OCS-URL</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="141"/>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="162"/>
+        <source>Failed to save data</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="148"/>
+        <source>The file has been downloaded</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="176"/>
+        <source>The file has been installed as program</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="180"/>
+        <source>The plasmoid has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="184"/>
+        <source>The plasma look and feel has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="188"/>
+        <source>The plasma desktop theme has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="192"/>
+        <source>The KWin effect has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="196"/>
+        <source>The KWin script has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="200"/>
+        <source>The KWin window switcher has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="203"/>
+        <source>The archive file has been extracted</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="206"/>
+        <source>The file has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="210"/>
+        <source>Failed to installation</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>main</name>
+    <message>
+        <location filename="../app/qml/main.qml" line="26"/>
+        <source>Download successfull</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="27"/>
+        <source>Installation successfull</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="28"/>
+        <source>Validation error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="29"/>
+        <source>Network error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="30"/>
+        <source>Saving file failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="31"/>
+        <source>Installation failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="56"/>
+        <source>Downloading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="66"/>
+        <source>Do you want to download?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="69"/>
+        <source>Do you want to install?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="73"/>
+        <source>URL</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="74"/>
+        <source>File</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="75"/>
+        <source>Type</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="80"/>
+        <source>Invalid OCS-URL</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="94"/>
+        <location filename="../app/qml/main.qml" line="107"/>
+        <location filename="../app/qml/main.qml" line="123"/>
+        <source>Details</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="96"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="98"/>
+        <location filename="../app/qml/main.qml" line="158"/>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="109"/>
+        <source>Open</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="114"/>
+        <location filename="../app/qml/main.qml" line="125"/>
+        <source>Close</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+</TS>
diff --git a/i18n/messages.qm b/i18n/messages.qm
new file mode 100644
index 0000000000000000000000000000000000000000..be651eede2edc9cb0da5c140b31664afee169fa8
--- /dev/null
+++ b/i18n/messages.qm
@@ -0,0 +1 @@
+<¸dÊÍ!¿`¡½Ý
\ No newline at end of file
diff --git a/i18n/messages.ts b/i18n/messages.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4998b50f8f8a6b17885ecde404892f6690e7cdb7
--- /dev/null
+++ b/i18n/messages.ts
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1">
+<context>
+    <name>OcsUrlHandler</name>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="37"/>
+        <source>Invalid OCS-URL</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="141"/>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="162"/>
+        <source>Failed to save data</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="148"/>
+        <source>The file has been downloaded</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="176"/>
+        <source>The file has been installed as program</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="180"/>
+        <source>The plasmoid has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="184"/>
+        <source>The plasma look and feel has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="188"/>
+        <source>The plasma desktop theme has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="192"/>
+        <source>The KWin effect has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="196"/>
+        <source>The KWin script has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="200"/>
+        <source>The KWin window switcher has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="203"/>
+        <source>The archive file has been extracted</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="206"/>
+        <source>The file has been installed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/src/handlers/ocsurlhandler.cpp" line="210"/>
+        <source>Failed to installation</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>main</name>
+    <message>
+        <location filename="../app/qml/main.qml" line="26"/>
+        <source>Download successfull</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="27"/>
+        <source>Installation successfull</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="28"/>
+        <source>Validation error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="29"/>
+        <source>Network error</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="30"/>
+        <source>Saving file failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="31"/>
+        <source>Installation failed</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="56"/>
+        <source>Downloading</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="66"/>
+        <source>Do you want to download?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="69"/>
+        <source>Do you want to install?</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="73"/>
+        <source>URL</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="74"/>
+        <source>File</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="75"/>
+        <source>Type</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="80"/>
+        <source>Invalid OCS-URL</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="94"/>
+        <location filename="../app/qml/main.qml" line="107"/>
+        <location filename="../app/qml/main.qml" line="123"/>
+        <source>Details</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="96"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="98"/>
+        <location filename="../app/qml/main.qml" line="158"/>
+        <source>Cancel</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="109"/>
+        <source>Open</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../app/qml/main.qml" line="114"/>
+        <location filename="../app/qml/main.qml" line="125"/>
+        <source>Close</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+</TS>
diff --git a/lib/lib.pri b/lib/lib.pri
new file mode 100644
index 0000000000000000000000000000000000000000..5343ea67e320f54da6851de3969e590c456d432d
--- /dev/null
+++ b/lib/lib.pri
@@ -0,0 +1 @@
+include($${PWD}/qtlib/qtlib.pri)
diff --git a/ocs-url.pro b/ocs-url.pro
new file mode 100644
index 0000000000000000000000000000000000000000..7a6c52c793ebfed7ca7880f0535d794419b71e7d
--- /dev/null
+++ b/ocs-url.pro
@@ -0,0 +1,18 @@
+TARGET = ocs-url
+
+TEMPLATE = app
+
+CONFIG += c++11
+
+DEFINES += QT_DEPRECATED_WARNINGS
+
+DISTFILES += README.md
+
+include(lib/lib.pri)
+include(app/app.pri)
+include(desktop/desktop.pri)
+include(i18n/i18n.pri)
+include(pkg/pkg.pri)
+include(scripts/scripts.pri)
+
+include(deployment.pri)
diff --git a/src/desktop/appimage-desktopintegration b/pkg/appimage/appimage-desktopintegration_ocs-url
similarity index 99%
rename from src/desktop/appimage-desktopintegration
rename to pkg/appimage/appimage-desktopintegration_ocs-url
index bc48aea4b4ea720d2ff1339d2acde0e6c730de44..7fe9f5e9a07a978c0e64cb9ac7d82daef70c4eba 100755
--- a/src/desktop/appimage-desktopintegration
+++ b/pkg/appimage/appimage-desktopintegration_ocs-url
@@ -25,7 +25,7 @@ VENDORPREFIX=appimagekit
 
 APPDIR="$(dirname "$(readlink -f "${THIS}")")"
 
-BIN="${APPDIR}/xdgurl"
+BIN="${APPDIR}/ocs-url"
 export PATH="${APPDIR}/usr/bin:$PATH"
 
 trap atexit EXIT
diff --git a/pkg/arch/PKGBUILD b/pkg/arch/PKGBUILD
deleted file mode 100644
index fbb56ae6f9b6ff0bc02d917c7f5631dbb206289b..0000000000000000000000000000000000000000
--- a/pkg/arch/PKGBUILD
+++ /dev/null
@@ -1,26 +0,0 @@
-# Maintainer: Akira Ohgaki <akiraohgaki@gmail.com>
-
-pkgname='xdgurl'
-pkgver='2.0.3'
-pkgrel='1'
-pkgdesc='An install helper program for desktop stuff.'
-arch=('i686' 'x86_64')
-url='https://github.com/xdgurl/xdgurl'
-license=('GPL3')
-depends=('qt5-base>=5.3.0' 'qt5-svg>=5.3.0' 'qt5-declarative>=5.3.0' 'qt5-quickcontrols>=5.3.0')
-#source=("https://github.com/xdgurl/xdgurl/archive/release-${pkgver}.tar.gz")
-source=("${pkgname}.tar.gz")
-md5sums=() #autofill using updpkgsums
-
-build() {
-    #cd "${pkgname}-release-${pkgver}"
-    cd "${pkgname}"
-    qmake PREFIX='/usr'
-    make
-}
-
-package() {
-    #cd "${pkgname}-release-${pkgver}"
-    cd "${pkgname}"
-    make INSTALL_ROOT="${pkgdir}" install
-}
diff --git a/pkg/archlinux/PKGBUILD b/pkg/archlinux/PKGBUILD
new file mode 100644
index 0000000000000000000000000000000000000000..a61184d6d4aad54e3e3316af43ac8a4bad4c5b99
--- /dev/null
+++ b/pkg/archlinux/PKGBUILD
@@ -0,0 +1,33 @@
+# Maintainer: Akira Ohgaki <akiraohgaki@gmail.com>
+
+pkgname='ocs-url'
+pkgver='3.0.0'
+pkgrel='1'
+pkgdesc='An install helper program for items served on OpenCollaborationServices (OCS).'
+arch=('i686' 'x86_64')
+url='https://github.com/ocs-url/ocs-url'
+license=('GPL3')
+depends=('qt5-base>=5.2.0' 'qt5-svg>=5.2.0' 'qt5-declarative>=5.2.0' 'qt5-quickcontrols>=5.2.0')
+makedepends=('git')
+#source=("https://github.com/ocs-url/ocs-url/archive/release-${pkgver}.tar.gz")
+source=("${pkgname}.tar.gz")
+md5sums=() #autofill using updpkgsums
+
+prepare() {
+    #cd "${pkgname}-release-${pkgver}"
+    cd "${pkgname}"
+    sh scripts/import.sh
+}
+
+build() {
+    #cd "${pkgname}-release-${pkgver}"
+    cd "${pkgname}"
+    qmake PREFIX="/usr"
+    make
+}
+
+package() {
+    #cd "${pkgname}-release-${pkgver}"
+    cd "${pkgname}"
+    make INSTALL_ROOT="${pkgdir}" install
+}
diff --git a/pkg/build.sh b/pkg/build.sh
deleted file mode 100644
index f848e2625191f03526aa93aa939dee882531f364..0000000000000000000000000000000000000000
--- a/pkg/build.sh
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/bin/bash
-
-PKGNAME='xdgurl'
-
-PROJDIR="$(cd "$(dirname "${0}")/../" && pwd)"
-
-BUILDDIR="${PROJDIR}/pkg/build"
-
-BUILDTYPE=''
-if [ "${1}" ]; then
-    BUILDTYPE="${1}"
-fi
-
-TREEISH='HEAD'
-if [ "${2}" ]; then
-    TREEISH="${2}"
-fi
-
-export_source() {
-    destdir="${BUILDDIR}"
-    if [ "${1}" ]; then
-        destdir="${1}"
-    fi
-    $(cd "${PROJDIR}" && git archive --prefix="${PKGNAME}/" --output="${destdir}/${PKGNAME}.tar.gz" "${TREEISH}")
-}
-
-build_ubuntu() {
-    #sudo apt install build-essential qt5-default libqt5svg5-dev qtdeclarative5-dev devscripts debhelper fakeroot
-
-    cd "${PROJDIR}"
-
-    mkdir -p "${BUILDDIR}"
-    export_source "${BUILDDIR}"
-    tar -xzvf "${BUILDDIR}/${PKGNAME}.tar.gz" -C "${BUILDDIR}"
-    cp -r "${PROJDIR}/pkg/ubuntu/debian" "${BUILDDIR}/${PKGNAME}"
-
-    cd "${BUILDDIR}/${PKGNAME}"
-    debuild -uc -us -b
-}
-
-build_fedora() {
-    #sudo dnf install make automake gcc gcc-c++ libtool qt5-qtbase-devel qt5-qtsvg-devel qt5-qtdeclarative-devel rpm-build
-
-    cd "${PROJDIR}"
-
-    mkdir -p "${BUILDDIR}"
-    mkdir "${BUILDDIR}/SOURCES"
-    mkdir "${BUILDDIR}/SPECS"
-    export_source "${BUILDDIR}/SOURCES"
-    cp "${PROJDIR}/pkg/fedora/xdgurl.spec" "${BUILDDIR}/SPECS"
-
-    rpmbuild --define "_topdir ${BUILDDIR}" -bb "${BUILDDIR}/SPECS/xdgurl.spec"
-}
-
-build_arch() {
-    #sudo pacman -S base-devel qt5-base qt5-svg qt5-declarative qt5-quickcontrols
-
-    cd "${PROJDIR}"
-
-    mkdir -p "${BUILDDIR}"
-    export_source "${BUILDDIR}"
-    cp "${PROJDIR}/pkg/arch/PKGBUILD" "${BUILDDIR}"
-
-    cd "${BUILDDIR}"
-    updpkgsums
-    makepkg -s
-}
-
-build_appimage() {
-    #sudo add-apt-repository ppa:beineri/opt-qt57-xenial
-    #sudo apt update
-
-    #sudo apt install build-essential fuse zsync desktop-file-utils
-    #sudo apt install qt57base qt57svg qt57declarative qt57quickcontrols
-    # Replace linuxdeployqt download URL to official download URL when the stable version released
-    #curl -L -o linuxdeployqt https://dl.dropboxusercontent.com/u/150776/temp/linuxdeployqt-799f704-x86-64.appimage
-    #sudo install -m 755 -p linuxdeployqt /usr/local/bin/linuxdeployqt
-
-    #sudo modprobe fuse
-    #source /opt/qt57/bin/qt57-env.sh
-
-    cd "${PROJDIR}"
-
-    export VERSION="$(git describe --always)"
-    mkdir -p "${BUILDDIR}"
-    export_source "${BUILDDIR}"
-    tar -xzvf "${BUILDDIR}/${PKGNAME}.tar.gz" -C "${BUILDDIR}"
-
-    cd "${BUILDDIR}/${PKGNAME}"
-    #qmake
-    /opt/qt57/bin/qmake
-    make
-    strip ./xdgurl
-
-    cd "${BUILDDIR}"
-    mkdir -p "${BUILDDIR}/${PKGNAME}.AppDir/usr/bin"
-    install -m 755 -p "${BUILDDIR}/${PKGNAME}/xdgurl" "${BUILDDIR}/${PKGNAME}.AppDir/xdgurl"
-    install -m 644 -p "${BUILDDIR}/${PKGNAME}/src/desktop/xdgurl.desktop" "${BUILDDIR}/${PKGNAME}.AppDir/xdgurl.desktop"
-    install -m 644 -p "${BUILDDIR}/${PKGNAME}/src/desktop/xdgurl.svg" "${BUILDDIR}/${PKGNAME}.AppDir/xdgurl.svg"
-    install -m 755 -p /usr/bin/update-desktop-database "${BUILDDIR}/${PKGNAME}.AppDir/usr/bin/update-desktop-database"
-    install -m 755 -p /usr/bin/desktop-file-validate "${BUILDDIR}/${PKGNAME}.AppDir/usr/bin/desktop-file-validate"
-    install -m 755 -p /usr/bin/desktop-file-install "${BUILDDIR}/${PKGNAME}.AppDir/usr/bin/desktop-file-install"
-    linuxdeployqt "${BUILDDIR}/${PKGNAME}.AppDir/xdgurl" -qmldir="${BUILDDIR}/${PKGNAME}/src/app/qml" -verbose=2 -bundle-non-qt-libs # https://github.com/probonopd/linuxdeployqt/issues/25
-    linuxdeployqt "${BUILDDIR}/${PKGNAME}.AppDir/xdgurl" -qmldir="${BUILDDIR}/${PKGNAME}/src/app/qml" -verbose=2 -bundle-non-qt-libs # twice because of #25
-    rm "${BUILDDIR}/${PKGNAME}.AppDir/AppRun"
-    install -m 755 -p "${BUILDDIR}/${PKGNAME}/src/desktop/appimage-desktopintegration" "${BUILDDIR}/${PKGNAME}.AppDir/AppRun"
-    linuxdeployqt --appimage-extract
-    ./squashfs-root/usr/bin/appimagetool "${BUILDDIR}/${PKGNAME}.AppDir"
-}
-
-if [ "${BUILDTYPE}" = 'ubuntu' ]; then
-    build_ubuntu
-elif [ "${BUILDTYPE}" = 'fedora' ]; then
-    build_fedora
-elif [ "${BUILDTYPE}" = 'arch' ]; then
-    build_arch
-elif [ "${BUILDTYPE}" = 'appimage' ]; then
-    build_appimage
-else
-    echo "sh $(basename "${0}") [ubuntu|fedora|arch|appimage] [tree_ish]"
-fi
diff --git a/pkg/fedora/xdgurl.spec b/pkg/fedora/ocs-url.spec
similarity index 55%
rename from pkg/fedora/xdgurl.spec
rename to pkg/fedora/ocs-url.spec
index 544b375641def9da9cafa928739d2a6d9984d757..a1ffd9fc5560bce885a80ba819bd072f3ebeabcb 100644
--- a/pkg/fedora/xdgurl.spec
+++ b/pkg/fedora/ocs-url.spec
@@ -1,27 +1,28 @@
-Summary: An install helper program for desktop stuff
-Name: xdgurl
-Version: 2.0.3
+Summary: OCS-URL
+Name: ocs-url
+Version: 3.0.0
 Release: 1%{?dist}
 License: GPLv3+
 Group: Applications/Internet
-URL: https://github.com/xdgurl/xdgurl
+URL: https://github.com/ocs-url/ocs-url
 
-#Source0: https://github.com/xdgurl/xdgurl/archive/release-%{version}.tar.gz
+#Source0: https://github.com/ocs-url/ocs-url/archive/release-%{version}.tar.gz
 Source0: %{name}.tar.gz
 
-Requires: qt5-qtbase >= 5.3.0, qt5-qtbase-gui >= 5.3.0, qt5-qtsvg >= 5.3.0, qt5-qtdeclarative >= 5.3.0, qt5-qtquickcontrols >= 5.3.0
-BuildRequires: make, automake, gcc, gcc-c++, libtool, qt5-qtbase-devel, qt5-qtsvg-devel, qt5-qtdeclarative-devel, rpm-build
+Requires: qt5-qtbase >= 5.2.0, qt5-qtbase-gui >= 5.2.0, qt5-qtsvg >= 5.2.0, qt5-qtdeclarative >= 5.2.0, qt5-qtquickcontrols >= 5.2.0
+BuildRequires: git make, automake, gcc, gcc-c++, libtool, qt5-qtbase-devel >= 5.2.0, qt5-qtsvg-devel >= 5.2.0, qt5-qtdeclarative-devel >= 5.2.0, rpm-build
 
 %description
-An install helper program for desktop stuff.
+An install helper program for items served on OpenCollaborationServices (OCS).
 
 %prep
 #%%autosetup -n %{name}-release-%{version}
 %autosetup -n %{name}
+sh scripts/import.sh
 
 %build
 %define debug_package %{nil}
-qmake-qt5 PREFIX='/usr'
+qmake-qt5 PREFIX="/usr"
 make
 
 %install
@@ -37,6 +38,16 @@ make INSTALL_ROOT="%{buildroot}" install
 rm -rf %{buildroot}
 
 %changelog
+* Thu Mar 02 2017 Akira Ohgaki <akiraohgaki@gmail.com> - 3.0.0-1
+- Rename xdgurl to ocs-url
+- Add ocs:// and ocss:// schemes
+- xdg:// and xdgs:// schemes still available for backward compatibile
+- New app icon
+- New dialog window
+- Labels and messages are translatable
+- Qt 5.2 support
+- Use the same configs of install-types with ocsstore
+
 * Wed Jan 25 2017 Akira Ohgaki <akiraohgaki@gmail.com> - 2.0.3-1
 - Change installation destination of type bin
 - Update qtlib
diff --git a/pkg/pkg.pri b/pkg/pkg.pri
new file mode 100644
index 0000000000000000000000000000000000000000..2ecc518745aa61d4e37947c2d1e78cd6e5383329
--- /dev/null
+++ b/pkg/pkg.pri
@@ -0,0 +1,12 @@
+DISTFILES += \
+    $${PWD}/ubuntu/debian/changelog \
+    $${PWD}/ubuntu/debian/compat \
+    $${PWD}/ubuntu/debian/control \
+    $${PWD}/ubuntu/debian/copyright \
+    $${PWD}/ubuntu/debian/rules \
+    $${PWD}/ubuntu/debian/ocs-url.install \
+    $${PWD}/fedora/ocs-url.spec \
+    $${PWD}/archlinux/PKGBUILD \
+    $${PWD}/snap/snapcraft.yaml \
+    $${PWD}/snap/snap/gui/ocs-url.desktop \
+    $${PWD}/appimage/appimage-desktopintegration_ocs-url
diff --git a/pkg/snap/snap/gui/ocs-url.desktop b/pkg/snap/snap/gui/ocs-url.desktop
new file mode 100644
index 0000000000000000000000000000000000000000..f0b1b9c5d6b16e05f07a6f01beb76ed3c7b89509
--- /dev/null
+++ b/pkg/snap/snap/gui/ocs-url.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=ocs-url
+Exec=ocs-url.ocs-url %u
+Icon=${SNAP}/usr/share/icons/hicolor/scalable/apps/ocs-url.svg
+Type=Application
+Terminal=false
+NoDisplay=true
+Categories=Network;Utility;
+MimeType=x-scheme-handler/ocs;x-scheme-handler/ocss;x-scheme-handler/xdg;x-scheme-handler/xdgs;
diff --git a/pkg/snap/snapcraft.yaml b/pkg/snap/snapcraft.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..fac30b8902d7e7218a8a2baad515b7f6d344077e
--- /dev/null
+++ b/pkg/snap/snapcraft.yaml
@@ -0,0 +1,42 @@
+name: ocs-url
+version: '0.0.0'
+summary: OCS-URL
+description: |
+  An install helper program for items served on OpenCollaborationServices (OCS).
+
+grade: devel
+confinement: strict
+
+icon: desktop/ocs-url.svg
+
+parts:
+  ocs-url:
+    prepare: |
+      sh scripts/import.sh
+    plugin: qmake
+    source: ./
+    qt-version: qt5
+    options:
+      - PREFIX="/usr"
+    build-packages:
+      - git
+      - build-essential
+      - qt5-default
+      - libqt5svg5-dev
+      - qtdeclarative5-dev
+      - snapcraft
+    stage-packages:
+      - libqt5svg5
+      - qml-module-qtquick-controls
+    after:
+      - desktop-qt5
+
+apps:
+  ocs-url:
+    command: usr/bin/ocs-url
+    plugs:
+      - home
+      - network
+      - opengl
+      - x11
+      - unity7
diff --git a/pkg/ubuntu/debian/changelog b/pkg/ubuntu/debian/changelog
index 45b73174bb88c0812be7f177f6d19cec2b7339bf..798fc5dd45986c519d7f13b736e2ae2ae80de10a 100644
--- a/pkg/ubuntu/debian/changelog
+++ b/pkg/ubuntu/debian/changelog
@@ -1,4 +1,17 @@
-xdgurl (2.0.3-0ubuntu1) xenial; urgency=low
+ocs-url (3.0.0-0ubuntu1) trusty; urgency=low
+
+  * Rename xdgurl to ocs-url
+  * Add ocs:// and ocss:// schemes
+  * xdg:// and xdgs:// schemes still available for backward compatibile
+  * New app icon
+  * New dialog window
+  * Labels and messages are translatable
+  * Qt 5.2 support
+  * Use the same configs of install-types with ocsstore
+
+ -- Akira Ohgaki <akiraohgaki@gmail.com>  Thu, 02 Mar 2017 18:39:39 +0000
+
+ocs-url (2.0.3-0ubuntu1) trusty; urgency=low
 
   * Change installation destination of type bin
   * Update qtlib
@@ -6,14 +19,14 @@ xdgurl (2.0.3-0ubuntu1) xenial; urgency=low
 
  -- Akira Ohgaki <akiraohgaki@gmail.com>  Wed, 25 Jan 2017 19:58:44 +0000
 
-xdgurl (2.0.2-0ubuntu1) xenial; urgency=low
+ocs-url (2.0.2-0ubuntu1) trusty; urgency=low
 
   * Update qtlibs
   * Small fix
 
  -- Akira Ohgaki <akiraohgaki@gmail.com>  Thu, 17 Nov 2016 17:30:24 +0000
 
-xdgurl (2.0.1-0ubuntu1) xenial; urgency=low
+ocs-url (2.0.1-0ubuntu1) trusty; urgency=low
 
   * Update library
   * Fix download/installation process
@@ -21,7 +34,7 @@ xdgurl (2.0.1-0ubuntu1) xenial; urgency=low
 
  -- Akira Ohgaki <akiraohgaki@gmail.com>  Mon, 14 Nov 2016 01:40:41 +0000
 
-xdgurl (2.0.0-0ubuntu1) xenial; urgency=low
+ocs-url (2.0.0-0ubuntu1) trusty; urgency=low
 
   * Re-implemented xdgurl as Qt program
   * Download progress bar
@@ -29,14 +42,14 @@ xdgurl (2.0.0-0ubuntu1) xenial; urgency=low
 
  -- Akira Ohgaki <akiraohgaki@gmail.com>  Fri, 28 Oct 2016 08:53:57 +0000
 
-xdgurl (1.0.1-0ubuntu1) xenial; urgency=low
+ocs-url (1.0.1-0ubuntu1) trusty; urgency=low
 
   * Clean successfull message
   * Return exit code
 
  -- Akira Ohgaki <akiraohgaki@gmail.com>  Fri, 15 Jul 2016 18:55:06 +0000
 
-xdgurl (1.0.0-0ubuntu1) xenial; urgency=low
+ocs-url (1.0.0-0ubuntu1) trusty; urgency=low
 
   * Initial release
 
diff --git a/pkg/ubuntu/debian/control b/pkg/ubuntu/debian/control
index efd11f99147e3df92679f0a9db8f6792695a8841..52f4b84cf6f166599d37b6e0eacf6de067f5a556 100644
--- a/pkg/ubuntu/debian/control
+++ b/pkg/ubuntu/debian/control
@@ -1,12 +1,12 @@
-Source: xdgurl
+Source: ocs-url
 Section: web
 Priority: optional
 Maintainer: Akira Ohgaki <akiraohgaki@gmail.com>
-Build-Depends: build-essential (>= 11), qt5-default (>= 5.3.0), libqt5svg5-dev (>= 5.3.0), qtdeclarative5-dev (>= 5.3.0), devscripts (>= 2.14), debhelper (>= 9), fakeroot (>= 1.20)
+Build-Depends: git, build-essential, qt5-default (>= 5.2.0), libqt5svg5-dev (>= 5.2.0), qtdeclarative5-dev (>= 5.2.0), devscripts, debhelper, fakeroot
 Standards-Version: 3.9.4
 
-Package: xdgurl
+Package: ocs-url
 Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, libqt5svg5 (>= 5.3.0), qml-module-qtquick2 (>= 5.3.0) | qtdeclarative5-qtquick2-plugin (>= 5.3.0), qml-module-qtquick-window2 (>= 5.3.0) | qtdeclarative5-window-plugin (>= 5.3.0), qml-module-qtquick-controls (>= 5.3.0) | qtdeclarative5-controls-plugin (>= 5.3.0), qml-module-qtquick-dialogs (>= 5.3.0) | qtdeclarative5-dialogs-plugin (>= 5.3.0)
-Description: An install helper program for desktop stuff
- An install helper program for desktop stuff.
+Depends: ${shlibs:Depends}, ${misc:Depends}, libqt5svg5 (>= 5.2.0), qml-module-qtquick2 (>= 5.2.0) | qtdeclarative5-qtquick2-plugin (>= 5.2.0), qml-module-qtquick-window2 (>= 5.2.0) | qtdeclarative5-window-plugin (>= 5.2.0), qml-module-qtquick-controls (>= 5.2.0) | qtdeclarative5-controls-plugin (>= 5.2.0)
+Description: OCS-URL
+ An install helper program for items served on OpenCollaborationServices (OCS).
diff --git a/pkg/ubuntu/debian/copyright b/pkg/ubuntu/debian/copyright
index 68078a2329aef059899c05e080d16e312bf11afc..f8bcc6179fea75ec2b1ccf82867b016f4a9ca886 100644
--- a/pkg/ubuntu/debian/copyright
+++ b/pkg/ubuntu/debian/copyright
@@ -1,7 +1,7 @@
 Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: xdgurl
+Upstream-Name: ocs-url
 Upstream-Contact: Akira Ohgaki <akiraohgaki@gmail.com>
-Source: https://github.com/xdgurl/xdgurl
+Source: https://github.com/ocs-url/ocs-url
 
 Files: *
 Copyright: 2016-2017, Akira Ohgaki
diff --git a/pkg/ubuntu/debian/ocs-url.install b/pkg/ubuntu/debian/ocs-url.install
new file mode 100644
index 0000000000000000000000000000000000000000..e5d62bfdce9a3ff0a7097a76e3f9e1a25ba138ac
--- /dev/null
+++ b/pkg/ubuntu/debian/ocs-url.install
@@ -0,0 +1,3 @@
+usr/bin/ocs-url
+usr/share/applications/ocs-url.desktop
+usr/share/icons/hicolor/scalable/apps/ocs-url.svg
diff --git a/pkg/ubuntu/debian/rules b/pkg/ubuntu/debian/rules
index 05dde7094a4e5c38332cccc8ca8c2f7b65eb1cd1..33be3a90e2248e692edaeba54bce693fbf795b02 100755
--- a/pkg/ubuntu/debian/rules
+++ b/pkg/ubuntu/debian/rules
@@ -4,7 +4,8 @@
 	dh $@
 
 override_dh_auto_configure:
-	qmake PREFIX='/usr'
+	sh scripts/import.sh
+	qmake PREFIX="/usr"
 
 override_dh_auto_install:
 	make INSTALL_ROOT="$(CURDIR)/debian/tmp" install
diff --git a/pkg/ubuntu/debian/xdgurl.install b/pkg/ubuntu/debian/xdgurl.install
deleted file mode 100644
index 44123c67f5636dc6d774bd04461f377155ea4872..0000000000000000000000000000000000000000
--- a/pkg/ubuntu/debian/xdgurl.install
+++ /dev/null
@@ -1,3 +0,0 @@
-usr/bin/xdgurl
-usr/share/applications/xdgurl.desktop
-usr/share/icons/hicolor/scalable/apps/xdgurl.svg
diff --git a/scripts/build.sh b/scripts/build.sh
new file mode 100644
index 0000000000000000000000000000000000000000..820d4906e74aebe23b49bd5c3f5d0328e457a67d
--- /dev/null
+++ b/scripts/build.sh
@@ -0,0 +1,182 @@
+#!/bin/bash
+
+################################################################################
+# This is utility script to make distribution packages
+################################################################################
+
+PKGNAME='ocs-url'
+
+BUILDTYPE=''
+if [ "${1}" ]; then
+    BUILDTYPE="${1}"
+fi
+
+TREEISH='HEAD'
+if [ "${2}" ]; then
+    TREEISH="${2}"
+fi
+
+PROJDIR="$(cd "$(dirname "${0}")/../" && pwd)"
+
+BUILDVER="$(cd "${PROJDIR}" && git describe --always)"
+
+BUILDDIR="${PROJDIR}/build_${PKGNAME}_${BUILDVER}_${BUILDTYPE}"
+
+SRCARCHIVE="${BUILDDIR}/${PKGNAME}.tar.gz"
+
+################################################################################
+# Utility functions
+################################################################################
+export_srcarchive() {
+    filepath="${1}"
+    $(cd "${PROJDIR}" && git archive --prefix="${PKGNAME}/" --output="${filepath}" "${TREEISH}")
+}
+
+transfer_file() {
+    filepath="${1}"
+    if [ -f "${filepath}" ]; then
+        filename="$(basename "${filepath}")"
+        curl -T "${filepath}" "https://transfer.sh/${filename}"
+    fi
+}
+
+################################################################################
+# ubuntu
+################################################################################
+pre_ubuntu() {
+    cd "${PROJDIR}"
+    mkdir -p "${BUILDDIR}"
+    export_srcarchive "${SRCARCHIVE}"
+}
+
+build_ubuntu() {
+    tar -xzvf "${SRCARCHIVE}" -C "${BUILDDIR}"
+    cp -r "${PROJDIR}/pkg/ubuntu/debian" "${BUILDDIR}/${PKGNAME}"
+    cd "${BUILDDIR}/${PKGNAME}"
+    debuild -uc -us -b
+}
+
+post_ubuntu() {
+    transfer_file "$(find ${BUILDDIR} -type f -name "${PKGNAME}*.deb")"
+}
+
+################################################################################
+# fedora
+################################################################################
+pre_fedora() {
+    cd "${PROJDIR}"
+    mkdir -p "${BUILDDIR}"
+    export_srcarchive "${SRCARCHIVE}"
+}
+
+build_fedora() {
+    mkdir "${BUILDDIR}/SOURCES"
+    mkdir "${BUILDDIR}/SPECS"
+    mv "${SRCARCHIVE}" "${BUILDDIR}/SOURCES"
+    cp "${PROJDIR}/pkg/fedora/${PKGNAME}.spec" "${BUILDDIR}/SPECS"
+    rpmbuild --define "_topdir ${BUILDDIR}" -bb "${BUILDDIR}/SPECS/${PKGNAME}.spec"
+}
+
+post_fedora() {
+    transfer_file "$(find ${BUILDDIR} -type f -name "${PKGNAME}*.rpm")"
+}
+
+################################################################################
+# archlinux
+################################################################################
+pre_archlinux() {
+    cd "${PROJDIR}"
+    mkdir -p "${BUILDDIR}"
+    export_srcarchive "${SRCARCHIVE}"
+}
+
+build_archlinux() {
+    cp "${PROJDIR}/pkg/archlinux/PKGBUILD" "${BUILDDIR}"
+    cd "${BUILDDIR}"
+    updpkgsums
+    makepkg -s
+}
+
+post_archlinux() {
+    transfer_file "$(find ${BUILDDIR} -type f -name "${PKGNAME}*.pkg.tar.xz")"
+}
+
+################################################################################
+# snap
+################################################################################
+pre_snap() {
+    cd "${PROJDIR}"
+    mkdir -p "${BUILDDIR}"
+    export_srcarchive "${SRCARCHIVE}"
+}
+
+build_snap() {
+    tar -xzvf "${SRCARCHIVE}" -C "${BUILDDIR}"
+    cp "${PROJDIR}/pkg/snap/snapcraft.yaml" "${BUILDDIR}/${PKGNAME}"
+    cp -r "${PROJDIR}/pkg/snap/setup" "${BUILDDIR}/${PKGNAME}"
+    cd "${BUILDDIR}/${PKGNAME}"
+    snapcraft
+}
+
+post_snap() {
+    transfer_file "$(find ${BUILDDIR} -type f -name "${PKGNAME}*.snap")"
+}
+
+################################################################################
+# appimage
+################################################################################
+pre_appimage() {
+    cd "${PROJDIR}"
+    mkdir -p "${BUILDDIR}"
+    export_srcarchive "${SRCARCHIVE}"
+}
+
+build_appimage() {
+    tar -xzvf "${SRCARCHIVE}" -C "${BUILDDIR}"
+    cd "${BUILDDIR}/${PKGNAME}"
+    qmake
+    make
+    strip "${PKGNAME}"
+
+    cd "${BUILDDIR}"
+
+    # Replace linuxdeployqt download URL to official download URL when the stable version released
+    curl -L -o linuxdeployqt https://dl.dropboxusercontent.com/u/150776/temp/linuxdeployqt-799f704-x86-64.appimage
+    chmod 755 linuxdeployqt
+
+    mkdir -p "${BUILDDIR}/${PKGNAME}.AppDir/usr/bin"
+    install -m 755 -p "${BUILDDIR}/${PKGNAME}/${PKGNAME}" "${BUILDDIR}/${PKGNAME}.AppDir/${PKGNAME}"
+    install -m 644 -p "${BUILDDIR}/${PKGNAME}/desktop/${PKGNAME}.desktop" "${BUILDDIR}/${PKGNAME}.AppDir/${PKGNAME}.desktop"
+    install -m 644 -p "${BUILDDIR}/${PKGNAME}/desktop/${PKGNAME}.svg" "${BUILDDIR}/${PKGNAME}.AppDir/${PKGNAME}.svg"
+    install -m 755 -p /usr/bin/update-desktop-database "${BUILDDIR}/${PKGNAME}.AppDir/usr/bin/update-desktop-database"
+    install -m 755 -p /usr/bin/desktop-file-validate "${BUILDDIR}/${PKGNAME}.AppDir/usr/bin/desktop-file-validate"
+    install -m 755 -p /usr/bin/desktop-file-install "${BUILDDIR}/${PKGNAME}.AppDir/usr/bin/desktop-file-install"
+    ./linuxdeployqt "${BUILDDIR}/${PKGNAME}.AppDir/${PKGNAME}" -qmldir="${BUILDDIR}/${PKGNAME}/app/qml" -verbose=2 -bundle-non-qt-libs # https://github.com/probonopd/linuxdeployqt/issues/25
+    ./linuxdeployqt "${BUILDDIR}/${PKGNAME}.AppDir/${PKGNAME}" -qmldir="${BUILDDIR}/${PKGNAME}/app/qml" -verbose=2 -bundle-non-qt-libs # twice because of #25
+    rm "${BUILDDIR}/${PKGNAME}.AppDir/AppRun"
+    install -m 755 -p "${BUILDDIR}/${PKGNAME}/pkg/appimage/appimage-desktopintegration_${PKGNAME}" "${BUILDDIR}/${PKGNAME}.AppDir/AppRun"
+    ./linuxdeployqt --appimage-extract
+    ./squashfs-root/usr/bin/appimagetool "${BUILDDIR}/${PKGNAME}.AppDir"
+}
+
+post_appimage() {
+    transfer_file "$(find ${BUILDDIR} -type f -name "${PKGNAME}*.AppImage")"
+}
+
+################################################################################
+# Make package
+################################################################################
+if [ "${BUILDTYPE}" = 'ubuntu' ]; then
+    pre_ubuntu && build_ubuntu && post_ubuntu
+elif [ "${BUILDTYPE}" = 'fedora' ]; then
+    pre_fedora && build_fedora && post_fedora
+elif [ "${BUILDTYPE}" = 'archlinux' ]; then
+    pre_archlinux && build_archlinux && post_archlinux
+elif [ "${BUILDTYPE}" = 'snap' ]; then
+    pre_snap && build_snap && post_snap
+elif [ "${BUILDTYPE}" = 'appimage' ]; then
+    pre_appimage && build_appimage && post_appimage
+else
+    echo "sh $(basename "${0}") [ubuntu|fedora|archlinux|snap|appimage] [tree_ish]"
+    exit 1
+fi
diff --git a/scripts/import.sh b/scripts/import.sh
new file mode 100644
index 0000000000000000000000000000000000000000..7b20f91779890fa510a777032e75de805f64d8af
--- /dev/null
+++ b/scripts/import.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+################################################################################
+# This is utility script to import build dependencies
+################################################################################
+
+PROJDIR="$(cd "$(dirname "${0}")/../" && pwd)"
+
+if [ ! -d "${PROJDIR}/lib/qtlib" ]; then
+    git clone https://github.com/akiraohgaki/qtlib.git -b master --single-branch --depth=1 "${PROJDIR}/lib/qtlib"
+fi
diff --git a/scripts/scripts.pri b/scripts/scripts.pri
new file mode 100644
index 0000000000000000000000000000000000000000..d8d91634794aaf353d96a89eb38607348153cd42
--- /dev/null
+++ b/scripts/scripts.pri
@@ -0,0 +1,3 @@
+DISTFILES += \
+    $${PWD}/build.sh \
+    $${PWD}/import.sh
diff --git a/src/app/app.pri b/src/app/app.pri
deleted file mode 100644
index b37beda3dc2a93b64009db66f8235a7ca4393592..0000000000000000000000000000000000000000
--- a/src/app/app.pri
+++ /dev/null
@@ -1,17 +0,0 @@
-QT += \
-    core \
-    gui \
-    qml \
-    quick \
-    svg
-
-HEADERS += \
-    $${PWD}/handlers/xdgurlhandler.h
-
-SOURCES += \
-    $${PWD}/main.cpp \
-    $${PWD}/handlers/xdgurlhandler.cpp
-
-RESOURCES += \
-    $${PWD}/configs/configs.qrc \
-    $${PWD}/qml/qml.qrc
diff --git a/src/app/configs/application.json b/src/app/configs/application.json
deleted file mode 100644
index 1419f6b09cc338abb33e834352bffe476a7c3bdd..0000000000000000000000000000000000000000
--- a/src/app/configs/application.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "id": "xdgurl",
-    "name": "xdgurl",
-    "version": "2.0.3",
-    "organization": "xdgurl",
-    "domain": "com.xdgurl.xdgurl",
-    "icon": ":/desktop/xdgurl.svg",
-    "description": "An install helper program for desktop stuff.",
-    "license": "GPL-3+",
-    "author": "Akira Ohgaki",
-    "contact": "akiraohgaki@gmail.com",
-    "homepage": "https://github.com/xdgurl/xdgurl"
-}
diff --git a/src/app/configs/destinations.json b/src/app/configs/destinations.json
deleted file mode 100644
index ed85557bb2cb708a88b695f623c97843c3315764..0000000000000000000000000000000000000000
--- a/src/app/configs/destinations.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
-    "bin": "$HOME/.local/bin",
-    "downloads": "$HOME/Downloads",
-    "documents": "$HOME/Documents",
-    "pictures": "$HOME/Pictures",
-    "music": "$HOME/Music",
-    "videos": "$HOME/Videos",
-    "wallpapers": "$XDG_DATA_HOME/wallpapers",
-    "fonts": "$HOME/.fonts",
-    "cursors": "$HOME/.icons",
-    "icons": "$XDG_DATA_HOME/icons",
-    "emoticons": "$XDG_DATA_HOME/emoticons",
-    "themes": "$HOME/.themes",
-    "emerald_themes": "$HOME/.emerald/themes",
-    "enlightenment_themes": "$HOME/.e/e/themes",
-    "enlightenment_backgrounds": "$HOME/.e/e/backgrounds",
-    "fluxbox_styles": "$HOME/.fluxbox/styles",
-    "pekwm_themes": "$HOME/.pekwm/themes",
-    "icewm_themes": "$HOME/.icewm/themes",
-    "plasma_plasmoids": "$XDG_DATA_HOME/plasma/plasmoids",
-    "plasma_look_and_feel": "$XDG_DATA_HOME/plasma/look-and-feel",
-    "plasma_desktopthemes": "$XDG_DATA_HOME/plasma/desktoptheme",
-    "kwin_effects": "$XDG_DATA_HOME/kwin/effects",
-    "kwin_scripts": "$XDG_DATA_HOME/kwin/scripts",
-    "kwin_tabbox": "$XDG_DATA_HOME/kwin/tabbox",
-    "aurorae_themes": "$XDG_DATA_HOME/aurorae/themes",
-    "dekorator_themes": "$XDG_DATA_HOME/deKorator/themes",
-    "qtcurve": "$XDG_DATA_HOME/QtCurve",
-    "color_schemes": "$XDG_DATA_HOME/color-schemes",
-    "gnome_shell_extensions": "$XDG_DATA_HOME/gnome-shell/extensions",
-    "cinnamon_applets": "$XDG_DATA_HOME/cinnamon/applets",
-    "cinnamon_desklets": "$XDG_DATA_HOME/cinnamon/desklets",
-    "cinnamon_extensions": "$XDG_DATA_HOME/cinnamon/extensions",
-    "nautilus_scripts": "$XDG_DATA_HOME/nautilus/scripts",
-    "amarok_scripts": "$KDEHOME/share/apps/amarok/scripts",
-    "yakuake_skins": "$KDEHOME/share/apps/yakuake/skins",
-    "cairo_clock_themes": "$HOME/.cairo-clock/themes"
-}
diff --git a/src/app/configs/destinations_alias.json b/src/app/configs/destinations_alias.json
deleted file mode 100644
index 438fb4dc92cf31716b7741064141b8a10a83f20d..0000000000000000000000000000000000000000
--- a/src/app/configs/destinations_alias.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-    "gnome_shell_themes": "themes",
-    "cinnamon_themes": "themes",
-    "gtk2_themes": "themes",
-    "gtk3_themes": "themes",
-    "metacity_themes": "themes",
-    "xfwm4_themes": "themes",
-    "openbox_themes": "themes",
-    "kvantum_themes": "themes",
-    "compiz_themes": "emerald_themes",
-    "beryl_themes": "emerald_themes",
-    "plasma4_plasmoids": "plasma_plasmoids",
-    "plasma5_plasmoids": "plasma_plasmoids",
-    "plasma5_look_and_feel": "plasma_look_and_feel",
-    "plasma5_desktopthemes": "plasma_desktopthemes",
-    "plasma_color_schemes": "color_schemes"
-}
diff --git a/src/app/main.cpp b/src/app/main.cpp
deleted file mode 100644
index 7f3aebc33194bd527678e9cb7b86bfed802bcdec..0000000000000000000000000000000000000000
--- a/src/app/main.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//#include <QtGlobal>
-#include <QString>
-#include <QStringList>
-#include <QUrl>
-#include <QJsonObject>
-#include <QCommandLineParser>
-//#include <QCoreApplication>
-#include <QGuiApplication>
-#include <QIcon>
-#include <QQmlApplicationEngine>
-#include <QQmlContext>
-
-#include "qtlib_config.h"
-
-#include "handlers/xdgurlhandler.h"
-
-int main(int argc, char *argv[])
-{
-    // Init
-//#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
-//    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
-//#endif
-    QGuiApplication app(argc, argv);
-
-    qtlib::Config config(":/configs");
-    QJsonObject configApplication = config.get("application");
-
-    app.setApplicationName(configApplication["name"].toString());
-    app.setApplicationVersion(configApplication["version"].toString());
-    app.setOrganizationName(configApplication["organization"].toString());
-    app.setOrganizationDomain(configApplication["domain"].toString());
-    app.setWindowIcon(QIcon::fromTheme(configApplication["id"].toString(), QIcon(configApplication["icon"].toString())));
-
-    // Setup CLI
-    QCommandLineParser clParser;
-    clParser.setApplicationDescription(configApplication["description"].toString());
-    clParser.addHelpOption();
-    clParser.addVersionOption();
-    clParser.addPositionalArgument("xdgurl", "XDG-URL");
-    clParser.process(app);
-
-    QStringList args = clParser.positionalArguments();
-
-    if (args.size() != 1) {
-        clParser.showHelp(1);
-    }
-
-    QString xdgUrl = args.at(0);
-
-    // Setup QML
-    QQmlApplicationEngine qmlAppEngine;
-    QQmlContext *qmlContext = qmlAppEngine.rootContext();
-    qmlContext->setContextProperty("xdgUrlHandler", new XdgUrlHandler(xdgUrl, config, &qmlAppEngine));
-    qmlAppEngine.load(QUrl("qrc:/qml/main.qml"));
-
-    return app.exec();
-}
diff --git a/src/app/qml/main.qml b/src/app/qml/main.qml
deleted file mode 100644
index 4ad2414fd1ed3c2961f56a78154eda587e9a907f..0000000000000000000000000000000000000000
--- a/src/app/qml/main.qml
+++ /dev/null
@@ -1,155 +0,0 @@
-import QtQuick 2.3
-import QtQuick.Window 2.0
-import QtQuick.Controls 1.2
-import QtQuick.Dialogs 1.2
-
-import "scripts/Utility.js" as Utility
-
-Window {
-    id: app
-    title: Qt.application.name
-    width: 400
-    height: 200
-    minimumWidth: 400
-    minimumHeight: 200
-    maximumWidth: 800
-    maximumHeight: 400
-
-    MessageDialog {
-        id: confirmDialog
-        title: app.title
-        icon: StandardIcon.Question
-        text: ""
-        informativeText: ""
-        detailedText: ""
-        standardButtons: StandardButton.Ok | StandardButton.Cancel
-        onAccepted: xdgUrlHandler.process()
-        onRejected: Qt.quit()
-    }
-
-    MessageDialog {
-        id: infoDialog
-        title: app.title
-        icon: StandardIcon.Information
-        text: ""
-        informativeText: ""
-        detailedText: ""
-        standardButtons: StandardButton.Open | StandardButton.Close
-        onAccepted: {
-            xdgUrlHandler.openDestination();
-            Qt.quit();
-        }
-        onRejected: Qt.quit()
-    }
-
-    MessageDialog {
-        id: errorDialog
-        title: app.title
-        icon: StandardIcon.Warning
-        text: ""
-        informativeText: ""
-        detailedText: ""
-        standardButtons: StandardButton.Close
-        onRejected: Qt.quit()
-    }
-
-    Dialog {
-        id: progressDialog
-        title: app.title
-        property alias primaryLabel: primaryLabel
-        property alias informativeLabel: informativeLabel
-        property alias progressBar: progressBar
-        property alias progressLabel: progressLabel
-        contentItem: Item {
-            implicitWidth: 400
-            implicitHeight: 150
-            Column {
-                anchors.fill: parent
-                anchors.margins: 12
-                spacing: 8
-                Label {
-                    id: primaryLabel
-                    text: " "
-                    font.bold: true
-                }
-                Label {
-                    id: informativeLabel
-                    text: " "
-                }
-                ProgressBar {
-                    id: progressBar
-                    maximumValue: 1
-                    minimumValue: 0
-                    value: 0
-                    anchors.left: parent.left
-                    anchors.right: parent.right
-                }
-                Label {
-                    id: progressLabel
-                    text: " "
-                    anchors.right: parent.right
-                }
-                Button {
-                    id: cancelButton
-                    text: "Cancel"
-                    anchors.right: parent.right
-                    onClicked: Qt.quit()
-                }
-            }
-        }
-    }
-
-    Component.onCompleted: {
-        var metadata = xdgUrlHandler.metadata();
-        var primaryMessages = {
-            "success_download": "Download successfull",
-            "success_install": "Installation successfull",
-            "error_validation": "Validation error",
-            "error_network": "Network error",
-            "error_save": "Saving file failed",
-            "error_install": "Installation failed"
-        };
-
-        xdgUrlHandler.started.connect(function() {
-            progressDialog.open();
-        });
-
-        xdgUrlHandler.finishedWithSuccess.connect(function(result) {
-            progressDialog.close();
-            infoDialog.text = primaryMessages[result.status];
-            infoDialog.informativeText = metadata.filename;
-            infoDialog.detailedText = result.message;
-            infoDialog.open();
-        });
-
-        xdgUrlHandler.finishedWithError.connect(function(result) {
-            progressDialog.close();
-            errorDialog.text = primaryMessages[result.status];
-            errorDialog.informativeText = metadata.filename;
-            errorDialog.detailedText = result.message;
-            errorDialog.open();
-        });
-
-        xdgUrlHandler.downloadProgress.connect(function(id, bytesReceived, bytesTotal) {
-            progressDialog.primaryLabel.text = "Downloading... ";
-            progressDialog.informativeLabel.text = metadata.filename;
-            progressDialog.progressBar.value = bytesReceived / bytesTotal;
-            progressDialog.progressLabel.text = Utility.convertByteToHumanReadable(bytesReceived)
-                    + " / " + Utility.convertByteToHumanReadable(bytesTotal)
-        });
-
-        if (xdgUrlHandler.isValid()) {
-            confirmDialog.text = "Do you want to " + metadata.command + "?";
-            confirmDialog.informativeText = metadata.filename;
-            confirmDialog.detailedText = "URL: " + metadata.url + "\n\n"
-                    + "File: " + metadata.filename + "\n\n"
-                    + "Type: " + metadata.type;
-            confirmDialog.open();
-        }
-        else {
-            errorDialog.text = "Validation error";
-            errorDialog.detailedText = "Invalid XDG-URL " + xdgUrlHandler.xdgUrl();
-            errorDialog.open();
-        }
-    }
-}
diff --git a/src/desktop/xdgurl.desktop b/src/desktop/xdgurl.desktop
deleted file mode 100644
index aba57f117912ed2f3ba256709fd5dac7464a5735..0000000000000000000000000000000000000000
--- a/src/desktop/xdgurl.desktop
+++ /dev/null
@@ -1,9 +0,0 @@
-[Desktop Entry]
-Name=xdgurl
-Exec=xdgurl %u
-Icon=xdgurl
-Type=Application
-Terminal=false
-NoDisplay=true
-Categories=Network;Utility;
-MimeType=x-scheme-handler/xdg;x-scheme-handler/xdgs;
diff --git a/src/desktop/xdgurl.svg b/src/desktop/xdgurl.svg
deleted file mode 100644
index a55a8e481d1abbe8fa585539fe9a41cdc3b53679..0000000000000000000000000000000000000000
--- a/src/desktop/xdgurl.svg
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   version="1.1"
-   id="svg2"
-   viewBox="0 0 1000 1000"
-   height="1000"
-   width="1000">
-  <defs
-     id="defs4" />
-  <metadata
-     id="metadata7">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title></dc:title>
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g
-     transform="translate(0,-52.362161)"
-     id="layer1">
-    <circle
-       r="475"
-       cy="552.36218"
-       cx="500"
-       id="path4138"
-       style="fill:#19a2ff;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
-    <circle
-       r="450"
-       cy="552.36218"
-       cx="500"
-       id="path4138-0"
-       style="fill:#53b2ff;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
-    <g
-       transform="translate(0,20)"
-       id="g4205">
-      <path
-         id="path4145"
-         style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:medium;line-height:125%;font-family:Futura;-inkscape-font-specification:'Futura Medium';letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-         d="m 192.87313,533.47911 -74.36008,-101.11803 56.93857,0 46.10326,64.24502 46.95309,-64.24502 58.63824,0 -76.48467,101.11803 88.59474,119.21524 -56.93858,0 -60.76282,-82.34221 -62.25002,82.34221 -58.42577,0 91.99404,-119.21524 z" />
-      <path
-         id="path4147"
-         style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:medium;line-height:125%;font-family:Futura;-inkscape-font-specification:'Futura Medium';letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-         d="m 472.62967,312.47491 48.01537,0 0,340.84056 -48.01537,0 0,-21.67066 c -18.83789,18.41297 -40.15445,27.61946 -63.94968,27.61946 -28.32765,0 -51.83961,-10.33959 -70.53586,-31.01878 -18.55461,-21.1041 -27.83192,-47.44882 -27.83192,-79.03415 0,-30.87715 9.27731,-56.65531 27.83192,-77.3345 18.41298,-20.82082 41.57084,-31.23123 69.47357,-31.23123 24.22015,0 45.8908,9.91468 65.01197,29.74403 z M 359.17742,549.21134 c 0,19.82935 5.31143,35.97612 15.9343,48.44029 10.90615,12.60581 24.64506,18.90871 41.21674,18.90871 17.70478,0 32.01024,-6.09045 42.91639,-18.27134 10.90615,-12.60581 16.35922,-28.61093 16.35922,-48.01537 0,-19.40445 -5.45307,-35.40957 -16.35922,-48.01538 -10.90615,-12.32253 -25.06997,-18.48379 -42.49148,-18.48379 -16.43004,0 -30.16895,6.23208 -41.21673,18.69625 -10.90615,12.60581 -16.35922,28.18602 -16.35922,46.74063 z" />
-      <path
-         id="path4149"
-         style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:medium;line-height:125%;font-family:Futura;-inkscape-font-specification:'Futura Medium';letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-         d="m 722.24998,648.95295 c 0,9.77304 -0.3541,18.34215 -1.06229,25.70734 -0.56655,7.50683 -1.41638,14.09301 -2.54949,19.75854 -3.39932,15.58021 -10.05632,28.96502 -19.97099,40.15445 -18.69625,21.52901 -44.4036,32.29352 -77.12204,32.29352 -27.61947,0 -50.35241,-7.43601 -68.19883,-22.30802 -18.41297,-15.29693 -29.03584,-36.47186 -31.86861,-63.52477 l 48.01537,0 c 1.8413,10.19796 4.88652,18.05889 9.13567,23.58278 9.91468,12.88908 24.36178,19.33362 43.34131,19.33362 34.98465,0 52.47698,-21.4582 52.47698,-64.37459 l 0,-28.89421 c -18.97953,19.40444 -40.86264,29.10666 -65.64934,29.10666 -28.18601,0 -51.27305,-10.19795 -69.26111,-30.59386 -18.1297,-20.67919 -27.19455,-46.52817 -27.19455,-77.54695 0,-30.16895 8.42748,-55.80548 25.28243,-76.90959 18.1297,-22.37884 42.06657,-33.56826 71.81061,-33.56826 26.06144,0 47.73209,9.70222 65.01196,29.10666 l 0,-27.37031 47.80292,0 z m -45.8908,-98.15532 c 0,-20.11264 -5.38225,-36.18859 -16.14676,-48.22784 C 649.30627,490.24726 635.3549,484.086 618.35831,484.086 c -18.1297,0 -32.43517,6.72782 -42.9164,20.18345 -9.48976,12.03925 -14.23464,27.61946 -14.23464,46.74063 0,18.83789 4.74488,34.27647 14.23464,46.31572 10.33959,13.17236 24.64506,19.75854 42.9164,19.75854 18.27133,0 32.71844,-6.657 43.34131,-19.971 9.77304,-12.03925 14.65956,-27.47782 14.65956,-46.31571 z" />
-      <path
-         style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-         d="m 739.50519,490.21255 36,0 0,36 -36,0 z"
-         id="rect4156" />
-      <path
-         style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-         d="m 739.53345,589.21057 36,0 0,36 -36,0 z"
-         id="rect4156-9" />
-      <path
-         style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-         d="m 852.99238,412.46896 22,0 -94.33913,290.17369 -22,0 z"
-         id="rect4156-5" />
-      <path
-         style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-         d="m 902.99238,412.46896 22,0 -94.33913,290.17369 -22,0 z"
-         id="rect4156-5-3" />
-    </g>
-  </g>
-</svg>
diff --git a/src/lib/qtlib/.gitignore b/src/lib/qtlib/.gitignore
deleted file mode 100644
index 75c107bcc90038bcdd0d643b20eb4d33a13b4245..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.pro.user
diff --git a/src/lib/qtlib/README.md b/src/lib/qtlib/README.md
deleted file mode 100644
index c042d940a2901ad45b5eb37249e495be9f60fd16..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# qtlib
-
-A library for Qt app.
-
-Copyright: Akira Ohgaki
-
-License: LGPL-3+
diff --git a/src/lib/qtlib/qtlib-test.pro b/src/lib/qtlib/qtlib-test.pro
deleted file mode 100644
index 7769787444482c0c01b5367587f20104631aa8bf..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/qtlib-test.pro
+++ /dev/null
@@ -1,13 +0,0 @@
-include(qtlib.pri)
-
-TARGET = qtlib-test
-
-TEMPLATE = app
-
-CONFIG += c++11
-
-QT += core
-
-SOURCES += test/main.cpp
-
-DISTFILES += README.md
diff --git a/src/lib/qtlib/qtlib.pri b/src/lib/qtlib/qtlib.pri
deleted file mode 100644
index 8d8e38182c47b2e2e8a5e28c514e65bac347562f..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/qtlib.pri
+++ /dev/null
@@ -1,31 +0,0 @@
-QT += \
-    core \
-    network
-
-HEADERS += \
-    $${PWD}/src/qtlib_file.h \
-    $${PWD}/src/qtlib_dir.h \
-    $${PWD}/src/qtlib_json.h \
-    $${PWD}/src/qtlib_config.h \
-    $${PWD}/src/qtlib_networkresource.h \
-    $${PWD}/src/qtlib_ocsapi.h \
-    $${PWD}/src/qtlib_package.h
-
-SOURCES += \
-    $${PWD}/src/qtlib_file.cpp \
-    $${PWD}/src/qtlib_dir.cpp \
-    $${PWD}/src/qtlib_json.cpp \
-    $${PWD}/src/qtlib_config.cpp \
-    $${PWD}/src/qtlib_networkresource.cpp \
-    $${PWD}/src/qtlib_ocsapi.cpp \
-    $${PWD}/src/qtlib_package.cpp
-
-INCLUDEPATH += $${PWD}/src
-
-unix:!ios:!android {
-    DEFINES += QTLIB_UNIX
-}
-
-android {
-    QT += androidextras
-}
diff --git a/src/lib/qtlib/src/qtlib_config.cpp b/src/lib/qtlib/src/qtlib_config.cpp
deleted file mode 100644
index 0c7b3961c1c5bd1b3ab30ae39831f16b4509fef9..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_config.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#include "qtlib_config.h"
-
-#include "qtlib_file.h"
-#include "qtlib_dir.h"
-#include "qtlib_json.h"
-
-namespace qtlib {
-
-Config::Config(const QString &configDirPath, QObject *parent)
-    : QObject(parent), configDirPath_(configDirPath)
-{}
-
-Config::Config(const Config &other, QObject *parent)
-    : QObject(parent)
-{
-    setConfigDirPath(other.configDirPath());
-}
-
-Config &Config::operator =(const Config &other)
-{
-    setConfigDirPath(other.configDirPath());
-    return *this;
-}
-
-QString Config::configDirPath() const
-{
-    return configDirPath_;
-}
-
-void Config::setConfigDirPath(const QString &configDirPath)
-{
-    configDirPath_ = configDirPath;
-}
-
-QJsonObject Config::get(const QString &name)
-{
-    QString configFilePath = configDirPath() + "/" + name + ".json";
-    QByteArray json = qtlib::File(configFilePath).readData();
-    if (json.isEmpty()) {
-        json = QString("{}").toUtf8(); // Blank JSON data as default
-    }
-    return qtlib::Json(json).toObject();
-}
-
-bool Config::set(const QString &name, const QJsonObject &object)
-{
-    QString configFilePath = configDirPath() + "/" + name + ".json";
-    QByteArray json = qtlib::Json(object).toJson();
-    qtlib::Dir(configDirPath()).make();
-    return qtlib::File(configFilePath).writeData(json);
-}
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/src/qtlib_config.h b/src/lib/qtlib/src/qtlib_config.h
deleted file mode 100644
index 456a9b66b006d2f36ad00b3525472490f804725d..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_config.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#pragma once
-
-#include <QObject>
-#include <QJsonObject>
-
-namespace qtlib {
-
-class Config : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit Config(const QString &configDirPath = "", QObject *parent = 0);
-
-    Config(const Config &other, QObject *parent = 0);
-    Config &operator =(const Config &other);
-
-    QString configDirPath() const;
-    void setConfigDirPath(const QString &configDirPath);
-
-    QJsonObject get(const QString &name);
-    bool set(const QString &name, const QJsonObject &object);
-
-private:
-    QString configDirPath_;
-};
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/src/qtlib_dir.cpp b/src/lib/qtlib/src/qtlib_dir.cpp
deleted file mode 100644
index 94512f234c894f92b502a7ab5814cb504a18fe7c..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_dir.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#include "qtlib_dir.h"
-
-#include <QDir>
-#include <QFile>
-#include <QFileInfo>
-#include <QStandardPaths>
-
-namespace qtlib {
-
-Dir::Dir(const QString &path, QObject *parent)
-    : QObject(parent), path_(path)
-{}
-
-Dir::Dir(const Dir &other, QObject *parent)
-    : QObject(parent)
-{
-    setPath(other.path());
-}
-
-Dir &Dir::operator =(const Dir &other)
-{
-    setPath(other.path());
-    return *this;
-}
-
-QString Dir::path() const
-{
-    return path_;
-}
-
-void Dir::setPath(const QString &path)
-{
-    path_ = path;
-}
-
-bool Dir::exists()
-{
-    return QDir(path()).exists();
-}
-
-QFileInfoList Dir::list()
-{
-    QDir dir(path());
-    dir.setFilter(QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
-    //dir.setSorting(QDir::DirsFirst | QDir::Name);
-    return dir.entryInfoList();
-}
-
-bool Dir::make()
-{
-    // This function will create all parent directories
-    QDir dir(path());
-    if (!dir.exists() && dir.mkpath(path())) {
-        return true;
-    }
-    return false;
-}
-
-bool Dir::copy(const QString &newPath)
-{
-    // This function will copy files recursively
-    return copyRecursively(path(), newPath);
-}
-
-bool Dir::move(const QString &newPath)
-{
-    return QDir(path()).rename(path(), newPath);
-}
-
-bool Dir::remove()
-{
-    // This function will remove files recursively
-    return QDir(path()).removeRecursively();
-}
-
-QString Dir::rootPath()
-{
-    return QDir::rootPath();
-}
-
-QString Dir::tempPath()
-{
-    return QDir::tempPath();
-}
-
-QString Dir::homePath()
-{
-    return QDir::homePath();
-}
-
-QString Dir::genericDataPath()
-{
-    return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
-}
-
-QString Dir::genericConfigPath()
-{
-    return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
-}
-
-QString Dir::genericCachePath()
-{
-    return QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation);
-}
-
-QString Dir::kdehomePath()
-{
-    // KDE System Administration/Environment Variables
-    // https://userbase.kde.org/KDE_System_Administration/Environment_Variables
-
-    // KDE 4 maybe uses $KDEHOME
-    QString kdehomePath = QString::fromLocal8Bit(qgetenv("KDEHOME").constData());
-    if (kdehomePath.isEmpty()) {
-        kdehomePath = homePath() + "/.kde";
-    }
-    return kdehomePath;
-}
-
-bool Dir::copyRecursively(const QString &srcPath, const QString &newPath)
-{
-    QFileInfo fileInfo(srcPath);
-    if (fileInfo.isSymLink() && !fileInfo.exists()) {
-        // Ignore broken symlink
-        return true;
-    }
-    else if (fileInfo.isFile()) {
-        return QFile(srcPath).copy(newPath);
-    }
-    else if (fileInfo.isDir()) {
-        QDir newDir(newPath);
-        QString newDirName = newDir.dirName();
-        newDir.cdUp();
-        if (newDir.mkdir(newDirName)) {
-            QDir dir(srcPath);
-            dir.setFilter(QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
-            QStringList entries = dir.entryList();
-            foreach (const QString &entry, entries) {
-                if (!copyRecursively(srcPath + "/" + entry, newPath + "/" + entry)) {
-                    return false;
-                }
-            }
-            return true;
-        }
-    }
-    return false;
-}
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/src/qtlib_dir.h b/src/lib/qtlib/src/qtlib_dir.h
deleted file mode 100644
index a8b5a5e4b1c9b0af56b80b7f43dfe88d04cdd30a..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_dir.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#pragma once
-
-#include <QObject>
-#include <QFileInfoList>
-
-namespace qtlib {
-
-class Dir : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit Dir(const QString &path = "", QObject *parent = 0);
-
-    Dir(const Dir &other, QObject *parent = 0);
-    Dir &operator =(const Dir &other);
-
-    QString path() const;
-    void setPath(const QString &path);
-
-    bool exists();
-    QFileInfoList list();
-    bool make();
-    bool copy(const QString &newPath);
-    bool move(const QString &newPath);
-    bool remove();
-
-    static QString rootPath();
-    static QString tempPath();
-    static QString homePath();
-    static QString genericDataPath();
-    static QString genericConfigPath();
-    static QString genericCachePath();
-    static QString kdehomePath();
-
-private:
-    bool copyRecursively(const QString &srcPath, const QString &newPath);
-
-    QString path_;
-};
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/src/qtlib_file.cpp b/src/lib/qtlib/src/qtlib_file.cpp
deleted file mode 100644
index ac4f740f01ae1a302b9ea7b1cfc017b2cfa41db2..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_file.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#include "qtlib_file.h"
-
-#include <QIODevice>
-#include <QTextStream>
-#include <QFile>
-
-namespace qtlib {
-
-File::File(const QString &path, QObject *parent)
-    : QObject(parent), path_(path)
-{}
-
-File::File(const File &other, QObject *parent)
-    : QObject(parent)
-{
-    setPath(other.path());
-}
-
-File &File::operator =(const File &other)
-{
-    setPath(other.path());
-    return *this;
-}
-
-QString File::path() const
-{
-    return path_;
-}
-
-void File::setPath(const QString &path)
-{
-    path_ = path;
-}
-
-bool File::exists()
-{
-    return QFile(path()).exists();
-}
-
-QByteArray File::readData()
-{
-    QByteArray data;
-    QFile file(path());
-    if (file.exists() && file.open(QIODevice::ReadOnly)) {
-        data = file.readAll();
-        file.close();
-    }
-    return data;
-}
-
-bool File::writeData(const QByteArray &data)
-{
-    QFile file(path());
-    if (file.open(QIODevice::WriteOnly)) {
-        file.write(data);
-        file.close();
-        return true;
-    }
-    return false;
-}
-
-QString File::readText()
-{
-    QString data;
-    QFile file(path());
-    if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) {
-        QTextStream in(&file);
-        in.setCodec("UTF-8");
-        data = in.readAll();
-        file.close();
-    }
-    return data;
-}
-
-bool File::writeText(const QString &data)
-{
-    QFile file(path());
-    if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
-        QTextStream out(&file);
-        out.setCodec("UTF-8");
-        out << data;
-        file.close();
-        return true;
-    }
-    return false;
-}
-
-bool File::copy(const QString &newPath)
-{
-    return QFile(path()).copy(newPath);
-}
-
-bool File::move(const QString &newPath)
-{
-    return QFile(path()).rename(newPath);
-}
-
-bool File::remove()
-{
-    return QFile(path()).remove();
-}
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/src/qtlib_file.h b/src/lib/qtlib/src/qtlib_file.h
deleted file mode 100644
index 5804b19b36e85caa5a66ef2f257ef54ee633957d..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_file.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#pragma once
-
-#include <QObject>
-
-namespace qtlib {
-
-class File : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit File(const QString &path = "", QObject *parent = 0);
-
-    File(const File &other, QObject *parent = 0);
-    File &operator =(const File &other);
-
-    QString path() const;
-    void setPath(const QString &path);
-
-    bool exists();
-    QByteArray readData();
-    bool writeData(const QByteArray &data);
-    QString readText();
-    bool writeText(const QString &data);
-    bool copy(const QString &newPath);
-    bool move(const QString &newPath);
-    bool remove();
-
-private:
-    QString path_;
-};
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/src/qtlib_json.cpp b/src/lib/qtlib/src/qtlib_json.cpp
deleted file mode 100644
index 49faa10d6c8a6ad352a1b3ae79982763c9ecd060..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_json.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#include "qtlib_json.h"
-
-#include <QJsonDocument>
-#include <QJsonParseError>
-
-namespace qtlib {
-
-Json::Json(const QByteArray &json, QObject *parent)
-    : QObject(parent), json_(json)
-{}
-
-Json::Json(const QJsonObject &object, QObject *parent)
-    : QObject(parent)
-{
-    fromObject(object);
-}
-
-Json::Json(const QJsonArray &array, QObject *parent)
-    : QObject(parent)
-{
-    fromArray(array);
-}
-
-Json::Json(const Json &other, QObject *parent)
-    : QObject(parent)
-{
-    setJson(other.json());
-}
-
-Json &Json::operator =(const Json &other)
-{
-    setJson(other.json());
-    return *this;
-}
-
-QByteArray Json::json() const
-{
-    return json_;
-}
-
-void Json::setJson(const QByteArray &json)
-{
-    json_ = json;
-}
-
-void Json::fromObject(const QJsonObject &object)
-{
-    setJson(QJsonDocument(object).toJson());
-}
-
-void Json::fromArray(const QJsonArray &array)
-{
-    setJson(QJsonDocument(array).toJson());
-}
-
-QByteArray Json::toJson()
-{
-    return QJsonDocument::fromJson(json()).toJson();
-}
-
-QJsonObject Json::toObject()
-{
-    return QJsonDocument::fromJson(json()).object();
-}
-
-QJsonArray Json::toArray()
-{
-    return QJsonDocument::fromJson(json()).array();
-}
-
-bool Json::isValid()
-{
-    QJsonParseError parseError;
-    QJsonDocument::fromJson(json(), &parseError);
-    if (parseError.error == QJsonParseError::NoError) {
-        return true;
-    }
-    return false;
-}
-
-bool Json::isObject()
-{
-    return QJsonDocument::fromJson(json()).isObject();
-}
-
-bool Json::isArray()
-{
-    return QJsonDocument::fromJson(json()).isArray();
-}
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/src/qtlib_json.h b/src/lib/qtlib/src/qtlib_json.h
deleted file mode 100644
index 5cb9a60a43939a6880492b7c6fa13a3106562036..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_json.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#pragma once
-
-#include <QObject>
-#include <QJsonObject>
-#include <QJsonArray>
-
-namespace qtlib {
-
-class Json : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit Json(const QByteArray &json = QByteArray(), QObject *parent = 0);
-    explicit Json(const QJsonObject &object, QObject *parent = 0);
-    explicit Json(const QJsonArray &array, QObject *parent = 0);
-
-    Json(const Json &other, QObject *parent = 0);
-    Json &operator =(const Json &other);
-
-    QByteArray json() const;
-    void setJson(const QByteArray &json);
-
-    void fromObject(const QJsonObject &object);
-    void fromArray(const QJsonArray &array);
-    QByteArray toJson();
-    QJsonObject toObject();
-    QJsonArray toArray();
-    bool isValid();
-    bool isObject();
-    bool isArray();
-
-private:
-    QByteArray json_;
-};
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/src/qtlib_networkresource.cpp b/src/lib/qtlib/src/qtlib_networkresource.cpp
deleted file mode 100644
index e7d415eb683cea798ff25c418af5e384deb70234..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_networkresource.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#include "qtlib_networkresource.h"
-
-#include <QEventLoop>
-
-#include "qtlib_file.h"
-
-namespace qtlib {
-
-NetworkResource::NetworkResource(const QString &id, const QUrl &url, bool async, QObject *parent)
-    : QObject(parent), id_(id), url_(url), async_(async)
-{
-    setManager(new QNetworkAccessManager(this));
-}
-
-NetworkResource::~NetworkResource()
-{
-    manager()->deleteLater();
-}
-
-NetworkResource::NetworkResource(const NetworkResource &other, QObject *parent)
-    : QObject(parent)
-{
-    setId(other.id());
-    setUrl(other.url());
-    setAsync(other.async());
-    setRequest(other.request());
-    setManager(new QNetworkAccessManager(this));
-}
-
-NetworkResource &NetworkResource::operator =(const NetworkResource &other)
-{
-    setId(other.id());
-    setUrl(other.url());
-    setAsync(other.async());
-    setRequest(other.request());
-    return *this;
-}
-
-QString NetworkResource::id() const
-{
-    return id_;
-}
-
-void NetworkResource::setId(const QString &id)
-{
-    id_ = id;
-}
-
-QUrl NetworkResource::url() const
-{
-    return url_;
-}
-
-void NetworkResource::setUrl(const QUrl &url)
-{
-    url_ = url;
-}
-
-bool NetworkResource::async() const
-{
-    return async_;
-}
-
-void NetworkResource::setAsync(bool async)
-{
-    async_ = async;
-}
-
-QNetworkRequest NetworkResource::request() const
-{
-    return request_;
-}
-
-void NetworkResource::setRequest(const QNetworkRequest &request)
-{
-    request_ = request;
-}
-
-QNetworkAccessManager *NetworkResource::manager() const
-{
-    return manager_;
-}
-
-QNetworkReply *NetworkResource::reply() const
-{
-    return reply_;
-}
-
-QString NetworkResource::method() const
-{
-    return method_;
-}
-
-QString NetworkResource::contentType() const
-{
-    return contentType_;
-}
-
-QByteArray NetworkResource::contentData() const
-{
-    return contentData_;
-}
-
-NetworkResource *NetworkResource::head()
-{
-    setMethod("HEAD");
-    return send(url(), async());
-}
-
-NetworkResource *NetworkResource::get()
-{
-    setMethod("GET");
-    return send(url(), async());
-}
-
-NetworkResource *NetworkResource::post(const QByteArray &contentData, const QString &contentType)
-{
-    setMethod("POST");
-    setContentType(contentType);
-    setContentData(contentData);
-    return send(url(), async());
-}
-
-NetworkResource *NetworkResource::post(const QUrlQuery &contentData)
-{
-    setMethod("POST");
-    setContentType("application/x-www-form-urlencoded");
-    setContentData(contentData.toString(QUrl::FullyEncoded).toUtf8());
-    return send(url(), async());
-}
-
-NetworkResource *NetworkResource::put(const QByteArray &contentData, const QString &contentType)
-{
-    setMethod("PUT");
-    setContentType(contentType);
-    setContentData(contentData);
-    return send(url(), async());
-}
-
-NetworkResource *NetworkResource::put(const QUrlQuery &contentData)
-{
-    setMethod("PUT");
-    setContentType("application/x-www-form-urlencoded");
-    setContentData(contentData.toString(QUrl::FullyEncoded).toUtf8());
-    return send(url(), async());
-}
-
-NetworkResource *NetworkResource::deleteResource()
-{
-    setMethod("DELETE");
-    return send(url(), async());
-}
-
-bool NetworkResource::isFinishedWithNoError()
-{
-    if (reply()->isFinished() && reply()->error() == QNetworkReply::NoError) {
-        return true;
-    }
-    return false;
-}
-
-QByteArray NetworkResource::readData()
-{
-    QByteArray data;
-    if (isFinishedWithNoError()) {
-        data = reply()->readAll();
-    }
-    return data;
-}
-
-bool NetworkResource::saveData(const QString &path)
-{
-    if (isFinishedWithNoError()) {
-        return qtlib::File(path).writeData(reply()->readAll());
-    }
-    return false;
-}
-
-void NetworkResource::abort()
-{
-    if (reply()->isRunning()) {
-        reply()->abort();
-    }
-}
-
-void NetworkResource::replyFinished()
-{
-    if (isFinishedWithNoError()) {
-        // Check if redirection
-        // Note: An auto redirection option is available since Qt 5.6
-        QUrl redirectUrl;
-        if (reply()->hasRawHeader("Location")) {
-            redirectUrl.setUrl(QString(reply()->rawHeader("Location")));
-        }
-        else if (reply()->hasRawHeader("Refresh")) {
-            redirectUrl.setUrl(QString(reply()->rawHeader("Refresh")).split("url=").last());
-        }
-        if (!redirectUrl.isEmpty()) {
-            if (redirectUrl.isRelative()) {
-                redirectUrl = reply()->url().resolved(redirectUrl);
-            }
-            reply()->deleteLater();
-            send(redirectUrl, true);
-            return;
-        }
-    }
-    emit finished(this);
-}
-
-void NetworkResource::replyDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
-{
-    emit downloadProgress(id(), bytesReceived, bytesTotal);
-}
-
-void NetworkResource::replyUploadProgress(qint64 bytesSent, qint64 bytesTotal)
-{
-    emit uploadProgress(id(), bytesSent, bytesTotal);
-}
-
-void NetworkResource::setManager(QNetworkAccessManager *manager)
-{
-    manager_ = manager;
-}
-
-void NetworkResource::setReply(QNetworkReply *reply)
-{
-    reply_ = reply;
-}
-
-void NetworkResource::setMethod(const QString &method)
-{
-    method_ = method;
-}
-
-void NetworkResource::setContentType(const QString &contentType)
-{
-    contentType_ = contentType;
-}
-
-void NetworkResource::setContentData(const QByteArray &contentData)
-{
-    contentData_ = contentData;
-}
-
-NetworkResource *NetworkResource::send(const QUrl &url, bool async)
-{
-    QNetworkRequest networkRequest = request();
-    networkRequest.setUrl(url);
-    if (method() == "HEAD") {
-        setReply(manager()->head(networkRequest));
-    }
-    else if (method() == "GET") {
-        setReply(manager()->get(networkRequest));
-    }
-    else if (method() == "POST") {
-        networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(contentType()));
-        setReply(manager()->post(networkRequest, contentData()));
-    }
-    else if (method() == "PUT") {
-        networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(contentType()));
-        setReply(manager()->put(networkRequest, contentData()));
-    }
-    else if (method() == "DELETE") {
-        setReply(manager()->deleteResource(networkRequest));
-    }
-    else {
-        Q_ASSERT(false);
-    }
-    connect(reply(), &QNetworkReply::finished, this, &NetworkResource::replyFinished);
-    connect(reply(), &QNetworkReply::downloadProgress, this, &NetworkResource::replyDownloadProgress);
-    connect(reply(), &QNetworkReply::uploadProgress, this, &NetworkResource::replyUploadProgress);
-    if (!async) {
-        QEventLoop eventLoop;
-        connect(this, &NetworkResource::finished, &eventLoop, &QEventLoop::quit);
-        eventLoop.exec();
-    }
-    return this;
-}
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/src/qtlib_networkresource.h b/src/lib/qtlib/src/qtlib_networkresource.h
deleted file mode 100644
index beae8fc20949f57e58a87a9049e3e4553e65950f..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_networkresource.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#pragma once
-
-#include <QObject>
-#include <QUrl>
-#include <QUrlQuery>
-#include <QNetworkRequest>
-#include <QNetworkAccessManager>
-#include <QNetworkReply>
-
-namespace qtlib {
-
-class NetworkResource : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit NetworkResource(const QString &id = "", const QUrl &url = QUrl(), bool async = true, QObject *parent = 0);
-    ~NetworkResource();
-
-    NetworkResource(const NetworkResource &other, QObject *parent = 0);
-    NetworkResource &operator =(const NetworkResource &other);
-
-    QString id() const;
-    void setId(const QString &id);
-    QUrl url() const;
-    void setUrl(const QUrl &url);
-    bool async() const;
-    void setAsync(bool async);
-    QNetworkRequest request() const;
-    void setRequest(const QNetworkRequest &request);
-    QNetworkAccessManager *manager() const;
-    QNetworkReply *reply() const;
-    QString method() const;
-    QString contentType() const;
-    QByteArray contentData() const;
-
-    NetworkResource *head();
-    NetworkResource *get();
-    NetworkResource *post(const QByteArray &contentData, const QString &contentType);
-    NetworkResource *post(const QUrlQuery &contentData);
-    NetworkResource *put(const QByteArray &contentData, const QString &contentType);
-    NetworkResource *put(const QUrlQuery &contentData);
-    NetworkResource *deleteResource();
-    bool isFinishedWithNoError();
-    QByteArray readData();
-    bool saveData(const QString &path);
-
-signals:
-    void finished(NetworkResource *resource);
-    void downloadProgress(QString id, qint64 bytesReceived, qint64 bytesTotal);
-    void uploadProgress(QString id, qint64 bytesSent, qint64 bytesTotal);
-
-public slots:
-    void abort();
-
-private slots:
-    void replyFinished();
-    void replyDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
-    void replyUploadProgress(qint64 bytesSent, qint64 bytesTotal);
-
-private:
-    void setManager(QNetworkAccessManager *manager);
-    void setReply(QNetworkReply *reply);
-    void setMethod(const QString &method);
-    void setContentType(const QString &contentType);
-    void setContentData(const QByteArray &contentData);
-
-    NetworkResource *send(const QUrl &url, bool async);
-
-    QString id_;
-    QUrl url_;
-    bool async_;
-    QNetworkRequest request_;
-    QNetworkAccessManager *manager_;
-    QNetworkReply *reply_;
-    QString method_;
-    QString contentType_;
-    QByteArray contentData_;
-};
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/src/qtlib_ocsapi.cpp b/src/lib/qtlib/src/qtlib_ocsapi.cpp
deleted file mode 100644
index f9f345d962a101c3e76bf6199d4a3687d5ba1bdc..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_ocsapi.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#include "qtlib_ocsapi.h"
-
-#include <QXmlStreamReader>
-
-#include "qtlib_json.h"
-#include "qtlib_networkresource.h"
-
-namespace qtlib {
-
-// OCS-API Specification
-// https://www.freedesktop.org/wiki/Specifications/open-collaboration-services/
-
-OcsApi::OcsApi(const QString &id, const QUrl &baseUrl, const QString &userName, const QString &password, QObject *parent)
-    : QObject(parent), id_(id), baseUrl_(baseUrl), userName_(userName), password_(password)
-{}
-
-OcsApi::OcsApi(const OcsApi &other, QObject *parent)
-    : QObject(parent)
-{
-    setId(other.id());
-    setBaseUrl(other.baseUrl());
-    setUserName(other.userName());
-    setPassword(other.password());
-}
-
-OcsApi &OcsApi::operator =(const OcsApi &other)
-{
-    setId(other.id());
-    setBaseUrl(other.baseUrl());
-    setUserName(other.userName());
-    setPassword(other.password());
-    return *this;
-}
-
-QString OcsApi::id() const
-{
-    return id_;
-}
-
-void OcsApi::setId(const QString &id)
-{
-    id_ = id;
-}
-
-QUrl OcsApi::baseUrl() const
-{
-    return baseUrl_;
-}
-
-void OcsApi::setBaseUrl(const QUrl &baseUrl)
-{
-    baseUrl_ = baseUrl;
-}
-
-QString OcsApi::userName() const
-{
-    return userName_;
-}
-
-void OcsApi::setUserName(const QString &userName)
-{
-    userName_ = userName;
-}
-
-QString OcsApi::password() const
-{
-    return password_;
-}
-
-void OcsApi::setPassword(const QString &password)
-{
-    password_ = password;
-}
-
-QJsonObject OcsApi::getConfig()
-{
-    QUrl url = baseUrl().resolved(QUrl("config"));
-    url.setQuery("format=json");
-    qtlib::NetworkResource resource(url.toString(), url, false);
-    return qtlib::Json(resource.get()->readData()).toObject();
-}
-
-QJsonObject OcsApi::checkPerson()
-{
-    QUrl url = baseUrl().resolved(QUrl("person/check"));
-    QUrlQuery formData;
-    formData.addQueryItem("login", userName());
-    formData.addQueryItem("password", password());
-    formData.addQueryItem("format", "json");
-    qtlib::NetworkResource resource(url.toString(), url, false);
-    return qtlib::Json(resource.post(formData)->readData()).toObject();
-}
-
-QJsonObject OcsApi::getPersonDataSet(const QUrlQuery &query)
-{
-    QUrl url = baseUrl().resolved(QUrl("person/data"));
-    url.setUserName(userName());
-    url.setPassword(password());
-    QUrlQuery newQuery(query);
-    newQuery.removeQueryItem("format");
-    newQuery.addQueryItem("format", "json");
-    url.setQuery(newQuery);
-    qtlib::NetworkResource resource(url.toString(), url, false);
-    return qtlib::Json(resource.get()->readData()).toObject();
-}
-
-QJsonObject OcsApi::getPersonData(const QString &personId)
-{
-    QUrl url = baseUrl().resolved(QUrl("person/data/" + personId));
-    url.setUserName(userName());
-    url.setPassword(password());
-    url.setQuery("format=json");
-    qtlib::NetworkResource resource(url.toString(), url, false);
-    return qtlib::Json(resource.get()->readData()).toObject();
-}
-
-QJsonObject OcsApi::getPersonSelf()
-{
-    QUrl url = baseUrl().resolved(QUrl("person/self"));
-    url.setUserName(userName());
-    url.setPassword(password());
-    url.setQuery("format=json");
-    qtlib::NetworkResource resource(url.toString(), url, false);
-    return qtlib::Json(resource.get()->readData()).toObject();
-}
-
-QJsonObject OcsApi::getContentCategories()
-{
-    QUrl url = baseUrl().resolved(QUrl("content/categories"));
-    url.setQuery("format=json");
-    qtlib::NetworkResource resource(url.toString(), url, false);
-    return qtlib::Json(resource.get()->readData()).toObject();
-}
-
-QJsonObject OcsApi::getContentDataSet(const QUrlQuery &query)
-{
-    QUrl url = baseUrl().resolved(QUrl("content/data"));
-    QUrlQuery newQuery(query);
-    newQuery.removeQueryItem("format");
-    newQuery.addQueryItem("format", "json");
-    url.setQuery(newQuery);
-    qtlib::NetworkResource resource(url.toString(), url, false);
-    return qtlib::Json(resource.get()->readData()).toObject();
-}
-
-QJsonObject OcsApi::getContentData(const QString &contentId)
-{
-    QUrl url = baseUrl().resolved(QUrl("content/data/" + contentId));
-    url.setQuery("format=json");
-    qtlib::NetworkResource resource(url.toString(), url, false);
-    return qtlib::Json(resource.get()->readData()).toObject();
-}
-
-QJsonObject OcsApi::getContentDownload(const QString &contentId, const QString &itemId)
-{
-    QUrl url = baseUrl().resolved(QUrl("content/download/" + contentId + "/" + itemId));
-    url.setQuery("format=json");
-    qtlib::NetworkResource resource(url.toString(), url, false);
-    return qtlib::Json(resource.get()->readData()).toObject();
-}
-
-QJsonArray OcsApi::getProviderFile(const QUrl &url)
-{
-    QJsonArray providers;
-    qtlib::NetworkResource resource(url.toString(), url, false);
-    QXmlStreamReader reader(resource.get()->readData());
-    QStringList whitelist;
-    whitelist << "id" << "location" << "name" << "icon" << "termsofuse" << "register";
-    while (!reader.atEnd() && !reader.hasError()) {
-        reader.readNext();
-        if (reader.isStartElement() && reader.name() == "provider") {
-            QJsonObject provider;
-            provider["_providerfile"] = url.toString();
-            providers.append(provider);
-            continue;
-        }
-        QString elementName = reader.name().toString();
-        if (!providers.isEmpty() && whitelist.contains(elementName)) {
-            int i(providers.size() - 1);
-            QJsonObject provider = providers[i].toObject();
-            provider[elementName] = reader.readElementText();
-            providers[i] = provider;
-        }
-    }
-    return providers;
-}
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/src/qtlib_ocsapi.h b/src/lib/qtlib/src/qtlib_ocsapi.h
deleted file mode 100644
index 93346d8efa77d0785cc277f3d741646901608cfb..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_ocsapi.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#pragma once
-
-#include <QObject>
-#include <QUrl>
-#include <QUrlQuery>
-#include <QJsonObject>
-#include <QJsonArray>
-
-namespace qtlib {
-
-class OcsApi : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit OcsApi(const QString &id = "", const QUrl &baseUrl = QUrl(), const QString &userName = "", const QString &password = "", QObject *parent = 0);
-
-    OcsApi(const OcsApi &other, QObject *parent = 0);
-    OcsApi &operator =(const OcsApi &other);
-
-    QString id() const;
-    void setId(const QString &id);
-    QUrl baseUrl() const;
-    void setBaseUrl(const QUrl &baseUrl);
-    QString userName() const;
-    void setUserName(const QString &userName);
-    QString password() const;
-    void setPassword(const QString &password);
-
-    QJsonObject getConfig();
-    QJsonObject checkPerson();
-    QJsonObject getPersonDataSet(const QUrlQuery &query = QUrlQuery());
-    QJsonObject getPersonData(const QString &personId);
-    QJsonObject getPersonSelf();
-    QJsonObject getContentCategories();
-    QJsonObject getContentDataSet(const QUrlQuery &query = QUrlQuery());
-    QJsonObject getContentData(const QString &contentId);
-    QJsonObject getContentDownload(const QString &contentId, const QString &itemId);
-
-    static QJsonArray getProviderFile(const QUrl &url);
-
-private:
-    QString id_;
-    QUrl baseUrl_;
-    QString userName_;
-    QString password_;
-};
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/src/qtlib_package.cpp b/src/lib/qtlib/src/qtlib_package.cpp
deleted file mode 100644
index fde761253b9023598af258feb3d1d8da3241458f..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_package.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#include "qtlib_package.h"
-
-#ifdef QTLIB_UNIX
-#include <QJsonObject>
-#include <QMimeDatabase>
-#include <QProcess>
-#endif
-
-#ifdef Q_OS_ANDROID
-#include <QAndroidJniObject>
-#endif
-
-namespace qtlib {
-
-Package::Package(const QString &path, QObject *parent)
-    : QObject(parent), path_(path)
-{}
-
-Package::Package(const Package &other, QObject *parent)
-    : QObject(parent)
-{
-    setPath(other.path());
-}
-
-Package &Package::operator =(const Package &other)
-{
-    setPath(other.path());
-    return *this;
-}
-
-QString Package::path() const
-{
-    return path_;
-}
-
-void Package::setPath(const QString &path)
-{
-    path_ = path;
-}
-
-#ifdef QTLIB_UNIX
-bool Package::installAsProgram(const QString &newPath)
-{
-    QStringList arguments;
-    arguments << "-m" << "755" << "-p" << path() << newPath;
-    return execute("install", arguments);
-}
-
-bool Package::installAsFile(const QString &newPath)
-{
-    QStringList arguments;
-    arguments << "-m" << "644" << "-p" << path() << newPath;
-    return execute("install", arguments);
-}
-
-bool Package::installAsArchive(const QString &destinationDirPath)
-{
-    QJsonObject archiveTypes;
-    archiveTypes["application/x-tar"] = QString("tar");
-    archiveTypes["application/x-gzip"] = QString("tar");
-    archiveTypes["application/gzip"] = QString("tar");
-    archiveTypes["application/x-bzip"] = QString("tar");
-    archiveTypes["application/x-bzip2"] = QString("tar");
-    archiveTypes["application/x-xz"] = QString("tar");
-    archiveTypes["application/x-lzma"] = QString("tar");
-    archiveTypes["application/x-lzip"] = QString("tar");
-    archiveTypes["application/x-compressed-tar"] = QString("tar");
-    archiveTypes["application/x-bzip-compressed-tar"] = QString("tar");
-    archiveTypes["application/x-bzip2-compressed-tar"] = QString("tar");
-    archiveTypes["application/x-xz-compressed-tar"] = QString("tar");
-    archiveTypes["application/x-lzma-compressed-tar"] = QString("tar");
-    archiveTypes["application/x-lzip-compressed-tar"] = QString("tar");
-    archiveTypes["application/zip"] = QString("zip");
-    archiveTypes["application/x-7z-compressed"] = QString("7z");
-    archiveTypes["application/x-rar"] = QString("rar");
-    archiveTypes["application/x-rar-compressed"] = QString("rar");
-
-    QString mimeType = QMimeDatabase().mimeTypeForFile(path()).name();
-
-    if (archiveTypes.contains(mimeType)) {
-        QString archiveType = archiveTypes[mimeType].toString();
-        QString program;
-        QStringList arguments;
-        if (archiveType == "tar") {
-            program = "tar";
-            arguments << "-xf" << path() << "-C" << destinationDirPath;
-        }
-        else if (archiveType == "zip") {
-            program = "unzip";
-            arguments << "-o" << path() << "-d" << destinationDirPath;
-        }
-        else if (archiveType == "7z") {
-            program = "7z";
-            arguments << "x" << path() << "-o" + destinationDirPath; // No space between -o and directory
-        }
-        else if (archiveType == "rar") {
-            program = "unrar";
-            arguments << "e" << path() << destinationDirPath;
-        }
-        return execute(program, arguments);
-    }
-    return false;
-}
-
-bool Package::installAsPlasmapkg(const QString &type)
-{
-    QStringList arguments;
-    arguments << "-t" << type << "-i" << path();
-    return execute("plasmapkg2", arguments);
-}
-
-bool Package::uninstallAsPlasmapkg(const QString &type)
-{
-    QStringList arguments;
-    arguments << "-t" << type << "-r" << path();
-    return execute("plasmapkg2", arguments);
-}
-#endif
-
-#ifdef Q_OS_ANDROID
-bool Package::installAsApk()
-{
-    QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
-    if (activity.isValid()) {
-        QString filePath = path();
-        if (filePath.startsWith("file://", Qt::CaseInsensitive)) {
-            filePath.replace("file://localhost", "", Qt::CaseInsensitive);
-            filePath.replace("file://", "", Qt::CaseInsensitive);
-        }
-
-        QAndroidJniObject fileUri = QAndroidJniObject::fromString("file://" + filePath);
-        QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", fileUri.object());
-        QAndroidJniObject mimeType = QAndroidJniObject::fromString("application/vnd.android.package-archive");
-
-        QAndroidJniObject ACTION_VIEW = QAndroidJniObject::getStaticObjectField("android/content/Intent", "ACTION_VIEW", "Ljava/lang/String");
-        QAndroidJniObject FLAG_ACTIVITY_NEW_TASK = QAndroidJniObject::getStaticObjectField("android/content/Intent", "FLAG_ACTIVITY_NEW_TASK", "Ljava/lang/Integer");
-
-        QAndroidJniObject intent("android/content/Intent", "(Ljava/lang/String;)V", ACTION_VIEW.object());
-        intent = intent.callObjectMethod("setDataAndType", "(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/Intent;", uri.object(), mimeType.object());
-        intent = intent.callObjectMethod("setFlags", "(I)Landroid/content/Intent;", FLAG_ACTIVITY_NEW_TASK.object());
-
-        activity.callMethod<void>("startActivity", "(Landroid/content/Intent;)V", intent.object());
-        return true;
-    }
-    return false;
-}
-#endif
-
-#ifdef QTLIB_UNIX
-bool Package::execute(const QString &program, const QStringList &arguments)
-{
-    QProcess process;
-    process.start(program, arguments);
-    if (process.waitForFinished()) {
-        process.waitForReadyRead();
-        return true;
-    }
-    return false;
-}
-#endif
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/src/qtlib_package.h b/src/lib/qtlib/src/qtlib_package.h
deleted file mode 100644
index e5bd1125023ff12a6dd3b9c61b4c2dae621c4c6f..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/src/qtlib_package.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * qtlib
- *
- * @author      Akira Ohgaki <akiraohgaki@gmail.com>
- * @copyright   Akira Ohgaki
- * @license     https://opensource.org/licenses/LGPL-3.0
- * @link        https://github.com/akiraohgaki/qtlib
- */
-
-#pragma once
-
-#include <QObject>
-
-namespace qtlib {
-
-class Package : public QObject
-{
-    Q_OBJECT
-
-public:
-    explicit Package(const QString &path = "", QObject *parent = 0);
-
-    Package(const Package &other, QObject *parent = 0);
-    Package &operator =(const Package &other);
-
-    QString path() const;
-    void setPath(const QString &path);
-
-#ifdef QTLIB_UNIX
-    bool installAsProgram(const QString &newPath);
-    bool installAsFile(const QString &newPath);
-    bool installAsArchive(const QString &destinationDirPath);
-    bool installAsPlasmapkg(const QString &type = "plasmoid");
-    bool uninstallAsPlasmapkg(const QString &type = "plasmoid");
-#endif
-
-#ifdef Q_OS_ANDROID
-    bool installAsApk();
-#endif
-
-private:
-#ifdef QTLIB_UNIX
-    bool execute(const QString &program, const QStringList &arguments);
-#endif
-
-    QString path_;
-};
-
-} // namespace qtlib
diff --git a/src/lib/qtlib/test/main.cpp b/src/lib/qtlib/test/main.cpp
deleted file mode 100644
index 9c2ab9447cdfc88ef2d0d1bb073afeed420107dd..0000000000000000000000000000000000000000
--- a/src/lib/qtlib/test/main.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-#include <QObject>
-#include <QCoreApplication>
-#include <QDebug>
-
-#include "qtlib_file.h"
-#include "qtlib_dir.h"
-#include "qtlib_json.h"
-#include "qtlib_config.h"
-#include "qtlib_networkresource.h"
-#include "qtlib_ocsapi.h"
-#include "qtlib_package.h"
-
-class Test : public QObject
-{
-public:
-    Test() {}
-    virtual ~Test() {}
-
-    void start()
-    {
-        qDebug() << "Start";
-
-        qtlib::NetworkResource *resource = new qtlib::NetworkResource(
-                    "LGPL-3.0",
-                    QUrl("https://api.opensource.org/license/LGPL-3.0"),
-                    false,
-                    this);
-        connect(resource, &qtlib::NetworkResource::downloadProgress, this, &Test::downloadProgress);
-        QJsonObject result = qtlib::Json(resource->get()->readData()).toObject();
-
-        qDebug() << resource->id() << ":" << result["name"].toString();
-
-        connect(resource, &qtlib::NetworkResource::finished, this, &Test::finished);
-        resource->setId(result["name"].toString());
-        resource->setUrl(QUrl(result["text"].toArray()[0].toObject()["url"].toString()));
-        resource->setAsync(true);
-        resource->get();
-    }
-
-public slots:
-    void finished(qtlib::NetworkResource *resource)
-    {
-        QString path = qtlib::Dir::tempPath() + "/" + resource->url().fileName();
-        resource->saveData(path);
-
-        qDebug() << "Downloaded" << resource->id() << ":" << path;
-        qDebug() << "Finished";
-
-        resource->deleteLater();
-        QCoreApplication::exit();
-    }
-
-    void downloadProgress(QString id, qint64 bytesReceived, qint64 bytesTotal)
-    {
-        qDebug() << "Progress" << id << ":" << bytesReceived << "/" << bytesTotal;
-    }
-};
-
-int main(int argc, char *argv[])
-{
-    QCoreApplication app(argc, argv);
-
-    Test test;
-    test.start();
-
-    return app.exec();
-}
diff --git a/xdgurl.pro b/xdgurl.pro
deleted file mode 100644
index 7e008d5a1016896ae32b8bc08ef6bb82109323e9..0000000000000000000000000000000000000000
--- a/xdgurl.pro
+++ /dev/null
@@ -1,27 +0,0 @@
-include(src/lib/qtlib/qtlib.pri)
-
-include(src/app/app.pri)
-
-TARGET = xdgurl
-
-TEMPLATE = app
-
-CONFIG += c++11
-
-RESOURCES += src/desktop/desktop.qrc
-
-DISTFILES += \
-    README.md \
-    src/desktop/xdgurl.desktop \
-    src/desktop/appimage-desktopintegration \
-    pkg/build.sh \
-    pkg/ubuntu/debian/changelog \
-    pkg/ubuntu/debian/compat \
-    pkg/ubuntu/debian/control \
-    pkg/ubuntu/debian/copyright \
-    pkg/ubuntu/debian/rules \
-    pkg/ubuntu/debian/xdgurl.install \
-    pkg/fedora/xdgurl.spec \
-    pkg/arch/PKGBUILD
-
-include(deployment.pri)