Description: <short summary of the patch>
 TODO: Put a short summary on the line above and replace this paragraph
 with a longer explanation of this change. Complete the meta-information
 with other relevant fields (see below for details). To make it easier, the
 information below has been extracted from the changelog. Adjust it or drop
 it.
 .
 nuntius-linux (0.2.0-1) unstable; urgency=medium
 .
   * Initial release (closes: #819980)
Author: Barak A. Pearlmutter <bap@debian.org>
Bug-Debian: https://bugs.debian.org/819980

---
The information above should follow the Patch Tagging Guidelines, please
checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:

Origin: <vendor|upstream|other>, <url of original patch>
Bug: <url in upstream bugtracker>
Bug-Debian: https://bugs.debian.org/<bugnumber>
Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
Forwarded: <no|not-needed|url proving that it has been forwarded>
Reviewed-By: <name and email of someone who approved the patch>
Last-Update: <YYYY-MM-DD>

--- /dev/null
+++ nuntius-linux-0.2.0/.tx/config
@@ -0,0 +1,8 @@
+[main]
+host = https://www.transifex.com
+type = PO
+
+[nuntius-linux.strings]
+file_filter = po/<lang>.po
+source_file = po/nuntius.pot
+source_lang = en
\ No newline at end of file
--- nuntius-linux-0.2.0.orig/Makefile.am
+++ nuntius-linux-0.2.0/Makefile.am
@@ -3,16 +3,14 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
 SUBDIRS = po
 
 # desktop file
-# (we can't use INTLTOOL_DESKTOP_RULE here due to lp#605826)
-%.desktop: %.desktop.in
-	$(AM_V_GEN) $(MKDIR_P) $(dir $@); LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
-applicationsdir = $(datadir)/applications
-applications_DATA = data/org.holylobster.nuntius.desktop
-dist_noinst_DATA = data/org.holylobster.nuntius.desktop.in
+desktopdir = $(datadir)/applications
+desktop_in_files = data/org.holylobster.nuntius.desktop.in
+desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
+@INTLTOOL_DESKTOP_RULE@
 
 # autostart file
 autostartdir = $(sysconfdir)/xdg/autostart
-autostart_DATA = $(applications_DATA)
+autostart_DATA = $(desktop_DATA)
 
 # appdata file
 appdatadir = $(datadir)/appdata
@@ -23,11 +21,15 @@ appdata_in_files = data/org.holylobster.
 # DBus service file
 servicedir = $(datadir)/dbus-1/services
 service_DATA = data/org.holylobster.nuntius.service
-dist_noinst_DATA += data/org.holylobster.nuntius.service.in
+dist_noinst_DATA = data/org.holylobster.nuntius.service.in
 
 data/org.holylobster.nuntius.service: data/org.holylobster.nuntius.service.in Makefile
 	$(AM_V_GEN) $(MKDIR_P) $(dir $@); sed -e "s|\@bindir\@|$(bindir)|" $< > $@
 
+# gsettings
+gsettings_SCHEMAS = data/org.holylobster.nuntius.gschema.xml
+@GSETTINGS_RULES@
+
 data_icons_public_icons = \
 	hicolor_apps_16x16_nuntius.png \
 	hicolor_apps_22x22_nuntius.png \
@@ -60,7 +62,8 @@ data-icons-uninstall-icons:
 AM_CPPFLAGS = \
 	-DGETTEXT_PACKAGE=\""$(GETTEXT_PACKAGE)"\" \
 	-DGNOMELOCALEDIR=\""$(localedir)"\" \
-	-DDATADIR=\""$(datadir)"\"
+	-DDATADIR=\""$(datadir)"\" \
+	-DTOOLSDIR=\""$(libexecdir)/$(PACKAGE)"\"
 
 AM_VALAFLAGS = \
 	--target-glib=2.40 \
@@ -71,7 +74,7 @@ AM_VALAFLAGS = \
 	--pkg posix \
 	--gresources  $(top_srcdir)/src/resources/nuntius.gresource.xml
 
-bin_PROGRAMS = nuntius
+bin_PROGRAMS = nuntius qrtest
 
 BUILT_SOURCES = \
 	src/resources.c
@@ -80,6 +83,9 @@ resource_files = $(shell $(GLIB_COMPILE_
 src/resources.c: $(top_srcdir)/src/resources/nuntius.gresource.xml $(resource_files)
 	$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(top_srcdir)/src/resources --generate-source $<
 
+toolsdir = $(libexecdir)/$(PACKAGE)
+tools_SCRIPTS = createcert.sh
+
 VALA_SOURCES = \
 	src/application.vala \
 	src/appslistpanel.vala \
@@ -87,14 +93,19 @@ VALA_SOURCES = \
 	src/connection.vala \
 	src/notification.vala \
 	src/notificationapp.vala \
+	src/notificationcounter.vala \
 	src/notificationsview.vala \
+	src/qrimage.vala \
+	src/smsnotification.vala \
+	src/testview.vala \
 	src/window.vala \
 	src/main.vala
 
 nuntius_SOURCES = \
 	$(BUILT_SOURCES) \
 	$(VALA_SOURCES) \
-	src/config.vapi
+	src/config.vapi \
+	src/qrencode.vapi
 
 AM_CFLAGS = \
 	$(NUNTIUS_CFLAGS) \
@@ -107,21 +118,33 @@ nuntius_LDADD = \
 	$(NUNTIUS_LIBS) \
 	-lm
 
+qrtest_SOURCES = \
+	tests/qrtest.vala \
+	src/qrimage.vala \
+	src/qrencode.vapi
+
+qrtest_LDFLAGS = -export-dynamic
+qrtest_LDADD = \
+	$(NUNTIUS_LIBS) \
+	-lm
+
+check-local: $(desktop_DATA)
+	$(DESKTOP_FILE_VALIDATE) $(desktop_DATA)
+
 install-data-local: data-icons-install-icons
 
 uninstall-local: data-icons-uninstall-icons
 
 EXTRA_DIST = \
-	$(applications_DATA) \
 	$(appdata_in_files) \
+	$(desktop_in_files) \
 	$(resource_files) \
-	data/org.holylobster.nuntius.appdata.xml \
 	src/resources/nuntius.gresource.xml \
 	$(addprefix data/icons/,$(data_icons_public_icons))
 
 CLEANFILES = \
 	$(appdata_DATA) \
-	$(applications_DATA) \
+	$(desktop_DATA) \
 	$(service_DATA)
 
 MAINTAINERCLEANFILES = \
--- nuntius-linux-0.2.0.orig/README.md
+++ nuntius-linux-0.2.0/README.md
@@ -7,6 +7,7 @@ Nuntius delivers notifications from your
 Nuntius is an Open Source project from HolyLobster.
 
 To use Nuntius you will need to install a companion tool on your phone or tablet and pair it via Bluetooth.
+You will also need to restart your session to auto-start nuntius.
 
 For more information on the project and the companion tools to install on the computer check https://github.com/holylobster
 
@@ -18,7 +19,7 @@ If you have suggestions on how to improv
 ##Packages
 You can install Nuntius from:
 
- * Fedora: yum install nuntius
+ * Fedora: `dnf install nuntius` (use `yum` instead of `dnf` on Fedora <= 21)
  * [Arch Linux (AUR)](https://aur.archlinux.org/packages/nuntius/)
 
 You will need to install Nuntius also on your phone or tablet.
--- nuntius-linux-0.2.0.orig/configure.ac
+++ nuntius-linux-0.2.0/configure.ac
@@ -1,6 +1,6 @@
-AC_PREREQ(2.63)
+AC_PREREQ([2.69])
 
-AC_INIT([nuntius], [0.2.0])
+AC_INIT([nuntius],[0.2.0])
 
 dnl http://people.gnome.org/~walters/docs/build-api.txt
 dnl We don't support separate builddir when building from git
@@ -10,7 +10,7 @@ AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_HEADERS(config.h)
 AC_CONFIG_SRCDIR(src/main.vala)
 
-AM_INIT_AUTOMAKE([1.11 tar-ustar dist-xz no-dist-gzip foreign])
+AM_INIT_AUTOMAKE([1.11 tar-ustar dist-xz no-dist-gzip foreign subdir-objects -Wall])
 m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
 
 IT_PROG_INTLTOOL([0.50.1])
@@ -25,20 +25,25 @@ AC_PROG_CC_STDC
 AC_PROG_INSTALL
 AM_PROG_VALAC([0.23.3])
 
+AC_PATH_PROG(DESKTOP_FILE_VALIDATE, desktop-file-validate, /bin/true)
 AC_PATH_PROG(GLIB_COMPILE_RESOURCES, glib-compile-resources)
 
+GLIB_GSETTINGS
+
 PKG_PROG_PKG_CONFIG
 
 PKG_CHECK_MODULES(NUNTIUS, [
     gio-2.0 >= 2.40
     gio-unix-2.0 >= 2.38
     glib-2.0 >= 2.38
-    gtk+-3.0 >= 3.10.0
+    gtk+-3.0 >= 3.14.0
     json-glib-1.0 >= 0.16.2
+    libqrencode >= 3.1.0
 ])
 
 AC_CONFIG_FILES([
     Makefile
+    data/org.holylobster.nuntius.gschema.xml
     po/Makefile.in
 ])
 
--- /dev/null
+++ nuntius-linux-0.2.0/createcert.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+function try {
+    "$@"
+    local status=$?
+    if [ $status -ne 0 ]; then
+        echo -e "\nError with $1" >&2
+        exit $?
+    fi
+    return $status
+}
+
+function create_cert() {
+    if [[ ! -f $HOME/.config/nuntius/nuntius.pem || ! -f $HOME/.config/nuntius/nuntius.key ]]; then
+        echo "Creating cert..."
+        cd $HOME/.config/nuntius
+        try openssl genrsa -out nuntius.key 2048
+        try openssl req -new -key nuntius.key -out nuntius.csr -subj "/O=Holylobster/OU=Nuntius"
+        try openssl x509 -req -days 3650 -in nuntius.csr -signkey nuntius.key -out nuntius.crt
+        try openssl x509 -in nuntius.crt -out nuntius.pem
+        exit $?
+    else
+        echo "Certificate already exist..."
+        exit 0
+    fi
+}
+
+if [[ ! -d $HOME/.config/nuntius ]]; then
+    echo "Creating nuntius config directory..."
+    mkdir -p $HOME/.config/nuntius
+fi
+
+create_cert
+
+# ex:set ts=4 et:
--- /dev/null
+++ nuntius-linux-0.2.0/data/org.holylobster.nuntius.gschema.xml.in
@@ -0,0 +1,21 @@
+<schemalist gettext-domain="@GETTEXT_PACKAGE@">
+  <schema id="org.holylobster.nuntius.state" path="/org/holylobster/nuntius/state/">
+    <child schema="org.holylobster.nuntius.state.window" name="window"/>
+  </schema>
+  <schema id="org.holylobster.nuntius.state.window" path="/org/holylobster/nuntius/state/window/">
+    <key type="i" name="state">
+      <default>0</default>
+      <summary>Window state</summary>
+      <description>
+        State of the window, e.g. maximized.
+      </description>
+    </key>
+    <key type="(ii)" name="size">
+      <default>(870, 690)</default>
+      <summary>Window width and height</summary>
+      <description>
+        Width and height of the window.
+      </description>
+    </key>
+  </schema>
+</schemalist>
--- nuntius-linux-0.2.0.orig/po/POTFILES.in
+++ nuntius-linux-0.2.0/po/POTFILES.in
@@ -1,4 +1,7 @@
 data/org.holylobster.nuntius.appdata.xml.in
 data/org.holylobster.nuntius.desktop.in
+[type: gettext/gsettings]data/org.holylobster.nuntius.gschema.xml.in
+src/application.vala
+[type: gettext/glade]src/resources/gtk/menus.ui
 [type: gettext/glade]src/resources/ui/appslistpanel.ui
 [type: gettext/glade]src/resources/ui/window.ui
--- /dev/null
+++ nuntius-linux-0.2.0/po/POTFILES.skip
@@ -0,0 +1 @@
+src/application.c
--- nuntius-linux-0.2.0.orig/po/de.po
+++ nuntius-linux-0.2.0/po/de.po
@@ -39,4 +39,4 @@ msgstr ""
 #: ../data/org.holylobster.nuntius.desktop.in.h:2
 msgid "notifications;"
 msgstr ""
-"Benachrichtigungen"
+"Benachrichtigungen;"
--- nuntius-linux-0.2.0.orig/po/pl.po
+++ nuntius-linux-0.2.0/po/pl.po
@@ -10,8 +10,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: nuntius-linux\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-03-10 20:10+0100\n"
-"PO-Revision-Date: 2015-03-10 20:11+0100\n"
+"POT-Creation-Date: 2015-03-22 15:35+0100\n"
+"PO-Revision-Date: 2015-03-22 15:37+0100\n"
 "Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
 "Language-Team: Polish <gnomepl@aviary.pl>\n"
 "Language: pl\n"
@@ -52,3 +52,51 @@ msgid "notifications;"
 msgstr ""
 "powiadomienia;powiadamianie;notyfikacje;wiadomości;komunikaty;telefon;tablet;"
 "smartfon;phablet;fablet;android;"
+
+#: ../data/org.holylobster.nuntius.gschema.xml.in.h:1
+msgid "Window state"
+msgstr "Stan okna"
+
+#: ../data/org.holylobster.nuntius.gschema.xml.in.h:2
+msgid "State of the window, e.g. maximized."
+msgstr "Stan okna, tzn. czy jest zmaksymalizowane."
+
+#: ../data/org.holylobster.nuntius.gschema.xml.in.h:3
+msgid "Window width and height"
+msgstr "Szerokość i wysokość okna"
+
+#: ../data/org.holylobster.nuntius.gschema.xml.in.h:4
+msgid "Width and height of the window."
+msgstr "Szerokość i wysokość okna."
+
+#: ../src/application.vala:286 ../src/resources/ui/window.ui.h:1
+msgid "Nuntius"
+msgstr "Nuntius"
+
+#: ../src/application.vala:289
+msgid ""
+"Deliver notifications from your phone or tablet to your computer over "
+"Bluetooth."
+msgstr ""
+"Wyświetlanie powiadomień z telefonu lub tabletu na komputerze za pomocą "
+"Bluetooth."
+
+#: ../src/application.vala:294
+msgid "translator-credits"
+msgstr ""
+"Piotr Drąg <piotrdrag@gmail.com>, 2015\n"
+"Aviary.pl <gnomepl@aviary.pl>, 2015"
+
+#. namespace Nuntius
+#. ex:set ts=4 et:
+#: ../src/resources/gtk/menus.ui.h:1
+msgid "_About"
+msgstr "_O programie"
+
+#: ../src/resources/ui/appslistpanel.ui.h:1
+msgid "Type to search"
+msgstr "Wyszukiwanie"
+
+#: ../src/resources/ui/window.ui.h:2
+msgid "All Applications"
+msgstr "Wszystkie programy"
--- nuntius-linux-0.2.0.orig/po/sk.po
+++ nuntius-linux-0.2.0/po/sk.po
@@ -1,22 +1,22 @@
 # SOME DESCRIPTIVE TITLE.
 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 # This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# Dušan Kazik <prescott66@gmail.com>, 2015.
 #
 msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-03-11 11:24+0100\n"
-"PO-Revision-Date: 2015-03-11 13:12+0100\n"
+"POT-Creation-Date: 2015-03-20 16:45+0100\n"
+"PO-Revision-Date: 2015-03-20 18:28+0100\n"
+"Last-Translator: Dušan Kazik <prescott66@gmail.com>\n"
+"Language-Team: \n"
+"Language: sk\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Last-Translator: Dušan Kazik <prescott66@gmail.com>\n"
-"Language-Team: \n"
 "X-Generator: Poedit 1.7.4\n"
 "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-"Language: sk\n"
 
 #: ../data/org.holylobster.nuntius.appdata.xml.in.h:1
 msgid ""
@@ -31,8 +31,8 @@ msgid ""
 "To use Nuntius you will need to install a companion tool on your phone or "
 "tablet and pair it via Bluetooth."
 msgstr ""
-"Na používanie programu Nuntius budete musieť vo vašom telefóne alebo "
-"tablete nainštalovať spoločný nástroj a spárovať ho cez Bluetooth."
+"Na používanie programu Nuntius budete musieť vo vašom telefóne alebo tablete "
+"nainštalovať spoločný nástroj a spárovať ho cez Bluetooth."
 
 #: ../data/org.holylobster.nuntius.desktop.in.h:1
 msgid ""
@@ -45,3 +45,35 @@ msgstr ""
 #: ../data/org.holylobster.nuntius.desktop.in.h:2
 msgid "notifications;"
 msgstr "oznámenia;upozornenia;"
+
+#: ../data/org.holylobster.nuntius.gschema.xml.in.h:1
+msgid "Window state"
+msgstr "Stav okna"
+
+#: ../data/org.holylobster.nuntius.gschema.xml.in.h:2
+msgid "State of the window, e.g. maximized."
+msgstr "Stav okna, napr. maximalizované."
+
+#: ../data/org.holylobster.nuntius.gschema.xml.in.h:3
+msgid "Window width and height"
+msgstr "Šírka a výška okna"
+
+#: ../data/org.holylobster.nuntius.gschema.xml.in.h:4
+msgid "Width and height of the window."
+msgstr "Šírka a výška okna."
+
+#: ../src/resources/gtk/menus.ui.h:1
+msgid "_About"
+msgstr "_O programe"
+
+#: ../src/resources/ui/appslistpanel.ui.h:1
+msgid "Type to search"
+msgstr "Text na vyhľadanie"
+
+#: ../src/resources/ui/window.ui.h:1
+msgid "Nuntius"
+msgstr "Nuntius"
+
+#: ../src/resources/ui/window.ui.h:2
+msgid "All Applications"
+msgstr "Všetky aplikácie"
--- nuntius-linux-0.2.0.orig/src/application.vala
+++ nuntius-linux-0.2.0/src/application.vala
@@ -34,72 +34,116 @@ public interface BluezProfileManager : O
     public abstract void unregister_profile(ObjectPath profile) throws IOError;
 }
 
-[DBus (name = "org.bluez.Profile1")]
-public class BluezProfile : Object {
-    HashTable<ObjectPath, DeviceConnection>? connections;
+public class Connections : Object {
+    private HashTable<string, Connection>? connections;
 
-    public BluezProfile(Cancellable cancellable) {
-        connections = new HashTable<ObjectPath, DeviceConnection>(str_hash, str_equal);
-
-        cancellable.connect(() => {
-            connections.remove_all();
-        });
-    }
-
-    public void release() {
-        print("release method called\n");
+    construct {
+        connections = new HashTable<string, Connection>(str_hash, str_equal);
     }
 
-    public void new_connection(ObjectPath device, Socket socket, HashTable<string, Variant> fd_properties) {
-        print("new_connection method called for device: %s\n", device);
-        var connection = new DeviceConnection(device, socket);
-
-        connections.insert(device, connection);
+    public void add_connection(Connection connection) {
+        connections.insert(connection.server_name, connection);
         connection.notify["connected"].connect(() => {
             if (!connection.connected) {
-                connections.remove(connection.device);
-                print("removed connection for device '%s'\n", connection.device);
+                connections.remove(connection.server_name);
+                print("removed connection for device '%s'\n",
+                      connection.server_name);
             }
         });
 
         connection.notification_posted.connect((notification) => {
-            var app = GLib.Application.get_default();
-            (app as Application).add_notification(notification);
+            var app = (Application) GLib.Application.get_default();
+            app.add_notification(notification);
+        });
+
+        connection.sms_received.connect((sms_notification) => {
+            var app = (Application) GLib.Application.get_default();
+            app.add_sms_notification(sms_notification);
         });
 
         connection.notification_removed.connect((id, package_name) => {
-            var app = GLib.Application.get_default();
-            (app as Application).mark_notification_read(id, package_name);
+            var app = (Application) GLib.Application.get_default();
+            app.mark_notification_read(id, package_name);
         });
     }
 
-    public void request_disconnection(ObjectPath device) {
-        print("request_disconnection method called for devices: %s\n", device);
-
-        var device_connection = connections.lookup(device);
-        if (device_connection != null) {
-            connections.remove(device);
+    public void remove_connection(string server_name) {
+        var connection = connections.lookup(server_name);
+        if (connection != null) {
+            connections.remove(server_name);
         }
     }
 
-    public bool has_any_device_connected() {
+    public bool is_connected() {
         return connections.size() > 0;
     }
 
-    public bool get_device_connected(ObjectPath device) {
-        return connections.get(device) != null;
+    public bool get_connected(string server_name) {
+        return connections.get(server_name) != null;
     }
 }
 
+[DBus (name = "org.bluez.Profile1")]
+public class BluezProfile : Object {
+    private Connections connections;
+
+    public BluezProfile(Connections connections) {
+        this.connections = connections;
+    }
+
+    public void release() {
+        print("release method called\n");
+    }
+
+    public void new_connection(ObjectPath device, Socket socket, HashTable<string, Variant> fd_properties) {
+        print("new_connection method called for device: %s\n", device);
+        var connection = new Connection(device,
+                                        SocketConnection.factory_create_connection(socket));
+
+        connections.add_connection(connection);
+    }
+
+    public void request_disconnection(ObjectPath device) {
+        print("request_disconnection method called for devices: %s\n", device);
+
+        connections.remove_connection(device);
+    }
+}
+
+private enum TcpConnectionStatus {
+    DISCONNECTED,
+    CONNECTING,
+    CONNECTED
+}
+
 public class Application : Gtk.Application {
-    Cancellable? cancellable;
-    DBusObjectManager manager;
-    BluezProfileManager? profile_manager;
-    BluezProfile? profile;
-    uint connect_devices_id;
-    bool first_activation;
-    Window window;
-    List<NotificationApp> _notification_apps;
+    private Cancellable? cancellable;
+    private Connections connections;
+    private DBusObjectManager manager;
+    private BluezProfileManager? profile_manager;
+    private BluezProfile? profile;
+    private uint connect_devices_id;
+    private bool first_activation;
+    private bool cert_created;
+    private Window window;
+    private string connect_host;
+    private TcpConnectionStatus tcp_status;
+    private TlsCertificate? cert;
+    private List<NotificationApp> _notification_apps;
+    private List<SmsNotification> sms_notifications;
+
+    private const GLib.ActionEntry[] app_entries = {
+        { "about", on_about_activate },
+        { "show-qrcode", on_show_qrcode_activate },
+        { "open-notifications-view", on_open_notifications_view_activate, "(ss)"},
+        { "send-sms", on_send_sms_activate, "(ss)"}
+    };
+
+    private const OptionEntry[] options = {
+        {"connect", '\0', 0, OptionArg.STRING, null,
+         N_("Connect to a specific server"), null},
+        {null}
+    };
 
     public signal void notification_app_added(NotificationApp notification_app);
 
@@ -108,12 +152,16 @@ public class Application : Gtk.Applicati
     }
 
     public Application() {
-        Object(application_id: "org.holylobster.nuntius");
+        Object(application_id: "org.holylobster.nuntius",
+               flags: ApplicationFlags.HANDLES_COMMAND_LINE);
+        add_main_option_entries(options);
     }
 
     construct {
         cancellable = new Cancellable();
+        cert_created = false;
         first_activation = true;
+        tcp_status = TcpConnectionStatus.DISCONNECTED;
         _notification_apps = new List<NotificationApp>();
     }
 
@@ -137,6 +185,8 @@ public class Application : Gtk.Applicati
         // Since it works as a daemon keep a hold forever on the primary instance
         hold();
 
+        add_action_entries(app_entries, this);
+
         var css_provider = new Gtk.CssProvider();
         try {
             var file = File.new_for_uri("resource:///org/holylobster/nuntius/css/nuntius-style.css");
@@ -148,7 +198,8 @@ public class Application : Gtk.Applicati
                                                  css_provider,
                                                  Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
 
-        profile = new BluezProfile(cancellable);
+        connections = new Connections();
+        profile = new BluezProfile(connections);
 
         var profile_path = new ObjectPath(get_dbus_object_path() + "/Profile");
 
@@ -177,6 +228,8 @@ public class Application : Gtk.Applicati
         } catch (Error e) {
             warning("%s", e.message);
         }
+
+        create_cert();
     }
 
     private void ensure_window() {
@@ -188,19 +241,134 @@ public class Application : Gtk.Applicati
         }
     }
 
+    private string? spawn_command(string[] args) {
+        try {
+            string[] spawn_args = args;
+            string[] spawn_env = Environ.get ();
+            string ls_stdout;
+            string ls_stderr;
+            int ls_status;
+
+            Process.spawn_sync (".",
+                                spawn_args,
+                                spawn_env,
+                                SpawnFlags.SEARCH_PATH,
+                                null,
+                                out ls_stdout,
+                                out ls_stderr,
+                                out ls_status);
+            return ls_stdout;
+
+        } catch (SpawnError e) {
+            stdout.printf ("Error: %s\n", e.message);
+            return null;
+        }
+    }
+
+    private void create_cert() {
+        var path_to_conf = GLib.Path.build_filename(GLib.Environment.get_user_config_dir(), "nuntius");
+        var cert_path = GLib.Path.build_filename(path_to_conf, "nuntius.pem");
+        var key_path = GLib.Path.build_filename(path_to_conf, "nuntius.key");
+        var file = File.new_for_path(cert_path);
+        if (!file.query_exists()) {
+            var script = GLib.Path.build_filename(Config.TOOLSDIR, "createcert.sh");
+            string[] spawn_args = { script };
+            spawn_command(spawn_args);
+            cert_created = true;
+        }
+        try {
+            cert = new TlsCertificate.from_files(cert_path, key_path);
+        } catch (Error e) {
+            warning("Failed to load certificate: %s", e.message);
+        }
+    }
+
+    private string get_fingerprint() {
+        string path_to_pem = GLib.Path.build_filename(GLib.Environment.get_user_config_dir(), "nuntius/nuntius.pem");
+        string[] spawn_args = {"openssl", "x509", "-in", path_to_pem, "-fingerprint", "-sha1"};
+        string result = spawn_command(spawn_args);
+        string[] splitted = result.split("=");
+        splitted = splitted[1].split("\n");
+        string fingerprint = splitted[0];
+        return fingerprint;
+    }
+
+    private void show_qrcode() {
+        var dialog = new Gtk.Dialog.with_buttons(_("Certificate Fingerprint"),
+                                                 window,
+                                                 Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
+                                                 _("_OK"),
+                                                 Gtk.ResponseType.OK);
+        dialog.border_width = 30;
+        dialog.set_default_size(300, 300);
+
+        dialog.response.connect(i => {
+            window.destroy();
+        });
+
+        var qr = new Nuntius.QRImage();
+        qr.text = get_fingerprint() + "-" + GLib.Environment.get_host_name();
+        qr.show();
+
+        dialog.get_content_area().pack_end(qr, true, true, 0);
+        dialog.show();
+    }
+
     protected override void activate() {
         // We want it to start as a daemon and not showing the window from
         // the beginning
         if (!first_activation) {
             ensure_window();
             window.present();
+            if (cert_created) {
+                show_qrcode();
+            }
         }
 
         first_activation = false;
 
+        if (tcp_status == TcpConnectionStatus.DISCONNECTED && connect_host != null && cert != null) {
+            var host = connect_host;
+            var client = new SocketClient();
+
+            tcp_status = TcpConnectionStatus.CONNECTING;
+
+            client.tls = true;
+            client.event.connect(on_socket_client_event);
+            client.connect_to_host_async.begin(connect_host, 12233, cancellable, (obj, res) => {
+                try {
+                    var connection = client.connect_to_host_async.end(res);
+                    tcp_status = TcpConnectionStatus.CONNECTED;
+                    connections.add_connection(new Connection(host, connection));
+                } catch (Error e) {
+                    tcp_status = TcpConnectionStatus.DISCONNECTED;
+                    warning("Could not connect to server: %s", connect_host);
+                }
+            });
+        }
+
         base.activate();
     }
 
+    private void on_socket_client_event(SocketClientEvent event, SocketConnectable? connectable, IOStream? ios) {
+        if (event == SocketClientEvent.TLS_HANDSHAKING) {
+            var tls = (TlsConnection) ios;
+            tls.accept_certificate.connect((cert, err) => {
+                return true;
+            });
+            tls.set_certificate(cert);
+        }
+    }
+
+    protected override int command_line(ApplicationCommandLine cl) {
+        var dict = cl.get_options_dict();
+
+        dict.lookup("connect", "s", out connect_host);
+        activate();
+
+        return 0;
+    }
+
     private async void connect_interface(DBusObject object, DBusInterface iface, bool dump) {
         if (!(iface is DBusProxy)) {
             return;
@@ -217,7 +385,7 @@ public class Application : Gtk.Applicati
         }
 
         // try to get the device
-        if (name == "org.bluez.Device1" && !profile.get_device_connected(path)) {
+        if (name == "org.bluez.Device1" && !connections.get_connected(path)) {
             try {
                 BluezDeviceBus device = Bus.get_proxy_sync(BusType.SYSTEM, "org.bluez", path);
 
@@ -253,7 +421,7 @@ public class Application : Gtk.Applicati
             }
         }
 
-        if (!profile.has_any_device_connected()) {
+        if (!connections.is_connected()) {
             // try to connect to the paired device every few seconds
             connect_devices_id = Timeout.add_seconds(5, on_try_to_connect_devices);
         }
@@ -266,6 +434,66 @@ public class Application : Gtk.Applicati
         return false;
     }
 
+    public void on_open_notifications_view_activate(GLib.SimpleAction action, GLib.Variant? parameter) {
+        string id, package_name;
+        parameter.get("(ss)", out id, out package_name);
+
+        Notification? notification = null;
+        notification = get_notification(id, package_name);
+        if (notification == null) {
+            return;
+        }
+
+        /* FIXME: just temporary until we add actions to the main UI */
+        if (notification.actions != null) {
+            var view = new TestView(notification);
+            view.show_all();
+            return;
+        }
+
+        /* FIXME for now just raise the main window */
+        activate();
+    }
+
+    private void on_about_activate() {
+        const string copyright = "Copyright \xc2\xa9 2015 Holy Lobster Team";
+
+        const string authors[] = {
+            "Andrea Curtoni <andrea.curtoni@gmail.com>",
+            "Ignacio Casal Quinteiro <icq@gnome.org>",
+            "Paolo Borelli <pborelli@gnome.org>",
+            null
+        };
+
+        Gtk.show_about_dialog(window,
+                              "program-name", _("Nuntius"),
+                              "logo-icon-name", "nuntius",
+                              "version", Config.VERSION,
+                              "comments", _("Deliver notifications from your phone or tablet to your computer over Bluetooth."),
+                              "copyright", copyright,
+                              "authors", authors,
+                              "license-type", Gtk.License.GPL_2_0,
+                              "wrap-license", false,
+                              "translator-credits", _("translator-credits"),
+                              null);
+    }
+
+    private void on_show_qrcode_activate() {
+        show_qrcode();
+    }
+
+    public Notification? get_notification(string id, string package_name) {
+        foreach (var napp in notification_apps) {
+            if (napp.id == package_name) {
+                var notification = napp.get_notification(id);
+                if (notification != null) {
+                    return notification;
+                }
+            }
+        }
+        return null;
+    }
+
     public void add_notification(Notification notification) {
         bool found = false;
 
@@ -278,7 +506,7 @@ public class Application : Gtk.Applicati
         }
 
         if (!found) {
-            var napp = new NotificationApp(notification.package_name);
+            var napp = new NotificationApp(notification.package_name, notification.connection);
             napp.add_notification(notification);
             _notification_apps.prepend(napp);
 
@@ -292,18 +520,45 @@ public class Application : Gtk.Applicati
     public void mark_notification_read(string id, string package_name) {
         Notification? notification = null;
 
-        foreach (var napp in _notification_apps) {
+        notification = get_notification(id, package_name);
+
+        if (notification != null) {
+            withdraw_notification(notification.id);
+            notification.read = true;
+        }
+    }
+
+    public void blacklist_application(string package_name) {
+        foreach (var napp in notification_apps) {
             if (napp.id == package_name) {
-                notification = napp.get_notification(id);
-                break;
+                napp.blacklist();
             }
         }
+    }
 
-        if (notification != null) {
-            withdraw_notification(notification.id);
+    public SmsNotification? get_sms_notification(string id) {
+        foreach (var sms_notification in sms_notifications) {
+            if (sms_notification.id == id) {
+                return sms_notification;
+            }
+        }
+        return null;
+    }
+
+    public void add_sms_notification(SmsNotification sms_notification) {
+        sms_notifications.prepend(sms_notification);
+        send_notification(sms_notification.id, sms_notification.to_gnotification());
+    }
+
+    public void on_send_sms_activate(GLib.SimpleAction action, GLib.Variant? parameter) {
+        string id, text;
+        parameter.get("(ss)", out id, out text);
+
+        if (id != null && text != null) {
+            var sms_notification = get_sms_notification(id);
 
-            if (!notification.read) {
-                notification.read = true;
+            if (sms_notification != null) {
+                sms_notification.send_sms_message(text);
             }
         }
     }
--- nuntius-linux-0.2.0.orig/src/appslist.vala
+++ nuntius-linux-0.2.0/src/appslist.vala
@@ -25,9 +25,8 @@ public class AppsList : Gtk.ListBox {
         [GtkChild]
         private Gtk.Label label;
         [GtkChild]
-        private Gtk.Frame notifications_unread_frame;
-        [GtkChild]
-        private Gtk.Label notifications_unread_label;
+        private NotificationCounter notification_counter;
+        private Gtk.Menu menu;
 
         private NotificationApp _notification_app;
 
@@ -40,9 +39,13 @@ public class AppsList : Gtk.ListBox {
             Object(notification_app: notification_app);
 
             image.set_from_gicon(notification_app.icon, Gtk.IconSize.BUTTON);
-            notifications_unread_label.set_label(notification_app.unread_notifications.to_string());
+            notification_app.bind_property("unread-notifications",
+                                           notification_counter,
+                                           "counter",
+                                           BindingFlags.SYNC_CREATE);
+
             if (notification_app.unread_notifications > 0) {
-                notifications_unread_frame.show();
+                notification_counter.show();
                 label.set_markup("<b>" + notification_app.app_name + "</b>");
             } else {
                 label.set_label(notification_app.app_name);
@@ -57,8 +60,7 @@ public class AppsList : Gtk.ListBox {
             });
 
             notification_app.notify["unread-notifications"].connect(() => {
-                notifications_unread_frame.set_visible(notification_app.unread_notifications > 0);
-                notifications_unread_label.set_label(notification_app.unread_notifications.to_string());
+                notification_counter.set_visible(notification_app.unread_notifications > 0);
 
                 if (notification_app.unread_notifications > 0) {
                     label.set_markup("<b>" + notification_app.app_name + "</b>");
@@ -67,6 +69,17 @@ public class AppsList : Gtk.ListBox {
                 }
             });
         }
+
+        public void show_popup_menu(Gdk.EventButton event) {
+            menu = new Gtk.Menu();
+            var item = new Gtk.MenuItem.with_label (_("Blacklist this application"));
+            item.activate.connect(() => {
+                notification_app.blacklist();
+            });
+            menu.append(item);
+            menu.show_all();
+            menu.popup(null, null, null, event.button, event.get_time());
+        }
     }
 
     private string? filter_text;
@@ -89,6 +102,24 @@ public class AppsList : Gtk.ListBox {
             var row = new AppRow(napp);
             add(row);
         });
+
+        button_press_event.connect((event) => {
+            if (event.type == Gdk.EventType.BUTTON_PRESS &&
+                event.button == Gdk.BUTTON_SECONDARY) {
+                print("button press right click\n");
+                unselect_all();
+
+                var row = get_row_at_y((int) event.y) as AppRow;
+                if (row != null) {
+                    select_row(get_row_at_y((int) event.y));
+                    row.show_popup_menu(event);
+                }
+
+                return true;
+            }
+
+            return false;
+        });
     }
 
     private void update_header(Gtk.ListBoxRow row, Gtk.ListBoxRow? before) {
--- nuntius-linux-0.2.0.orig/src/config.vapi
+++ nuntius-linux-0.2.0/src/config.vapi
@@ -4,5 +4,6 @@ namespace Config {
     public const string DATADIR;
     public const string GETTEXT_PACKAGE;
     public const string GNOMELOCALEDIR;
+    public const string TOOLSDIR;
 }
 
--- nuntius-linux-0.2.0.orig/src/connection.vala
+++ nuntius-linux-0.2.0/src/connection.vala
@@ -17,40 +17,48 @@
 
 namespace Nuntius {
 
-public class DeviceConnection : Object {
-    Cancellable cancellable;
-    Socket socket;
-    SocketConnection? connection;
-    DataInputStream? input;
-    bool _connected;
-    ObjectPath _device;
+public class Connection : Object {
+    private Cancellable cancellable;
+    private SocketConnection? _connection;
+    private DataInputStream? input;
+    private DataOutputStream? output;
+    private bool _connected;
+    private string _server_name;
 
     public bool connected {
         get { return _connected; }
         set { _connected = value; }
     }
 
-    public ObjectPath device {
-        get { return _device; }
+    public string server_name {
+        get { return _server_name; }
+        set construct { _server_name = value; }
+    }
+
+    public SocketConnection? connection {
+        get { return _connection; }
+        set construct { _connection = value; }
     }
 
     public signal void notification_posted(Notification notification);
 
+    public signal void sms_received(SmsNotification notification);
+
     public signal void notification_removed(string id, string package_name);
 
-    public DeviceConnection(ObjectPath device, Socket socket) {
-        cancellable = new Cancellable();
-        this.socket = socket;
-        _connected = true;
-        _device = device;
+    public Connection(string server_name, SocketConnection connection) {
+        Object(connected: true, server_name: server_name, connection: connection);
 
-        connection = SocketConnection.factory_create_connection(socket);
-        input = new DataInputStream(connection.get_input_stream());
+        input = new DataInputStream(_connection.get_input_stream());
         input.set_newline_type(DataStreamNewlineType.CR_LF);
-
+        output = new DataOutputStream(_connection.get_output_stream());
         read_message();
     }
 
+    construct {
+        cancellable = new Cancellable();
+    }
+
     protected override void dispose() {
         if (cancellable != null) {
             cancellable.cancel();
@@ -63,6 +71,15 @@ public class DeviceConnection : Object {
         base.dispose();
     }
 
+    public void send_message(string msg) {
+        try {
+            output.put_string(msg + "\n");
+        } catch (Error e) {
+            print("Couldn't send message to " + _server_name);
+        }
+        print(msg);
+    }
+
     void read_message() {
         input.read_line_async.begin(Priority.DEFAULT, cancellable, (obj, res) => {
             try {
@@ -94,6 +111,7 @@ public class DeviceConnection : Object {
                 case "notificationPosted":
                     foreach (var i in eventItems) {
                         Notification? notification = null;
+                        string? key = null;
 
                         var object = i.get_object();
                         var id = object.get_int_member("id").to_string();
@@ -105,16 +123,36 @@ public class DeviceConnection : Object {
                             icon = new BytesIcon(new Bytes(Base64.decode(object.get_string_member("icon"))));
                         }
 
+                        if (object.has_member("key")) {
+                            key = object.get_string_member("key");
+                        }
+
                         var notification_object = object.get_object_member("notification");
                         if (notification_object.has_member("title")) {
                             var title = notification_object.get_string_member("title");
                             string? text = null;
+                            string? flags = null;
+                            string[]? actions_string = null;
+
+                            if (notification_object.has_member("flags")) {
+                                flags = notification_object.get_string_member("flags");
+                            }
 
                             if (notification_object.has_member("text")) {
                                 text = notification_object.get_string_member("text");
                             }
 
-                            notification = new Notification(id, package_name, app_name, title, text, icon);
+                            if (notification_object.has_member("actions")) {
+                                var actions = notification_object.get_array_member("actions").get_elements();
+                                var number_of_actions = notification_object.get_array_member("actions").get_length();
+                                actions_string = new string[number_of_actions];
+                                var count = 0;
+                                foreach (var action in actions) {
+                                    actions_string[count] = action.get_object().get_string_member("title");
+                                    count++;
+                                }
+                            }
+                            notification = new Notification(this, id, package_name, app_name, title, flags, key, text, icon, actions_string);
 
                             notification_posted(notification);
                         }
@@ -125,12 +163,43 @@ public class DeviceConnection : Object {
                         var object = i.get_object();
                         var id = object.get_int_member("id").to_string();
                         var package_name = object.get_string_member("packageName");
-
                         notification_removed(id, package_name);
                     }
                     break;
                 case "listNotifications":
                     break;
+                case "sms":
+                    foreach (var i in eventItems) {
+                        var object = i.get_object();
+                        string? id = null;
+                        string? sender = null;
+                        string? sender_num = null;
+                        string? msg = null;
+                        BytesIcon? icon = null;
+
+                        if (object.has_member("id")) {
+                            id = object.get_string_member("id");
+                        }
+
+                        if (object.has_member("sender")) {
+                            sender = object.get_string_member("sender");
+                        }
+
+                        if (object.has_member("sender_num")) {
+                            sender_num = object.get_string_member("sender_num");
+                        }
+
+                        if (object.has_member("message")) {
+                            msg = object.get_string_member("message");
+                        }
+
+                        if (object.has_member("icon")) {
+                            icon = new BytesIcon(new Bytes(Base64.decode(object.get_string_member("icon"))));
+                        }
+                        SmsNotification notification = new SmsNotification(this, id, sender, sender_num, msg, icon);
+                        sms_received(notification);
+                    }
+                    break;
                 default:
                     warning("Unknown event: %s", event);
                     break;
--- nuntius-linux-0.2.0.orig/src/notification.vala
+++ nuntius-linux-0.2.0/src/notification.vala
@@ -18,52 +18,85 @@
 namespace Nuntius {
 
 public class Notification : Object {
-    private string _id;
-    private string _package_name;
-    private string _app_name;
-    private string _title;
-    private string _body;
-    private BytesIcon _icon;
-    private bool _read;
-
-    public string id {
-        get { return _id; }
-        set construct { _id = value; }
-    }
-
-    public string package_name {
-        get { return _package_name; }
-        set construct { _package_name = value; }
-    }
+    public string id { get; construct set; }
+    public string package_name { get; construct set; }
+    public string app_name { get; construct set; }
+    public string title { get; construct set; }
+    public string body { get; construct set; }
+    public string? flag { get; construct set; }
+    public string? key { get; construct set; }
+    public BytesIcon icon { get; construct set; }
+    public string[]? actions { get; construct set; }
+    public Connection connection { get; construct set; }
 
-    public string app_name {
-        get { return _app_name; }
-        set construct { _app_name = value; }
-    }
-
-    public string title {
-        get { return _title; }
-        set construct { _title = value; }
-    }
-
-    public string body {
-        get { return _body; }
-        set construct { _body = value; }
-    }
-
-    public BytesIcon icon {
-        get { return _icon; }
-        set construct { _icon = value; }
-    }
+    private bool _read;
 
+    [CCode (notify = false)]
     public bool read {
         get { return _read; }
-        set { _read = value; }
+        set {
+            if (_read != value) {
+                _read = value;
+                notify_property("read");
+            }
+        }
         default = false;
     }
 
-    public Notification(string id, string package_name, string app_name, string title, string? body, BytesIcon? icon) {
-        Object(id: id, package_name: package_name, app_name: app_name, title: title, body: body, icon: icon);
+    public Notification(Connection connection, string id, string package_name, string app_name, string title, string? flag, string? key, string? body, BytesIcon? icon, string[]? actions) {
+        Object(connection: connection, id: id, package_name: package_name, app_name: app_name, title: title, flag: flag, key: key, body: body, icon: icon, actions: actions);
+    }
+
+    public void send_dismiss_message() {
+        Json.Builder builder = new Json.Builder();
+        builder.begin_object();
+        builder.set_member_name("event");
+        builder.add_string_value("dismiss");
+        builder.set_member_name("notification");
+        builder.begin_object();
+
+        if (key != null){
+            builder.set_member_name("key");
+            builder.add_string_value(_key);
+        } else {
+            builder.set_member_name("packageName");
+            builder.add_string_value(_package_name);
+            builder.set_member_name("flag");
+            builder.add_string_value(_flag);
+            builder.set_member_name("id");
+            builder.add_string_value(_id);
+        }
+        builder.end_object();
+        builder.end_object();
+
+        Json.Generator generator = new Json.Generator();
+        Json.Node root = builder.get_root();
+        generator.set_root(root);
+        string dismiss_message = generator.to_data(null);
+        connection.send_message(dismiss_message);
+    }
+
+    public void send_action_message(string s) {
+        Json.Builder builder = new Json.Builder();
+        builder.begin_object();
+        builder.set_member_name("event");
+        builder.add_string_value("action");
+        builder.set_member_name("action");
+        builder.begin_object();
+
+        builder.set_member_name("key");
+        builder.add_string_value(_key);
+        builder.set_member_name("actionName");
+        builder.add_string_value(s);
+
+        builder.end_object();
+        builder.end_object();
+
+        Json.Generator generator = new Json.Generator();
+        Json.Node root = builder.get_root();
+        generator.set_root(root);
+        string action_message = generator.to_data(null);
+        connection.send_message(action_message);
     }
 
     public GLib.Notification to_gnotification() {
@@ -77,6 +110,9 @@ public class Notification : Object {
             notification.set_icon(icon);
         }
 
+        var variant = new Variant("(ss)", id, package_name);
+        notification.set_default_action_and_target_value("app.open-notifications-view", variant);
+
         return notification;
     }
 }
--- nuntius-linux-0.2.0.orig/src/notificationapp.vala
+++ nuntius-linux-0.2.0/src/notificationapp.vala
@@ -18,16 +18,12 @@
 namespace Nuntius {
 
 public class NotificationApp : Object {
-    private string _id;
+    public string id { get; construct set; }
+    public Connection connection { get; construct set; }
     private string _app_name;
     private BytesIcon _icon;
     private uint _unread_notifications;
-    List<Notification> _notifications;
-
-    public string id {
-        get { return _id; }
-        set construct { _id = value; }
-    }
+    private List<Notification> _notifications;
 
     public string app_name {
         get { return _app_name; }
@@ -45,8 +41,8 @@ public class NotificationApp : Object {
         get { return _notifications; }
     }
 
-    public NotificationApp(string id) {
-        Object(id: id);
+    public NotificationApp(string id, Connection connection) {
+        Object(id: id, connection: connection);
     }
 
     construct {
@@ -95,6 +91,28 @@ public class NotificationApp : Object {
 
         return n;
     }
+
+    public void blacklist() {
+        Json.Builder builder = new Json.Builder();
+        builder.begin_object();
+        builder.set_member_name("event");
+        builder.add_string_value("blacklist");
+        builder.set_member_name("app");
+        builder.begin_object();
+
+        builder.set_member_name("packageName");
+        builder.add_string_value(id);
+
+        builder.end_object();
+        builder.end_object();
+
+        Json.Generator generator = new Json.Generator();
+        Json.Node root = builder.get_root();
+        generator.set_root(root);
+
+        string blacklist_message = generator.to_data(null);
+        connection.send_message(blacklist_message);
+    }
 }
 
 } // namespace Nuntius
--- /dev/null
+++ nuntius-linux-0.2.0/src/notificationcounter.vala
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 - Holy Lobster
+ *
+ * Nuntius is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Nuntius is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Nuntius. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Nuntius {
+
+[GtkTemplate (ui = "/org/holylobster/nuntius/ui/notificationcounter.ui")]
+public class NotificationCounter : Gtk.Frame {
+    private uint _counter;
+
+    [GtkChild]
+    private Gtk.Label label_counter;
+
+    public uint counter {
+        get { return _counter; }
+        set {
+            _counter = value;
+            label_counter.set_label(_counter.to_string());
+        }
+    }
+}
+
+} // namespace Nuntius
+
+/* ex:set ts=4 et: */
--- nuntius-linux-0.2.0.orig/src/notificationsview.vala
+++ nuntius-linux-0.2.0/src/notificationsview.vala
@@ -132,12 +132,21 @@ public class NotificationsView : Gtk.Tex
             buf.insert(ref it, "\n\n", -1);
         }
 
+#if VALA_0_28
         buf.insert_with_tags(ref it, notification.title, -1, notification_tag, title_tag, null);
 
         if (notification.body != null) {
             buf.insert_with_tags(ref it, "\n\n", -1, notification_tag, null);
             buf.insert_with_tags(ref it, notification.body, -1, notification_tag, null);
         }
+#else
+        buf.insert_with_tags(it, notification.title, -1, notification_tag, title_tag, null);
+
+        if (notification.body != null) {
+            buf.insert_with_tags(it, "\n\n", -1, notification_tag, null);
+            buf.insert_with_tags(it, notification.body, -1, notification_tag, null);
+        }
+#endif
 
         buf.insert(ref it, "\n\n\n", -1);
 
--- /dev/null
+++ nuntius-linux-0.2.0/src/qrencode.vapi
@@ -0,0 +1,45 @@
+
+/*
+ * Minimal VAPI file for LIBQRENCODE Barcode library.
+ */
+namespace Qrencode {
+
+    [CCode (cheader_filename = "qrencode.h", cname = "QRcode", unref_function = "QRcode_free")]
+    public class QRcode {
+        [CCode (cname = "QRcode_encodeString")]
+        public QRcode.encodeString(string digits, int version, EcLevel level, Mode hint, int casesensitive);
+
+        public int version;
+        public int width;
+        [CCode (array_length = false)]
+        public uint8[] data;
+    }
+
+    [CCode (cheader_filename = "qrencode.h", cname="QRencLevel")]
+    public enum EcLevel {
+        [CCode (cname="QR_ECLEVEL_L")]
+        L,
+        [CCode (cname="QR_ECLEVEL_M")]
+        M,
+        [CCode (cname="QR_ECLEVEL_Q")]
+        Q,
+        [CCode (cname="QR_ECLEVEL_H")]
+        H
+    }
+
+    [CCode (cheader_filename = "qrencode.h", cname="QRencodeMode")]
+    public enum Mode {
+        [CCode (cname="QR_MODE_NUL")]
+        NUL,
+        [CCode (cname="QR_MODE_NUM")]
+        NUM,
+        [CCode (cname="QR_MODE_AN")]
+        AN,
+        [CCode (cname="QR_MODE_8")]
+        B8,
+        [CCode (cname="QR_MODE_KANJI")]
+        KANJI,
+        [CCode (cname="QR_MODE_STRUCTURE")]
+        STRUCTURE
+    }
+}
--- /dev/null
+++ nuntius-linux-0.2.0/src/qrimage.vala
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 - Holy Lobster
+ *
+ * Nuntius is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Nuntius is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Nuntius. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Nuntius {
+
+public class QRImage : Gtk.DrawingArea {
+    private string _text;
+    private Qrencode.QRcode? qrcode;
+    private const double MIN_SQUARE_SIZE = 1.0;
+
+    [CCode (notify = false)]
+    public string text {
+        get { return _text; }
+        set {
+            if (_text != value) {
+                _text = value;
+                qrcode = new Qrencode.QRcode.encodeString(_text, 0,
+                                                          Qrencode.EcLevel.M,
+                                                          Qrencode.Mode.B8, 1);
+                notify_property("text");
+
+                queue_draw();
+            }
+        }
+    }
+
+    protected override bool draw(Cairo.Context cr) {
+        if (qrcode != null) {
+            uint width, height;
+
+            width = get_allocated_width();
+            height = get_allocated_height();
+
+            /* make it square */
+            if (height < width) {
+                width = height;
+            }
+
+            double square_size = width / qrcode.width;
+            if (square_size < MIN_SQUARE_SIZE) {
+                square_size = MIN_SQUARE_SIZE;
+            }
+
+            cr.save();
+
+            cr.set_source_rgb(0, 0, 0);
+
+            for (int iy = 0; iy < qrcode.width; iy++) {
+                for (int ix = 0; ix < qrcode.width; ix++) {
+                    /* Symbol data is represented as an array contains
+                     * width*width uchars. Each uchar represents a module
+                     * (dot). If the less significant bit of the uchar
+                     * is 1, the corresponding module is black. The other
+                     * bits are meaningless for us.
+                     */
+                    if ((qrcode.data[iy * qrcode.width + ix] & 1) != 0) {
+                        cr.rectangle(ix * square_size, iy * square_size, square_size, square_size);
+                        cr.fill();
+                    }
+                }
+            }
+
+            cr.restore();
+        }
+
+        return false;
+    }
+}
+
+} // namespace Nuntius
+
+/* ex:set ts=4 et: */
--- nuntius-linux-0.2.0.orig/src/resources/css/nuntius-style.css
+++ nuntius-linux-0.2.0/src/resources/css/nuntius-style.css
@@ -39,7 +39,7 @@ NuntiusAppsListPanel.frame:dir(rtl) {
   background-color: transparent;
 }
 
-.nuntius-notifications-unread {
+NuntiusNotificationCounter {
   border-style: none;
   border-radius: 10px;
   background-color: darker(@theme_selected_bg_color);
--- /dev/null
+++ nuntius-linux-0.2.0/src/resources/gtk/menus.ui
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <menu id="app-menu">
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Show _QR Code</attribute>
+        <attribute name="action">app.show-qrcode</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_About</attribute>
+        <attribute name="action">app.about</attribute>
+      </item>
+    </section>
+  </menu>
+</interface>
--- nuntius-linux-0.2.0.orig/src/resources/nuntius.gresource.xml
+++ nuntius-linux-0.2.0/src/resources/nuntius.gresource.xml
@@ -4,6 +4,8 @@
     <file preprocess="xml-stripblanks">ui/window.ui</file>
     <file preprocess="xml-stripblanks">ui/appslistpanel.ui</file>
     <file preprocess="xml-stripblanks">ui/approw.ui</file>
+    <file preprocess="xml-stripblanks">ui/notificationcounter.ui</file>
+    <file preprocess="xml-stripblanks">gtk/menus.ui</file>
     <file>css/nuntius-style.css</file>
   </gresource>
 </gresources>
--- nuntius-linux-0.2.0.orig/src/resources/ui/approw.ui
+++ nuntius-linux-0.2.0/src/resources/ui/approw.ui
@@ -38,24 +38,11 @@
           </packing>
         </child>
         <child>
-          <object class="GtkFrame" id="notifications_unread_frame">
+          <object class="NuntiusNotificationCounter" id="notification_counter">
             <property name="visible">False</property>
             <property name="can_focus">False</property>
             <property name="halign">end</property>
             <property name="valign">center</property>
-            <style>
-              <class name="nuntius-notifications-unread"/>
-            </style>
-            <child>
-              <object class="GtkLabel" id="notifications_unread_label">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="halign">start</property>
-                <property name="valign">center</property>
-                <property name="ellipsize">end</property>
-                <property name="label">50</property>
-              </object>
-            </child>
           </object>
           <packing>
             <property name="left_attach">2</property>
--- /dev/null
+++ nuntius-linux-0.2.0/src/resources/ui/notificationcounter.ui
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.1 -->
+<interface>
+  <template class="NuntiusNotificationCounter" parent="GtkFrame">
+    <property name="can_focus">False</property>
+    <property name="shadow_type">none</property>
+    <child>
+      <object class="GtkLabel" id="label_counter">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="halign">center</property>
+        <property name="valign">center</property>
+        <property name="ellipsize">end</property>
+      </object>
+    </child>
+  </template>
+</interface>
--- /dev/null
+++ nuntius-linux-0.2.0/src/smsnotification.vala
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 - Holy Lobster
+ *
+ * Nuntius is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Nuntius is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Nuntius. If not, see <http://www.gnu.org/licenses/>.
+ */
+namespace Nuntius {
+
+public class SmsNotification : Object {
+    public string id { get; construct set; }
+    public string sender { get; construct set; }
+    public string sender_num { get; construct set; }
+    public string message { get; construct set; }
+    public BytesIcon icon { get; construct set; }
+    public Connection connection { get; construct set; }
+
+    public SmsNotification(Connection connection, string id, string sender, string sender_num, string message, BytesIcon icon) {
+        Object(connection: connection, id: id, sender: sender, sender_num: sender_num, message: message, icon: icon);
+    }
+
+    public void send_sms_message(string message) {
+        Json.Builder builder = new Json.Builder();
+        builder.begin_object();
+        builder.set_member_name("event");
+        builder.add_string_value("sms");
+        builder.set_member_name("sms");
+        builder.begin_object();
+
+        builder.set_member_name("senderNum");
+        builder.add_string_value(_sender_num);
+
+        builder.set_member_name("msg");
+        builder.add_string_value(message);
+
+        builder.end_object();
+        builder.end_object();
+
+        Json.Generator generator = new Json.Generator();
+        Json.Node root = builder.get_root();
+        generator.set_root(root);
+        string sms_message = generator.to_data(null);
+        connection.send_message(sms_message);
+    }
+
+    public GLib.Notification to_gnotification() {
+        GLib.Notification notification = new GLib.Notification(sender);
+
+        notification.set_body(message);
+        notification.set_icon(icon);
+
+        // FIXME: just a test message until we have UI to type the reply
+        var variant = new Variant("(ss)", id, "Sent by Nuntius");
+        notification.add_button_with_target_value(_("Reply"),"app.send-sms", variant);
+
+        return notification;
+    }
+}
+
+}
--- /dev/null
+++ nuntius-linux-0.2.0/src/testview.vala
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015 - Holy Lobster
+ *
+ * Nuntius is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Nuntius is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Nuntius. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Nuntius {
+
+/* Just a temporary UI to send actions, this should go in the main UI */
+public class TestView : Gtk.Window {
+
+    Notification notification;
+
+    public TestView(Notification notification) {
+        this.notification = notification;
+
+        // Sets the title of the Window:
+        this.title = notification.title;
+
+        // Center window at startup:
+        this.window_position = Gtk.WindowPosition.CENTER;
+
+        // Sets the default size of a window:
+        this.set_default_size(500,150);
+
+        // Whether the titlebar should be hidden during maximization.
+        this.hide_titlebar_when_maximized = false;
+
+        // Method called on pressing [X]
+        this.destroy.connect(() => {
+            stdout.printf("Bye!\n");
+        });
+
+        Gtk.Box vertical_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
+        vertical_box.set_margin_left(20);
+        vertical_box.set_margin_right(20);
+        this.add(vertical_box);
+
+        Gtk.Box notification_area = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 10);
+        vertical_box.pack_start(notification_area);
+
+        Gtk.Image icon = new Gtk.Image();
+        icon.set_from_gicon(notification.icon, Gtk.IconSize.DIALOG);
+        notification_area.pack_start(icon);
+
+        var label = new Gtk.Label(notification.body);
+        notification_area.pack_start(label);
+
+        Gtk.Box button_area = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 10);
+        vertical_box.pack_start(button_area, false, false, 10);
+        var dismiss_button = new Gtk.Button.with_label("Dismiss");
+
+        dismiss_button.clicked.connect(() => {
+            notification.send_dismiss_message();
+        });
+
+        button_area.pack_start(dismiss_button);
+
+        if (notification.actions != null) {
+            var actions = notification.actions;
+            foreach(string s in actions) {
+                var action_button = new Gtk.Button.with_label(s);
+                button_area.pack_start(action_button);
+                action_button.clicked.connect(() => {
+                    notification.send_action_message(s);
+                });
+            }
+        }
+
+        var blacklist_button = new Gtk.Button.with_label("Blacklist this app");
+
+        blacklist_button.clicked.connect(() => {
+            var app = (Application) GLib.Application.get_default();
+            app.blacklist_application(notification.package_name);
+        });
+
+        button_area.pack_start(blacklist_button);
+    }
+}
+
+}
--- nuntius-linux-0.2.0.orig/src/window.vala
+++ nuntius-linux-0.2.0/src/window.vala
@@ -26,14 +26,50 @@ public class Window : Gtk.ApplicationWin
     [GtkChild]
     private Gtk.HeaderBar titlebar_right;
 
+    private GLib.Settings settings;
+
     public Window(Application app) {
         Object(application: app);
     }
 
     construct {
+        settings = new Settings("org.holylobster.nuntius.state.window");
+        settings.delay ();
+
+        destroy.connect(() => {
+            settings.apply();
+        });
+
+        // Setup window geometry saving
+        Gdk.WindowState window_state = (Gdk.WindowState)settings.get_int("state");
+        if (Gdk.WindowState.MAXIMIZED in window_state) {
+            maximize();
+        }
+
+        int width, height;
+        settings.get ("size", "(ii)", out width, out height);
+        resize(width, height);
+
         apps_list_panel.selection_changed.connect(on_selection_changed);
     }
 
+    protected override bool configure_event(Gdk.EventConfigure event) {
+        if (get_realized() && !(Gdk.WindowState.MAXIMIZED in get_window ().get_state())) {
+            settings.set("size", "(ii)", event.width, event.height);
+        }
+
+        return base.configure_event(event);
+    }
+
+    protected override bool window_state_event(Gdk.EventWindowState event) {
+        settings.set_int("state", event.new_window_state);
+        return base.window_state_event(event);
+    }
+
+    protected override bool delete_event(Gdk.EventAny event) {
+        return base.hide_on_delete();
+    }
+
     private void on_selection_changed(NotificationApp? notification_app) {
         if (notification_app == null) {
             titlebar_right.title = null;
--- /dev/null
+++ nuntius-linux-0.2.0/tests/qrtest.vala
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 - Holy Lobster
+ *
+ * Nuntius is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Nuntius is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Nuntius. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+public static int main(string[] args) {
+    Gtk.init(ref args);
+
+    var window = new Gtk.Window();
+    window.title = "QR Test";
+    window.border_width = 10;
+    window.set_default_size(350, 70);
+    window.destroy.connect(Gtk.main_quit);
+
+    var qr = new Nuntius.QRImage();
+    qr.text = "This is a test";
+
+    window.add(qr);
+    window.show_all();
+
+    Gtk.main();
+
+    return 0;
+}
+
+/* ex:set ts=4 et: */
