From fd6e173bcaf1e4e3753b3d9549888adde88e9a70 Mon Sep 17 00:00:00 2001
From: guinux <nuxgui@gmail.com>
Date: Fri, 24 Aug 2018 18:32:36 +0200
Subject: [PATCH] enhance modularity and add python bindings

---
 examples/{ => alpm}/pactree.vala             |    0
 examples/python/empty_transaction.py         |   53 +
 examples/python/list_installed_pkgs.py       |   15 +
 examples/python/list_installed_pkgs_async.py |   28 +
 resources/pamac.manager.gresource.xml        |    4 +
 resources/pamac.transaction.gresource.xml    |    4 -
 src/clean_cache.vala                         |    4 +-
 src/cli.vala                                 | 2456 +++++-------------
 src/common.vala                              |    1 -
 src/common_daemon.vala                       |   52 +
 src/database.vala                            |  555 ++++
 src/installer.vala                           |   90 +-
 src/manager.vala                             |    1 +
 src/manager_window.vala                      |  492 ++--
 src/meson.build                              |   51 +-
 src/pamac_config.vala                        |   37 +-
 src/preferences_dialog.vala                  |   52 +-
 src/system_daemon.vala                       |  106 +-
 src/transaction-cli.vala                     |  479 ++++
 src/transaction-gtk.vala                     |  480 ++++
 src/transaction.vala                         | 1555 +++--------
 src/tray.vala                                |    8 +-
 src/updates_priv.vala                        |   26 +
 src/user_daemon.vala                         |   58 +-
 src/version.vala                             |    2 +-
 25 files changed, 3139 insertions(+), 3470 deletions(-)
 rename examples/{ => alpm}/pactree.vala (100%)
 create mode 100755 examples/python/empty_transaction.py
 create mode 100755 examples/python/list_installed_pkgs.py
 create mode 100755 examples/python/list_installed_pkgs_async.py
 create mode 100644 src/common_daemon.vala
 create mode 100644 src/database.vala
 create mode 100644 src/transaction-cli.vala
 create mode 100644 src/transaction-gtk.vala
 create mode 100644 src/updates_priv.vala

diff --git a/examples/pactree.vala b/examples/alpm/pactree.vala
similarity index 100%
rename from examples/pactree.vala
rename to examples/alpm/pactree.vala
diff --git a/examples/python/empty_transaction.py b/examples/python/empty_transaction.py
new file mode 100755
index 00000000..b359f8fe
--- /dev/null
+++ b/examples/python/empty_transaction.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+
+import gi
+gi.require_version('Pamac', '1.0')
+from gi.repository import GLib, Pamac
+
+def on_emit_action (transaction, action, data):
+	print(action)
+
+def on_emit_action_progress (transaction, action, status, progress, data):
+	print("{} {}".format(action, status))
+
+def on_emit_warning (transaction, message, data):
+	print(message)
+
+def on_emit_error (transaction, message, details, details_length, data):
+	if details_length > 0:
+		print("{}:".format(message))
+		for detail in details:
+			print(detail)
+	else:
+		print(message)
+
+def start_transaction():
+	# /!\ the transaction will run without confirmation /!\
+	# you need to override Transaction.ask_confirmation() method
+	# in order to implement your own confirmation step
+	to_install = []
+	to_remove = []
+	to_load = []
+	to_build = []
+	overwrite_files = []
+	if transaction.get_lock():
+		transaction.start (to_install, to_remove, to_load, to_build, overwrite_files)
+		# launch a loop to wait for finished signal to be emitted
+		loop.run()
+
+def on_trans_finished (transaction, success, data):
+	transaction.unlock()
+	loop.quit()
+
+if __name__ == "__main__":
+	loop = GLib.MainLoop()
+	config = Pamac.Config(conf_path="/etc/pamac.conf")
+	db = Pamac.Database(config=config)
+	transaction = Pamac.Transaction(database=db)
+	data = None
+	transaction.connect ("emit-action", on_emit_action, data)
+	transaction.connect ("emit-action-progress", on_emit_action_progress, data)
+	transaction.connect ("emit-error", on_emit_error, data)
+	transaction.connect ("emit-warning", on_emit_warning, data)
+	transaction.connect ("finished", on_trans_finished, data)
+	start_transaction()
diff --git a/examples/python/list_installed_pkgs.py b/examples/python/list_installed_pkgs.py
new file mode 100755
index 00000000..a422b790
--- /dev/null
+++ b/examples/python/list_installed_pkgs.py
@@ -0,0 +1,15 @@
+#!/usr/bin/python
+
+import gi
+gi.require_version('Pamac', '1.0')
+from gi.repository import Pamac
+
+def list_installed_pkgs():
+	pkgs = db.get_installed_pkgs()
+	for pkg in pkgs:
+		print(pkg.name, pkg.version)
+
+if __name__ == "__main__":
+	config = Pamac.Config(conf_path="/etc/pamac.conf")
+	db = Pamac.Database(config=config)
+	list_installed_pkgs()
diff --git a/examples/python/list_installed_pkgs_async.py b/examples/python/list_installed_pkgs_async.py
new file mode 100755
index 00000000..ded6c960
--- /dev/null
+++ b/examples/python/list_installed_pkgs_async.py
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+
+import gi
+gi.require_version('Pamac', '1.0')
+from gi.repository import GLib, Pamac
+
+def on_installed_pkgs_ready_callback(source_object, result, user_data):
+	try:
+		pkgs = source_object.get_installed_pkgs_finish(result)
+	except GLib.GError as e:
+		print("Error: ", e.message)
+	else:
+		for pkg in pkgs:
+			print(pkg.name, pkg.version)
+	finally:
+		loop.quit()
+
+def list_installed_pkgs_async():
+	pkgs = db.get_installed_pkgs_async(on_installed_pkgs_ready_callback, None)
+	# launch a loop to wait for the callback to be called
+	loop.run()
+
+if __name__ == "__main__":
+	loop = GLib.MainLoop()
+	config = Pamac.Config(conf_path="/etc/pamac.conf")
+	db = Pamac.Database(config=config)
+	list_installed_pkgs_async()
+
diff --git a/resources/pamac.manager.gresource.xml b/resources/pamac.manager.gresource.xml
index b1b7a6b3..3e773005 100644
--- a/resources/pamac.manager.gresource.xml
+++ b/resources/pamac.manager.gresource.xml
@@ -13,4 +13,8 @@
     <file preprocess="to-pixdata">package-upgrade.png</file>
     <file preprocess="to-pixdata">package-generic.png</file>
   </gresource>
+  <gresource prefix="/org/manjaro/pamac/preferences">
+    <file preprocess="xml-stripblanks">preferences_dialog.ui</file>
+    <file preprocess="xml-stripblanks">choose_ignorepkgs_dialog.ui</file>
+  </gresource>
 </gresources>
diff --git a/resources/pamac.transaction.gresource.xml b/resources/pamac.transaction.gresource.xml
index 90c24d15..8963a0b2 100644
--- a/resources/pamac.transaction.gresource.xml
+++ b/resources/pamac.transaction.gresource.xml
@@ -6,8 +6,4 @@
     <file preprocess="xml-stripblanks">choose_provider_dialog.ui</file>
     <file preprocess="xml-stripblanks">transaction_sum_dialog.ui</file>
   </gresource>
-  <gresource prefix="/org/manjaro/pamac/preferences">
-    <file preprocess="xml-stripblanks">preferences_dialog.ui</file>
-    <file preprocess="xml-stripblanks">choose_ignorepkgs_dialog.ui</file>
-  </gresource>
 </gresources>
diff --git a/src/clean_cache.vala b/src/clean_cache.vala
index 060496b6..5bbc563c 100644
--- a/src/clean_cache.vala
+++ b/src/clean_cache.vala
@@ -20,11 +20,11 @@
 int main () {
 	var pamac_config = new Pamac.Config ("/etc/pamac.conf");
 	string rm_only_uninstalled_str = "";
-	if (pamac_config.rm_only_uninstalled) {
+	if (pamac_config.clean_rm_only_uninstalled) {
 		rm_only_uninstalled_str = "-u";
 	}
 	try {
-		Process.spawn_command_line_sync ("paccache -q --nocolor %s -r -k %llu".printf (rm_only_uninstalled_str, pamac_config.keep_num_pkgs));
+		Process.spawn_command_line_sync ("paccache -q --nocolor %s -r -k %llu".printf (rm_only_uninstalled_str, pamac_config.clean_keep_num_pkgs));
 	} catch (SpawnError e) {
 		stderr.printf ("SpawnError: %s\n", e.message);
 	}
diff --git a/src/cli.vala b/src/cli.vala
index 1c6c6a98..b1ea7758 100644
--- a/src/cli.vala
+++ b/src/cli.vala
@@ -18,136 +18,42 @@
  */
 
 namespace Pamac {
-	[DBus (name = "org.manjaro.pamac.user")]
-	interface UserDaemon : Object {
-		public abstract AlpmPackage get_installed_pkg (string pkgname) throws Error;
-		public abstract AlpmPackage[] get_installed_pkgs_sync () throws Error;
-		public abstract AlpmPackage[] get_foreign_pkgs_sync () throws Error;
-		public abstract AlpmPackage[] get_orphans_sync () throws Error;
-		public abstract AlpmPackage find_installed_satisfier (string depstring) throws Error;
-		public abstract AlpmPackage get_sync_pkg (string pkgname) throws Error;
-		public abstract AlpmPackage find_sync_satisfier (string depstring) throws Error;
-		public abstract AlpmPackage[] search_pkgs_sync (string search_string) throws Error;
-		public abstract async AURPackage[] search_in_aur (string search_string) throws Error;
-		public abstract string[] get_repos_names () throws Error;
-		public abstract AlpmPackage[] get_repo_pkgs_sync (string repo) throws Error;
-		public abstract string[] get_groups_names () throws Error;
-		public abstract AlpmPackage[] get_group_pkgs_sync (string groupname) throws Error;
-		public abstract AlpmPackageDetails get_pkg_details (string pkgname, string app_name) throws Error;
-		public abstract string[] get_pkg_files (string pkgname) throws Error;
-		public abstract HashTable<string,Variant> search_files (string[] files) throws Error;
-		public abstract async AURPackageDetails get_aur_details (string pkgname) throws Error;
-		public abstract void start_get_updates (bool check_aur_updates, bool refresh_files_dbs) throws Error;
-		[DBus (no_reply = true)]
-		public abstract void quit () throws Error;
-		public signal void get_updates_finished (Updates updates);
-	}
-	[DBus (name = "org.manjaro.pamac.system")]
-	interface SystemDaemon : Object {
-		public abstract void set_environment_variables (HashTable<string,string> variables) throws Error;
-		public abstract ErrorInfos get_current_error () throws Error;
-		public abstract bool get_lock () throws Error;
-		public abstract bool unlock () throws Error;
-		public abstract void start_get_authorization () throws Error;
-		public abstract void clean_cache (uint64 keep_nb, bool only_uninstalled) throws Error;
-		public abstract void start_set_pkgreason (string pkgname, uint reason) throws Error;
-		public abstract void start_refresh (bool force) throws Error;
-		public abstract void start_sysupgrade_prepare (bool enable_downgrade, string[] temporary_ignorepkgs, string[] to_build, string[] overwrite_files) throws Error;
-		public abstract void start_trans_prepare (int transflags, string[] to_install, string[] to_remove, string[] to_load, string[] to_build, string[] overwrite_files) throws Error;
-		public abstract void choose_provider (int provider) throws Error;
-		public abstract TransactionSummary get_transaction_summary () throws Error;
-		public abstract void start_trans_commit () throws Error;
-		public abstract void trans_release () throws Error;
-		public abstract void trans_cancel () throws Error;
-		public abstract void start_get_updates (bool check_aur_updates) throws Error;
-		[DBus (no_reply = true)]
-		public abstract void quit () throws Error;
-		public signal void get_updates_finished (Updates updates);
-		public signal void emit_event (uint primary_event, uint secondary_event, string[] details);
-		public signal void emit_providers (string depend, string[] providers);
-		public signal void emit_progress (uint progress, string pkgname, uint percent, uint n_targets, uint current_target);
-		public signal void emit_download (string filename, uint64 xfered, uint64 total);
-		public signal void emit_totaldownload (uint64 total);
-		public signal void emit_log (uint level, string msg);
-		public signal void set_pkgreason_finished ();
-		public signal void refresh_finished (bool success);
-		public signal void trans_prepare_finished (bool success);
-		public signal void trans_commit_finished (bool success);
-		public signal void get_authorization_finished (bool authorized);
-	}
-
 	class Cli: GLib.Application {
-		enum TransType {
-			STANDARD = (1 << 0),
-			UPDATE = (1 << 1),
-			BUILD = (1 << 2)
-		}
 		public ApplicationCommandLine cmd;
-		UserDaemon user_daemon;
-		SystemDaemon system_daemon;
-		Pamac.Config pamac_config;
-		int transflags;
+		public TransactionCli transaction;
+		public Database database;
+		delegate void TransactionAction ();
 		string[] to_install;
 		string[] to_remove;
 		string[] to_load;
 		string[] to_build;
-		uint64 total_download;
-		uint64 already_downloaded;
-		string previous_textbar;
-		float previous_percent;
-		string previous_filename;
-		string current_action;
-		string previous_action;
-		bool enable_aur;
 		bool force_refresh;
 		bool enable_downgrade;
-		bool sysupgrade_after_trans;
-		bool no_confirm_commit;
-		bool building;
-		bool asking_user_input;
-		uint64 previous_xfered;
-		uint64 download_rate;
-		uint64 rates_nb;
-		Timer timer;
-		string aur_build_dir;
 		string[] temporary_ignorepkgs;
 		string[] overwrite_files;
-		Queue<string> to_build_queue;
-		string[] aur_pkgs_to_install;
-		string[] to_install_first;
-		Cancellable build_cancellable;
 		Subprocess pkttyagent;
 
 		public Cli () {
 			application_id = "org.manjaro.pamac.cli";
 			flags = ApplicationFlags.HANDLES_COMMAND_LINE;
-			pamac_config = new Pamac.Config ("/etc/pamac.conf");
-			transflags = 0;
 			to_install = {};
 			to_remove = {};
 			to_load = {};
 			to_build = {};
-			// progress data
-			previous_textbar = "";
-			previous_filename = "";
-			previous_action = "";
-			enable_aur = false;
 			force_refresh = false;
 			enable_downgrade = false;
-			sysupgrade_after_trans = false;
-			no_confirm_commit = false;
-			building = false;
-			asking_user_input = false;
-			timer = new Timer ();
-			aur_build_dir = pamac_config.aur_build_dir;
-			temporary_ignorepkgs = {};
 			overwrite_files = {};
-			to_build_queue = new Queue<string> ();
-			build_cancellable = new Cancellable ();
+			var config = new Config ("/etc/pamac.conf");
+			database = new Database (config);
+			transaction = new TransactionCli (database);
+			transaction.finished.connect (on_transaction_finished);
+			transaction.sysupgrade_finished.connect (on_transaction_finished);
+			transaction.refresh_finished.connect (on_refresh_finished);
+			// Use tty polkit authentication agent
 			try {
-				user_daemon = Bus.get_proxy_sync (BusType.SESSION, "org.manjaro.pamac.user", "/org/manjaro/pamac/user");
+				pkttyagent = new Subprocess.newv ({"pkttyagent"}, SubprocessFlags.NONE);
 			} catch (Error e) {
-				print_error (e.message);
+				stdout.printf ("%s: %s\n", dgettext (null, "Error"), e.message);
 			}
 			// watch CTRl + C
 			Unix.signal_add (Posix.Signal.INT, trans_cancel);
@@ -273,7 +179,7 @@ namespace Pamac {
 					if (args[2] == "--help" || args[2] == "-h") {
 						display_build_help ();
 					} else if (args[2] == "--builddir") {
-						aur_build_dir = args[3];
+						transaction.database.config.aur_build_dir = args[3];
 						build_pkgs (args[4:args.length]);
 					} else {
 						build_pkgs (args[2:args.length]);
@@ -338,7 +244,8 @@ namespace Pamac {
 					if (args[2] == "--help" || args[2] == "-h") {
 						display_checkupdates_help ();
 					} else if (args[2] == "--aur" || args[2] == "-a") {
-						enable_aur = true;
+						transaction.database.config.enable_aur = true;
+						transaction.database.config.check_aur_updates = true;
 						checkupdates ();
 					} else {
 						display_checkupdates_help ();
@@ -356,9 +263,10 @@ namespace Pamac {
 						error = true;
 						break;
 					} else if (arg == "--aur"|| arg == "-a") {
-						enable_aur = true;
+						transaction.database.config.enable_aur = true;
+						transaction.database.config.check_aur_updates = true;
 					} else if (arg == "--builddir") {
-						aur_build_dir = args[i+1];
+						transaction.database.config.aur_build_dir = args[i+1];
 						i++;
 					} else if (arg == "--force-refresh") {
 						force_refresh = true;
@@ -382,7 +290,7 @@ namespace Pamac {
 					i++;
 				}
 				if (!error) {
-					start_refresh ();
+					try_lock_and_run (start_refresh);
 				}
 			} else {
 				display_help ();
@@ -392,70 +300,23 @@ namespace Pamac {
 
 		public override void shutdown () {
 			base.shutdown ();
-			try {
-				user_daemon.quit ();
-				if (system_daemon != null) {
-					system_daemon.quit ();
-					pkttyagent.force_exit ();
-				}
-			} catch (Error e) {
-				print_error (e.message);
-			}
+			database.stop_daemon ();
+			transaction.stop_daemon ();
+			pkttyagent.force_exit ();
 		}
 
 		bool trans_cancel () {
-			if (building) {
-				build_cancellable.cancel ();
-			} else if (asking_user_input) {
-				try {
-					system_daemon.trans_release ();
-				} catch (Error e) {
-					print_error (e.message);
-				}
+			if (transaction.asking_user_input) {
+				transaction.release ();
 			} else {
-				try {
-					system_daemon.trans_cancel ();
-				} catch (Error e) {
-					print_error (e.message);
-				}
+				transaction.cancel ();
 			}
-			stdout.printf ("\n%s.\n", dgettext (null, "Transaction cancelled"));
+			stdout.printf ("\n");
 			this.release ();
 			cmd.set_exit_status (1);
 			return false;
 		}
 
-		void connecting_system_daemon () {
-			if (system_daemon == null) {
-				try {
-					system_daemon = Bus.get_proxy_sync (BusType.SYSTEM, "org.manjaro.pamac.system", "/org/manjaro/pamac/system");
-					// Set environment variables
-					system_daemon.set_environment_variables (pamac_config.environment_variables);
-					system_daemon.emit_event.connect (on_emit_event);
-					system_daemon.emit_providers.connect (on_emit_providers);
-					system_daemon.emit_progress.connect (on_emit_progress);
-					system_daemon.emit_download.connect (on_emit_download);
-					system_daemon.emit_totaldownload.connect (on_emit_totaldownload);
-					system_daemon.emit_log.connect (on_emit_log);
-					system_daemon.trans_prepare_finished.connect (on_trans_prepare_finished);
-					system_daemon.trans_commit_finished.connect (on_trans_commit_finished);
-					// Use tty polkit authentication agent
-					pkttyagent = new Subprocess.newv ({"pkttyagent"}, SubprocessFlags.NONE);
-				} catch (Error e) {
-					print_error (e.message);
-				}
-			}
-		}
-
-		int get_term_width () {
-			int width = 80;
-			Linux.winsize win;
-			if (Linux.ioctl (Posix.STDOUT_FILENO, Linux.Termios.TIOCGWINSZ, out win) == 0) {
-				width = win.ws_col;
-			}
-			return width;
-		}
-
 		string concatenate_strings (string[] list) {
 			var str_builder = new StringBuilder ();
 			foreach (unowned string str in list) {
@@ -468,7 +329,7 @@ namespace Pamac {
 		}
 
 		string[] split_string (string str, int margin, int width = 0) {
-			int term_width = get_term_width ();
+			int term_width = transaction.get_term_width ();
 			if (width == 0) {
 				width = term_width;
 			}
@@ -517,31 +378,8 @@ namespace Pamac {
 			stdout.printf ("%s\n", str_builder.str);
 		}
 
-		void print_progress (string action, string state, bool new_line) {
-			var str_builder = new StringBuilder ();
-			str_builder.append (action);
-			int width = get_term_width () - action.char_count () - 1;
-			if (new_line) {
-				stdout.printf ("%s %*s\n", action, width, state);
-			} else {
-				stdout.printf ("%s %*s\r", action, width, state);
-			}
-			stdout.flush ();
-		}
-
-		void print_error (string msg, string[] details = {}) {
-			if (details.length > 0) {
-				if (details.length == 1) {
-					stdout.printf ("%s: %s: %s\n", dgettext (null, "Error"), msg, details[0]);
-				} else {
-					stdout.printf ("%s: %s:\n", dgettext (null, "Error"), msg);
-					foreach (unowned string detail in details) {
-						stdout.printf ("%s\n", detail);
-					}
-				}
-			} else {
-				stdout.printf ("%s: %s\n", dgettext (null, "Error"), msg);
-			}
+		void print_error (string message) {
+			stdout.printf ("%s: %s\n", dgettext (null, "Error"), message);
 			cmd.set_exit_status (1);
 		}
 
@@ -807,29 +645,84 @@ namespace Pamac {
 		}
 
 		void search_pkgs (string search_string) {
-			try {
-				var pkgs = user_daemon.search_pkgs_sync (search_string);
+			var pkgs = database.search_pkgs (search_string);
+			if (pkgs.length == 0) {
+				cmd.set_exit_status (1);
+				return;
+			}
+			int version_length = 0;
+			int repo_length = 0;
+			foreach (unowned AlpmPackage pkg in pkgs) {
+				if (pkg.version.length > version_length) {
+					version_length = pkg.version.length;
+				}
+				if (pkg.repo.length > repo_length) {
+					repo_length = pkg.repo.length;
+				}
+			}
+			int available_width = transaction.get_term_width () - (version_length + repo_length + 3);
+			foreach (unowned AlpmPackage pkg in pkgs) {
+				string name = pkg.name;
+				if (pkg.origin == 2) {
+					name = "%s [%s]".printf (pkg.name, dgettext (null, "Installed"));
+				}
+				var str_builder = new StringBuilder ();
+				str_builder.append (name);
+				str_builder.append (" ");
+				int diff = available_width - name.char_count ();
+				if (diff > 0) {
+					while (diff > 0) {
+						str_builder.append (" ");
+						diff--;
+					}
+				}
+				str_builder.append ("%-*s %s \n".printf (version_length, pkg.version, pkg.repo));
+				stdout.printf ("%s", str_builder.str);
+				string[] cuts = split_string (pkg.desc, 2, available_width);
+				foreach (unowned string cut in cuts) {
+					print_aligned ("", cut, 2);
+				}
+			}
+		}
+
+		void search_in_aur (string search_string) {
+			this.hold ();
+			database.search_in_aur_async.begin (search_string, (obj,res) => {
+				AURPackage[] pkgs = database.search_in_aur_async.end (res);
 				if (pkgs.length == 0) {
+					this.release ();
 					cmd.set_exit_status (1);
 					return;
 				}
 				int version_length = 0;
-				int repo_length = 0;
-				foreach (unowned AlpmPackage pkg in pkgs) {
+				foreach (unowned AURPackage pkg in pkgs) {
 					if (pkg.version.length > version_length) {
 						version_length = pkg.version.length;
 					}
-					if (pkg.repo.length > repo_length) {
-						repo_length = pkg.repo.length;
-					}
 				}
-				int available_width = get_term_width () - (version_length + repo_length + 3);
-				foreach (unowned AlpmPackage pkg in pkgs) {
+				int aur_length = dgettext (null, "AUR").char_count ();
+				int available_width = transaction.get_term_width () - (version_length + aur_length + 3);
+				// sort aur pkgs by popularity
+				var results = new List<AURPackage?> ();
+				foreach (unowned AURPackage pkg in pkgs) {
+					results.append (pkg);
+				}
+				results.sort ((pkg1, pkg2) => {
+					double diff = pkg2.popularity - pkg1.popularity;
+					if (diff < 0) {
+						return -1;
+					} else if (diff > 0) {
+						return 1;
+					} else {
+						return 0;
+					}
+				});
+				foreach (unowned AURPackage pkg in results) {
+					var str_builder = new StringBuilder ();
 					string name = pkg.name;
-					if (pkg.origin == 2) {
+					if (pkg.installed_version != "") {
 						name = "%s [%s]".printf (pkg.name, dgettext (null, "Installed"));
 					}
-					var str_builder = new StringBuilder ();
 					str_builder.append (name);
 					str_builder.append (" ");
 					int diff = available_width - name.char_count ();
@@ -839,76 +732,13 @@ namespace Pamac {
 							diff--;
 						}
 					}
-					str_builder.append ("%-*s %s \n".printf (version_length, pkg.version, pkg.repo));
+					str_builder.append ("%-*s %s \n".printf (version_length, pkg.version, dgettext (null, "AUR")));
 					stdout.printf ("%s", str_builder.str);
 					string[] cuts = split_string (pkg.desc, 2, available_width);
 					foreach (unowned string cut in cuts) {
 						print_aligned ("", cut, 2);
 					}
 				}
-			} catch (Error e) {
-				print_error (e.message);
-			}
-		}
-
-		void search_in_aur (string search_string) {
-			this.hold ();
-			user_daemon.search_in_aur.begin (search_string, (obj,res) => {
-				try {
-					AURPackage[] pkgs = user_daemon.search_in_aur.end (res);
-					if (pkgs.length == 0) {
-						this.release ();
-						cmd.set_exit_status (1);
-						return;
-					}
-					int version_length = 0;
-					foreach (unowned AURPackage pkg in pkgs) {
-						if (pkg.version.length > version_length) {
-							version_length = pkg.version.length;
-						}
-					}
-					int aur_length = dgettext (null, "AUR").char_count ();
-					int available_width = get_term_width () - (version_length + aur_length + 3);
-					// sort aur pkgs by popularity
-					var results = new List<AURPackage?> ();
-					foreach (unowned AURPackage pkg in pkgs) {
-						results.append (pkg);
-					}
-					results.sort ((pkg1, pkg2) => {
-						double diff = pkg2.popularity - pkg1.popularity;
-						if (diff < 0) {
-							return -1;
-						} else if (diff > 0) {
-							return 1;
-						} else {
-							return 0;
-						}
-					});
-					foreach (unowned AURPackage pkg in results) {
-						var str_builder = new StringBuilder ();
-						string name = pkg.name;
-						if (pkg.installed_version != "") {
-							name = "%s [%s]".printf (pkg.name, dgettext (null, "Installed"));
-						}
-						str_builder.append (name);
-						str_builder.append (" ");
-						int diff = available_width - name.char_count ();
-						if (diff > 0) {
-							while (diff > 0) {
-								str_builder.append (" ");
-								diff--;
-							}
-						}
-						str_builder.append ("%-*s %s \n".printf (version_length, pkg.version, dgettext (null, "AUR")));
-						stdout.printf ("%s", str_builder.str);
-						string[] cuts = split_string (pkg.desc, 2, available_width);
-						foreach (unowned string cut in cuts) {
-							print_aligned ("", cut, 2);
-						}
-					}
-				} catch (Error e) {
-					print_error (e.message);
-				}
 				this.release ();
 			});
 		}
@@ -944,40 +774,253 @@ namespace Pamac {
 				}
 			}
 			foreach (unowned string pkgname in pkgnames) {
-				try {
-					var details =  user_daemon.get_pkg_details (pkgname, "");
+				var details =  database.get_pkg_details (pkgname, "");
+				if (details.name == "") {
+					print_error (dgettext (null, "target not found: %s").printf (pkgname) + "\n");
+					continue;
+				}
+				// Name
+				print_aligned (properties[0], ": %s".printf (details.name), max_length);
+				// Version
+				print_aligned (properties[1], ": %s".printf (details.version), max_length);
+				// Description
+				string[] cuts = split_string (details.desc, max_length + 2);
+				print_aligned (properties[2], ": %s".printf (cuts[0]), max_length);
+				int i = 1;
+				while (i < cuts.length) {
+					print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
+					i++;
+				}
+				// URL
+				print_aligned (properties[3], ": %s".printf (details.url), max_length);
+				// Licenses
+				print_aligned (properties[4], ": %s".printf (details.licenses[0]), max_length);
+				i = 1;
+				while (i < details.licenses.length) {
+					print_aligned ("", "%s".printf (details.licenses[i]), max_length + 2);
+					i++;
+				}
+				// Repository
+				print_aligned (properties[5], ": %s".printf (details.repo), max_length);
+				// Size
+				print_aligned (properties[6], ": %s".printf (format_size (details.size)), max_length);
+				// Groups
+				if (details.groups.length > 0) {
+					cuts = split_string (concatenate_strings (details.groups), max_length + 2);
+					print_aligned (properties[7], ": %s".printf (cuts[0]), max_length);
+					i = 1;
+					while (i < cuts.length) {
+						print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
+						i++;
+					}
+				}
+				// Depends
+				if (details.depends.length > 0) {
+					cuts = split_string (concatenate_strings (details.depends), max_length + 2);
+					print_aligned (properties[8], ": %s".printf (cuts[0]), max_length);
+					i = 1;
+					while (i < cuts.length) {
+						print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
+						i++;
+					}
+				}
+				// Opt depends
+				if (details.optdepends.length > 0) {
+					string depstring = details.optdepends[0];
+					var satisfier = AlpmPackage ();
+					satisfier = database.find_installed_satisfier (depstring);
+					if (satisfier.name != "") {
+						depstring = "%s [%s]".printf (depstring, dgettext (null, "Installed"));
+					}
+					cuts = split_string (depstring, max_length + 2);
+					print_aligned (properties[9], ": %s".printf (cuts[0]), max_length);
+					i = 1;
+					while (i < cuts.length) {
+						print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
+						i++;
+					}
+					i = 1;
+					while (i < details.optdepends.length) {
+						depstring = details.optdepends[i];
+						satisfier = AlpmPackage ();
+						satisfier = database.find_installed_satisfier (depstring);
+						if (satisfier.name != "") {
+							depstring = "%s [%s]".printf (depstring, dgettext (null, "Installed"));
+						}
+						cuts = split_string (depstring, max_length + 2);
+						int j = 0;
+						while (j < cuts.length) {
+							print_aligned ("", "%s".printf (cuts[j]), max_length + 2);
+							j++;
+						}
+						i++;
+					}
+				}
+				// Required by
+				if (details.requiredby.length > 0) {
+					cuts = split_string (concatenate_strings (details.requiredby), max_length + 2);
+					print_aligned (properties[10], ": %s".printf (cuts[0]), max_length);
+					i = 1;
+					while (i < cuts.length) {
+						print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
+						i++;
+					}
+				}
+				// Optional for
+				if (details.optionalfor.length > 0) {
+					cuts = split_string (concatenate_strings (details.optionalfor), max_length + 2);
+					print_aligned (properties[11], ": %s".printf (cuts[0]), max_length);
+					i = 1;
+					while (i < cuts.length) {
+						print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
+						i++;
+					}
+				}
+				// Provides
+				if (details.provides.length > 0) {
+					cuts = split_string (concatenate_strings (details.provides), max_length + 2);
+					print_aligned (properties[12], ": %s".printf (cuts[0]), max_length);
+					i = 1;
+					while (i < cuts.length) {
+						print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
+						i++;
+					}
+				}
+				// Replaces
+				if (details.replaces.length > 0) {
+					cuts = split_string (concatenate_strings (details.replaces), max_length + 2);
+					print_aligned (properties[13], ": %s".printf (cuts[0]), max_length);
+					i = 1;
+					while (i < cuts.length) {
+						print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
+						i++;
+					}
+				}
+				// Conflicts
+				if (details.conflicts.length > 0) {
+					cuts = split_string (concatenate_strings (details.conflicts), max_length + 2);
+					print_aligned (properties[14], ": %s".printf (cuts[0]), max_length);
+					i = 1;
+					while (i < cuts.length) {
+						print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
+						i++;
+					}
+				}
+				// Maintainer
+				cuts = split_string (details.packager, max_length + 2);
+				print_aligned (properties[15], ": %s".printf (cuts[0]), max_length);
+				i = 1;
+				while (i < cuts.length) {
+					print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
+					i++;
+				}
+				// Build date
+				print_aligned (properties[16], ": %s".printf (details.builddate), max_length);
+				// Install date
+				if (details.installdate != "") {
+					print_aligned (properties[17], ": %s".printf (details.installdate), max_length);
+				}
+				// Reason
+				if (details.reason != "") {
+					cuts = split_string (details.reason, max_length + 2);
+					print_aligned (properties[18], ": %s".printf (cuts[0]), max_length);
+					i = 1;
+					while (i < cuts.length) {
+						print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
+						i++;
+					}
+				}
+				// Signature
+				if (details.has_signature != "") {
+					print_aligned (properties[19], ": %s".printf (details.has_signature), max_length);
+				}
+				// Backup files
+				if (details.backups.length > 0) {
+					print_aligned (properties[20], ": %s".printf (details.backups[0]), max_length);
+					i = 1;
+					while (i < details.backups.length) {
+						print_aligned ("", "%s".printf (details.backups[i]), max_length + 2);
+						i++;
+					}
+				}
+				stdout.printf ("\n");
+			}
+		}
+
+		void display_aur_infos (string[] pkgnames) {
+			string[] properties = {};
+			properties += dgettext (null, "Name");
+			properties += dgettext (null, "Package Base");
+			properties += dgettext (null, "Version");
+			properties += dgettext (null, "Description");
+			properties += dgettext (null, "URL");
+			properties += dgettext (null, "Licenses");
+			properties += dgettext (null, "Depends On");
+			properties += dgettext (null, "Make Dependencies");
+			properties += dgettext (null, "Check Dependencies");
+			properties += dgettext (null, "Optional Dependencies");
+			properties += dgettext (null, "Provides");
+			properties += dgettext (null, "Replaces");
+			properties += dgettext (null, "Conflicts With");
+			properties += dgettext (null, "Packager");
+			properties += dgettext (null, "First Submitted");
+			properties += dgettext (null, "Last Modified");
+			properties += dgettext (null, "Votes");
+			properties += dgettext (null, "Out of Date");
+			int max_length = 0;
+			foreach (unowned string prop in properties) {
+				// use char_count to handle special characters
+				if (prop.char_count () > max_length) {
+					max_length = prop.length;
+				}
+			}
+			foreach (string pkgname in pkgnames) {
+				this.hold ();
+				database.get_aur_details_async.begin (pkgname, (obj, res) => {
+					var details = database.get_aur_details_async.end (res);
 					if (details.name == "") {
 						print_error (dgettext (null, "target not found: %s").printf (pkgname) + "\n");
-						continue;
+						this.release ();
+						return;
 					}
 					// Name
 					print_aligned (properties[0], ": %s".printf (details.name), max_length);
+					// Package Base
+					if (details.packagebase != details.name) {
+						print_aligned (properties[1], ": %s".printf (details.packagebase), max_length);
+					}
 					// Version
-					print_aligned (properties[1], ": %s".printf (details.version), max_length);
+					print_aligned (properties[2], ": %s".printf (details.version), max_length);
 					// Description
 					string[] cuts = split_string (details.desc, max_length + 2);
-					print_aligned (properties[2], ": %s".printf (cuts[0]), max_length);
+					print_aligned (properties[3], ": %s".printf (cuts[0]), max_length);
 					int i = 1;
 					while (i < cuts.length) {
 						print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
 						i++;
 					}
 					// URL
-					print_aligned (properties[3], ": %s".printf (details.url), max_length);
+					print_aligned (properties[4], ": %s".printf (details.url), max_length);
 					// Licenses
-					print_aligned (properties[4], ": %s".printf (details.licenses[0]), max_length);
+					print_aligned (properties[5], ": %s".printf (details.licenses[0]), max_length);
 					i = 1;
 					while (i < details.licenses.length) {
 						print_aligned ("", "%s".printf (details.licenses[i]), max_length + 2);
 						i++;
 					}
-					// Repository
-					print_aligned (properties[5], ": %s".printf (details.repo), max_length);
-					// Size
-					print_aligned (properties[6], ": %s".printf (format_size (details.size)), max_length);
-					// Groups
-					if (details.groups.length > 0) {
-						cuts = split_string (concatenate_strings (details.groups), max_length + 2);
+					// Depends
+					if (details.depends.length > 0) {
+						cuts = split_string (concatenate_strings (details.depends), max_length + 2);
+						print_aligned (properties[6], ": %s".printf (cuts[0]), max_length);
+						i = 1;
+						while (i < cuts.length) {
+							print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
+							i++;
+						}
+					}
+					// Make Depends
+					if (details.makedepends.length > 0) {
+						cuts = split_string (concatenate_strings (details.makedepends), max_length + 2);
 						print_aligned (properties[7], ": %s".printf (cuts[0]), max_length);
 						i = 1;
 						while (i < cuts.length) {
@@ -985,9 +1028,9 @@ namespace Pamac {
 							i++;
 						}
 					}
-					// Depends
-					if (details.depends.length > 0) {
-						cuts = split_string (concatenate_strings (details.depends), max_length + 2);
+					// Check Depends
+					if (details.checkdepends.length > 0) {
+						cuts = split_string (concatenate_strings (details.checkdepends), max_length + 2);
 						print_aligned (properties[8], ": %s".printf (cuts[0]), max_length);
 						i = 1;
 						while (i < cuts.length) {
@@ -999,11 +1042,7 @@ namespace Pamac {
 					if (details.optdepends.length > 0) {
 						string depstring = details.optdepends[0];
 						var satisfier = AlpmPackage ();
-						try {
-							satisfier = user_daemon.find_installed_satisfier (depstring);
-						} catch (Error e) {
-							print_error (e.message);
-						}
+						satisfier = database.find_installed_satisfier (depstring);
 						if (satisfier.name != "") {
 							depstring = "%s [%s]".printf (depstring, dgettext (null, "Installed"));
 						}
@@ -1018,11 +1057,7 @@ namespace Pamac {
 						while (i < details.optdepends.length) {
 							depstring = details.optdepends[i];
 							satisfier = AlpmPackage ();
-							try {
-								satisfier = user_daemon.find_installed_satisfier (depstring);
-							} catch (Error e) {
-								print_error (e.message);
-							}
+							satisfier = database.find_installed_satisfier (depstring);
 							if (satisfier.name != "") {
 								depstring = "%s [%s]".printf (depstring, dgettext (null, "Installed"));
 							}
@@ -1035,30 +1070,10 @@ namespace Pamac {
 							i++;
 						}
 					}
-					// Required by
-					if (details.requiredby.length > 0) {
-						cuts = split_string (concatenate_strings (details.requiredby), max_length + 2);
-						print_aligned (properties[10], ": %s".printf (cuts[0]), max_length);
-						i = 1;
-						while (i < cuts.length) {
-							print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
-							i++;
-						}
-					}
-					// Optional for
-					if (details.optionalfor.length > 0) {
-						cuts = split_string (concatenate_strings (details.optionalfor), max_length + 2);
-						print_aligned (properties[11], ": %s".printf (cuts[0]), max_length);
-						i = 1;
-						while (i < cuts.length) {
-							print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
-							i++;
-						}
-					}
 					// Provides
 					if (details.provides.length > 0) {
 						cuts = split_string (concatenate_strings (details.provides), max_length + 2);
-						print_aligned (properties[12], ": %s".printf (cuts[0]), max_length);
+						print_aligned (properties[10], ": %s".printf (cuts[0]), max_length);
 						i = 1;
 						while (i < cuts.length) {
 							print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
@@ -1068,7 +1083,7 @@ namespace Pamac {
 					// Replaces
 					if (details.replaces.length > 0) {
 						cuts = split_string (concatenate_strings (details.replaces), max_length + 2);
-						print_aligned (properties[13], ": %s".printf (cuts[0]), max_length);
+						print_aligned (properties[11], ": %s".printf (cuts[0]), max_length);
 						i = 1;
 						while (i < cuts.length) {
 							print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
@@ -1078,7 +1093,7 @@ namespace Pamac {
 					// Conflicts
 					if (details.conflicts.length > 0) {
 						cuts = split_string (concatenate_strings (details.conflicts), max_length + 2);
-						print_aligned (properties[14], ": %s".printf (cuts[0]), max_length);
+						print_aligned (properties[12], ": %s".printf (cuts[0]), max_length);
 						i = 1;
 						while (i < cuts.length) {
 							print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
@@ -1086,231 +1101,22 @@ namespace Pamac {
 						}
 					}
 					// Maintainer
-					cuts = split_string (details.packager, max_length + 2);
-					print_aligned (properties[15], ": %s".printf (cuts[0]), max_length);
-					i = 1;
-					while (i < cuts.length) {
-						print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
-						i++;
-					}
-					// Build date
-					print_aligned (properties[16], ": %s".printf (details.builddate), max_length);
-					// Install date
-					if (details.installdate != "") {
-						print_aligned (properties[17], ": %s".printf (details.installdate), max_length);
-					}
-					// Reason
-					if (details.reason != "") {
-						cuts = split_string (details.reason, max_length + 2);
-						print_aligned (properties[18], ": %s".printf (cuts[0]), max_length);
-						i = 1;
-						while (i < cuts.length) {
-							print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
-							i++;
-						}
-					}
-					// Signature
-					if (details.has_signature != "") {
-						print_aligned (properties[19], ": %s".printf (details.has_signature), max_length);
-					}
-					// Backup files
-					if (details.backups.length > 0) {
-						print_aligned (properties[20], ": %s".printf (details.backups[0]), max_length);
-						i = 1;
-						while (i < details.backups.length) {
-							print_aligned ("", "%s".printf (details.backups[i]), max_length + 2);
-							i++;
-						}
+					if (details.maintainer != "") {
+						print_aligned (properties[13], ": %s".printf (details.maintainer), max_length);
+					}
+					// First Submitted
+					print_aligned (properties[14], ": %s".printf (details.firstsubmitted), max_length);
+					// Last Modified
+					print_aligned (properties[15], ": %s".printf (details.lastmodified), max_length);
+					// Votes
+					print_aligned (properties[16], ": %s".printf (details.numvotes.to_string ()), max_length);
+					// Last Modified
+					if (details.outofdate != "") {
+						print_aligned (properties[17], ": %s".printf (details.outofdate), max_length);
 					}
 					stdout.printf ("\n");
-				} catch (Error e) {
-					print_error (e.message);
-				}
-			}
-		}
-
-		void display_aur_infos (string[] pkgnames) {
-			string[] properties = {};
-			properties += dgettext (null, "Name");
-			properties += dgettext (null, "Package Base");
-			properties += dgettext (null, "Version");
-			properties += dgettext (null, "Description");
-			properties += dgettext (null, "URL");
-			properties += dgettext (null, "Licenses");
-			properties += dgettext (null, "Depends On");
-			properties += dgettext (null, "Make Dependencies");
-			properties += dgettext (null, "Check Dependencies");
-			properties += dgettext (null, "Optional Dependencies");
-			properties += dgettext (null, "Provides");
-			properties += dgettext (null, "Replaces");
-			properties += dgettext (null, "Conflicts With");
-			properties += dgettext (null, "Packager");
-			properties += dgettext (null, "First Submitted");
-			properties += dgettext (null, "Last Modified");
-			properties += dgettext (null, "Votes");
-			properties += dgettext (null, "Out of Date");
-			int max_length = 0;
-			foreach (unowned string prop in properties) {
-				// use char_count to handle special characters
-				if (prop.char_count () > max_length) {
-					max_length = prop.length;
-				}
-			}
-			foreach (string pkgname in pkgnames) {
-				this.hold ();
-				user_daemon.get_aur_details.begin (pkgname, (obj, res) => {
-					try {
-						var details = user_daemon.get_aur_details.end (res);
-						if (details.name == "") {
-							print_error (dgettext (null, "target not found: %s").printf (pkgname) + "\n");
-							this.release ();
-							return;
-						}
-						// Name
-						print_aligned (properties[0], ": %s".printf (details.name), max_length);
-						// Package Base
-						if (details.packagebase != details.name) {
-							print_aligned (properties[1], ": %s".printf (details.packagebase), max_length);
-						}
-						// Version
-						print_aligned (properties[2], ": %s".printf (details.version), max_length);
-						// Description
-						string[] cuts = split_string (details.desc, max_length + 2);
-						print_aligned (properties[3], ": %s".printf (cuts[0]), max_length);
-						int i = 1;
-						while (i < cuts.length) {
-							print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
-							i++;
-						}
-						// URL
-						print_aligned (properties[4], ": %s".printf (details.url), max_length);
-						// Licenses
-						print_aligned (properties[5], ": %s".printf (details.licenses[0]), max_length);
-						i = 1;
-						while (i < details.licenses.length) {
-							print_aligned ("", "%s".printf (details.licenses[i]), max_length + 2);
-							i++;
-						}
-						// Depends
-						if (details.depends.length > 0) {
-							cuts = split_string (concatenate_strings (details.depends), max_length + 2);
-							print_aligned (properties[6], ": %s".printf (cuts[0]), max_length);
-							i = 1;
-							while (i < cuts.length) {
-								print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
-								i++;
-							}
-						}
-						// Make Depends
-						if (details.makedepends.length > 0) {
-							cuts = split_string (concatenate_strings (details.makedepends), max_length + 2);
-							print_aligned (properties[7], ": %s".printf (cuts[0]), max_length);
-							i = 1;
-							while (i < cuts.length) {
-								print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
-								i++;
-							}
-						}
-						// Check Depends
-						if (details.checkdepends.length > 0) {
-							cuts = split_string (concatenate_strings (details.checkdepends), max_length + 2);
-							print_aligned (properties[8], ": %s".printf (cuts[0]), max_length);
-							i = 1;
-							while (i < cuts.length) {
-								print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
-								i++;
-							}
-						}
-						// Opt depends
-						if (details.optdepends.length > 0) {
-							string depstring = details.optdepends[0];
-							var satisfier = AlpmPackage ();
-							try {
-								satisfier = user_daemon.find_installed_satisfier (depstring);
-							} catch (Error e) {
-								print_error (e.message);
-							}
-							if (satisfier.name != "") {
-								depstring = "%s [%s]".printf (depstring, dgettext (null, "Installed"));
-							}
-							cuts = split_string (depstring, max_length + 2);
-							print_aligned (properties[9], ": %s".printf (cuts[0]), max_length);
-							i = 1;
-							while (i < cuts.length) {
-								print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
-								i++;
-							}
-							i = 1;
-							while (i < details.optdepends.length) {
-								depstring = details.optdepends[i];
-								satisfier = AlpmPackage ();
-								try {
-									satisfier = user_daemon.find_installed_satisfier (depstring);
-								} catch (Error e) {
-									print_error (e.message);
-								}
-								if (satisfier.name != "") {
-									depstring = "%s [%s]".printf (depstring, dgettext (null, "Installed"));
-								}
-								cuts = split_string (depstring, max_length + 2);
-								int j = 0;
-								while (j < cuts.length) {
-									print_aligned ("", "%s".printf (cuts[j]), max_length + 2);
-									j++;
-								}
-								i++;
-							}
-						}
-						// Provides
-						if (details.provides.length > 0) {
-							cuts = split_string (concatenate_strings (details.provides), max_length + 2);
-							print_aligned (properties[10], ": %s".printf (cuts[0]), max_length);
-							i = 1;
-							while (i < cuts.length) {
-								print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
-								i++;
-							}
-						}
-						// Replaces
-						if (details.replaces.length > 0) {
-							cuts = split_string (concatenate_strings (details.replaces), max_length + 2);
-							print_aligned (properties[11], ": %s".printf (cuts[0]), max_length);
-							i = 1;
-							while (i < cuts.length) {
-								print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
-								i++;
-							}
-						}
-						// Conflicts
-						if (details.conflicts.length > 0) {
-							cuts = split_string (concatenate_strings (details.conflicts), max_length + 2);
-							print_aligned (properties[12], ": %s".printf (cuts[0]), max_length);
-							i = 1;
-							while (i < cuts.length) {
-								print_aligned ("", "%s".printf (cuts[i]), max_length + 2);
-								i++;
-							}
-						}
-						// Maintainer
-						if (details.maintainer != "") {
-							print_aligned (properties[13], ": %s".printf (details.maintainer), max_length);
-						}
-						// First Submitted
-						print_aligned (properties[14], ": %s".printf (details.firstsubmitted), max_length);
-						// Last Modified
-						print_aligned (properties[15], ": %s".printf (details.lastmodified), max_length);
-						// Votes
-						print_aligned (properties[16], ": %s".printf (details.numvotes.to_string ()), max_length);
-						// Last Modified
-						if (details.outofdate != "") {
-							print_aligned (properties[17], ": %s".printf (details.outofdate), max_length);
-						}
-						stdout.printf ("\n");
-					} catch (Error e) {
-						print_error (e.message);
-					}
-					this.release ();
-				});
+					this.release ();
+				});
 			}
 		}
 
@@ -1341,9 +1147,9 @@ namespace Pamac {
 			}
 			int total_width = name_length + version_length + repo_length + size_length + 4;
 			int margin = 0;
-			if (get_term_width () > total_width) {
+			if (transaction.get_term_width () > total_width) {
 				// divide available space between columns
-				int available_width = get_term_width () - total_width;
+				int available_width = transaction.get_term_width () - total_width;
 				margin = available_width / 4;
 				// get left space to size
 				size_length += available_width - (margin * 4);
@@ -1352,7 +1158,7 @@ namespace Pamac {
 				// use this code to correctly aligned text with special characters
 				var str_builder = new StringBuilder ();
 				string name = pkg.name;
-				if (pkg.installed_version != "") {
+				if (print_installed && pkg.installed_version != "") {
 					name = "%s [%s]".printf (pkg.name, dgettext (null, "Installed"));
 				}
 				str_builder.append (name);
@@ -1372,54 +1178,34 @@ namespace Pamac {
 		}
 
 		void list_installed () {
-			try {
-				var pkgs = user_daemon.get_installed_pkgs_sync ();
-				print_pkgs (pkgs, false);
-			} catch (Error e) {
-				print_error (e.message);
-			}
+			var pkgs = database.get_installed_pkgs ();
+			print_pkgs (pkgs, false);
 		}
 
 		void list_orphans () {
-			try {
-				var pkgs = user_daemon.get_orphans_sync ();
-				print_pkgs (pkgs, false);
-			} catch (Error e) {
-				print_error (e.message);
-			}
+			var pkgs = database.get_orphans ();
+			print_pkgs (pkgs, false);
 		}
 
 		void list_foreign () {
-			try {
-				var pkgs = user_daemon.get_foreign_pkgs_sync ();
-				print_pkgs (pkgs, false);
-			} catch (Error e) {
-				print_error (e.message);
-			}
+			var pkgs = database.get_foreign_pkgs ();
+			print_pkgs (pkgs, false);
 		}
 
 		void list_groups (string[] names) {
 			if (names.length == 0) {
-				try {
-					string[] grpnames = user_daemon.get_groups_names ();
-					foreach (unowned string name in grpnames) {
-						stdout.printf ("%s\n", name);
-					}
-				} catch (Error e) {
-					print_error (e.message);
+				string[] grpnames = database.get_groups_names ();
+				foreach (unowned string name in grpnames) {
+					stdout.printf ("%s\n", name);
 				}
 				return;
 			}
 			foreach (unowned string name in names) {
-				try {
-					var pkgs = user_daemon.get_group_pkgs_sync (name);
-					if (pkgs.length == 0) {
-						print_error (dgettext (null, "target not found: %s").printf (name));
-					} else {
-						print_pkgs (pkgs, true);
-					}
-				} catch (Error e) {
-					print_error (e.message);
+				var pkgs = database.get_group_pkgs (name);
+				if (pkgs.length == 0) {
+					print_error (dgettext (null, "target not found: %s").printf (name));
+				} else {
+					print_pkgs (pkgs, true);
 				}
 				stdout.printf ("\n");
 			}
@@ -1427,26 +1213,18 @@ namespace Pamac {
 
 		void list_repos (string[] names) {
 			if (names.length == 0) {
-				try {
-					string[] grpnames = user_daemon.get_repos_names ();
-					foreach (unowned string name in grpnames) {
-						stdout.printf ("%s\n", name);
-					}
-				} catch (Error e) {
-					print_error (e.message);
+				string[] grpnames = database.get_repos_names ();
+				foreach (unowned string name in grpnames) {
+					stdout.printf ("%s\n", name);
 				}
 				return;
 			}
 			foreach (unowned string name in names) {
-				try {
-					var pkgs = user_daemon.get_repo_pkgs_sync (name);
-					if (pkgs.length == 0) {
-						print_error (dgettext (null, "target not found: %s").printf (name));
-					} else {
-						print_pkgs (pkgs, true);
-					}
-				} catch (Error e) {
-					print_error (e.message);
+				var pkgs = database.get_repo_pkgs (name);
+				if (pkgs.length == 0) {
+					print_error (dgettext (null, "target not found: %s").printf (name));
+				} else {
+					print_pkgs (pkgs, true);
 				}
 				stdout.printf ("\n");
 			}
@@ -1454,74 +1232,45 @@ namespace Pamac {
 
 		void list_files (string[] names) {
 			foreach (unowned string name in names) {
-				try {
-					string[] files = user_daemon.get_pkg_files (name);
-					if (files.length == 0) {
-						print_error (dgettext (null, "target not found: %s").printf (name));
-					} else {
-						foreach (unowned string path in files) {
-							stdout.printf ("%s\n", path);
-						}
+				string[] files = database.get_pkg_files (name);
+				if (files.length == 0) {
+					print_error (dgettext (null, "target not found: %s").printf (name));
+				} else {
+					foreach (unowned string path in files) {
+						stdout.printf ("%s\n", path);
 					}
-				} catch (Error e) {
-					print_error (e.message);
 				}
 				stdout.printf ("\n");
 			}
 		}
 
 		void search_files (string[] files) {
-			try {
-				HashTable<string, Variant> result = user_daemon.search_files (files);
-				if (result.size () == 0) {
-					foreach (unowned string file in files) {
-						stdout.printf (dgettext (null, "No package owns %s\n").printf (file));
-					}
-					cmd.set_exit_status (1);
-					return;
+			HashTable<string, Variant> result = database.search_files (files);
+			if (result.size () == 0) {
+				foreach (unowned string file in files) {
+					stdout.printf (dgettext (null, "No package owns %s\n").printf (file));
 				}
-				var iter = HashTableIter<string, Variant> (result);
-				unowned string pkgname;
-				unowned Variant files_list;
-				while (iter.next (out pkgname, out files_list)) {
-					foreach (unowned string file in (string[]) files_list) {
-						stdout.printf ("%s\n", dgettext (null, "%s is owned by %s").printf (file, pkgname));
-					}
-				}
-			} catch (Error e) {
-				print_error (e.message);
+				cmd.set_exit_status (1);
+				return;
 			}
-		}
-
-		AlpmPackage get_installed_pkg (string pkgname) {
-			try {
-				return user_daemon.get_installed_pkg (pkgname);
-			} catch (Error e) {
-				print_error (e.message);
-				return AlpmPackage () {
-					name = "",
-					version = "",
-					desc = "",
-					repo = "",
-					icon = ""
-				};
+			var iter = HashTableIter<string, Variant> (result);
+			unowned string pkgname;
+			unowned Variant files_list;
+			while (iter.next (out pkgname, out files_list)) {
+				foreach (unowned string file in (string[]) files_list) {
+					stdout.printf ("%s\n", dgettext (null, "%s is owned by %s").printf (file, pkgname));
+				}
 			}
 		}
 
 		void checkupdates () {
 			this.hold ();
-			user_daemon.get_updates_finished.connect (on_get_updates_finished);
-			try {
-				user_daemon.start_get_updates (enable_aur, false);
-			} catch (Error e) {
-				print_error (e.message);
-				user_daemon.get_updates_finished.disconnect (on_get_updates_finished);
-				this.release ();
-			}
+			database.start_get_updates ();
+			database.get_updates_finished.connect (on_get_updates_finished);
 		}
 
 		void on_get_updates_finished (Updates updates) {
-			user_daemon.get_updates_finished.disconnect (on_get_updates_for_sysupgrade_finished);
+			database.get_updates_finished.disconnect (on_get_updates_finished);
 			uint updates_nb = updates.repos_updates.length + updates.aur_updates.length;
 			if (updates_nb == 0) {
 				stdout.printf ("%s\n", dgettext (null, "Your system is up-to-date"));
@@ -1556,9 +1305,9 @@ namespace Pamac {
 				}
 				int total_width = name_length + version_length + repo_length + 3;
 				int margin = 0;
-				if (get_term_width () > total_width) {
+				if (transaction.get_term_width () > total_width) {
 					// divide available space between columns
-					int available_width = get_term_width () - total_width;
+					int available_width = transaction.get_term_width () - total_width;
 					margin = available_width / 3;
 					// get left space to repo
 					repo_length += available_width - (margin * 3);
@@ -1580,1321 +1329,294 @@ namespace Pamac {
 		}
 
 		void install_pkgs (string[] targets) {
-			try {
-				foreach (unowned string target in targets) {
-					bool found = false;
-					// check for local or remote path
-					if (".pkg.tar" in target) {
-						if ("://" in target) {
-							if ("file://" in target) {
-								// handle file:// uri
-								var file = File.new_for_uri (target);
-								string? absolute_path = file.get_path ();
-								if (absolute_path != null) {
-									to_load += absolute_path;
-									found = true;
-								}
-							} else {
-								// add url in to_load, pkg will be downloaded by system_daemon
-								to_load += target;
-								found = true;
-							}
-						} else {
-							// handle local or absolute path
-							var file = File.new_for_path (target);
+			foreach (unowned string target in targets) {
+				bool found = false;
+				// check for local or remote path
+				if (".pkg.tar" in target) {
+					if ("://" in target) {
+						if ("file://" in target) {
+							// handle file:// uri
+							var file = File.new_for_uri (target);
 							string? absolute_path = file.get_path ();
 							if (absolute_path != null) {
 								to_load += absolute_path;
 								found = true;
 							}
+						} else {
+							// add url in to_load, pkg will be downloaded by system_daemon
+							to_load += target;
+							found = true;
 						}
 					} else {
-						var pkg = user_daemon.find_sync_satisfier (target);
-						if (pkg.name != "") {
-							to_install += target;
+						// handle local or absolute path
+						var file = File.new_for_path (target);
+						string? absolute_path = file.get_path ();
+						if (absolute_path != null) {
+							to_load += absolute_path;
 							found = true;
-						} else {
-							string[] groupnames = user_daemon.get_groups_names ();
-							if (target in groupnames) {
-								ask_group_confirmation (target);
-								found = true;
-							}
 						}
 					}
-					if (!found) {
-						print_error (dgettext (null, "target not found: %s").printf (target));
-						return;
+				} else {
+					var pkg = database.find_sync_satisfier (target);
+					if (pkg.name != "") {
+						to_install += target;
+						found = true;
+					} else {
+						string[] groupnames = database.get_groups_names ();
+						if (target in groupnames) {
+							ask_group_confirmation (target);
+							found = true;
+						}
 					}
 				}
-			} catch (Error e) {
-				print_error (e.message);
+				if (!found) {
+					print_error (dgettext (null, "target not found: %s").printf (target));
+					return;
+				}
 			}
 			if (to_install.length == 0 && to_load.length == 0) {
 				stdout.printf (dgettext (null, "Nothing to do") + ".\n");
 				return;
 			}
 			// do not install a package if it is already installed and up to date
-			transflags = (1 << 13); //Alpm.TransFlag.NEEDED
-			stdout.printf (dgettext (null, "Preparing") + "...\n");
-			this.hold ();
-			start_trans_prepare ();
+			transaction.flags = (1 << 13); //Alpm.TransFlag.NEEDED
+			try_lock_and_run (start_transaction);
 		}
 
 		void ask_group_confirmation (string grpname) {
-			try {
-				var pkgs = user_daemon.get_group_pkgs_sync (grpname);
-				// print pkgs
-				int name_length = 0;
-				int version_length = 0;
-				int repo_length = 0;
-				foreach (unowned AlpmPackage pkg in pkgs) {
-					if (pkg.name.length > name_length) {
-						name_length = pkg.name.length;
-					}
-					if (pkg.version.length > version_length) {
-						version_length = pkg.version.length;
-					}
-					if (pkg.repo.length > repo_length) {
-						repo_length = pkg.repo.length;
-					}
+			var pkgs = database.get_group_pkgs (grpname);
+			// print pkgs
+			int name_length = 0;
+			int version_length = 0;
+			int repo_length = 0;
+			foreach (unowned AlpmPackage pkg in pkgs) {
+				if (pkg.name.length > name_length) {
+					name_length = pkg.name.length;
 				}
-				int num_length = pkgs.length.to_string ().length + 1;
-				int total_width = num_length + name_length + version_length + repo_length + 4;
-				int margin = 0;
-				if (get_term_width () > total_width) {
-					// divide available space between columns
-					int available_width = get_term_width () - total_width;
-					margin = available_width / 3;
-					// get left space to repo
-					repo_length += available_width - (margin * 3);
+				if (pkg.version.length > version_length) {
+					version_length = pkg.version.length;
 				}
-				stdout.printf ("%s:\n".printf (dngettext (null, "There is %u member in group %s",
-							"There are %u members in group %s", pkgs.length).printf (pkgs.length, grpname)));
-				int num = 1;
-				foreach (unowned AlpmPackage pkg in pkgs) {
-					stdout.printf ("%*s %-*s %-*s %s \n", num_length, "%i:".printf (num),
-															name_length + margin, pkg.name,
-															version_length + margin, pkg.version,
-															pkg.repo);
-					num++;
-				}
-				// get user input
-				asking_user_input = true;
-				while (true) {
-					stdout.printf ("%s: ", dgettext (null, "Enter a selection (default=all)"));
-					string ans = stdin.read_line ();
-					int64 nb;
-					int64[] numbers = {};
-					// remvove trailing newline
-					ans = ans.replace ("\n", "");
-					// just return use default
-					if (ans == "") {
-						foreach (unowned AlpmPackage pkg in pkgs) {
-							to_install += pkg.name;
-						}
-						break;
-					} else {
-						// split ","
-						string[] splitted = ans.split (",");
-						foreach (unowned string part in splitted) {
-							// check for range
-							if ("-" in part) {
-								string[] splitted2 = part.split ("-", 2);
-								// get all numbers in range
-								int64 beg_num, end_num;
-								if (int64.try_parse (splitted2[0], out beg_num)) {
-									if (int64.try_parse (splitted2[1], out end_num)) {
-										nb = beg_num;
-										while (nb <= end_num) {
-											if (nb >= 1 && nb < pkgs.length) {
-												numbers += nb;
-											}
-											nb++;
+				if (pkg.repo.length > repo_length) {
+					repo_length = pkg.repo.length;
+				}
+			}
+			int num_length = pkgs.length.to_string ().length + 1;
+			int total_width = num_length + name_length + version_length + repo_length + 4;
+			int margin = 0;
+			if (transaction.get_term_width () > total_width) {
+				// divide available space between columns
+				int available_width = transaction.get_term_width () - total_width;
+				margin = available_width / 3;
+				// get left space to repo
+				repo_length += available_width - (margin * 3);
+			}
+			stdout.printf ("%s:\n".printf (dngettext (null, "There is %u member in group %s",
+						"There are %u members in group %s", pkgs.length).printf (pkgs.length, grpname)));
+			int num = 1;
+			foreach (unowned AlpmPackage pkg in pkgs) {
+				stdout.printf ("%*s %-*s %-*s %s \n", num_length, "%i:".printf (num),
+														name_length + margin, pkg.name,
+														version_length + margin, pkg.version,
+														pkg.repo);
+				num++;
+			}
+			// get user input
+			transaction.asking_user_input = true;
+			while (true) {
+				stdout.printf ("%s: ", dgettext (null, "Enter a selection (default=all)"));
+				string ans = stdin.read_line ();
+				int64 nb;
+				int64[] numbers = {};
+				// remvove trailing newline
+				ans = ans.replace ("\n", "");
+				// just return use default
+				if (ans == "") {
+					foreach (unowned AlpmPackage pkg in pkgs) {
+						to_install += pkg.name;
+					}
+					break;
+				} else {
+					// split ","
+					string[] splitted = ans.split (",");
+					foreach (unowned string part in splitted) {
+						// check for range
+						if ("-" in part) {
+							string[] splitted2 = part.split ("-", 2);
+							// get all numbers in range
+							int64 beg_num, end_num;
+							if (int64.try_parse (splitted2[0], out beg_num)) {
+								if (int64.try_parse (splitted2[1], out end_num)) {
+									nb = beg_num;
+									while (nb <= end_num) {
+										if (nb >= 1 && nb < pkgs.length) {
+											numbers += nb;
 										}
+										nb++;
 									}
 								}
-							} else if (int64.try_parse (part, out nb)) {
-								if (nb >= 1 && nb < pkgs.length) {
-									numbers += nb;
-								}
+							}
+						} else if (int64.try_parse (part, out nb)) {
+							if (nb >= 1 && nb < pkgs.length) {
+								numbers += nb;
 							}
 						}
 					}
-					stdout.printf ("\n");
-					if (numbers.length > 0) {
-						foreach (int64 number in numbers) {
-							to_install += pkgs[number -1].name;
-						}
-						break;
+				}
+				stdout.printf ("\n");
+				if (numbers.length > 0) {
+					foreach (int64 number in numbers) {
+						to_install += pkgs[number -1].name;
 					}
+					break;
 				}
-			} catch (Error e) {
-				print_error (e.message);
 			}
 		}
 
 		void reinstall_pkgs (string[] names) {
-			try {
-				foreach (unowned string name in names) {
-					bool found = false;
-					string version = "";
-					var local_pkg = user_daemon.get_installed_pkg (name);
-					if (local_pkg.name != "") {
-						version = local_pkg.version;
-						var sync_pkg = user_daemon.get_sync_pkg (name);
-						if (sync_pkg.name != "") {
-							if (local_pkg.version == sync_pkg.version) {
-								to_install += name;
-								found = true;
-							}
-						}
-					} else {
-						string[] groupnames = user_daemon.get_groups_names ();
-						if (name in groupnames) {
+			foreach (unowned string name in names) {
+				bool found = false;
+				string version = "";
+				var local_pkg = database.get_installed_pkg (name);
+				if (local_pkg.name != "") {
+					version = local_pkg.version;
+					var sync_pkg = database.get_sync_pkg (name);
+					if (sync_pkg.name != "") {
+						if (local_pkg.version == sync_pkg.version) {
+							to_install += name;
 							found = true;
-							var pkgs = user_daemon.get_group_pkgs_sync (name);
-							foreach (unowned AlpmPackage pkg in pkgs) {
-								if (pkg.version == pkg.installed_version) {
-									to_install += name;
-								}
-							}
 						}
 					}
-					if (!found) {
-						if (version == "") {
-							print_error (dgettext (null, "target not found: %s").printf (name));
-						} else {
-							print_error (dgettext (null, "target not found: %s").printf (name + "-" + version));
+				} else {
+					string[] groupnames = database.get_groups_names ();
+					if (name in groupnames) {
+						found = true;
+						var pkgs = database.get_group_pkgs (name);
+						foreach (unowned AlpmPackage pkg in pkgs) {
+							if (pkg.version == pkg.installed_version) {
+								to_install += name;
+							}
 						}
-						return;
 					}
 				}
-			} catch (Error e) {
-				print_error (e.message);
+				if (!found) {
+					if (version == "") {
+						print_error (dgettext (null, "target not found: %s").printf (name));
+					} else {
+						print_error (dgettext (null, "target not found: %s").printf (name + "-" + version));
+					}
+					return;
+				}
 			}
-			if (to_install.length == 0 && to_load.length == 0) {
+			if (to_install.length == 0) {
 				stdout.printf (dgettext (null, "Nothing to do") + ".\n");
 				return;
 			}
-			stdout.printf (dgettext (null, "Preparing") + "...\n");
-			this.hold ();
-			start_trans_prepare ();
+			try_lock_and_run (start_transaction);
 		}
 
 		void remove_pkgs (string[] names, bool recurse = false) {
 			bool group_found = false;
-			try {
-				foreach (unowned string name in names) {
-					bool found = false;
-					var local_pkg = user_daemon.get_installed_pkg (name);
-					if (local_pkg.name != "") {
-						to_remove += name;
+			foreach (unowned string name in names) {
+				bool found = false;
+				var local_pkg = database.get_installed_pkg (name);
+				if (local_pkg.name != "") {
+					to_remove += name;
+					found = true;
+				} else {
+					string[] groupnames = database.get_groups_names ();
+					if (name in groupnames) {
 						found = true;
-					} else {
-						string[] groupnames = user_daemon.get_groups_names ();
-						if (name in groupnames) {
-							found = true;
-							var pkgs = user_daemon.get_group_pkgs_sync (name);
-							foreach (unowned AlpmPackage pkg in pkgs) {
-								if (pkg.version == pkg.installed_version) {
-									to_remove += pkg.name;
-									group_found = true;
-								}
+						var pkgs = database.get_group_pkgs (name);
+						foreach (unowned AlpmPackage pkg in pkgs) {
+							if (pkg.version == pkg.installed_version) {
+								to_remove += pkg.name;
+								group_found = true;
 							}
 						}
 					}
-					if (!found) {
-						print_error (dgettext (null, "target not found: %s").printf (name));
-						return;
-					}
 				}
-			} catch (Error e) {
-				print_error (e.message);
+				if (!found) {
+					print_error (dgettext (null, "target not found: %s").printf (name));
+					return;
+				}
 			}
 			if (to_remove.length == 0) {
 				stdout.printf (dgettext (null, "Nothing to do") + ".\n");
 				return;
 			}
 			if (group_found) {
-				transflags |= (1 << 15); //Alpm.TransFlag.UNNEEDED
+				transaction.flags = (1 << 15); //Alpm.TransFlag.UNNEEDED
 			} else {
-				transflags |= (1 << 4); //Alpm.TransFlag.CASCADE
+				transaction.flags = (1 << 4); //Alpm.TransFlag.CASCADE
 			}
 			if (recurse) {
-				transflags |= (1 << 5); //Alpm.TransFlag.RECURSE
+				transaction.flags |= (1 << 5); //Alpm.TransFlag.RECURSE
 			}
-			stdout.printf (dgettext (null, "Preparing") + "...\n");
-			this.hold ();
-			start_trans_prepare ();
+			try_lock_and_run (start_transaction);
 		}
 
 		void remove_orphans () {
-			try {
-				var pkgs = user_daemon.get_orphans_sync ();
-				foreach (unowned AlpmPackage pkg in pkgs) {
-					to_remove += pkg.name;
-				}
-				stdout.printf (dgettext (null, "Preparing") + "...\n");
-				transflags = (1 << 4); //Alpm.TransFlag.CASCADE
-				transflags |= (1 << 5); //Alpm.TransFlag.RECURSE
-				this.hold ();
-				start_trans_prepare ();
-			} catch (Error e) {
-				print_error (e.message);
+			var pkgs = database.get_orphans ();
+			foreach (unowned AlpmPackage pkg in pkgs) {
+				to_remove += pkg.name;
 			}
+			transaction.flags = (1 << 4); //Alpm.TransFlag.CASCADE
+			transaction.flags |= (1 << 5); //Alpm.TransFlag.RECURSE
+			try_lock_and_run (start_transaction);
 		}
 
-		void start_get_updates_for_sysupgrade () {
-			if (!sysupgrade_after_trans) {
-				stdout.printf (dgettext (null, "Starting full system upgrade") + "...\n");
-			}
-			sysupgrade_after_trans = false;
-			system_daemon.get_updates_finished.connect (on_get_updates_for_sysupgrade_finished);
-			try {
-				system_daemon.start_get_updates (enable_aur);
-			} catch (Error e) {
-				print_error (e.message);
-				system_daemon.get_updates_finished.disconnect (on_get_updates_for_sysupgrade_finished);
-				this.release ();
-			}
+		void build_pkgs (string[] to_build) {
+			this.to_build = to_build;
+			try_lock_and_run (start_transaction);
 		}
 
-		void on_get_updates_for_sysupgrade_finished (Updates updates) {
-			system_daemon.get_updates_finished.disconnect (on_get_updates_for_sysupgrade_finished);
-			to_install_first = {};
-			// get syncfirst updates
-			if (updates.is_syncfirst) {
-				foreach (unowned AlpmPackage infos in updates.repos_updates) {
-					to_install_first += infos.name;
-				}
-				start_sysupgrade_prepare ();
-			} else {
-				if (updates.aur_updates.length != 0) {
-					string[] to_build = {};
-					foreach (unowned AURPackage infos in updates.aur_updates) {
-						if (!(infos.name in temporary_ignorepkgs)) {
-							to_build += infos.name;
-						}
-					}
-					if (updates.repos_updates.length != 0) {
-						start_sysupgrade_prepare (to_build);
-					} else {
-						// only aur updates
-						this.release ();
-						build_pkgs (to_build);
-					}
-				} else {
-					if (updates.repos_updates.length != 0) {
-						start_sysupgrade_prepare ();
-					} else {
-						stdout.printf (dgettext (null, "Nothing to do") + ".\n");
-						unlock ();
-						this.release ();
-					}
-				}
-			}
-		}
-
-		void build_pkgs (string[] to_build) {
-			this.to_build = to_build;
-			this.hold ();
-			start_trans_prepare ();
-		}
-
-		async void build_aur_packages () {
-			string pkgname = to_build_queue.pop_head ();
-			stdout.printf ("%s...\n", dgettext (null, "Building %s").printf (pkgname));
-			build_cancellable.reset ();
-			string [] built_pkgs = {};
-			int status = 1;
-			string builddir;
-			if (aur_build_dir == "/tmp") {
-				builddir = "/tmp/pamac-build-%s".printf (Environment.get_user_name ());
-			} else {
-				builddir = aur_build_dir;
-			}
-			status = yield spawn_cmdline ({"mkdir", "-p", builddir});
-			if (status == 0) {
-				status = yield spawn_cmdline ({"rm", "-rf", pkgname}, builddir);
-				if (!build_cancellable.is_cancelled ()) {
-					if (status == 0) {
-						building = true;
-						status = yield spawn_cmdline ({"git", "clone", "https://aur.archlinux.org/%s.git".printf (pkgname)}, builddir);
-						if (status == 0) {
-							string pkgdir = "%s/%s".printf (builddir, pkgname);
-							status = yield spawn_cmdline ({"makepkg", "-cf"}, pkgdir);
-							building = false;
-							if (status == 0) {
-								// get built pkgs path
-								var launcher = new SubprocessLauncher (SubprocessFlags.STDOUT_PIPE);
-								launcher.set_cwd (pkgdir);
-								try {
-									Subprocess process = launcher.spawnv ({"makepkg", "--packagelist"});
-									yield process.wait_async (null);
-									if (process.get_if_exited ()) {
-										status = process.get_exit_status ();
-									}
-									if (status == 0) {
-										var dis = new DataInputStream (process.get_stdout_pipe ());
-										string? line;
-										// Read lines until end of file (null) is reached
-										while ((line = dis.read_line ()) != null) {
-											var file = GLib.File.new_for_path (line);
-											string filename = file.get_basename ();
-											string name_version_release = filename.slice (0, filename.last_index_of_char ('-'));
-											string name_version = name_version_release.slice (0, name_version_release.last_index_of_char ('-'));
-											string name = name_version.slice (0, name_version.last_index_of_char ('-'));
-											if (name in aur_pkgs_to_install) {
-												if (!(line in built_pkgs)) {
-													built_pkgs += line;
-												}
-											}
-										}
-									}
-								} catch (Error e) {
-									print_error (e.message);
-								}
-							}
-						}
-					}
-				} else {
-					status = 1;
-				}
-			}
-			if (status == 0 && built_pkgs.length > 0) {
-				no_confirm_commit = true;
-				stdout.printf ("\n");
-				to_build = {};
-				to_install = {};
-				to_load = built_pkgs;
-				start_trans_prepare ();
-			} else {
-				on_trans_commit_finished (false);
-			}
-		}
-
-		async int spawn_cmdline (string[] args, string? working_directory = null) {
-			int status = 1;
-			var launcher = new SubprocessLauncher (SubprocessFlags.NONE);
-			launcher.set_cwd (working_directory);
-			launcher.set_environ (Environ.get ());
-			try {
-				Subprocess process = launcher.spawnv (args);
-				try {
-					yield process.wait_async (build_cancellable);
-					if (process.get_if_exited ()) {
-						status = process.get_exit_status ();
-					}
-				} catch (Error e) {
-					// cancelled
-					process.send_signal (Posix.Signal.INT);
-					process.send_signal (Posix.Signal.KILL);
-				}
-			} catch (Error e) {
-				print_error (e.message);
-			}
-			return status;
-		}
-
-		bool get_lock () {
-			bool locked = false;
-			connecting_system_daemon ();
-			try {
-				locked = system_daemon.get_lock ();
-			} catch (Error e) {
-				print_error (e.message);
-			}
-			return locked;
-		}
-
-		void unlock () {
-			try {
-				system_daemon.unlock ();
-			} catch (Error e) {
-				print_error (e.message);
-			}
-		}
-
-		async bool check_authorization () {
-			SourceFunc callback = check_authorization.callback;
-			bool authorized = false;
-			ulong handler_id = system_daemon.get_authorization_finished.connect ((authorized_) => {
-				authorized = authorized_;
-				Idle.add ((owned) callback);
-			});
-			try {
-				system_daemon.start_get_authorization ();
-			} catch (Error e) {
-				print_error (e.message);
-			}
-			yield;
-			system_daemon.disconnect (handler_id);
-			return authorized;
-		}
-
-		void start_refresh () {
-			this.hold ();
-			if (get_lock ()) {
-				// let's time to pkttyagent to get registred
-				Timeout.add (200, () => {
-					check_authorization.begin ((obj, res) => {
-						bool authorized = check_authorization.end (res);
-						if (authorized) {
-							stdout.printf ("%s...\n", dgettext (null, "Synchronizing package databases"));
-							try {
-								system_daemon.refresh_finished.connect (on_refresh_finished);
-								system_daemon.start_refresh (force_refresh);
-							} catch (Error e) {
-								print_error (e.message);
-								system_daemon.refresh_finished.disconnect (on_refresh_finished);
-							}
-						} else {
-							unlock ();
-							this.release ();
-							cmd.set_exit_status (1);
-						}
-					});
-					return false;
-				});
-			} else {
-				stdout.printf (dgettext (null, "Waiting for another package manager to quit") + "...\n");
-				Timeout.add (5000, () => {
-					bool locked = get_lock ();
-					if (locked) {
-						check_authorization.begin ((obj, res) => {
-							bool authorized = check_authorization.end (res);
-							if (authorized) {
-								stdout.printf ("%s...\n", dgettext (null, "Synchronizing package databases"));
-								try {
-									system_daemon.refresh_finished.connect (on_refresh_finished);
-									system_daemon.start_refresh (force_refresh);
-								} catch (Error e) {
-									print_error (e.message);
-									system_daemon.refresh_finished.disconnect (on_refresh_finished);
-								}
-							} else {
-								unlock ();
-								this.release ();
-								cmd.set_exit_status (1);
-							}
-						});
-					}
-					return !locked;
-				});
-			}
-		}
-
-		void on_refresh_finished (bool success) {
-			previous_filename = "";
-			system_daemon.refresh_finished.disconnect (on_refresh_finished);
-			if (success) {
-				start_get_updates_for_sysupgrade ();
-			} else {
-				unlock ();
-				this.release ();
-				cmd.set_exit_status (1);
-			}
-		}
-
-		void start_trans_prepare () {
-			if (get_lock ()) {
-				try {
-					system_daemon.start_trans_prepare (transflags, to_install, to_remove, to_load, to_build, overwrite_files);
-				} catch (Error e) {
-					print_error (e.message);
-					on_trans_prepare_finished (false);
-				}
+		void start_transaction () {
+			this.hold ();
+			transaction.start (to_install, to_remove, to_load, to_build, overwrite_files);
+		}
+
+		void try_lock_and_run (TransactionAction action) {
+			if (transaction.get_lock ()) {
+				action ();
 			} else {
 				stdout.printf (dgettext (null, "Waiting for another package manager to quit") + "...\n");
+				this.hold ();
 				Timeout.add (5000, () => {
-					bool locked = get_lock ();
+					bool locked = transaction.get_lock ();
 					if (locked) {
-						try {
-							system_daemon.start_trans_prepare (transflags, to_install, to_remove, to_load, to_build, overwrite_files);
-						} catch (Error e) {
-							print_error (e.message);
-						}
+						this.release ();
+						action ();
 					}
 					return !locked;
 				});
 			}
 		}
 
-		void start_sysupgrade_prepare (string[] to_build = {}) {
-			try {
-				// this will respond with on_trans_prepare_finished signal
-				system_daemon.start_sysupgrade_prepare (false, temporary_ignorepkgs, to_build, overwrite_files);
-			} catch (Error e) {
-				print_error (e.message);
-				on_trans_prepare_finished (false);
-			}
-		}
-
-		TransType set_transaction_sum () {
-			// return 0 if transaction_sum is empty, 2, if there are only aur updates, 1 otherwise
-			TransType type = 0;
-			uint64 dsize = 0;
-			uint64 rsize = 0;
-			int64 isize = 0;
-			int max_name_length = 0;
-			int max_version_length = 0;
-			int max_installed_version_length = 0;
-			int max_size_length = 0;
-			int margin = 0;
-			var summary = TransactionSummary ();
-			try {
-				summary = system_daemon.get_transaction_summary ();
-			} catch (Error e) {
-				print_error (e.message);
-			}
-			// first pass to compute trans type, pkgs size and strings length
-			if (summary.to_remove.length > 0) {
-				type |= TransType.STANDARD;
-				if (!no_confirm_commit) {
-					foreach (unowned AlpmPackage infos in summary.to_remove) {
-						rsize += infos.size;
-						if (infos.name.length > max_name_length) {
-							max_name_length = infos.name.length;
-						}
-						if (infos.version.length > max_version_length) {
-							max_version_length = infos.version.length;
-						}
-					}
-				}
-			}
-			if (summary.aur_conflicts_to_remove.length > 0) {
-				if (!no_confirm_commit) {
-					// do not add type enum because it is just infos
-					foreach (unowned AlpmPackage infos in summary.aur_conflicts_to_remove) {
-						rsize += infos.size;
-						if (infos.name.length > max_name_length) {
-							max_name_length = infos.name.length;
-						}
-						if (infos.version.length > max_version_length) {
-							max_version_length = infos.version.length;
-						}
-					}
-				}
-			}
-			if (summary.to_downgrade.length > 0) {
-				type |= TransType.STANDARD;
-				if (!no_confirm_commit) {
-					foreach (unowned AlpmPackage infos in summary.to_downgrade) {
-						dsize += infos.download_size;
-						var pkg = get_installed_pkg (infos.name);
-						isize += ((int64) infos.size - (int64) pkg.size);
-						if (infos.name.length > max_name_length) {
-							max_name_length = infos.name.length;
-						}
-						if (infos.version.length > max_version_length) {
-							max_version_length = infos.version.length;
-						}
-						if (infos.installed_version.length > max_installed_version_length) {
-							max_installed_version_length = infos.installed_version.length;
-						}
-						string size = format_size (pkg.size);
-						if (size.length > max_size_length) {
-							max_size_length = size.length;
-						}
-					}
-				}
-			}
-			if (summary.to_build.length > 0) {
-				type |= TransType.BUILD;
-				// populate build queue
-				foreach (unowned string name in summary.aur_pkgbases_to_build) {
-					to_build_queue.push_tail (name);
-				}
-				aur_pkgs_to_install = {};
-				foreach (unowned AURPackage infos in summary.to_build) {
-					aur_pkgs_to_install += infos.name;
-					if (!no_confirm_commit) {
-						if (infos.name.length > max_name_length) {
-							max_name_length = infos.name.length;
-						}
-						if (infos.version.length > max_version_length) {
-							max_version_length = infos.version.length;
-						}
-					}
-				}
-			}
-			if (summary.to_install.length > 0) {
-				type |= TransType.STANDARD;
-				if (!no_confirm_commit) {
-					foreach (unowned AlpmPackage infos in summary.to_install) {
-						dsize += infos.download_size;
-						var pkg = get_installed_pkg (infos.name);
-						isize += ((int64) infos.size - (int64) pkg.size);
-						if (infos.name.length > max_name_length) {
-							max_name_length = infos.name.length;
-						}
-						if (infos.version.length > max_version_length) {
-							max_version_length = infos.version.length;
-						}
-						string size = format_size (pkg.size);
-						if (size.length > max_size_length) {
-							max_size_length = size.length;
-						}
-					}
-				}
-			}
-			if (summary.to_reinstall.length > 0) {
-				type |= TransType.STANDARD;
-				if (!no_confirm_commit) {
-					foreach (unowned AlpmPackage infos in summary.to_reinstall) {
-						dsize += infos.download_size;
-						var pkg = get_installed_pkg (infos.name);
-						if (infos.name.length > max_name_length) {
-							max_name_length = infos.name.length;
-						}
-						if (infos.version.length > max_version_length) {
-							max_version_length = infos.version.length;
-						}
-						string size = format_size (pkg.size);
-						if (size.length > max_size_length) {
-							max_size_length = size.length;
-						}
-					}
-				}
-			}
-			if (summary.to_upgrade.length > 0) {
-				type |= TransType.UPDATE;
-				if (!no_confirm_commit) {
-					foreach (unowned AlpmPackage infos in summary.to_upgrade) {
-						dsize += infos.download_size;
-						var pkg = get_installed_pkg (infos.name);
-						isize += ((int64) infos.size - (int64) pkg.size);
-						if (infos.name.length > max_name_length) {
-							max_name_length = infos.name.length;
-						}
-						if (infos.version.length > max_version_length) {
-							max_version_length = infos.version.length;
-						}
-						if (infos.installed_version.length > max_installed_version_length) {
-							max_installed_version_length = infos.installed_version.length;
-						}
-						string size = format_size (pkg.size);
-						if (size.length > max_size_length) {
-							max_size_length = size.length;
-						}
-					}
-				}
-			}
-			// second pass to print details
-			if (!no_confirm_commit) {
-				max_installed_version_length += 2; // because of (%s)
-				int total_width = max_name_length + max_version_length + max_installed_version_length + max_size_length + 6;
-				if (get_term_width () > total_width) {
-					// divide available space between columns
-					int available_width = get_term_width () - total_width;
-					margin = available_width / 4;
-					// get left space to size
-					max_size_length += available_width - (margin * 4);
-				}
-				if (summary.to_upgrade.length > 0) {
-					stdout.printf (dgettext (null, "To upgrade") + " (%u):\n".printf (summary.to_upgrade.length));
-					foreach (unowned AlpmPackage infos in summary.to_upgrade) {
-						stdout.printf ("  %-*s %-*s %-*s %*s \n", max_name_length + margin, infos.name,
-															max_version_length + margin, infos.version,
-															max_installed_version_length + margin, "(%s)".printf (infos.installed_version),
-															max_size_length + margin, format_size (infos.size));
-					}
-				}
-				if (summary.to_reinstall.length > 0) {
-					stdout.printf (dgettext (null, "To reinstall") + " (%u):\n".printf (summary.to_reinstall.length));
-					foreach (unowned AlpmPackage infos in summary.to_reinstall) {
-						stdout.printf ("  %-*s %-*s %*s \n", max_name_length + margin, infos.name,
-															max_version_length + margin, infos.version,
-															max_size_length + margin, format_size (infos.size));
-					}
-				}
-				if (summary.to_install.length > 0) {
-					stdout.printf (dgettext (null, "To install") + " (%u):\n".printf (summary.to_install.length));
-					foreach (unowned AlpmPackage infos in summary.to_install) {
-						stdout.printf ("  %-*s %-*s %*s \n", max_name_length + margin, infos.name,
-															max_version_length + margin, infos.version,
-															max_size_length + margin, format_size (infos.size));
-					}
-				}
-				if (summary.to_build.length > 0) {
-					stdout.printf (dgettext (null, "To build") + " (%u):\n".printf (summary.to_build.length));
-					foreach (unowned AURPackage infos in summary.to_build) {
-						stdout.printf ("  %-*s %-*s\n", max_name_length + margin, infos.name,
-														max_version_length + margin, infos.version);
-					}
-				}
-				if (summary.to_downgrade.length > 0) {
-					stdout.printf (dgettext (null, "To downgrade") + " (%u):\n".printf (summary.to_downgrade.length));
-					foreach (unowned AlpmPackage infos in summary.to_downgrade) {
-						stdout.printf ("  %-*s %-*s %-*s %*s \n", max_name_length + margin, infos.name,
-															max_version_length + margin, infos.version,
-															max_installed_version_length + margin, "(%s)".printf (infos.installed_version),
-															max_size_length + margin, format_size (infos.size));
-					}
-				}
-				bool to_remove_printed = false;
-				if (summary.to_remove.length > 0) {
-					stdout.printf (dgettext (null, "To remove") + " (%u):\n".printf (summary.to_remove.length));
-					to_remove_printed = true;
-					foreach (unowned AlpmPackage infos in summary.to_remove) {
-						stdout.printf ("  %-*s %-*s\n", max_name_length + margin, infos.name,
-														max_version_length + margin, infos.version);
-					}
-				}
-				if (summary.aur_conflicts_to_remove.length > 0) {
-					if (!to_remove_printed) {
-						stdout.printf (dgettext (null, "To remove") + " (%u):\n".printf (summary.aur_conflicts_to_remove.length));
-					}
-					foreach (unowned AlpmPackage infos in summary.aur_conflicts_to_remove) {
-						stdout.printf ("  %-*s %-*s\n", max_name_length + margin, infos.name,
-														max_version_length + margin, infos.version);
-					}
-				}
-				stdout.printf ("\n");
-				if (dsize > 0) {
-					stdout.printf ("%s: %s\n", dgettext (null, "Total download size"), format_size (dsize));
-				}
-				if (isize > 0) {
-					stdout.printf ("%s: %s\n", dgettext (null, "Total installed size"), format_size (isize));
-				} else if (isize < 0) {
-					stdout.printf ("%s: -%s\n", dgettext (null, "Total installed size"), format_size (isize.abs ()));
-				}
-				if (rsize > 0) {
-					stdout.printf ("%s: %s\n", dgettext (null, "Total removed size"), format_size (rsize));
-				}
-			}
-			return type;
+		void start_refresh () {
+			this.hold ();
+			// let's time to pkttyagent to get registred
+			Timeout.add (200, () => {
+				transaction.start_refresh (force_refresh);
+				return false;
+			});
 		}
 
-		void on_trans_prepare_finished (bool success) {
+		void on_refresh_finished (bool success) {
 			if (success) {
-				TransType type = set_transaction_sum ();
-				if (to_install_first.length != 0) {
-					if (ask_confirmation ()) {
-						sysupgrade_after_trans = true;
-						no_confirm_commit = true;
-						trans_release ();
-						to_install = to_install_first;
-						start_trans_prepare ();
-						to_install_first = {};
-					} else {
-						stdout.printf (dgettext (null, "Transaction cancelled") + ".\n");
-						trans_release ();
-						unlock ();
-						this.release ();
-						cmd.set_exit_status (1);
-					}
-				} else if (no_confirm_commit) {
-					// no_confirm_commit or only updates
-					start_trans_commit ();
-				} else if (type != 0) {
-					if (ask_confirmation ()) {
-						if (type == Type.BUILD) {
-							// there only AUR packages to build
-							trans_release ();
-							on_trans_commit_finished (true);
-						} else {
-							start_trans_commit ();
-						}
-					} else {
-						stdout.printf (dgettext (null, "Transaction cancelled") + ".\n");
-						trans_release ();
-						unlock ();
-						this.release ();
-						cmd.set_exit_status (1);
-					}
-				} else {
-					stdout.printf (dgettext (null, "Nothing to do") + ".\n");
-					trans_release ();
-					unlock ();
-					this.release ();
-				}
+				transaction.start_sysupgrade (enable_downgrade, temporary_ignorepkgs, overwrite_files);
 			} else {
-				var err = get_current_error ();
-				if (err.message != "") {
-					print_error (err.message, err.details);
-				}
-				unlock ();
+				transaction.unlock ();
 				this.release ();
 				cmd.set_exit_status (1);
 			}
 		}
 
-		bool ask_confirmation () {
-			stdout.printf ("%s ? %s ", dgettext (null, "Commit transaction"), dgettext (null, "[y/N]"));
-			char buf[32];
-			if (stdin.gets (buf) != null) {
-				string ans = (string) buf;
-				// remove trailing newline and uppercase
-				ans = ans.replace ("\n", "").down ();
-				// just return use default
-				if (ans != "") {
-					if (ans == dgettext (null, "y") ||
-						ans == dgettext (null, "yes")) {
-						return true;
-					}
-				}
-			}
-			return false;
-		}
-
-		void start_trans_commit () {
-			try {
-				asking_user_input = true;
-				system_daemon.start_trans_commit ();
-			} catch (Error e) {
-				print_error (e.message);
-				on_trans_commit_finished (false);
-			}
-		}
-
-		void on_trans_commit_finished (bool success) {
-			asking_user_input = false;
-			// needed before build_aur_packages
-			no_confirm_commit = false;
-			if (success) {
-				if (to_build_queue.get_length () != 0) {
-					stdout.printf ("\n");
-					check_authorization.begin ((obj, res) => {
-						bool authorized = check_authorization.end (res);
-						if (authorized) {
-							build_aur_packages.begin ();
-						} else {
-							to_build_queue.clear ();
-							on_trans_commit_finished (false);
-						}
-					});
-				} else {
-					if (sysupgrade_after_trans) {
-						no_confirm_commit = true;
-						start_get_updates_for_sysupgrade ();
-					} else {
-						stdout.printf (dgettext (null, "Transaction successfully finished") + ".\n");
-						unlock ();
-						this.release ();
-					}
-				}
-			} else {
-				var err = get_current_error ();
-				if (err.message != "") {
-					print_error (err.message, err.details);
-				}
-				to_build_queue.clear ();
-				unlock ();
-				this.release ();
+		void on_transaction_finished (bool success) {
+			transaction.unlock ();
+			this.release ();
+			if (!success) {
 				cmd.set_exit_status (1);
 			}
-			total_download = 0;
-			already_downloaded = 0;
-			previous_filename = "";
-		}
-
-		void trans_release () {
-			try {
-				system_daemon.trans_release ();
-			} catch (Error e) {
-				print_error (e.message);
-			}
-		}
-
-		ErrorInfos get_current_error () {
-			try {
-				return system_daemon.get_current_error ();
-			} catch (Error e) {
-				print_error (e.message);
-				return ErrorInfos ();
-			}
-		}
-
-		void on_emit_event (uint primary_event, uint secondary_event, string[] details) {
-			string? action = null;
-			switch (primary_event) {
-				case 1: //Alpm.Event.Type.CHECKDEPS_START
-					action = dgettext (null, "Checking dependencies") + "...\n";
-					asking_user_input = false;
-					break;
-				case 3: //Alpm.Event.Type.FILECONFLICTS_START
-					current_action = dgettext (null, "Checking file conflicts") + "...";
-					break;
-				case 5: //Alpm.Event.Type.RESOLVEDEPS_START
-					action = dgettext (null, "Resolving dependencies") + "...\n";
-					asking_user_input = false;
-					break;
-				case 7: //Alpm.Event.Type.INTERCONFLICTS_START
-					action = dgettext (null, "Checking inter-conflicts") + "...\n";
-					break;
-				case 11: //Alpm.Event.Type.PACKAGE_OPERATION_START
-					switch (secondary_event) {
-						// special case handle differently
-						case 1: //Alpm.Package.Operation.INSTALL
-							previous_filename = details[0];
-							current_action = dgettext (null, "Installing %s").printf ("%s (%s)".printf (details[0], details[1])) + "...";
-							break;
-						case 2: //Alpm.Package.Operation.UPGRADE
-							previous_filename = details[0];
-							current_action = dgettext (null, "Upgrading %s").printf ("%s (%s -> %s)".printf (details[0], details[1], details[2])) + "...";
-							break;
-						case 3: //Alpm.Package.Operation.REINSTALL
-							previous_filename = details[0];
-							current_action = dgettext (null, "Reinstalling %s").printf ("%s (%s)".printf (details[0], details[1])) + "...";
-							break;
-						case 4: //Alpm.Package.Operation.DOWNGRADE
-							previous_filename = details[0];
-							current_action = dgettext (null, "Downgrading %s").printf ("%s (%s -> %s)".printf (details[0], details[1], details[2])) + "...";
-							break;
-						case 5: //Alpm.Package.Operation.REMOVE
-							previous_filename = details[0];
-							current_action = dgettext (null, "Removing %s").printf ("%s (%s)".printf (details[0], details[1])) + "...";
-							break;
-					}
-					break;
-				case 13: //Alpm.Event.Type.INTEGRITY_START
-					current_action = dgettext (null, "Checking integrity") + "...";
-					break;
-				case 15: //Alpm.Event.Type.LOAD_START
-					current_action = dgettext (null, "Loading packages files") + "...";
-					break;
-				case 17: //Alpm.Event.Type.DELTA_INTEGRITY_START
-					action = dgettext (null, "Checking delta integrity") + "...\n";
-					break;
-				case 19: //Alpm.Event.Type.DELTA_PATCHES_START
-					action = dgettext (null, "Applying deltas") + "...\n";
-					break;
-				case 21: //Alpm.Event.Type.DELTA_PATCH_START
-					action = dgettext (null, "Generating %s with %s").printf (details[0], details[1]) + "...\n";
-					break;
-				case 22: //Alpm.Event.Type.DELTA_PATCH_DONE
-					action = dgettext (null, "Generation succeeded") + "...\n";
-					break;
-				case 23: //Alpm.Event.Type.DELTA_PATCH_FAILED
-					action = dgettext (null, "Generation failed") + "...\n";
-					break;
-				case 24: //Alpm.Event.Type.SCRIPTLET_INFO
-					// hooks output are also emitted as SCRIPTLET_INFO
-					//if (previous_filename != "") {
-						//stdout.printf (dgettext (null, "Configuring %s").printf (previous_filename) + "...\n");
-					//}
-					foreach (unowned string detail in split_string (details[0].replace ("\n", ""), 0, get_term_width ())) {
-						stdout.printf ("%s\n", detail);
-					}
-					break;
-				case 25: //Alpm.Event.Type.RETRIEVE_START
-					action = dgettext (null, "Downloading") + "...\n";
-					asking_user_input = false;
-					break;
-				case 26: //Alpm.Event.Type.RETRIEVE_DONE
-				case 27: //Alpm.Event.Type.RETRIEVE_FAILED
-					stdout.printf ("\n");
-					break;
-				case 28: //Alpm.Event.Type.PKGDOWNLOAD_START
-					// special case handle differently
-					string name_version_release = details[0].slice (0, details[0].last_index_of_char ('-'));
-					current_action = dgettext (null, "Downloading %s").printf (name_version_release) + "...";
-					break;
-				case 31: //Alpm.Event.Type.DISKSPACE_START
-					current_action = dgettext (null, "Checking available disk space") + "...";
-					break;
-				case 33: //Alpm.Event.Type.OPTDEP_REMOVAL
-					action =  dgettext (null, "Warning") + ": " + dgettext (null, "%s optionally requires %s").printf (details[0], details[1]) + "\n";
-					break;
-				case 34: //Alpm.Event.Type.DATABASE_MISSING
-					action = dgettext (null, "Database file for %s does not exist").printf (details[0]) + "\n";
-					break;
-				case 35: //Alpm.Event.Type.KEYRING_START
-					current_action = dgettext (null, "Checking keyring") + "...";
-					break;
-				case 37: //Alpm.Event.Type.KEY_DOWNLOAD_START
-					action = dgettext (null, "Downloading required keys") + "...\n";
-					break;
-				case 39: //Alpm.Event.Type.PACNEW_CREATED
-					action = dgettext (null, "%s installed as %s.pacnew").printf (details[0], details[0]) + "\n";
-					break;
-				case 40: //Alpm.Event.Type.PACSAVE_CREATED
-					action = dgettext (null, "%s installed as %s.pacsave").printf (details[0], details[0]) + "\n";
-					break;
-				case 41: //Alpm.Event.Type.HOOK_START
-					switch (secondary_event) {
-						case 1: //Alpm.HookWhen.PRE_TRANSACTION
-							action = dgettext (null, "Running pre-transaction hooks") + ":\n";
-							break;
-						case 2: //Alpm.HookWhen.POST_TRANSACTION
-							previous_filename = "";
-							action = dgettext (null, "Running post-transaction hooks") + ":\n";
-							break;
-						default:
-							break;
-					}
-					break;
-				case 43: // Alpm.Event.Type.HOOK_RUN_START
-					if (details[1] != "") {
-						print_progress (details[1], "[%s/%s]".printf (details[2], details[3]), true);
-					} else {
-						print_progress (details[0], "[%s/%s]".printf (details[2], details[3]), true);
-					}
-					break;
-				default:
-					break;
-			}
-			if (action != null) {
-				stdout.printf (action);
-			}
-		}
-
-		void on_emit_providers (string depend, string[] providers) {
-			AlpmPackage[] pkgs = {};
-			foreach (unowned string pkgname in providers) {
-				try {
-					var pkg = user_daemon.get_sync_pkg (pkgname);
-					if (pkg.name != "")  {
-						pkgs += pkg;
-					}
-				} catch (Error e) {
-					print_error (e.message);
-				}
-			}
-			// print pkgs
-			int name_length = 0;
-			int version_length = 0;
-			int repo_length = 0;
-			foreach (unowned AlpmPackage pkg in pkgs) {
-				if (pkg.name.length > name_length) {
-					name_length = pkg.name.length;
-				}
-				if (pkg.version.length > version_length) {
-					version_length = pkg.version.length;
-				}
-				if (pkg.repo.length > repo_length) {
-					repo_length = pkg.repo.length;
-				}
-			}
-			int num_length = providers.length.to_string ().length + 1;
-			int total_width = num_length + name_length + version_length + repo_length + 4;
-			int margin = 0;
-			if (get_term_width () > total_width) {
-				// divide available space between columns
-				int available_width = get_term_width () - total_width;
-				margin = available_width / 3;
-				// get left space to repo
-				repo_length += available_width - (margin * 3);
-			}
-			stdout.printf ("%s:\n".printf (dgettext (null, "Choose a provider for %s").printf (depend)));
-			int num = 1;
-			foreach (unowned AlpmPackage pkg in pkgs) {
-				stdout.printf ("%*s %-*s %-*s %-*s \n", num_length, "%i:".printf (num),
-														name_length + margin, pkg.name,
-														version_length + margin, pkg.version,
-														repo_length + margin, pkg.repo);
-				num++;
-			}
-			// get user input
-			asking_user_input = true;
-			while (true) {
-				stdout.printf ("%s: ", dgettext (null, "Enter a number (default=%d)").printf (1));
-				string ans = stdin.read_line  ();
-				int64 nb;
-				// remvove trailing newline
-				ans = ans.replace ("\n", "");
-				// just return use default
-				if (ans == "") {
-					nb = 1;
-				} else if (!int64.try_parse (ans, out nb)) {
-					nb = 0;
-				}
-				stdout.printf ("\n");
-				if (nb >= 1 && nb <= providers.length) {
-					int index = (int) nb - 1;
-					try {
-						system_daemon.choose_provider (index);
-					} catch (Error e) {
-						print_error (e.message);
-					}
-					break;
-				}
-			}
-		}
-
-		void on_emit_progress (uint progress, string pkgname, uint percent, uint n_targets, uint current_target) {
-			switch (progress) {
-				case 0: //Alpm.Progress.ADD_START
-				case 1: //Alpm.Progress.UPGRADE_START
-				case 2: //Alpm.Progress.DOWNGRADE_START
-				case 3: //Alpm.Progress.REINSTALL_START
-				case 4: //Alpm.Progress.REMOVE_START
-				case 5: //Alpm.Progress.CONFLICTS_START
-				case 6: //Alpm.Progress.DISKSPACE_START
-				case 7: //Alpm.Progress.INTEGRITY_START
-				case 8: //Alpm.Progress.LOAD_START
-				case 9: //Alpm.Progress.KEYRING_START
-					if (current_action == previous_action) {
-						if (percent != previous_percent) {
-							previous_percent = percent;
-							if (percent != 100) {
-								print_progress (current_action, "[%u/%u]".printf (current_target, n_targets), false);
-							} else {
-								print_progress (current_action, "[%u/%u]".printf (current_target, n_targets), true);
-							}
-						}
-					} else {
-						previous_action = current_action;
-						previous_percent = percent;
-						if (percent != 100) {
-							print_progress (current_action, "[%u/%u]".printf (current_target, n_targets), false);
-						} else {
-							print_progress (current_action, "[%u/%u]".printf (current_target, n_targets), true);
-						}
-					}
-					break;
-				default:
-					break;
-			}
-		}
-
-		void on_emit_download (string filename, uint64 xfered, uint64 total) {
-			var text = new StringBuilder ();
-			float fraction;
-			if (total_download > 0) {
-				if (xfered == 0) {
-					// start download pkg is handled by Alpm.Event.Type.PKGDOWNLOAD_START
-					previous_xfered = 0;
-					fraction = previous_percent;
-					text.append (previous_textbar);
-					timer.start ();
-				} else {
-					if (timer.elapsed () > 0.1) {
-						download_rate = ((download_rate * rates_nb) + (uint64) ((xfered - previous_xfered) / timer.elapsed ())) / (rates_nb + 1);
-						rates_nb++;
-					}
-					previous_xfered = xfered;
-					uint64 downloaded_total = xfered + already_downloaded;
-					fraction = (float) downloaded_total / total_download;
-					if (fraction <= 1) {
-						text.append ("%s/%s  ".printf (format_size (xfered + already_downloaded), format_size (total_download)));
-						uint64 remaining_seconds = 0;
-						if (download_rate > 0) {
-							remaining_seconds = (total_download - downloaded_total) / download_rate;
-						}
-						// display remaining time after 5s and only if more than 10s are remaining
-						if (remaining_seconds > 9 && rates_nb > 9) {
-							if (remaining_seconds <= 50) {
-								text.append (dgettext (null, "About %u seconds remaining").printf ((uint) Math.ceilf ((float) remaining_seconds / 10) * 10));
-							} else {
-								uint remaining_minutes = (uint) Math.ceilf ((float) remaining_seconds / 60);
-								text.append (dngettext (null, "About %lu minute remaining",
-											"About %lu minutes remaining", remaining_minutes).printf (remaining_minutes));
-							}
-						}
-					} else {
-						text.append ("%s".printf (format_size (xfered + already_downloaded)));
-					}
-					if (xfered == total) {
-						previous_filename = "";
-						already_downloaded += total;
-					} else {
-						timer.start ();
-					}
-				}
-			} else {
-				if (xfered == 0) {
-					previous_xfered = 0;
-					download_rate = 0;
-					rates_nb = 0;
-					fraction = 0;
-					timer.start ();
-					if (filename.has_suffix (".db") || filename.has_suffix (".files")) {
-						current_action = dgettext (null, "Refreshing %s").printf (filename) + "...";
-					} else {
-						// case of download pkg from url start
-						string name_version_release = filename.slice (0, filename.last_index_of_char ('-'));
-						current_action = dgettext (null, "Downloading %s").printf (name_version_release) + "...";
-					}
-				} else if (xfered == total) {
-					timer.stop ();
-					fraction = 1;
-					previous_filename = "";
-				} else {
-					if (timer.elapsed () > 0.1) {
-						download_rate = ((download_rate * rates_nb) + (uint64) ((xfered - previous_xfered) / timer.elapsed ())) / (rates_nb + 1);
-						rates_nb++;
-					}
-					previous_xfered = xfered;
-					fraction = (float) xfered / total;
-					if (fraction <= 1) {
-						text.append ("%s/%s  ".printf (format_size (xfered), format_size (total)));
-						uint64 remaining_seconds = 0;
-						if (download_rate > 0) {
-							remaining_seconds = (total - xfered) / download_rate;
-						}
-						// display remaining time after 5s and only if more than 10s are remaining
-						if (remaining_seconds > 9 && rates_nb > 9) {
-							if (remaining_seconds <= 50) {
-								text.append (dgettext (null, "About %u seconds remaining").printf ((uint) Math.ceilf ((float) remaining_seconds / 10) * 10));
-							} else {
-								uint remaining_minutes = (uint) Math.ceilf ((float) remaining_seconds / 60);
-								text.append (dngettext (null, "About %lu minute remaining",
-											"About %lu minutes remaining", remaining_minutes).printf (remaining_minutes));
-							}
-						}
-					} else {
-						text.append ("%s".printf (format_size (xfered)));
-					}
-					// reinitialize timer
-					timer.start ();
-				}
-			}
-			if (current_action == previous_action) {
-				previous_textbar = text.str;
-				// clean line
-				stdout.printf ("\r%*s", get_term_width (), "");
-				stdout.printf ("\r%s", text.str);
-				stdout.flush ();
-			} else {
-				previous_action = current_action;
-				// clean line
-				stdout.printf ("\r%*s", get_term_width (), "");
-				stdout.printf ("\r%s\n", current_action);
-				stdout.printf (text.str);
-				stdout.flush ();
-			}
-		}
-
-		void on_emit_totaldownload (uint64 total) {
-			download_rate = 0;
-			rates_nb = 0;
-			previous_percent = 0;
-			previous_textbar = "";
-			total_download = total;
-			// this is emitted at the end of the total download
-			// with the value 0 so stop our timer
-			if (total == 0) {
-				timer.stop ();
-			}
-		}
-
-		void on_emit_log (uint level, string msg) {
-			// msg ends with \n
-			string? line = null;
-			if (level == 1) { //Alpm.LogLevel.ERROR
-				if (previous_filename != "") {
-					line = dgettext (null, "Error") + ": " + previous_filename + ": " + msg;
-				} else {
-					line = dgettext (null, "Error") + ": " + msg;
-				}
-			} else if (level == (1 << 1)) { //Alpm.LogLevel.WARNING
-				// do not show warning when manjaro-system remove db.lck
-				if (previous_filename != "manjaro-system") {
-					if (previous_filename != "") {
-						line = dgettext (null, "Warning") + ": " + previous_filename + ": " + msg;
-					} else {
-						line = dgettext (null, "Warning") + ": " + msg;
-					}
-				}
-			}
-			if (line != null) {
-				// keep a nice output in case of download
-				stdout.printf ("\r%s", line);
-				stdout.printf (previous_textbar);
-				stdout.flush ();
-			}
 		}
 
 		public static int main (string[] args) {
diff --git a/src/common.vala b/src/common.vala
index d126b57c..53cc04d7 100644
--- a/src/common.vala
+++ b/src/common.vala
@@ -30,7 +30,6 @@ namespace Pamac {
 	}
 
 	public struct Updates {
-		public bool is_syncfirst;
 		public AlpmPackage[] repos_updates;
 		public AURPackage[] aur_updates;
 	}
diff --git a/src/common_daemon.vala b/src/common_daemon.vala
new file mode 100644
index 00000000..0cfc8da2
--- /dev/null
+++ b/src/common_daemon.vala
@@ -0,0 +1,52 @@
+/*
+ *  pamac-vala
+ *
+ *  Copyright (C) 2014-2018 Guillaume Benoit <guillaume@manjaro.org>
+ *
+ *  This program 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 get of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Pamac {
+	public struct TransactionSummary {
+		public AlpmPackage[] to_install;
+		public AlpmPackage[] to_upgrade;
+		public AlpmPackage[] to_downgrade;
+		public AlpmPackage[] to_reinstall;
+		public AlpmPackage[] to_remove;
+		public AURPackage[] to_build;
+		public AlpmPackage[] aur_conflicts_to_remove;
+		public string[] aur_pkgbases_to_build;
+	}
+
+	public struct Updates {
+		public AlpmPackage[] repos_updates;
+		public AURPackage[] aur_updates;
+	}
+
+	public struct UpdatesPriv {
+		public bool syncfirst;
+		public AlpmPackage[] repos_updates;
+		public AURPackage[] aur_updates;
+	}
+
+	public struct ErrorInfos {
+		public uint no;
+		public string message;
+		public string[] details;
+		public ErrorInfos () {
+			message = "";
+		}
+	}
+}
+
diff --git a/src/database.vala b/src/database.vala
new file mode 100644
index 00000000..5219251c
--- /dev/null
+++ b/src/database.vala
@@ -0,0 +1,555 @@
+/*
+ *  pamac-vala
+ *
+ *  Copyright (C) 2014-2018 Guillaume Benoit <guillaume@manjaro.org>
+ *
+ *  This program 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 get of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Pamac {
+	[DBus (name = "org.manjaro.pamac.user")]
+	interface UserDaemon : Object {
+		public abstract void enable_appstream () throws Error;
+		public abstract void refresh_handle () throws Error;
+		public abstract string[] get_mirrors_countries () throws Error;
+		public abstract string get_mirrors_choosen_country () throws Error;
+		public abstract string get_lockfile () throws Error;
+		public abstract AlpmPackage get_installed_pkg (string pkgname) throws Error;
+		public abstract bool get_checkspace () throws Error;
+		public abstract string[] get_ignorepkgs () throws Error;
+		public abstract bool should_hold (string pkgname) throws Error;
+		public abstract uint get_pkg_reason (string pkgname) throws Error;
+		public abstract uint get_pkg_origin (string pkgname) throws Error;
+		public abstract AlpmPackage[] get_installed_pkgs () throws Error;
+		public abstract AlpmPackage[] get_installed_apps () throws Error;
+		public abstract AlpmPackage[] get_explicitly_installed_pkgs () throws Error;
+		public abstract AlpmPackage[] get_foreign_pkgs () throws Error;
+		public abstract AlpmPackage[] get_orphans () throws Error;
+		public abstract async AlpmPackage[] get_installed_pkgs_async () throws Error;
+		public abstract async AlpmPackage[] get_installed_apps_async () throws Error;
+		public abstract async AlpmPackage[] get_explicitly_installed_pkgs_async () throws Error;
+		public abstract async AlpmPackage[] get_foreign_pkgs_async() throws Error;
+		public abstract async AlpmPackage[] get_orphans_async () throws Error;
+		public abstract AlpmPackage find_installed_satisfier (string depstring) throws Error;
+		public abstract AlpmPackage get_sync_pkg (string pkgname) throws Error;
+		public abstract AlpmPackage find_sync_satisfier (string depstring) throws Error;
+		public abstract AlpmPackage[] search_pkgs (string search_string) throws Error;
+		public abstract async AlpmPackage[] search_pkgs_async (string search_string) throws Error;
+		public abstract async AURPackage[] search_in_aur_async (string search_string) throws Error;
+		public abstract HashTable<string, Variant> search_files (string[] files) throws Error;
+		public abstract AlpmPackage[] get_category_pkgs (string category) throws Error;
+		public abstract async AlpmPackage[] get_category_pkgs_async (string category) throws Error;
+		public abstract string[] get_repos_names () throws Error;
+		public abstract AlpmPackage[] get_repo_pkgs (string repo) throws Error;
+		public abstract async AlpmPackage[] get_repo_pkgs_async (string repo) throws Error;
+		public abstract string[] get_groups_names () throws Error;
+		public abstract AlpmPackage[] get_group_pkgs (string groupname) throws Error;
+		public abstract async AlpmPackage[] get_group_pkgs_async (string groupname) throws Error;
+		public abstract AlpmPackageDetails get_pkg_details (string pkgname, string app_name) throws Error;
+		public abstract string[] get_pkg_files (string pkgname) throws Error;
+		public abstract async AURPackageDetails get_aur_details_async (string pkgname) throws Error;
+		public abstract string[] get_pkg_uninstalled_optdeps (string pkgname) throws Error;
+		public abstract void start_get_updates (bool check_aur_updates, bool refresh_files_dbs) throws Error;
+		[DBus (no_reply = true)]
+		public abstract void quit () throws Error;
+		public signal void emit_get_updates_progress (uint percent);
+		public signal void get_updates_finished (Updates updates);
+	}
+
+	public class Database: Object {
+		UserDaemon user_daemon;
+
+		public signal void get_updates_progress (uint percent);
+		public signal void get_updates_finished (Updates updates);
+
+		public Config config { get; construct set; }
+
+		public Database (Config config) {
+			Object (config: config);
+		}
+
+		construct {
+			connecting_user_daemon ();
+			if (config.enable_aur == false) {
+				config.check_aur_updates = false;
+			}
+		}
+
+		// destruction
+		~Database () {
+			stop_daemon ();
+		}
+    
+		void connecting_user_daemon () {
+			if (user_daemon == null) {
+				try {
+					user_daemon = Bus.get_proxy_sync (BusType.SESSION, "org.manjaro.pamac.user", "/org/manjaro/pamac/user");
+				} catch (Error e) {
+					stderr.printf ("Error: %s\n", e.message);
+				}
+			}
+		}
+
+		public void stop_daemon () {
+			try {
+				user_daemon.quit ();
+			} catch (Error e) {
+				stderr.printf ("quit: %s\n", e.message);
+			}
+		}
+
+		public void enable_appstream () {
+			try {
+				user_daemon.enable_appstream ();
+			} catch (Error e) {
+				stderr.printf ("enable_appstream: %s\n", e.message);
+			}
+		}
+
+		public void refresh () {
+			try {
+				user_daemon.refresh_handle ();
+			} catch (Error e) {
+				stderr.printf ("refresh_handle: %s\n", e.message);
+			}
+		}
+
+		public string[] get_mirrors_countries () {
+			string[] countries = {};
+			try {
+				countries = user_daemon.get_mirrors_countries ();
+			} catch (Error e) {
+				stderr.printf ("get_mirrors_countries: %s\n", e.message);
+			}
+			return countries;
+		}
+
+		public string get_mirrors_choosen_country () {
+			string country = "";
+			try {
+				country = user_daemon.get_mirrors_choosen_country ();
+			} catch (Error e) {
+				stderr.printf ("get_mirrors_choosen_country: %s\n", e.message);
+			}
+			return country;
+		}
+
+		public bool get_checkspace () {
+			bool checkspace = false;
+			try {
+				checkspace = user_daemon.get_checkspace ();
+			} catch (Error e) {
+				stderr.printf ("get_checkspace: %s\n", e.message);
+			}
+			return checkspace;
+		}
+
+		public string[] get_ignorepkgs () {
+			string[] ignorepkgs = {};
+			try {
+				ignorepkgs = user_daemon.get_ignorepkgs ();
+			} catch (Error e) {
+				stderr.printf ("get_ignorepkgs: %s\n", e.message);
+			}
+			return ignorepkgs;
+		}
+
+		public AlpmPackage get_installed_pkg (string pkgname) {
+			try {
+				return user_daemon.get_installed_pkg (pkgname);
+			} catch (Error e) {
+				stderr.printf ("get_installed_pkg: %s\n", e.message);
+				return AlpmPackage () {
+					name = "",
+					version = "",
+					desc = "",
+					repo = "",
+					icon = ""
+				};
+			}
+		}
+
+		public AlpmPackage find_installed_satisfier (string depstring) {
+			try {
+				return user_daemon.find_installed_satisfier (depstring);
+			} catch (Error e) {
+				stderr.printf ("find_installed_satisfier: %s\n", e.message);
+				return AlpmPackage () {
+					name = "",
+					version = "",
+					desc = "",
+					repo = ""
+				};
+			}
+		}
+
+		public bool should_hold (string pkgname) {
+			bool should_hold = false;
+			try {
+				should_hold = user_daemon.should_hold (pkgname);
+			} catch (Error e) {
+				stderr.printf ("should_hold: %s\n", e.message);
+			}
+			return should_hold;
+		}
+
+		public uint get_pkg_reason (string pkgname) {
+			uint reason = 0;
+			try {
+				reason = user_daemon.get_pkg_reason (pkgname);
+			} catch (Error e) {
+				stderr.printf ("get_pkg_reason: %s\n", e.message);
+			}
+			return reason;
+		}
+
+		public uint get_pkg_origin (string pkgname) {
+			uint origin = 0;
+			try {
+				origin = user_daemon.get_pkg_origin (pkgname);
+			} catch (Error e) {
+				stderr.printf ("get_pkg_origin: %s\n", e.message);
+			}
+			return origin;
+		}
+
+		public AlpmPackage[] get_installed_pkgs () {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = user_daemon.get_installed_pkgs ();
+			} catch (Error e) {
+				stderr.printf ("get_installed_pkgs: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public AlpmPackage[] get_installed_apps () {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = user_daemon.get_installed_apps ();
+			} catch (Error e) {
+				stderr.printf ("get_installed_apps: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public AlpmPackage[] get_explicitly_installed_pkgs () {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = user_daemon.get_explicitly_installed_pkgs ();
+			} catch (Error e) {
+				stderr.printf ("get_explicitly_installed_pkgs: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public AlpmPackage[] get_foreign_pkgs () {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = user_daemon.get_foreign_pkgs ();
+			} catch (Error e) {
+				stderr.printf ("get_foreign_pkgs: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public AlpmPackage[] get_orphans () {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = user_daemon.get_orphans ();
+			} catch (Error e) {
+				stderr.printf ("get_orphans: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public async AlpmPackage[] get_installed_pkgs_async () {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = yield user_daemon.get_installed_pkgs_async ();
+			} catch (Error e) {
+				stderr.printf ("get_installed_pkgs_async: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public async AlpmPackage[] get_installed_apps_async () {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = yield user_daemon.get_installed_apps_async ();
+			} catch (Error e) {
+				stderr.printf ("get_installed_apps_async: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public async AlpmPackage[] get_explicitly_installed_pkgs_async () {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = yield user_daemon.get_explicitly_installed_pkgs_async ();
+			} catch (Error e) {
+				stderr.printf ("get_explicitly_installed_pkgs_async: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public async AlpmPackage[] get_foreign_pkgs_async () {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = yield user_daemon.get_foreign_pkgs_async ();
+			} catch (Error e) {
+				stderr.printf ("get_foreign_pkgs_async: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public async AlpmPackage[] get_orphans_async () {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = yield user_daemon.get_orphans_async ();
+			} catch (Error e) {
+				stderr.printf ("get_orphans_async: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public AlpmPackage get_sync_pkg (string pkgname) {
+			try {
+				return user_daemon.get_sync_pkg (pkgname);
+			} catch (Error e) {
+				stderr.printf ("get_sync_pkg: %s\n", e.message);
+				return AlpmPackage () {
+					name = "",
+					version = "",
+					desc = "",
+					repo = ""
+				};
+			}
+		}
+
+		public AlpmPackage find_sync_satisfier (string depstring) {
+			try {
+				return user_daemon.find_sync_satisfier (depstring);
+			} catch (Error e) {
+				stderr.printf ("find_sync_satisfier: %s\n", e.message);
+				return AlpmPackage () {
+					name = "",
+					version = "",
+					desc = "",
+					repo = ""
+				};
+			}
+		}
+
+		public AlpmPackage[] search_pkgs (string search_string) {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = user_daemon.search_pkgs (search_string);
+			} catch (Error e) {
+				stderr.printf ("search_pkgs: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public async AlpmPackage[] search_pkgs_async (string search_string) {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = yield user_daemon.search_pkgs_async (search_string);
+			} catch (Error e) {
+				stderr.printf ("search_pkgs_async: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public async AURPackage[] search_in_aur_async (string search_string) {
+			AURPackage[] pkgs = {};
+			if (config.enable_aur) {
+				try {
+					pkgs = yield user_daemon.search_in_aur_async (search_string);
+				} catch (Error e) {
+					stderr.printf ("search_in_aur_async: %s\n", e.message);
+				}
+			}
+			return pkgs;
+		}
+
+		public HashTable<string, Variant> search_files (string[] files) {
+			var result = new HashTable<string, Variant> (str_hash, str_equal);
+			try {
+				result = user_daemon.search_files (files);
+			} catch (Error e) {
+				stderr.printf ("search_files: %s\n", e.message);
+			}
+			return result;
+		}
+
+		public AlpmPackage[] get_category_pkgs (string category) {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = user_daemon.get_category_pkgs (category);
+			} catch (Error e) {
+				stderr.printf ("get_category_pkgs: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public async AlpmPackage[] get_category_pkgs_async (string category) {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = yield user_daemon.get_category_pkgs_async (category);
+			} catch (Error e) {
+				stderr.printf ("get_category_pkgs_async: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public string[] get_repos_names () {
+			string[] repos_names = {};
+			try {
+				repos_names = user_daemon.get_repos_names ();
+			} catch (Error e) {
+				stderr.printf ("get_repos_names: %s\n", e.message);
+			}
+			return repos_names;
+		}
+
+		public AlpmPackage[] get_repo_pkgs (string repo) {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = user_daemon.get_repo_pkgs (repo);
+			} catch (Error e) {
+				stderr.printf ("get_repo_pkgs: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public async AlpmPackage[] get_repo_pkgs_async (string repo) {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = yield user_daemon.get_repo_pkgs_async (repo);
+			} catch (Error e) {
+				stderr.printf ("get_repo_pkgs_async: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public string[] get_groups_names () {
+			string[] groups_names = {};
+			try {
+				groups_names = user_daemon.get_groups_names ();
+			} catch (Error e) {
+				stderr.printf ("get_groups_names: %s\n", e.message);
+			}
+			return groups_names;
+		}
+
+		public AlpmPackage[] get_group_pkgs (string group_name) {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = user_daemon.get_group_pkgs (group_name);
+			} catch (Error e) {
+				stderr.printf ("get_group_pkgs: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public async AlpmPackage[] get_group_pkgs_async (string group_name) {
+			AlpmPackage[] pkgs = {};
+			try {
+				pkgs = yield user_daemon.get_group_pkgs_async (group_name);
+			} catch (Error e) {
+				stderr.printf ("get_group_pkgs_async: %s\n", e.message);
+			}
+			return pkgs;
+		}
+
+		public string[] get_pkg_uninstalled_optdeps (string pkgname) {
+			string[] optdeps = {};
+			try {
+				optdeps = user_daemon.get_pkg_uninstalled_optdeps (pkgname);
+			} catch (Error e) {
+				stderr.printf ("get_pkg_uninstalled_optdeps: %s\n", e.message);
+			}
+			return optdeps;
+		}
+
+		public AlpmPackageDetails get_pkg_details (string pkgname, string app_name) {
+			try {
+				return user_daemon.get_pkg_details (pkgname, app_name);
+			} catch (Error e) {
+				stderr.printf ("get_pkg_details: %s\n", e.message);
+				return AlpmPackageDetails () {
+					name = "",
+					version = "",
+					desc = "",
+					repo = "",
+					url = "",
+					packager = "",
+					builddate = "",
+					installdate = "",
+					reason = "",
+					has_signature = ""
+				};
+			}
+		}
+
+		public string[] get_pkg_files (string pkgname) {
+			try {
+				return user_daemon.get_pkg_files (pkgname);
+			} catch (Error e) {
+				stderr.printf ("get_pkg_files: %s\n", e.message);
+				return {};
+			}
+		}
+
+		public async AURPackageDetails get_aur_details_async (string pkgname) {
+			var pkg = AURPackageDetails () {
+				name = "",
+				version = "",
+				desc = "",
+				packagebase = "",
+				url = "",
+				maintainer = ""
+			};
+			if (config.enable_aur) {
+				try {
+					pkg = yield user_daemon.get_aur_details_async (pkgname);
+				} catch (Error e) {
+					stderr.printf ("get_aur_details_async: %s\n", e.message);
+				}
+			}
+			return pkg;
+		}
+
+		public void start_get_updates () {
+			user_daemon.emit_get_updates_progress.connect (on_emit_get_updates_progress);
+			user_daemon.get_updates_finished.connect (on_get_updates_finished);
+			try {
+				user_daemon.start_get_updates (config.check_aur_updates, false);
+			} catch (Error e) {
+				stderr.printf ("start_get_updates: %s\n", e.message);
+			}
+		}
+
+		void on_emit_get_updates_progress (uint percent) {
+			get_updates_progress (percent);
+		}
+
+		void on_get_updates_finished (Updates updates) {
+			user_daemon.emit_get_updates_progress.disconnect (on_emit_get_updates_progress);
+			user_daemon.get_updates_finished.disconnect (on_get_updates_finished);
+			get_updates_finished (updates);
+		}
+	}
+}
diff --git a/src/installer.vala b/src/installer.vala
index f9abf2d4..f5820ac4 100644
--- a/src/installer.vala
+++ b/src/installer.vala
@@ -21,7 +21,8 @@ namespace Pamac {
 
 	public class Installer: Gtk.Application {
 		ApplicationCommandLine cmd;
-		Transaction transaction;
+		Database database;
+		TransactionGtk transaction;
 		ProgressDialog progress_dialog;
 		bool important_details;
 
@@ -38,11 +39,13 @@ namespace Pamac {
 			base.startup ();
 
 			important_details = false;
+			var pamac_config = new Config ("/etc/pamac.conf");
+			database = new Database (pamac_config);
 			// integrate progress box and term widget
 			progress_dialog = new ProgressDialog ();
-			transaction = new Transaction (progress_dialog as Gtk.ApplicationWindow);
-			transaction.mode = Transaction.Mode.INSTALLER;
+			transaction = new TransactionGtk (database, progress_dialog as Gtk.ApplicationWindow);
 			transaction.finished.connect (on_transaction_finished);
+			transaction.sysupgrade_finished.connect (on_transaction_finished);
 			transaction.important_details_outpout.connect (on_important_details_outpout);
 			progress_dialog.box.pack_start (transaction.progress_box);
 			progress_dialog.box.reorder_child (transaction.progress_box, 0);
@@ -55,40 +58,64 @@ namespace Pamac {
 		public override int command_line (ApplicationCommandLine cmd) {
 			this.cmd = cmd;
 			string[] args = cmd.get_arguments ();
-			foreach (unowned string target in args[1:args.length]) {
-				// check for local or remote path
-				if (".pkg.tar" in target) {
-					if ("://" in target) {
-						if ("file://" in target) {
-							// handle file:// uri
-							var file = File.new_for_uri (target);
-							string? absolute_path = file.get_path ();
-							if (absolute_path != null) {
-								transaction.to_load.add (absolute_path);
+			string[] to_install = {};
+			string[] to_remove = {};
+			string[] to_load = {};
+			if (args.length == 1) {
+				display_help ();
+				return cmd.get_exit_status ();
+			}
+			if (args[1] == "--help" || args[1] == "-h") {
+				display_help ();
+				return cmd.get_exit_status ();
+			} else {
+				bool add_to_remove = false;
+				int i = 1;
+				while (i < args.length) {
+					unowned string target = args[i];
+					if (target == "--remove") {
+						add_to_remove = true;
+					} else {
+						if (add_to_remove) {
+							to_remove += target;
+						} else if (".pkg.tar" in target) {
+							// check for local or remote path
+							if ("://" in target) {
+								if ("file://" in target) {
+									// handle file:// uri
+									var file = File.new_for_uri (target);
+									string? absolute_path = file.get_path ();
+									if (absolute_path != null) {
+										to_load += absolute_path;
+									}
+								} else {
+									// add url in to_load, pkg will be downloaded by system_daemon
+									to_load += target;
+								}
+							} else {
+								// handle local or absolute path
+								var file = File.new_for_path (target);
+								string? absolute_path = file.get_path ();
+								if (absolute_path != null) {
+									to_load += absolute_path;
+								}
 							}
 						} else {
-							// add url in to_load, pkg will be downloaded by system_daemon
-							transaction.to_load.add (target);
-						}
-					} else {
-						// handle local or absolute path
-						var file = File.new_for_path (target);
-						string? absolute_path = file.get_path ();
-						if (absolute_path != null) {
-							transaction.to_load.add (absolute_path);
+							to_install += target;
 						}
 					}
-				} else {
-					transaction.to_install.add (target);
+					i++;
 				}
 			}
-			if (transaction.to_install.length == 0 && transaction.to_load.length == 0) {
+			if (to_install.length == 0 
+				&& to_load.length == 0
+				&& to_remove.length == 0) {
 				stdout.printf (dgettext (null, "Nothing to do") + ".\n");
 			} else {
 				this.hold ();
 				progress_dialog.show ();
 				if (transaction.get_lock ()) {
-					transaction.run ();
+					transaction.start (to_install, to_remove, to_load, {}, {});
 				} else {
 					transaction.progress_box.action_label.label = dgettext (null, "Waiting for another package manager to quit") + "...";
 					transaction.start_progressbar_pulse ();
@@ -96,7 +123,7 @@ namespace Pamac {
 						bool locked = transaction.get_lock ();
 						if (locked) {
 							transaction.stop_progressbar_pulse ();
-							transaction.run ();
+							transaction.start (to_install, to_remove, to_load, {}, {});
 						}
 						return !locked;
 					});
@@ -105,6 +132,15 @@ namespace Pamac {
 			return cmd.get_exit_status ();
 		}
 
+		void display_help () {
+			stdout.printf (dgettext (null, "Install packages from repositories, path or url"));
+			stdout.printf (" / ");
+			stdout.printf (dgettext (null, "Remove packages"));
+			stdout.printf ("\n\n");
+			stdout.printf ("pamac-installer <%s> [--remove] [%s]".printf (dgettext (null, "package(s)"), dgettext (null, "package(s)")));
+			stdout.printf ("\n");
+		}
+
 		void on_important_details_outpout (bool must_show) {
 			important_details = true;
 			progress_dialog.expander.expanded = true;
diff --git a/src/manager.vala b/src/manager.vala
index 8ec1929b..a0d68580 100644
--- a/src/manager.vala
+++ b/src/manager.vala
@@ -106,6 +106,7 @@ namespace Pamac {
 		public override void shutdown () {
 			base.shutdown ();
 			if (!pamac_run) {
+				manager_window.database.stop_daemon ();
 				manager_window.transaction.stop_daemon ();
 			}
 		}
diff --git a/src/manager_window.vala b/src/manager_window.vala
index 485553ce..6504f63b 100644
--- a/src/manager_window.vala
+++ b/src/manager_window.vala
@@ -170,8 +170,15 @@ namespace Pamac {
 
 		public Queue<string> display_package_queue;
 		string current_package_displayed;
-
-		public Transaction transaction;
+		public GenericSet<string?> to_install;
+		public GenericSet<string?> to_remove;
+		public GenericSet<string?> to_load;
+		public GenericSet<string?> to_build;
+		public GenericSet<string?> to_update;
+		public GenericSet<string?> temporary_ignorepkgs;
+
+		public TransactionGtk transaction;
+		public Database database;
 		delegate void TransactionAction ();
 
 		bool refreshing;
@@ -185,8 +192,6 @@ namespace Pamac {
 		AlpmPackage[] repos_updates;
 		AURPackage[] aur_updates;
 
-		bool extern_lock;
-
 		uint search_entry_timeout_id;
 		string search_string;
 		Gtk.Label pending_label;
@@ -263,20 +268,20 @@ namespace Pamac {
 				if (origin == 2) { //origin == Alpm.Package.From.LOCALDB
 					if (unlikely (transaction.transaction_summary.contains (pkgname))) {
 						pixbuf = installed_locked_icon;
-					} else if (unlikely (transaction.should_hold (pkgname))) {
+					} else if (unlikely (database.should_hold (pkgname))) {
 						pixbuf = installed_locked_icon;
-					} else if (unlikely (transaction.to_install.contains (pkgname))) {
+					} else if (unlikely (to_install.contains (pkgname))) {
 						pixbuf = to_reinstall_icon;
-					} else if (unlikely (transaction.to_remove.contains (pkgname))) {
+					} else if (unlikely (to_remove.contains (pkgname))) {
 						pixbuf = to_remove_icon;
 					} else {
 						pixbuf = installed_icon;
 					}
 				} else if (unlikely (transaction.transaction_summary.contains (pkgname))) {
 					pixbuf = available_locked_icon;
-				} else if (unlikely (transaction.to_install.contains (pkgname))) {
+				} else if (unlikely (to_install.contains (pkgname))) {
 					pixbuf = to_install_icon;
-				} else if (unlikely (transaction.to_update.contains (pkgname))) {
+				} else if (unlikely (to_update.contains (pkgname))) {
 					pixbuf = to_upgrade_icon;
 				} else {
 					pixbuf = uninstalled_icon;
@@ -305,7 +310,7 @@ namespace Pamac {
 				string pkgname;
 				treemodel.get (treeiter, 0, out origin, 1, out pkgname);
 				if (filters_stack.visible_child_name == "updates") {
-					if (unlikely (transaction.temporary_ignorepkgs.contains (pkgname))) {
+					if (unlikely (temporary_ignorepkgs.contains (pkgname))) {
 						pixbuf = uninstalled_icon;
 					} else {
 						pixbuf = to_upgrade_icon;
@@ -313,16 +318,16 @@ namespace Pamac {
 				} else if ((uint) origin == 2) { //origin == Alpm.Package.From.LOCALDB
 					if (unlikely (transaction.transaction_summary.contains (pkgname))) {
 						pixbuf = installed_locked_icon;
-					} else if (unlikely (transaction.should_hold (pkgname))) {
+					} else if (unlikely (database.should_hold (pkgname))) {
 						pixbuf = installed_locked_icon;
-					} else if (unlikely (transaction.to_install.contains (pkgname))) {
+					} else if (unlikely (to_install.contains (pkgname))) {
 						pixbuf = to_reinstall_icon;
-					} else if (unlikely (transaction.to_remove.contains (pkgname))) {
+					} else if (unlikely (to_remove.contains (pkgname))) {
 						pixbuf = to_remove_icon;
 					} else {
 						pixbuf = installed_icon;
 					}
-				} else if (unlikely (transaction.to_build.contains (pkgname))) {
+				} else if (unlikely (to_build.contains (pkgname))) {
 					pixbuf = to_install_icon;
 				} else {
 					pixbuf = uninstalled_icon;
@@ -345,28 +350,38 @@ namespace Pamac {
 				stderr.printf ("%s\n", e.message);
 			}
 
-			transaction = new Transaction (this as Gtk.ApplicationWindow);
+			var config = new Config ("/etc/pamac.conf");
+			database = new Database (config);
+			database.enable_appstream ();
+			database.get_updates_progress.connect (on_get_updates_progress);
+			database.get_updates_finished.connect (on_get_updates_finished);
+
+			transaction = new TransactionGtk (database, this as Gtk.ApplicationWindow);
+			transaction.no_confirm_upgrade = true;
 			transaction.start_downloading.connect (on_start_downloading);
 			transaction.stop_downloading.connect (on_stop_downloading);
 			transaction.start_building.connect (on_start_building);
 			transaction.stop_building.connect (on_stop_building);
 			transaction.important_details_outpout.connect (on_important_details_outpout);
+			transaction.refresh_finished.connect (on_refresh_finished);
+			transaction.sysupgrade_finished.connect (on_transaction_finished);
 			transaction.finished.connect (on_transaction_finished);
 			transaction.write_pamac_config_finished.connect (on_write_pamac_config_finished);
 			transaction.set_pkgreason_finished.connect (on_set_pkgreason_finished);
-			transaction.generate_mirrors_list.connect (on_generate_mirrors_list);
+			transaction.start_generating_mirrors_list.connect (on_start_generating_mirrors_list);
 			transaction.generate_mirrors_list_finished.connect (on_generate_mirrors_list_finished);
-			transaction.run_preferences_dialog_finished.connect (on_run_preferences_dialog_finished);
-			transaction.get_updates_progress.connect (on_get_updates_progress);
-			transaction.get_updates_finished.connect (on_get_updates_finished);
 
 			// integrate progress box and term widget
 			main_stack.add_named (transaction.term_window, "term");
 			transaction_infobox.pack_start (transaction.progress_box);
 
-			Timeout.add (500, check_extern_lock);
-
 			display_package_queue = new Queue<string> ();
+			to_install = new GenericSet<string?> (str_hash, str_equal);
+			to_remove = new GenericSet<string?> (str_hash, str_equal);
+			to_load = new GenericSet<string?> (str_hash, str_equal);
+			to_build = new GenericSet<string?> (str_hash, str_equal);
+			to_update = new GenericSet<string?> (str_hash, str_equal);
+			temporary_ignorepkgs = new GenericSet<string?> (str_hash, str_equal);
 
 			main_stack.notify["visible-child"].connect (on_main_stack_visible_child_changed);
 			filters_stack.notify["visible-child"].connect (on_filters_stack_visible_child_changed);
@@ -400,24 +415,6 @@ namespace Pamac {
 			}
 		}
 
-		bool check_extern_lock () {
-			if (extern_lock) {
-				if (!transaction.lockfile.query_exists ()) {
-					extern_lock = false;
-					transaction.refresh_handle ();
-					scroll_to_top = false;
-					refresh_packages_list ();
-				}
-			} else {
-				if (transaction.lockfile.query_exists ()) {
-					if (!transaction_running && !refreshing && !sysupgrade_running) {
-						extern_lock = true;
-					}
-				}
-			}
-			return true;
-		}
-
 		void on_write_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon,
 											bool enable_aur) {
 			support_aur (enable_aur);
@@ -425,12 +422,11 @@ namespace Pamac {
 
 		void on_set_pkgreason_finished () {
 			transaction.unlock ();
-			transaction.refresh_handle ();
 			scroll_to_top = false;
 			refresh_packages_list ();
 			if (main_stack.visible_child_name == "details") {
-				if (transaction.get_installed_pkg (current_package_displayed).name != ""
-					|| transaction.get_sync_pkg (current_package_displayed).name != "") {
+				if (database.get_installed_pkg (current_package_displayed).name != ""
+					|| database.get_sync_pkg (current_package_displayed).name != "") {
 					display_package_properties (current_package_displayed);
 				} else {
 					display_aur_properties (current_package_displayed);
@@ -495,7 +491,7 @@ namespace Pamac {
 						string name;
 						uint64 dsize;
 						packages_list.get (iter, 1, out name, 5, out dsize);
-						if (transaction.to_update.contains (name)) {
+						if (to_update.contains (name)) {
 							total_dsize += dsize;
 						}
 						return false;
@@ -506,7 +502,7 @@ namespace Pamac {
 						transaction.progress_box.action_label.label = "";
 					}
 					if (!transaction_running && !generate_mirrors_list && !refreshing && !sysupgrade_running
-						&& (transaction.to_update.length > 0)) {
+						&& (to_update.length > 0)) {
 						apply_button.sensitive = true;
 					} else {
 						apply_button.sensitive = false;
@@ -514,7 +510,7 @@ namespace Pamac {
 					cancel_button.sensitive = false;
 					show_transaction_infobox ();
 				} else {
-					uint total_pending = transaction.to_install.length + transaction.to_remove.length + transaction.to_build.length;
+					uint total_pending = to_install.length + to_remove.length + to_build.length;
 					if (total_pending == 0) {
 						if (filters_stack.visible_child_name != "pending") {
 							active_pending_row (false);
@@ -540,8 +536,8 @@ namespace Pamac {
 		void show_default_pkgs () {
 			this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH));
 			origin_stack.visible_child_name = "repos";
-			transaction.get_installed_apps.begin ((obj, res) => {
-				populate_packages_list (transaction.get_installed_apps.end (res));
+			database.get_installed_apps_async.begin ((obj, res) => {
+				populate_packages_list (database.get_installed_apps_async.end (res));
 			});
 		}
 
@@ -584,13 +580,13 @@ namespace Pamac {
 			active_pending_row (false);
 			filters_listbox.select_row (filters_listbox.get_row_at_index (0));
 
-			foreach (unowned string repo in transaction.get_repos_names ()) {
+			foreach (unowned string repo in database.get_repos_names ()) {
 				label = create_list_label (repo);
 				repos_listbox.add (label);
 			}
 			repos_listbox.select_row (repos_listbox.get_row_at_index (0));
 
-			foreach (unowned string group in transaction.get_groups_names ()) {
+			foreach (unowned string group in database.get_groups_names ()) {
 				label = create_list_label (group);
 				groups_listbox.add (label);
 			}
@@ -658,7 +654,13 @@ namespace Pamac {
 			files_row.add (label);
 			properties_listbox.add (files_row);
 			properties_listbox.select_row (properties_listbox.get_row_at_index (0));
+		}
 
+		void clear_lists () {
+			to_install.remove_all ();
+			to_remove.remove_all ();
+			to_build.remove_all ();
+			to_load.remove_all ();
 		}
 
 		void on_mark_explicit_button_clicked (Gtk.Button button) {
@@ -702,7 +704,7 @@ namespace Pamac {
 			container.foreach ((widget) => {
 				if (widget.name == "GtkButton") {
 					var dep_button = widget as Gtk.Button;
-					AlpmPackage pkg = transaction.find_sync_satisfier (dep_button.label);
+					AlpmPackage pkg = database.find_sync_satisfier (dep_button.label);
 					if (pkg.name != "") {
 						dep_name = pkg.name;
 					}
@@ -715,10 +717,10 @@ namespace Pamac {
 			string dep_name = find_install_button_dep_name (button);
 			if (button.active) {
 				button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION);
-				transaction.to_install.add (dep_name);
+				to_install.add (dep_name);
 			} else {
 				button.get_style_context ().remove_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION);
-				transaction.to_install.remove (dep_name);
+				to_install.remove (dep_name);
 			}
 			set_pendings_operations ();
 		}
@@ -740,13 +742,13 @@ namespace Pamac {
 					dep_button.relief = Gtk.ReliefStyle.NONE;
 					dep_button.clicked.connect (on_dep_button_clicked);
 					box2.pack_start (dep_button, false);
-					if (transaction.find_installed_satisfier (dep).name == "") {
+					if (database.find_installed_satisfier (dep).name == "") {
 						var install_dep_button = new Gtk.ToggleButton.with_label (dgettext (null, "Install"));
 						install_dep_button.margin = 3;
 						install_dep_button.toggled.connect (on_install_dep_button_toggled);
 						box2.pack_end (install_dep_button, false);
 						string dep_name = find_install_button_dep_name (install_dep_button);
-						install_dep_button.active = (dep_name in transaction.to_install); 
+						install_dep_button.active = (dep_name in to_install); 
 					}
 					box.pack_start (box2);
 				} else {
@@ -806,7 +808,7 @@ namespace Pamac {
 		}
 
 		void set_package_details (string pkgname, string app_name) {
-			AlpmPackageDetails details = transaction.get_pkg_details (pkgname, app_name);
+			AlpmPackageDetails details = database.get_pkg_details (pkgname, app_name);
 			// download screenshot
 			app_screenshot.pixbuf = null;
 			if (details.screenshot != "") {
@@ -865,17 +867,17 @@ namespace Pamac {
 			if (details.origin == 2) { //Alpm.Package.From.LOCALDB
 				install_togglebutton.visible = false;
 				remove_togglebutton.visible = true;
-				remove_togglebutton.active = transaction.to_remove.contains (details.name);
+				remove_togglebutton.active = to_remove.contains (details.name);
 				reinstall_togglebutton.visible = false;
-				AlpmPackage find_pkg = transaction.get_sync_pkg (details.name);
+				AlpmPackage find_pkg = database.get_sync_pkg (details.name);
 				if (find_pkg.name != "") {
 					if (find_pkg.version == details.version) {
 						reinstall_togglebutton.visible = true;
-						reinstall_togglebutton.active = transaction.to_install.contains (details.name);
+						reinstall_togglebutton.active = to_install.contains (details.name);
 					}
 				} else {
-					transaction.get_aur_details.begin (details.name, (obj, res) => {
-						AURPackageDetails aur_details = transaction.get_aur_details.end (res);
+					database.get_aur_details_async.begin (details.name, (obj, res) => {
+						AURPackageDetails aur_details = database.get_aur_details_async.end (res);
 						if (aur_details.name != "") {
 							// always show reinstall button for VCS package
 							if (aur_details.name.has_suffix ("-git") ||
@@ -884,7 +886,7 @@ namespace Pamac {
 								aur_details.name.has_suffix ("-hg") ||
 								aur_details.version == details.version) {
 								reinstall_togglebutton.visible = true;
-								reinstall_togglebutton.active = transaction.to_build.contains (details.name);
+								reinstall_togglebutton.active = to_build.contains (details.name);
 							}
 						}
 					});
@@ -893,7 +895,7 @@ namespace Pamac {
 				remove_togglebutton.visible = false;
 				reinstall_togglebutton.visible = false;
 				install_togglebutton.visible = true;
-				install_togglebutton.active = transaction.to_install.contains (details.name);
+				install_togglebutton.active = to_install.contains (details.name);
 			}
 			// details
 			details_grid.foreach (destroy_widget);
@@ -1016,8 +1018,8 @@ namespace Pamac {
 			while (Gtk.events_pending ()) {
 				Gtk.main_iteration ();
 			}
-			transaction.get_aur_details.begin (pkgname, (obj, res) => {
-				AURPackageDetails details = transaction.get_aur_details.end (res);
+			database.get_aur_details_async.begin (pkgname, (obj, res) => {
+				AURPackageDetails details = database.get_aur_details_async.end (res);
 				// infos
 				name_label.set_markup ("<big><b>%s  %s</b></big>".printf (details.name, details.version));
 				app_image.pixbuf = package_icon;
@@ -1034,11 +1036,11 @@ namespace Pamac {
 				}
 				licenses_label.set_text (licenses.str);
 				install_togglebutton.visible = true;
-				install_togglebutton.active = transaction.to_build.contains (details.name);
-				AlpmPackage pkg = transaction.get_installed_pkg (details.name);
+				install_togglebutton.active = to_build.contains (details.name);
+				AlpmPackage pkg = database.get_installed_pkg (details.name);
 				if (pkg.name != "") {
 					remove_togglebutton.visible = true;
-					remove_togglebutton.active = transaction.to_remove.contains (pkg.name);
+					remove_togglebutton.active = to_remove.contains (pkg.name);
 				}
 				// details
 				properties_listbox.visible = true;
@@ -1122,16 +1124,16 @@ namespace Pamac {
 		void on_install_togglebutton_toggled () {
 			if (install_togglebutton.active) {
 				install_togglebutton.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION);
-				if (transaction.get_pkg_origin (current_package_displayed) == 3) { //Alpm.Package.From.SYNCDB
-					transaction.to_install.add (current_package_displayed);
+				if (database.get_pkg_origin (current_package_displayed) == 3) { //Alpm.Package.From.SYNCDB
+					to_install.add (current_package_displayed);
 				} else {
-					transaction.to_build.add (current_package_displayed);
+					to_build.add (current_package_displayed);
 				}
 			} else {
 				install_togglebutton.get_style_context ().remove_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION);
-				if (transaction.to_install.remove (current_package_displayed)) {
+				if (to_install.remove (current_package_displayed)) {
 				} else {
-					transaction.to_build.remove (current_package_displayed);
+					to_build.remove (current_package_displayed);
 				}
 			}
 			set_pendings_operations ();
@@ -1143,11 +1145,11 @@ namespace Pamac {
 				reinstall_togglebutton.active = false;
 				reinstall_togglebutton.get_style_context ().remove_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION);
 				remove_togglebutton.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION);
-				transaction.to_install.remove (current_package_displayed);
-				transaction.to_remove.add (current_package_displayed);
+				to_install.remove (current_package_displayed);
+				to_remove.add (current_package_displayed);
 			} else {
 				remove_togglebutton.get_style_context ().remove_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION);
-				transaction.to_remove.remove (current_package_displayed);
+				to_remove.remove (current_package_displayed);
 			}
 			set_pendings_operations ();
 		}
@@ -1158,18 +1160,18 @@ namespace Pamac {
 				remove_togglebutton.active = false;
 				remove_togglebutton.get_style_context ().remove_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION);
 				reinstall_togglebutton.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION);
-				transaction.to_remove.remove (current_package_displayed);
-				AlpmPackage find_pkg = transaction.get_sync_pkg (current_package_displayed);
+				to_remove.remove (current_package_displayed);
+				AlpmPackage find_pkg = database.get_sync_pkg (current_package_displayed);
 				if (find_pkg.name != "") {
-					transaction.to_install.add (current_package_displayed);
+					to_install.add (current_package_displayed);
 				} else {
 					// availability in AUR was checked in set_package_details
-					transaction.to_build.add (current_package_displayed);
+					to_build.add (current_package_displayed);
 				}
 			} else {
 				reinstall_togglebutton.get_style_context ().remove_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION);
-				transaction.to_install.remove (current_package_displayed);
-				transaction.to_build.remove (current_package_displayed);
+				to_install.remove (current_package_displayed);
+				to_build.remove (current_package_displayed);
 			}
 			set_pendings_operations ();
 		}
@@ -1319,7 +1321,7 @@ namespace Pamac {
 		public void refresh_packages_list () {
 			button_back.visible = (main_stack.visible_child_name != "browse" || filters_stack.visible_child_name != "filters");
 			if (filters_stack.visible_child_name != "pending") {
-				uint total_pending = transaction.to_install.length + transaction.to_remove.length + transaction.to_build.length;
+				uint total_pending = to_install.length + to_remove.length + to_build.length;
 				if (total_pending == 0) {
 					active_pending_row (false);
 				}
@@ -1406,7 +1408,7 @@ namespace Pamac {
 					select_all_button.visible = false;
 					apply_button.sensitive = false;
 					this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH));
-					transaction.start_get_updates ();
+					database.start_get_updates ();
 					break;
 				case "pending":
 					this.title = dgettext (null, "Pending");
@@ -1415,23 +1417,23 @@ namespace Pamac {
 					save_packages_sort_order ();
 					// order pending by name
 					packages_list.set_sort_column_id (2, Gtk.SortType.ASCENDING);
-					if (transaction.to_build.length != 0) {
+					if (to_build.length != 0) {
 						show_sidebar ();
 					} else {
 						hide_sidebar ();
 					}
 					AlpmPackage[] pkgs = {};
-					foreach (unowned string pkgname in transaction.to_install) {
-						AlpmPackage pkg = transaction.get_installed_pkg (pkgname);
+					foreach (unowned string pkgname in to_install) {
+						AlpmPackage pkg = database.get_installed_pkg (pkgname);
 						if (pkg.name == "") {
-							pkg = transaction.get_sync_pkg (pkgname);
+							pkg = database.get_sync_pkg (pkgname);
 						}
 						if (pkg.name != "") {
 							pkgs += pkg;
 						}
 					}
-					foreach (unowned string pkgname in transaction.to_remove) {
-						AlpmPackage pkg = transaction.get_installed_pkg (pkgname);
+					foreach (unowned string pkgname in to_remove) {
+						AlpmPackage pkg = database.get_installed_pkg (pkgname);
 						if (pkg.name != "") {
 							pkgs += pkg;
 						}
@@ -1439,11 +1441,11 @@ namespace Pamac {
 					if (pkgs.length > 0) {
 						populate_packages_list (pkgs);
 					}
-					if (transaction.to_build.length != 0) {
+					if (to_build.length != 0) {
 						AURPackage[] aur_pkgs = {};
-						foreach (unowned string pkgname in transaction.to_build) {
-							transaction.get_aur_details.begin (pkgname, (obj, res) => {
-								AURPackageDetails details_pkg = transaction.get_aur_details.end (res);
+						foreach (unowned string pkgname in to_build) {
+							database.get_aur_details_async.begin (pkgname, (obj, res) => {
+								AURPackageDetails details_pkg = database.get_aur_details_async.end (res);
 								if (details_pkg.name != "") {
 									var aur_pkg = AURPackage () {
 										name = details_pkg.name,
@@ -1510,36 +1512,36 @@ namespace Pamac {
 				string depstring = button.label;
 				// if depstring contains a version restriction search a satisfier directly
 				if (">" in depstring || "=" in depstring || "<" in depstring) {
-					var pkg = transaction.find_installed_satisfier (depstring);
+					var pkg = database.find_installed_satisfier (depstring);
 					if (pkg.name != "") {
 						display_package_properties (pkg.name);
 					} else {
-						pkg = transaction.find_sync_satisfier (depstring);
+						pkg = database.find_sync_satisfier (depstring);
 						if (pkg.name != "") {
 							display_package_properties (pkg.name);
 						}
 					}
 				} else {
 					// just search for the name first to search for AUR after
-					if (transaction.get_installed_pkg (depstring).name != "") {
+					if (database.get_installed_pkg (depstring).name != "") {
 						display_package_properties (depstring);
-					} else if (transaction.get_sync_pkg (depstring).name != "") {
+					} else if (database.get_sync_pkg (depstring).name != "") {
 						display_package_properties (depstring);
 					} else {
 						this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH));
 						while (Gtk.events_pending ()) {
 							Gtk.main_iteration ();
 						}
-						transaction.get_aur_details.begin (depstring, (obj, res) => {
+						database.get_aur_details_async.begin (depstring, (obj, res) => {
 							this.get_window ().set_cursor (null);
-							if (transaction.get_aur_details.end (res).name != "") {
+							if (database.get_aur_details_async.end (res).name != "") {
 								display_aur_properties (depstring);
 							} else {
-								var pkg = transaction.find_installed_satisfier (depstring);
+								var pkg = database.find_installed_satisfier (depstring);
 								if (pkg.name != "") {
 									display_package_properties (pkg.name);
 								} else {
-									pkg = transaction.find_sync_satisfier (depstring);
+									pkg = database.find_sync_satisfier (depstring);
 									if (pkg.name != "") {
 										display_package_properties (pkg.name);
 									}
@@ -1557,7 +1559,7 @@ namespace Pamac {
 					while (Gtk.events_pending ()) {
 						Gtk.main_iteration ();
 					}
-					string[] files = transaction.get_pkg_files (current_package_displayed);
+					string[] files = database.get_pkg_files (current_package_displayed);
 					StringBuilder text = new StringBuilder ();
 					foreach (unowned string file in files) {
 						if (text.len > 0) {
@@ -1580,19 +1582,19 @@ namespace Pamac {
 			string pkgname;
 			packages_list.get (iter, 0, out origin, 1, out pkgname);
 			if (!transaction.transaction_summary.contains (pkgname)) {
-				if (transaction.to_install.remove (pkgname)) {
-				} else if (transaction.to_remove.remove (pkgname)) {
+				if (to_install.remove (pkgname)) {
+				} else if (to_remove.remove (pkgname)) {
 				} else {
 					if (origin == 2) { //Alpm.Package.From.LOCALDB
-						if (!transaction.should_hold (pkgname)) {
-							transaction.to_remove.add (pkgname);
+						if (!database.should_hold (pkgname)) {
+							to_remove.add (pkgname);
 						}
-					} else if (transaction.to_update.remove (pkgname)) {
-						transaction.temporary_ignorepkgs.add (pkgname);
-					} else if (transaction.temporary_ignorepkgs.remove (pkgname)) {
-						transaction.to_update.add (pkgname);
+					} else if (to_update.remove (pkgname)) {
+						temporary_ignorepkgs.add (pkgname);
+					} else if (temporary_ignorepkgs.remove (pkgname)) {
+						to_update.add (pkgname);
 					} else {
-						transaction.to_install.add (pkgname);
+						to_install.add (pkgname);
 					}
 				}
 			}
@@ -1625,21 +1627,21 @@ namespace Pamac {
 			string pkgname;
 			aur_list.get (iter, 0, out origin, 1, out pkgname);
 			if (filters_stack.visible_child_name == "updates") {
-				if (transaction.to_update.remove (pkgname)) {
-					transaction.temporary_ignorepkgs.add (pkgname);
-				} else if (transaction.temporary_ignorepkgs.remove (pkgname)) {
-					transaction.to_update.add (pkgname);
+				if (to_update.remove (pkgname)) {
+					temporary_ignorepkgs.add (pkgname);
+				} else if (temporary_ignorepkgs.remove (pkgname)) {
+					to_update.add (pkgname);
 				}
 			} else if (origin == 2) { //Alpm.Package.From.LOCALDB
 				if (!transaction.transaction_summary.contains (pkgname)) {
-					if (transaction.to_remove.remove (pkgname)) {
-					} else if (!transaction.should_hold (pkgname)) {
-						transaction.to_remove.add (pkgname);
+					if (to_remove.remove (pkgname)) {
+					} else if (!database.should_hold (pkgname)) {
+						to_remove.add (pkgname);
 					}
 				}
-			} else if (transaction.to_build.remove (pkgname)) {
+			} else if (to_build.remove (pkgname)) {
 			} else {
-				transaction.to_build.add (pkgname);
+				to_build.add (pkgname);
 			}
 			set_pendings_operations ();
 		}
@@ -1653,18 +1655,18 @@ namespace Pamac {
 				case "details":
 					string? pkgname = display_package_queue.pop_tail ();
 					if (pkgname != null) {
-						AlpmPackage pkg = transaction.get_installed_pkg (pkgname);
+						AlpmPackage pkg = database.get_installed_pkg (pkgname);
 						if (pkg.name == "") {
-							pkg = transaction.get_sync_pkg (pkgname);
+							pkg = database.get_sync_pkg (pkgname);
 						}
 						if (pkg.name == "") {
-							transaction.get_aur_details.begin (pkgname, (obj, res) => {
-								if (transaction.get_aur_details.end (res).name != "") {
+							database.get_aur_details_async.begin (pkgname, (obj, res) => {
+								if (database.get_aur_details_async.end (res).name != "") {
 									display_aur_properties (pkgname);
 								} else {
-									pkg = transaction.find_installed_satisfier (pkgname);
+									pkg = database.find_installed_satisfier (pkgname);
 									if (pkg.name == "") {
-										pkg = transaction.find_sync_satisfier (pkgname);
+										pkg = database.find_sync_satisfier (pkgname);
 									}
 									if (pkg.name != "") {
 										display_package_properties (pkgname);
@@ -1688,12 +1690,12 @@ namespace Pamac {
 
 		void on_install_item_activate () {
 			foreach (unowned string pkgname in selected_pkgs) {
-				if (transaction.get_pkg_origin (pkgname) == 3) { //Alpm.Package.From.SYNCDB
-					transaction.to_install.add (pkgname);
+				if (database.get_pkg_origin (pkgname) == 3) { //Alpm.Package.From.SYNCDB
+					to_install.add (pkgname);
 				}
 			}
 			foreach (unowned string pkgname in selected_aur) {
-				transaction.to_build.add (pkgname);
+				to_build.add (pkgname);
 			}
 			set_pendings_operations ();
 		}
@@ -1711,10 +1713,10 @@ namespace Pamac {
 
 		void on_remove_item_activate () {
 			foreach (unowned string pkgname in selected_pkgs) {
-				transaction.to_install.remove (pkgname);
-				if (!transaction.should_hold (pkgname)) {
-					if (transaction.get_pkg_origin (pkgname) == 2) { //Alpm.Package.From.LOCALDB
-						transaction.to_remove.add (pkgname);
+				to_install.remove (pkgname);
+				if (!database.should_hold (pkgname)) {
+					if (database.get_pkg_origin (pkgname) == 2) { //Alpm.Package.From.LOCALDB
+						to_remove.add (pkgname);
 					}
 				}
 			}
@@ -1723,18 +1725,18 @@ namespace Pamac {
 
 		void on_deselect_item_activate () {
 			foreach (unowned string pkgname in selected_pkgs) {
-				if (transaction.to_install.remove (pkgname)) {
-				} else if (transaction.to_update.remove (pkgname)) {
-					transaction.temporary_ignorepkgs.add (pkgname);
+				if (to_install.remove (pkgname)) {
+				} else if (to_update.remove (pkgname)) {
+					temporary_ignorepkgs.add (pkgname);
 				} else {
-					transaction.to_remove.remove (pkgname);
+					to_remove.remove (pkgname);
 				}
 			}
 			foreach (unowned string pkgname in selected_aur) {
-				if (transaction.to_build.remove (pkgname)) {
+				if (to_build.remove (pkgname)) {
 				} else {
-					transaction.to_update.remove (pkgname);
-					transaction.temporary_ignorepkgs.add (pkgname);
+					to_update.remove (pkgname);
+					temporary_ignorepkgs.add (pkgname);
 				}
 			}
 			set_pendings_operations ();
@@ -1742,12 +1744,12 @@ namespace Pamac {
 
 		void on_upgrade_item_activate () {
 			foreach (unowned string pkgname in selected_pkgs) {
-				transaction.temporary_ignorepkgs.remove (pkgname);
-				transaction.to_update.add (pkgname);
+				temporary_ignorepkgs.remove (pkgname);
+				to_update.add (pkgname);
 			}
 			foreach (unowned string pkgname in selected_aur) {
-				transaction.temporary_ignorepkgs.remove (pkgname);
-				transaction.to_update.add (pkgname);
+				temporary_ignorepkgs.remove (pkgname);
+				to_update.add (pkgname);
 			}
 			set_pendings_operations ();
 		}
@@ -1811,7 +1813,7 @@ namespace Pamac {
 			int index = row.get_index ();
 			switch (index) {
 				case 0: // repos
-					if ((transaction.to_install.length + transaction.to_remove.length) > 0) {
+					if ((to_install.length + to_remove.length) > 0) {
 						origin_stack.visible_child_name = "repos";
 					} else {
 						origin_stack.visible_child_name = "no_item";
@@ -1843,8 +1845,8 @@ namespace Pamac {
 					while (Gtk.events_pending ()) {
 						Gtk.main_iteration ();
 					}
-					transaction.search_pkgs.begin (search_string, (obj, res) => {
-						populate_packages_list (transaction.search_pkgs.end (res));
+					database.search_pkgs_async.begin (search_string, (obj, res) => {
+						populate_packages_list (database.search_pkgs_async.end (res));
 					});
 					break;
 				case 1: // aur
@@ -1862,8 +1864,8 @@ namespace Pamac {
 					while (Gtk.events_pending ()) {
 						Gtk.main_iteration ();
 					}
-					transaction.search_in_aur.begin (search_string, (obj, res) => {
-						populate_aur_list (transaction.search_in_aur.end (res));
+					database.search_in_aur_async.begin (search_string, (obj, res) => {
+						populate_aur_list (database.search_in_aur_async.end (res));
 					});
 					break;
 				default:
@@ -1909,11 +1911,11 @@ namespace Pamac {
 						packages_list.get (iter, 0, out origin, 1, out pkgname, 3, out pkgversion);
 						selected_pkgs.append (pkgname);
 						details_item.sensitive = true;
-						if (transaction.to_install.contains (pkgname)
-							|| transaction.to_remove.contains (pkgname)
-							|| transaction.to_update.contains (pkgname)) {
+						if (to_install.contains (pkgname)
+							|| to_remove.contains (pkgname)
+							|| to_update.contains (pkgname)) {
 							deselect_item.sensitive = true;
-						} else if (transaction.temporary_ignorepkgs.contains (pkgname)) {
+						} else if (temporary_ignorepkgs.contains (pkgname)) {
 							upgrade_item.sensitive = true;
 						} else if (origin == 2) { //Alpm.Package.From.LOCALDB
 							remove_item.sensitive = true;
@@ -1930,14 +1932,14 @@ namespace Pamac {
 							packages_list.get (iter, 0, out origin, 1, out pkgname);
 							selected_pkgs.append (pkgname);
 							if (!deselect_item.sensitive) {
-								if (transaction.to_install.contains (pkgname)
-									|| transaction.to_remove.contains (pkgname)
-									|| transaction.to_update.contains (pkgname)) {
+								if (to_install.contains (pkgname)
+									|| to_remove.contains (pkgname)
+									|| to_update.contains (pkgname)) {
 									deselect_item.sensitive = true;
 								}
 							}
 							if (origin == 3) { //Alpm.Package.From.SYNCDB
-								if (transaction.temporary_ignorepkgs.contains (pkgname)) {
+								if (temporary_ignorepkgs.contains (pkgname)) {
 									upgrade_item.sensitive = true;
 								} else {
 									install_item.sensitive = true;
@@ -1998,7 +2000,7 @@ namespace Pamac {
 						aur_list.get_iter (out iter, path);
 						string pkgname;
 						aur_list.get (iter, 1, out pkgname);
-						AlpmPackage pkg = transaction.get_installed_pkg (pkgname);
+						AlpmPackage pkg = database.get_installed_pkg (pkgname);
 						if (pkg.name != "") {
 							selected_pkgs.append (pkgname);
 							// there is for sure a pkg to remove
@@ -2008,17 +2010,17 @@ namespace Pamac {
 						}
 					}
 					foreach (unowned string pkgname in selected_aur) {
-						if (transaction.to_build.contains (pkgname)) {
+						if (to_build.contains (pkgname)) {
 							deselect_item.sensitive = true;
 						} else {
 							install_item.sensitive = true;
 						}
 					}
 					foreach (unowned string pkgname in selected_pkgs) {
-						if (transaction.to_remove.contains (pkgname)
-							|| transaction.to_update.contains (pkgname)) {
+						if (to_remove.contains (pkgname)
+							|| to_update.contains (pkgname)) {
 							deselect_item.sensitive = true;
-						} else if (transaction.temporary_ignorepkgs.contains (pkgname)) {
+						} else if (temporary_ignorepkgs.contains (pkgname)) {
 							upgrade_item.sensitive = true;
 						}
 					}
@@ -2116,17 +2118,17 @@ namespace Pamac {
 				});
 				switch (origin_stack.visible_child_name) {
 					case "repos":
-						transaction.search_pkgs.begin (search_string, (obj, res) => {
-							if (transaction.enable_aur) {
+						database.search_pkgs_async.begin (search_string, (obj, res) => {
+							if (database.config.enable_aur) {
 								show_sidebar ();
 							} else {
 								hide_sidebar ();
 							}
-							var pkgs = transaction.search_pkgs.end (res);
-							if (pkgs.length == 0 && transaction.enable_aur) {
+							var pkgs = database.search_pkgs_async.end (res);
+							if (pkgs.length == 0 && database.config.enable_aur) {
 								packages_list.clear ();
-								transaction.search_in_aur.begin (search_string, (obj, res) => {
-									if (transaction.search_in_aur.end (res).length > 0) {
+								database.search_in_aur_async.begin (search_string, (obj, res) => {
+									if (database.search_in_aur_async.end (res).length > 0) {
 										origin_stack.visible_child_name = "aur";
 									} else {
 										populate_packages_list (pkgs);
@@ -2139,14 +2141,14 @@ namespace Pamac {
 						aur_list.clear ();
 						break;
 					case "aur":
-						transaction.search_in_aur.begin (search_string, (obj, res) => {
-							populate_aur_list (transaction.search_in_aur.end (res));
+						database.search_in_aur_async.begin (search_string, (obj, res) => {
+							populate_aur_list (database.search_in_aur_async.end (res));
 						});
 						packages_list.clear ();
 						break;
 					case "updated":
 						// select repos
-						if (transaction.enable_aur) {
+						if (database.config.enable_aur) {
 							show_sidebar ();
 						} else {
 							hide_sidebar ();
@@ -2155,7 +2157,7 @@ namespace Pamac {
 						break;
 					case "no_item":
 						// select repos
-						if (transaction.enable_aur) {
+						if (database.config.enable_aur) {
 							show_sidebar ();
 						} else {
 							hide_sidebar ();
@@ -2233,8 +2235,8 @@ namespace Pamac {
 			} else if (category == dgettext (null, "System Tools")) {
 				matching_cat = "System";
 			}
-			transaction.get_category_pkgs.begin (matching_cat, (obj, res) => {
-				populate_packages_list (transaction.get_category_pkgs.end (res));
+			database.get_category_pkgs_async.begin (matching_cat, (obj, res) => {
+				populate_packages_list (database.get_category_pkgs_async.end (res));
 			});
 		}
 
@@ -2245,8 +2247,8 @@ namespace Pamac {
 			var label = row.get_child () as Gtk.Label;
 			string group_name = label.label;
 			this.title = group_name;
-			transaction.get_group_pkgs.begin (group_name, (obj, res) => {
-				populate_packages_list (transaction.get_group_pkgs.end (res));
+			database.get_group_pkgs_async.begin (group_name, (obj, res) => {
+				populate_packages_list (database.get_group_pkgs_async.end (res));
 			});
 		}
 
@@ -2259,23 +2261,23 @@ namespace Pamac {
 			int index = row.get_index ();
 			switch (index) {
 				case 0: // Installed
-					transaction.get_installed_pkgs.begin ((obj, res) => {
-						populate_packages_list (transaction.get_installed_pkgs.end (res));
+					database.get_installed_pkgs_async.begin ((obj, res) => {
+						populate_packages_list (database.get_installed_pkgs_async.end (res));
 					});
 					break;
 				case 1: // Explicitly installed
-					transaction.get_explicitly_installed_pkgs.begin ((obj, res) => {
-						populate_packages_list (transaction.get_explicitly_installed_pkgs.end (res));
+					database.get_explicitly_installed_pkgs_async.begin ((obj, res) => {
+						populate_packages_list (database.get_explicitly_installed_pkgs_async.end (res));
 					});
 					break;
 				case 2: // Orphans
-					transaction.get_orphans.begin ((obj, res) => {
-						populate_packages_list (transaction.get_orphans.end (res));
+					database.get_orphans_async.begin ((obj, res) => {
+						populate_packages_list (database.get_orphans_async.end (res));
 					});
 					break;
 				case 3: // Foreign
-					transaction.get_foreign_pkgs.begin ((obj, res) => {
-						populate_packages_list (transaction.get_foreign_pkgs.end (res));
+					database.get_foreign_pkgs_async.begin ((obj, res) => {
+						populate_packages_list (database.get_foreign_pkgs_async.end (res));
 					});
 					break;
 				default:
@@ -2290,8 +2292,8 @@ namespace Pamac {
 			var label = row.get_child () as Gtk.Label;
 			string repo = label.label;
 			this.title = repo;
-			transaction.get_repo_pkgs.begin (repo, (obj, res) => {
-				populate_packages_list (transaction.get_repo_pkgs.end (res));
+			database.get_repo_pkgs_async.begin (repo, (obj, res) => {
+				populate_packages_list (database.get_repo_pkgs_async.end (res));
 			});
 		}
 
@@ -2400,7 +2402,7 @@ namespace Pamac {
 				SList<string> packages_paths = chooser.get_filenames ();
 				if (packages_paths.length () != 0) {
 					foreach (unowned string path in packages_paths) {
-						transaction.to_load.add (path);
+						to_load.add (path);
 					}
 					chooser.destroy ();
 					try_lock_and_run (run_transaction);
@@ -2417,18 +2419,33 @@ namespace Pamac {
 		void on_preferences_button_clicked () {
 			if (transaction.get_lock ()) {
 				this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH));
-				transaction.run_preferences_dialog ();
+				run_preferences_dialog ();
 			} else {
 				transaction.display_error (dgettext (null, "Waiting for another package manager to quit"), {});
 			}
 		}
 
+		public void run_preferences_dialog () {
+			transaction.check_authorization.begin ((obj, res) => {
+				bool authorized = transaction.check_authorization.end (res);
+				if (authorized) {
+					var preferences_dialog = new PreferencesDialog (transaction);
+					preferences_dialog.run ();
+					preferences_dialog.destroy ();
+					while (Gtk.events_pending ()) {
+						Gtk.main_iteration ();
+					}
+				}
+				on_run_preferences_dialog_finished ();
+			});
+		}
+
 		void on_run_preferences_dialog_finished () {
 			transaction.unlock ();
 			if (filters_stack.visible_child_name == "updates") {
 				origin_stack.visible_child_name = "checking";
 				checking_spinner.active = true;
-				transaction.start_get_updates ();
+				database.start_get_updates ();
 			} else {
 				this.get_window ().set_cursor (null);
 			}
@@ -2456,7 +2473,7 @@ namespace Pamac {
 			if (transaction_running || sysupgrade_running) {
 				main_stack.visible_child_name = "term";
 			} else {
-				uint total_pending = transaction.to_install.length + transaction.to_remove.length + transaction.to_build.length;
+				uint total_pending = to_install.length + to_remove.length + to_build.length;
 				if (total_pending == 0) {
 					main_stack.visible_child_name = "term";
 				}
@@ -2468,6 +2485,7 @@ namespace Pamac {
 			if (filters_stack.visible_child_name == "updates") {
 				force_refresh = false;
 				refreshing = true;
+				sysupgrade_running = true;
 				try_lock_and_run (run_refresh);
 			} else {
 				try_lock_and_run (run_transaction);
@@ -2489,7 +2507,23 @@ namespace Pamac {
 			apply_button.sensitive = false;
 			cancel_button.sensitive = false;
 			show_transaction_infobox ();
-			transaction.run ();
+			string[] to_install_ = {};
+			string[] to_remove_ = {};
+			string[] to_load_ = {};
+			string[] to_build_ = {};
+			foreach (unowned string name in to_install) {
+				to_install_ += name;
+			}
+			foreach (unowned string name in to_remove) {
+				to_remove_ += name;
+			}
+			foreach (unowned string path in to_load) {
+				to_load_ += path;
+			}
+			foreach (unowned string name in to_build) {
+				to_build_ += name;
+			}
+			transaction.start (to_install_, to_remove_, to_load_, to_build_, {});
 			// let time to update packages states
 			Timeout.add (500, () => {
 				refresh_state_icons ();
@@ -2501,7 +2535,11 @@ namespace Pamac {
 			sysupgrade_running = true;
 			apply_button.sensitive = false;
 			cancel_button.sensitive = false;
-			transaction.sysupgrade (false);
+			string[] temp_ign_pkgs = {};
+			foreach (unowned string name in temporary_ignorepkgs) {
+				temp_ign_pkgs += name;
+			}
+			transaction.start_sysupgrade (false, temp_ign_pkgs, {});
 			// let time to update packages states
 			Timeout.add (500, () => {
 				refresh_state_icons ();
@@ -2514,7 +2552,7 @@ namespace Pamac {
 			if (waiting) {
 				waiting = false;
 				transaction.stop_progressbar_pulse ();
-				transaction.to_load.remove_all ();
+				to_load.remove_all ();
 				transaction.unlock ();
 				set_pendings_operations ();
 			} else if (transaction_running) {
@@ -2526,15 +2564,15 @@ namespace Pamac {
 			} else if (sysupgrade_running) {
 				sysupgrade_running = false;
 				transaction.cancel ();
-				transaction.to_build.remove_all ();
+				to_build.remove_all ();
 			} else {
-				transaction.clear_lists ();
+				clear_lists ();
 				set_pendings_operations ();
 				scroll_to_top = false;
 				refresh_packages_list ();
 				if (main_stack.visible_child_name == "details") {
-					if (transaction.get_installed_pkg (current_package_displayed).name != ""
-						|| transaction.get_sync_pkg (current_package_displayed).name != "") {
+					if (database.get_installed_pkg (current_package_displayed).name != ""
+						|| database.get_sync_pkg (current_package_displayed).name != "") {
 						display_package_properties (current_package_displayed);
 					} else {
 						display_aur_properties (current_package_displayed);
@@ -2549,6 +2587,7 @@ namespace Pamac {
 		[GtkCallback]
 		void on_refresh_button_clicked () {
 			force_refresh = true;
+			refreshing = true;
 			try_lock_and_run (run_refresh);
 		}
 
@@ -2577,7 +2616,7 @@ namespace Pamac {
 		}
 
 		void populate_updates () {
-			transaction.to_update.remove_all ();
+			to_update.remove_all ();
 			if ((repos_updates.length + aur_updates.length) == 0) {
 				if (!refreshing && !transaction_running && !sysupgrade_running) {
 					hide_transaction_infobox ();
@@ -2587,15 +2626,15 @@ namespace Pamac {
 			} else {
 				if (repos_updates.length > 0) {
 					foreach (unowned AlpmPackage pkg in repos_updates) {
-						if (!transaction.temporary_ignorepkgs.contains (pkg.name)) {
-							transaction.to_update.add (pkg.name);
+						if (!temporary_ignorepkgs.contains (pkg.name)) {
+							to_update.add (pkg.name);
 						}
 					}
 				}
 				if (aur_updates.length > 0) {
 					foreach (unowned AURPackage pkg in aur_updates) {
-						if (!transaction.temporary_ignorepkgs.contains (pkg.name)) {
-							transaction.to_update.add (pkg.name);
+						if (!temporary_ignorepkgs.contains (pkg.name)) {
+							to_update.add (pkg.name);
 						}
 					}
 					show_sidebar ();
@@ -2638,7 +2677,7 @@ namespace Pamac {
 			}
 		}
 
-		void on_generate_mirrors_list () {
+		void on_start_generating_mirrors_list () {
 			generate_mirrors_list = true;
 			apply_button.sensitive = false;
 			show_transaction_infobox ();
@@ -2648,11 +2687,35 @@ namespace Pamac {
 			generate_mirrors_list = false;
 		}
 
+		void on_refresh_finished (bool success) {
+			refreshing = false;
+			if (sysupgrade_running) {
+				run_sysupgrade ();
+			} else {
+				database.refresh ();
+				scroll_to_top = false;
+				refresh_packages_list ();
+				if (main_stack.visible_child_name == "details") {
+					if (database.get_installed_pkg (current_package_displayed).name != ""
+						|| database.get_sync_pkg (current_package_displayed).name != "") {
+						display_package_properties (current_package_displayed);
+					} else {
+						display_aur_properties (current_package_displayed);
+					}
+				} else if (main_stack.visible_child_name == "term") {
+					button_back.visible = true;
+				}
+			}
+		}
+
 		void on_transaction_finished (bool success) {
-			transaction.refresh_handle ();
+			transaction.unlock ();
+			database.refresh ();
+			scroll_to_top = false;
+			refresh_packages_list ();
 			if (main_stack.visible_child_name == "details") {
-				if (transaction.get_installed_pkg (current_package_displayed).name != ""
-					|| transaction.get_sync_pkg (current_package_displayed).name != "") {
+				if (database.get_installed_pkg (current_package_displayed).name != ""
+					|| database.get_sync_pkg (current_package_displayed).name != "") {
 					display_package_properties (current_package_displayed);
 				} else {
 					display_aur_properties (current_package_displayed);
@@ -2660,22 +2723,15 @@ namespace Pamac {
 			} else if (main_stack.visible_child_name == "term") {
 				button_back.visible = true;
 			}
-			transaction.to_load.remove_all ();
-			if (refreshing) {
-				refreshing = false;
-				run_sysupgrade ();
-			} else if (sysupgrade_running) {
+			if (sysupgrade_running) {
 				sysupgrade_running = false;
-				transaction.to_build.remove_all ();
-				transaction.unlock ();
-				scroll_to_top = false;
-				refresh_packages_list ();
+				to_build.remove_all ();
 			} else {
 				transaction_running = false;
 				generate_mirrors_list = false;
-				transaction.unlock ();
-				scroll_to_top = false;
-				refresh_packages_list ();
+			}
+			if (success) {
+				clear_lists ();
 			}
 			set_pendings_operations ();
 		}
diff --git a/src/meson.build b/src/meson.build
index 0fe02463..bc174612 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -31,16 +31,9 @@ common_vala_args = ['--pkg=posix', '--target-glib=2.38']
 common_c_args = ['-DGETTEXT_PACKAGE="pamac"']
 
 common_sources = ['common.vala', 'package.vala', 'pamac_config.vala']
-transaction_sources = ['transaction.vala', 'choose_provider_dialog.vala', 'transaction_sum_dialog.vala', 'progress_box.vala']
+transaction_gtk_sources = ['transaction-gtk.vala', 'choose_provider_dialog.vala', 'transaction_sum_dialog.vala', 'progress_box.vala']
 preferences_sources = ['preferences_dialog.vala', 'choose_ignorepkgs_dialog.vala']
 
-executable('pamac',
-	sources: [common_sources, 'version.vala','cli.vala'],
-	dependencies: [gio, posix, math],
-	vala_args: [common_vala_args, '--pkg=linux'],
-	c_args: common_c_args,
-	install: true)
-
 executable('pamac-clean-cache',
 	sources: ['pamac_config.vala', 'clean_cache.vala'],
 	dependencies: [gio],
@@ -72,25 +65,51 @@ executable('pamac-user-daemon',
 	install : true)
 
 executable('pamac-system-daemon',
-	sources: [common_sources, 'alpm_config.vala', 'aur.vala', 'system_daemon.vala'],
+	sources: ['common_daemon.vala', 'package.vala', 'pamac_config.vala', 'alpm_config.vala', 'aur.vala', 'system_daemon.vala'],
 	dependencies: [vala_deps, alpm_deps, json, libsoup, polkit, libcurl, appstream],
 	vala_args: [common_vala_args, alpm_vala_args, '--thread'],
 	c_args: [common_c_args, alpm_c_args],
 	install : true)
 
 libpamac = library('pamac',
-	sources: [common_sources, transaction_sources, preferences_sources, transaction_resources],
-	dependencies: [gtk3, gdk3, vte3, libnotify, posix, math],
+	sources: [common_sources, 'updates_priv.vala', 'database.vala', 'transaction.vala', 'transaction-cli.vala'],
+	dependencies: [gio, posix, math],
+	vala_args: [common_vala_args, '--pkg=linux'],
+	c_args: common_c_args,
+	vala_gir: 'Pamac-1.0.gir',
+	install: true,
+	install_dir: [true, true, true, true])
+
+libpamac_dep = declare_dependency(link_with: libpamac)
+
+executable('pamac',
+	sources: ['version.vala','cli.vala'],
+	dependencies: [gio, posix, math, libpamac_dep],
+	vala_args: common_vala_args,
+	c_args: common_c_args,
+	install: true)
+
+libpamac_gtk = library('pamac-gtk',
+	sources: [transaction_gtk_sources, transaction_resources],
+	dependencies: [gio, gtk3, vte3, libnotify, posix, math, libpamac_dep],
 	vala_args: common_vala_args,
 	c_args: common_c_args,
 	install: true,
 	install_dir: [true, true, true])
 
-libpamac_dep = declare_dependency(link_with: libpamac)
+# create typelib files
+g_ir_compiler = find_program('g-ir-compiler')
+custom_target('pamac typelib', command: [g_ir_compiler, '--shared-library', 'libpamac', '--output', '@OUTPUT@', join_paths(meson.current_build_dir(), 'Pamac-1.0.gir')],
+	output: 'Pamac-1.0.typelib',
+	depends: libpamac,
+	install: true,
+	install_dir: join_paths(get_option('libdir'), 'girepository-1.0'))
+
+libpamac_gtk_dep = declare_dependency(link_with: libpamac_gtk)
 
 executable('pamac-manager',
-	sources: ['version.vala', 'history_dialog.vala', 'manager_window.vala', 'manager.vala', manager_resources],
-	dependencies: [vala_deps, gtk3, gdk3, gdk_pixbuf2, libsoup, libpamac_dep],
+	sources: ['version.vala', 'history_dialog.vala', preferences_sources, 'manager_window.vala', 'manager.vala', manager_resources],
+	dependencies: [gtk3, libsoup, libpamac_dep, libpamac_gtk_dep],
 	vala_args: common_vala_args,
 	c_args: common_c_args,
 	install: true)
@@ -98,10 +117,10 @@ executable('pamac-manager',
 # create pamac-updater symlink
 meson.add_install_script('sh', '-c',
 	'ln -sf pamac-manager ${DESTDIR}/${MESON_INSTALL_PREFIX}/@0@/pamac-updater'.format(get_option('bindir')))
- 
+
 executable('pamac-installer',
 	sources: ['progress_dialog.vala', 'installer.vala', installer_resources],
-	dependencies: [gtk3, libpamac_dep],
+	dependencies: [gtk3, libpamac_dep, libpamac_gtk_dep],
 	vala_args: common_vala_args,
 	c_args: common_c_args,
 	install: true)
diff --git a/src/pamac_config.vala b/src/pamac_config.vala
index 00d5048a..10668eb8 100644
--- a/src/pamac_config.vala
+++ b/src/pamac_config.vala
@@ -18,27 +18,30 @@
  */
 
 namespace Pamac {
-	public class Config {
-		string conf_path;
+	public class Config: Object {
 		HashTable<string,string> _environment_variables;
 
-		public bool recurse { get; private set; }
-		public uint64 refresh_period { get; private set; }
-		public bool no_update_hide_icon { get; private set; }
-		public bool enable_aur { get; private set; }
-		public string aur_build_dir { get; private set; }
-		public bool check_aur_updates { get; private set; }
-		public bool download_updates { get; private set; }
-		public uint64 keep_num_pkgs { get; private set; }
-		public bool rm_only_uninstalled { get; private set; }
+		public string conf_path { get; construct; }
+		public bool recurse { get; set; }
+		public uint64 refresh_period { get; set; }
+		public bool no_update_hide_icon { get; set; }
+		public bool enable_aur { get; set; }
+		public string aur_build_dir { get; set; }
+		public bool check_aur_updates { get; set; }
+		public bool download_updates { get; set; }
+		public uint64 clean_keep_num_pkgs { get;  set; }
+		public bool clean_rm_only_uninstalled { get; set; }
 		public unowned HashTable<string,string> environment_variables {
 			get {
 				return _environment_variables;
 			}
 		}
 
-		public Config (string path) {
-			conf_path = path;
+		public Config (string conf_path) {
+			Object(conf_path: conf_path);
+		}
+
+		construct {
 			//get environment variables
 			_environment_variables = new HashTable<string,string> (str_hash, str_equal);
 			var utsname = Posix.utsname();
@@ -76,8 +79,8 @@ namespace Pamac {
 			aur_build_dir = "/tmp";
 			check_aur_updates = false;
 			download_updates = false;
-			keep_num_pkgs = 3;
-			rm_only_uninstalled = false;
+			clean_keep_num_pkgs = 3;
+			clean_rm_only_uninstalled = false;
 			parse_file (conf_path);
 		}
 
@@ -112,10 +115,10 @@ namespace Pamac {
 						} else if (key == "KeepNumPackages") {
 							if (splitted.length == 2) {
 								unowned string val = splitted[1]._strip ();
-								keep_num_pkgs = uint64.parse (val);
+								clean_keep_num_pkgs = uint64.parse (val);
 							}
 						} else if (key == "OnlyRmUninstalled") {
-							rm_only_uninstalled = true;
+							clean_rm_only_uninstalled = true;
 						} else if (key == "NoUpdateHideIcon") {
 							no_update_hide_icon = true;
 						} else if (key == "EnableAUR") {
diff --git a/src/preferences_dialog.vala b/src/preferences_dialog.vala
index cea978fb..b400c52c 100644
--- a/src/preferences_dialog.vala
+++ b/src/preferences_dialog.vala
@@ -62,11 +62,11 @@ namespace Pamac {
 		Gtk.CheckButton cache_only_uninstalled_checkbutton;
 
 		Gtk.ListStore ignorepkgs_liststore;
-		Transaction transaction;
+		TransactionGtk transaction;
 		uint64 previous_refresh_period;
 		string preferences_choosen_country;
 
-		public PreferencesDialog (Transaction transaction) {
+		public PreferencesDialog (TransactionGtk transaction) {
 			int use_header_bar;
 			Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header_bar);
 			Object (transient_for: transaction.application_window, use_header_bar: use_header_bar);
@@ -75,9 +75,9 @@ namespace Pamac {
 			refresh_period_label.set_markup (dgettext (null, "How often to check for updates, value in hours") +":");
 			cache_keep_nb_label.set_markup (dgettext (null, "Number of versions of each package to keep in the cache") +":");
 			aur_build_dir_label.set_markup (dgettext (null, "Build directory") +":");
-			remove_unrequired_deps_button.active = transaction.recurse;
-			check_space_button.active = transaction.get_checkspace ();
-			if (transaction.refresh_period == 0) {
+			remove_unrequired_deps_button.active = transaction.database.config.recurse;
+			check_space_button.active = transaction.database.get_checkspace ();
+			if (transaction.database.config.refresh_period == 0) {
 				check_updates_button.active = false;
 				refresh_period_label.sensitive = false;
 				// set default value
@@ -89,18 +89,18 @@ namespace Pamac {
 				ignorepkgs_box.sensitive = false;
 			} else {
 				check_updates_button.active = true;
-				refresh_period_spin_button.value = transaction.refresh_period;
-				previous_refresh_period = transaction.refresh_period;
+				refresh_period_spin_button.value = transaction.database.config.refresh_period;
+				previous_refresh_period = transaction.database.config.refresh_period;
 			}
-			no_update_hide_icon_checkbutton.active = transaction.no_update_hide_icon;
-			download_updates_checkbutton.active = transaction.download_updates;
-			cache_keep_nb_spin_button.value = transaction.keep_num_pkgs;
-			cache_only_uninstalled_checkbutton.active = transaction.rm_only_uninstalled;
+			no_update_hide_icon_checkbutton.active = transaction.database.config.no_update_hide_icon;
+			download_updates_checkbutton.active = transaction.database.config.download_updates;
+			cache_keep_nb_spin_button.value = transaction.database.config.clean_keep_num_pkgs;
+			cache_only_uninstalled_checkbutton.active = transaction.database.config.clean_rm_only_uninstalled;
 
 			// populate ignorepkgs_liststore
 			ignorepkgs_liststore = new Gtk.ListStore (1, typeof (string));
 			ignorepkgs_treeview.set_model (ignorepkgs_liststore);
-			foreach (unowned string ignorepkg in transaction.get_ignorepkgs ()) {
+			foreach (unowned string ignorepkg in transaction.database.get_ignorepkgs ()) {
 				ignorepkgs_liststore.insert_with_values (null, -1, 0, ignorepkg);
 			}
 			remove_unrequired_deps_button.state_set.connect (on_remove_unrequired_deps_button_state_set);
@@ -114,17 +114,17 @@ namespace Pamac {
 			cache_only_uninstalled_checkbutton.toggled.connect (on_cache_only_uninstalled_checkbutton_toggled);
 			transaction.write_pamac_config_finished.connect (on_write_pamac_config_finished);
 
-			AlpmPackage pkg = transaction.find_installed_satisfier ("pacman-mirrors");
+			AlpmPackage pkg = transaction.database.find_installed_satisfier ("pacman-mirrors");
 			if (pkg.name == "") {
 				mirrors_config_box.visible = false;
 			} else {
 				mirrors_country_comboboxtext.append_text (dgettext (null, "Worldwide"));
 				mirrors_country_comboboxtext.active = 0;
 				if (transaction.preferences_available_countries.length == 0) {
-					transaction.preferences_available_countries = transaction.get_mirrors_countries ();
+					transaction.preferences_available_countries = transaction.database.get_mirrors_countries ();
 				}
 				int index = 1;
-				preferences_choosen_country = transaction.get_mirrors_choosen_country ();
+				preferences_choosen_country = transaction.database.get_mirrors_choosen_country ();
 				foreach (unowned string country in transaction.preferences_available_countries) {
 					mirrors_country_comboboxtext.append_text (country);
 					if (country == preferences_choosen_country) {
@@ -135,18 +135,18 @@ namespace Pamac {
 				mirrors_country_comboboxtext.changed.connect (on_mirrors_country_comboboxtext_changed);
 			}
 
-			enable_aur_button.active = transaction.enable_aur;
-			aur_build_dir_label.sensitive = transaction.enable_aur;
-			aur_build_dir_file_chooser.sensitive = transaction.enable_aur;
-			aur_build_dir_file_chooser.set_filename (transaction.aur_build_dir);
+			enable_aur_button.active = transaction.database.config.enable_aur;
+			aur_build_dir_label.sensitive = transaction.database.config.enable_aur;
+			aur_build_dir_file_chooser.sensitive = transaction.database.config.enable_aur;
+			aur_build_dir_file_chooser.set_filename (transaction.database.config.aur_build_dir);
 			// add /tmp choice always visible
 			try {
 				aur_build_dir_file_chooser.add_shortcut_folder ("/tmp");
 			} catch (GLib.Error e) {
 				stderr.printf ("%s\n", e.message);
 			}
-			check_aur_updates_checkbutton.active = transaction.check_aur_updates;
-			check_aur_updates_checkbutton.sensitive = transaction.enable_aur;
+			check_aur_updates_checkbutton.active = transaction.database.config.check_aur_updates;
+			check_aur_updates_checkbutton.sensitive = transaction.database.config.enable_aur;
 			enable_aur_button.state_set.connect (on_enable_aur_button_state_set);
 			aur_build_dir_file_chooser.file_set.connect (on_aur_build_dir_set);
 			check_aur_updates_checkbutton.toggled.connect (on_check_aur_updates_checkbutton_toggled);
@@ -268,10 +268,10 @@ namespace Pamac {
 			while (Gtk.events_pending ()) {
 				Gtk.main_iteration ();
 			}
-			transaction.get_installed_pkgs.begin ((obj, res) => {
-				var pkgs = transaction.get_installed_pkgs.end (res);
+			transaction.database.get_installed_pkgs_async.begin ((obj, res) => {
+				var pkgs = transaction.database.get_installed_pkgs_async.end (res);
 				// make a copy of ignorepkgs to store uninstalled ones
-				string[] ignorepkgs = transaction.get_ignorepkgs ();
+				string[] ignorepkgs = transaction.database.get_ignorepkgs ();
 				var ignorepkgs_set = new GenericSet<string?> (str_hash, str_equal);
 				foreach (unowned string ignorepkg in ignorepkgs) {
 					ignorepkgs_set.add (ignorepkg);
@@ -342,7 +342,7 @@ namespace Pamac {
 		void on_write_alpm_config_finished (bool checkspace) {
 			check_space_button.state = checkspace;
 			ignorepkgs_liststore.clear ();
-			foreach (unowned string ignorepkg in transaction.get_ignorepkgs ()) {
+			foreach (unowned string ignorepkg in transaction.database.get_ignorepkgs ()) {
 				ignorepkgs_liststore.insert_with_values (null, -1, 0, ignorepkg);
 			}
 		}
@@ -363,7 +363,7 @@ namespace Pamac {
 
 		[GtkCallback]
 		void on_cache_clean_button_clicked () {
-			transaction.clean_cache (transaction.keep_num_pkgs, transaction.rm_only_uninstalled);
+			transaction.clean_cache (transaction.database.config.clean_keep_num_pkgs, transaction.database.config.clean_rm_only_uninstalled);
 		}
 	}
 }
diff --git a/src/system_daemon.vala b/src/system_daemon.vala
index f13363d5..040177d2 100644
--- a/src/system_daemon.vala
+++ b/src/system_daemon.vala
@@ -86,7 +86,7 @@ namespace Pamac {
 		public signal void emit_log (uint level, string msg);
 		public signal void set_pkgreason_finished ();
 		public signal void refresh_finished (bool success);
-		public signal void get_updates_finished (Updates updates);
+		public signal void get_updates_finished (UpdatesPriv updates);
 		public signal void download_updates_finished ();
 		public signal void trans_prepare_finished (bool success);
 		public signal void trans_commit_finished (bool success);
@@ -107,6 +107,7 @@ namespace Pamac {
 			aurdb_path = "/tmp/pamac-aur";
 			aur_updates_results = new Json.Array ();
 			timer = new Timer ();
+			current_error = ErrorInfos ();
 			lock_id = new BusName ("");
 			refresh_handle ();
 			check_old_lock ();
@@ -306,7 +307,7 @@ namespace Pamac {
 
 		public void start_write_pamac_config (HashTable<string,Variant> new_pamac_conf, GLib.BusName sender) throws Error {
 			check_authorization.begin (sender, (obj, res) => {
-				var pamac_config = new Pamac.Config ("/etc/pamac.conf");
+				var pamac_config = new Config ("/etc/pamac.conf");
 				bool authorized = check_authorization.end (res);
 				if (authorized ) {
 					pamac_config.write (new_pamac_conf);
@@ -754,6 +755,7 @@ namespace Pamac {
 		}
 
 		private void get_updates () {
+			bool syncfirst = false;
 			AlpmPackage[] updates_infos = {};
 			unowned Alpm.Package? pkg = null;
 			unowned Alpm.Package? candidate = null;
@@ -764,76 +766,72 @@ namespace Pamac {
 					if (candidate != null) {
 						var infos = initialise_pkg_struct (candidate);
 						updates_infos += (owned) infos;
+						syncfirst = true;
 					}
 				}
 			}
-			if (updates_infos.length != 0) {
-				var updates = Updates () {
-					is_syncfirst = true,
-					repos_updates = (owned) updates_infos,
-					aur_updates = {}
-				};
-				get_updates_finished (updates);
-			} else {
-				string[] local_pkgs = {};
-				unowned Alpm.List<unowned Alpm.Package> pkgcache = alpm_handle.localdb.pkgcache;
-				while (pkgcache != null) {
-					unowned Alpm.Package installed_pkg = pkgcache.data;
-					// check if installed_pkg is in IgnorePkg or IgnoreGroup
-					if (alpm_handle.should_ignore (installed_pkg) == 0) {
+			string[] local_pkgs = {};
+			unowned Alpm.List<unowned Alpm.Package> pkgcache = alpm_handle.localdb.pkgcache;
+			while (pkgcache != null) {
+				unowned Alpm.Package installed_pkg = pkgcache.data;
+				// check if installed_pkg is in IgnorePkg or IgnoreGroup
+				if (alpm_handle.should_ignore (installed_pkg) == 0) {
+					if (syncfirst) {
+						candidate = null;
+					} else {
 						candidate = installed_pkg.sync_newversion (alpm_handle.syncdbs);
-						if (candidate != null) {
-							var infos = initialise_pkg_struct (candidate);
-							updates_infos += (owned) infos;
-						} else {
-							if (check_aur_updates && (!aur_updates_checked)) {
-								// check if installed_pkg is a local pkg
-								unowned Alpm.List<unowned Alpm.DB> syncdbs = alpm_handle.syncdbs;
-								while (syncdbs != null) {
-									unowned Alpm.DB db = syncdbs.data;
-									pkg = Alpm.find_satisfier (db.pkgcache, installed_pkg.name);
-									if (pkg != null) {
-										break;
-									}
-									syncdbs.next ();
-								}
-								if (pkg == null) {
-									local_pkgs += installed_pkg.name;
+					}
+					if (candidate != null) {
+						var infos = initialise_pkg_struct (candidate);
+						updates_infos += (owned) infos;
+					} else {
+						if (check_aur_updates && (!aur_updates_checked)) {
+							// check if installed_pkg is a local pkg
+							unowned Alpm.List<unowned Alpm.DB> syncdbs = alpm_handle.syncdbs;
+							while (syncdbs != null) {
+								unowned Alpm.DB db = syncdbs.data;
+								pkg = Alpm.find_satisfier (db.pkgcache, installed_pkg.name);
+								if (pkg != null) {
+									break;
 								}
+								syncdbs.next ();
+							}
+							if (pkg == null) {
+								local_pkgs += installed_pkg.name;
 							}
 						}
 					}
-					pkgcache.next ();
 				}
-				if (check_aur_updates) {
-					// get aur updates
-					if (!aur_updates_checked) {
-						AUR.multiinfo.begin (local_pkgs, (obj, res) => {
-							aur_updates_results = AUR.multiinfo.end (res);
-							aur_updates_checked = true;
-							var updates = Updates () {
-								is_syncfirst = false,
-								repos_updates = (owned) updates_infos,
-								aur_updates = get_aur_updates_infos ()
-							};
-							get_updates_finished (updates);
-						});
-					} else {
-						var updates = Updates () {
-							is_syncfirst = false,
+				pkgcache.next ();
+			}
+			if (check_aur_updates) {
+				// get aur updates
+				if (!aur_updates_checked) {
+					AUR.multiinfo.begin (local_pkgs, (obj, res) => {
+						aur_updates_results = AUR.multiinfo.end (res);
+						aur_updates_checked = true;
+						var updates = UpdatesPriv () {
+							syncfirst = syncfirst,
 							repos_updates = (owned) updates_infos,
 							aur_updates = get_aur_updates_infos ()
 						};
 						get_updates_finished (updates);
-					}
+					});
 				} else {
-					var updates = Updates () {
-						is_syncfirst = false,
+					var updates = UpdatesPriv () {
+						syncfirst = syncfirst,
 						repos_updates = (owned) updates_infos,
-						aur_updates = {}
+						aur_updates = get_aur_updates_infos ()
 					};
 					get_updates_finished (updates);
 				}
+			} else {
+				var updates = UpdatesPriv () {
+					syncfirst = syncfirst,
+					repos_updates = (owned) updates_infos,
+					aur_updates = {}
+				};
+				get_updates_finished (updates);
 			}
 		}
 
diff --git a/src/transaction-cli.vala b/src/transaction-cli.vala
new file mode 100644
index 00000000..35081168
--- /dev/null
+++ b/src/transaction-cli.vala
@@ -0,0 +1,479 @@
+/*
+ *  pamac-vala
+ *
+ *  Copyright (C) 2018 Guillaume Benoit <guillaume@manjaro.org>
+ *
+ *  This program 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 get of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Pamac {
+	public class TransactionCli: Transaction {
+		bool downloading;
+		string current_line;
+		string current_action;
+
+		public bool asking_user_input { get; set; }
+
+		public TransactionCli (Database database) {
+			Object (database: database);
+		}
+
+		construct {
+			downloading = false;
+			current_line = "";
+			current_action = "";
+			asking_user_input = false;
+			// connect to signal
+			emit_action.connect (print_action);
+			emit_action_progress.connect (print_action_progress);
+			emit_hook_progress.connect (print_hook_progress);
+			emit_script_output.connect (on_emit_script_output);
+			emit_warning.connect (print_warning);
+			emit_error.connect (print_error);
+			refresh_finished.connect (on_refresh_finished);
+			finished.connect (on_finished);
+			sysupgrade_finished.connect (on_finished);
+			start_downloading.connect (() => {
+				downloading = true;
+			});
+			stop_downloading.connect (() => {
+				downloading = false;
+			});
+		}
+
+		protected override async int run_cmd_line (string[] args, string working_directory, Cancellable cancellable) {
+			int status = 1;
+			var launcher = new SubprocessLauncher (SubprocessFlags.NONE);
+			launcher.set_cwd (working_directory);
+			launcher.set_environ (Environ.get ());
+			try {
+				Subprocess process = launcher.spawnv (args);
+				try {
+					yield process.wait_async (cancellable);
+					if (process.get_if_exited ()) {
+						status = process.get_exit_status ();
+					}
+				} catch (Error e) {
+					// cancelled
+					process.send_signal (Posix.Signal.INT);
+					process.send_signal (Posix.Signal.KILL);
+				}
+			} catch (Error e) {
+				print_error (e.message, {});
+			}
+			return status;
+		}
+
+		public int get_term_width () {
+			int width = 80;
+			Linux.winsize win;
+			if (Linux.ioctl (Posix.STDOUT_FILENO, Linux.Termios.TIOCGWINSZ, out win) == 0) {
+				width = win.ws_col;
+			}
+			return width;
+		}
+
+		void display_current_line () {
+			if (current_line != "") {
+				// clean line
+				stdout.printf ("\r%*s\r", get_term_width (), "");
+				stdout.printf (current_line);
+				stdout.printf ("\n");
+				current_line = "";
+			}
+		}
+
+		void on_emit_script_output (string line) {
+			display_current_line ();
+			stdout.printf (line);
+			stdout.printf ("\n");
+		}
+
+		void print_action (string action) {
+			if (action == dgettext (null, "Checking dependencies")
+				|| action == dgettext (null, "Resolving dependencies")
+				|| action == dgettext (null, "Downloading")) {
+				asking_user_input = false;
+			}
+			display_current_line ();
+			current_line = "";
+			stdout.printf (action);
+			stdout.printf ("\n");
+		}
+
+		void print_action_progress (string action, string status, double progress) {
+			if (downloading) {
+				if (progress == 0) {
+					current_action = action;
+					current_line = status;
+					stdout.printf (action);
+					stdout.printf ("\n");
+					stdout.printf (status);
+				} else if (progress == 1) {
+					current_line = "";
+					// clean line
+					stdout.printf ("\r%*s\r", get_term_width (), "");
+				} else if (action == current_action) {
+					current_line = status;
+					// clean line
+					stdout.printf ("\r%*s\r", get_term_width (), "");
+					stdout.printf (status);
+				} else {
+					current_action = action;
+					current_line = status;
+					// clean line
+					stdout.printf ("\r%*s\r", get_term_width (), "");
+					stdout.printf (action);
+					stdout.printf ("\n");
+					stdout.printf (status);
+				}
+			} else {
+				if (action != current_action) {
+					current_action = action;
+					display_current_line ();
+				}
+				int width = get_term_width () - action.char_count () - 1;
+				string current_status = "[%s]".printf (status);
+				current_line = "%s %*s".printf (action, width, current_status);
+				stdout.printf (current_line);
+				stdout.printf ("\r");
+			}
+			stdout.flush ();
+		}
+
+		void print_hook_progress (string action, string details, string status, double progress) {
+			if (action != current_action) {
+				current_action = action;
+				display_current_line ();
+				stdout.printf (action);
+				stdout.printf ("\n");
+			}
+			int width = get_term_width () - details.char_count () - 1;
+			string current_status = "[%s]".printf (status);
+			stdout.printf ("%s %*s\n".printf (details, width, current_status));
+		}
+
+		void print_warning (string line) {
+			display_current_line ();
+			stdout.printf (line);
+			stdout.printf ("\n");
+		}
+
+		void print_error (string message, string[] details) {
+			display_current_line ();
+			if (downloading) {
+				// when downloading errors have no details
+				stdout.printf ("%s\n", message);
+			} else if (details.length > 0) {
+				if (details.length == 1) {
+					stdout.printf ("%s: %s: %s\n", dgettext (null, "Error"), message, details[0]);
+				} else {
+					stdout.printf ("%s: %s:\n", dgettext (null, "Error"), message);
+					foreach (unowned string detail in details) {
+						stdout.printf ("%s\n", detail);
+					}
+				}
+			} else {
+				stdout.printf ("%s: %s\n", dgettext (null, "Error"), message);
+			}
+		}
+
+		protected override int choose_provider (string depend, string[] providers) {
+			AlpmPackage[] pkgs = {};
+			foreach (unowned string pkgname in providers) {
+				var pkg = database.get_sync_pkg (pkgname);
+				if (pkg.name != "")  {
+					pkgs += pkg;
+				}
+			}
+			// print pkgs
+			int name_length = 0;
+			int version_length = 0;
+			int repo_length = 0;
+			foreach (unowned AlpmPackage pkg in pkgs) {
+				if (pkg.name.length > name_length) {
+					name_length = pkg.name.length;
+				}
+				if (pkg.version.length > version_length) {
+					version_length = pkg.version.length;
+				}
+				if (pkg.repo.length > repo_length) {
+					repo_length = pkg.repo.length;
+				}
+			}
+			int num_length = providers.length.to_string ().length + 1;
+			int total_width = num_length + name_length + version_length + repo_length + 4;
+			int margin = 0;
+			if (get_term_width () > total_width) {
+				// divide available space between columns
+				int available_width = get_term_width () - total_width;
+				margin = available_width / 3;
+				// get left space to repo
+				repo_length += available_width - (margin * 3);
+			}
+			stdout.printf ("%s:\n".printf (dgettext (null, "Choose a provider for %s").printf (depend)));
+			int num = 1;
+			foreach (unowned AlpmPackage pkg in pkgs) {
+				stdout.printf ("%*s %-*s %-*s %-*s \n", num_length, "%i:".printf (num),
+														name_length + margin, pkg.name,
+														version_length + margin, pkg.version,
+														repo_length + margin, pkg.repo);
+				num++;
+			}
+			// get user input
+			asking_user_input = true;
+			while (true) {
+				stdout.printf ("%s: ", dgettext (null, "Enter a number (default=%d)").printf (1));
+				string ans = stdin.read_line  ();
+				int64 nb;
+				// remvove trailing newline
+				ans = ans.replace ("\n", "");
+				// just return use default
+				if (ans == "") {
+					nb = 1;
+				} else if (!int64.try_parse (ans, out nb)) {
+					nb = 0;
+				}
+				stdout.printf ("\n");
+				if (nb >= 1 && nb <= providers.length) {
+					int index = (int) nb - 1;
+					return index;
+				}
+			}
+		}
+
+		protected override bool ask_confirmation (TransactionSummary summary) {
+			uint64 dsize = 0;
+			uint64 rsize = 0;
+			int64 isize = 0;
+			int max_name_length = 0;
+			int max_version_length = 0;
+			int max_installed_version_length = 0;
+			int max_size_length = 0;
+			int margin = 0;
+			// first pass to compute pkgs size and strings length
+			if (summary.to_remove.length > 0) {
+				foreach (unowned AlpmPackage infos in summary.to_remove) {
+					rsize += infos.size;
+					if (infos.name.length > max_name_length) {
+						max_name_length = infos.name.length;
+					}
+					if (infos.version.length > max_version_length) {
+						max_version_length = infos.version.length;
+					}
+				}
+			}
+			if (summary.aur_conflicts_to_remove.length > 0) {
+				foreach (unowned AlpmPackage infos in summary.aur_conflicts_to_remove) {
+					rsize += infos.size;
+					if (infos.name.length > max_name_length) {
+						max_name_length = infos.name.length;
+					}
+					if (infos.version.length > max_version_length) {
+						max_version_length = infos.version.length;
+					}
+				}
+			}
+			if (summary.to_downgrade.length > 0) {
+				foreach (unowned AlpmPackage infos in summary.to_downgrade) {
+					dsize += infos.download_size;
+					var pkg = database.get_installed_pkg (infos.name);
+					isize += ((int64) infos.size - (int64) pkg.size);
+					if (infos.name.length > max_name_length) {
+						max_name_length = infos.name.length;
+					}
+					if (infos.version.length > max_version_length) {
+						max_version_length = infos.version.length;
+					}
+					if (infos.installed_version.length > max_installed_version_length) {
+						max_installed_version_length = infos.installed_version.length;
+					}
+					string size = format_size (pkg.size);
+					if (size.length > max_size_length) {
+						max_size_length = size.length;
+					}
+				}
+			}
+			if (summary.to_build.length > 0) {
+				foreach (unowned AURPackage infos in summary.to_build) {
+					if (infos.name.length > max_name_length) {
+						max_name_length = infos.name.length;
+					}
+					if (infos.version.length > max_version_length) {
+						max_version_length = infos.version.length;
+					}
+				}
+			}
+			if (summary.to_install.length > 0) {
+				foreach (unowned AlpmPackage infos in summary.to_install) {
+					dsize += infos.download_size;
+					var pkg = database.get_installed_pkg (infos.name);
+					isize += ((int64) infos.size - (int64) pkg.size);
+					if (infos.name.length > max_name_length) {
+						max_name_length = infos.name.length;
+					}
+					if (infos.version.length > max_version_length) {
+						max_version_length = infos.version.length;
+					}
+					string size = format_size (pkg.size);
+					if (size.length > max_size_length) {
+						max_size_length = size.length;
+					}
+				}
+			}
+			if (summary.to_reinstall.length > 0) {
+				foreach (unowned AlpmPackage infos in summary.to_reinstall) {
+					dsize += infos.download_size;
+					var pkg = database.get_installed_pkg (infos.name);
+					if (infos.name.length > max_name_length) {
+						max_name_length = infos.name.length;
+					}
+					if (infos.version.length > max_version_length) {
+						max_version_length = infos.version.length;
+					}
+					string size = format_size (pkg.size);
+					if (size.length > max_size_length) {
+						max_size_length = size.length;
+					}
+				}
+			}
+			if (summary.to_upgrade.length > 0) {
+				foreach (unowned AlpmPackage infos in summary.to_upgrade) {
+					dsize += infos.download_size;
+					var pkg = database.get_installed_pkg (infos.name);
+					isize += ((int64) infos.size - (int64) pkg.size);
+					if (infos.name.length > max_name_length) {
+						max_name_length = infos.name.length;
+					}
+					if (infos.version.length > max_version_length) {
+						max_version_length = infos.version.length;
+					}
+					if (infos.installed_version.length > max_installed_version_length) {
+						max_installed_version_length = infos.installed_version.length;
+					}
+					string size = format_size (pkg.size);
+					if (size.length > max_size_length) {
+						max_size_length = size.length;
+					}
+				}
+			}
+			// second pass to print details
+			max_installed_version_length += 2; // because of (%s)
+			int total_width = max_name_length + max_version_length + max_installed_version_length + max_size_length + 6;
+			if (get_term_width () > total_width) {
+				// divide available space between columns
+				int available_width = get_term_width () - total_width;
+				margin = available_width / 4;
+				// get left space to size
+				max_size_length += available_width - (margin * 4);
+			}
+			if (summary.to_upgrade.length > 0) {
+				stdout.printf (dgettext (null, "To upgrade") + " (%u):\n".printf (summary.to_upgrade.length));
+				foreach (unowned AlpmPackage infos in summary.to_upgrade) {
+					stdout.printf ("  %-*s %-*s %-*s %*s \n", max_name_length + margin, infos.name,
+														max_version_length + margin, infos.version,
+														max_installed_version_length + margin, "(%s)".printf (infos.installed_version),
+														max_size_length + margin, format_size (infos.size));
+				}
+			}
+			if (summary.to_reinstall.length > 0) {
+				stdout.printf (dgettext (null, "To reinstall") + " (%u):\n".printf (summary.to_reinstall.length));
+				foreach (unowned AlpmPackage infos in summary.to_reinstall) {
+					stdout.printf ("  %-*s %-*s %*s \n", max_name_length + margin, infos.name,
+														max_version_length + margin, infos.version,
+														max_size_length + margin, format_size (infos.size));
+				}
+			}
+			if (summary.to_install.length > 0) {
+				stdout.printf (dgettext (null, "To install") + " (%u):\n".printf (summary.to_install.length));
+				foreach (unowned AlpmPackage infos in summary.to_install) {
+					stdout.printf ("  %-*s %-*s %*s \n", max_name_length + margin, infos.name,
+														max_version_length + margin, infos.version,
+														max_size_length + margin, format_size (infos.size));
+				}
+			}
+			if (summary.to_build.length > 0) {
+				stdout.printf (dgettext (null, "To build") + " (%u):\n".printf (summary.to_build.length));
+				foreach (unowned AURPackage infos in summary.to_build) {
+					stdout.printf ("  %-*s %-*s\n", max_name_length + margin, infos.name,
+													max_version_length + margin, infos.version);
+				}
+			}
+			if (summary.to_downgrade.length > 0) {
+				stdout.printf (dgettext (null, "To downgrade") + " (%u):\n".printf (summary.to_downgrade.length));
+				foreach (unowned AlpmPackage infos in summary.to_downgrade) {
+					stdout.printf ("  %-*s %-*s %-*s %*s \n", max_name_length + margin, infos.name,
+														max_version_length + margin, infos.version,
+														max_installed_version_length + margin, "(%s)".printf (infos.installed_version),
+														max_size_length + margin, format_size (infos.size));
+				}
+			}
+			bool to_remove_printed = false;
+			if (summary.to_remove.length > 0) {
+				stdout.printf (dgettext (null, "To remove") + " (%u):\n".printf (summary.to_remove.length));
+				to_remove_printed = true;
+				foreach (unowned AlpmPackage infos in summary.to_remove) {
+					stdout.printf ("  %-*s %-*s\n", max_name_length + margin, infos.name,
+													max_version_length + margin, infos.version);
+				}
+			}
+			if (summary.aur_conflicts_to_remove.length > 0) {
+				if (!to_remove_printed) {
+					stdout.printf (dgettext (null, "To remove") + " (%u):\n".printf (summary.aur_conflicts_to_remove.length));
+				}
+				foreach (unowned AlpmPackage infos in summary.aur_conflicts_to_remove) {
+					stdout.printf ("  %-*s %-*s\n", max_name_length + margin, infos.name,
+													max_version_length + margin, infos.version);
+				}
+			}
+			stdout.printf ("\n");
+			if (dsize > 0) {
+				stdout.printf ("%s: %s\n", dgettext (null, "Total download size"), format_size (dsize));
+			}
+			if (isize > 0) {
+				stdout.printf ("%s: %s\n", dgettext (null, "Total installed size"), format_size (isize));
+			} else if (isize < 0) {
+				stdout.printf ("%s: -%s\n", dgettext (null, "Total installed size"), format_size (isize.abs ()));
+			}
+			if (rsize > 0) {
+				stdout.printf ("%s: %s\n", dgettext (null, "Total removed size"), format_size (rsize));
+			}
+			// ask user confirmation
+			asking_user_input = true;
+			stdout.printf ("%s ? %s ", dgettext (null, "Commit transaction"), dgettext (null, "[y/N]"));
+			char buf[32];
+			if (stdin.gets (buf) != null) {
+				string ans = (string) buf;
+				// remove trailing newline and uppercase
+				ans = ans.replace ("\n", "").down ();
+				// just return use default
+				if (ans != "") {
+					if (ans == dgettext (null, "y") ||
+						ans == dgettext (null, "yes")) {
+						return true;
+					}
+				}
+			}
+			return false;
+		}
+
+		void on_refresh_finished (bool success) {
+			asking_user_input = false;
+		}
+
+		void on_finished (bool success) {
+			asking_user_input = false;
+		}
+	}
+}
diff --git a/src/transaction-gtk.vala b/src/transaction-gtk.vala
new file mode 100644
index 00000000..145b35d3
--- /dev/null
+++ b/src/transaction-gtk.vala
@@ -0,0 +1,480 @@
+/*
+ *  pamac-vala
+ *
+ *  Copyright (C) 2014-2018 Guillaume Benoit <guillaume@manjaro.org>
+ *
+ *  This program 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 get of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Pamac {
+	public class TransactionGtk: Transaction {
+		//dialogs
+		public string[] preferences_available_countries;
+		TransactionSumDialog transaction_sum_dialog;
+		public GenericSet<string?> transaction_summary;
+		StringBuilder warning_textbuffer;
+		string current_action;
+		public ProgressBox progress_box;
+		uint pulse_timeout_id;
+		Vte.Terminal term;
+		Vte.Pty pty;
+		public Gtk.ScrolledWindow term_window;
+		//parent window
+		public Gtk.ApplicationWindow? application_window { get; construct; }
+
+		public TransactionGtk (Database database, Gtk.ApplicationWindow? application_window) {
+			Object (database: database, application_window: application_window);
+		}
+
+		construct {
+			//creating dialogs
+			this.application_window = application_window;
+			transaction_sum_dialog = new TransactionSumDialog (application_window);
+			transaction_summary = new GenericSet<string?> (str_hash, str_equal);
+			warning_textbuffer = new StringBuilder ();
+			current_action = "";
+			progress_box = new ProgressBox ();
+			progress_box.progressbar.text = "";
+			//creating terminal
+			term = new Vte.Terminal ();
+			term.set_scrollback_lines (-1);
+			term.expand = true;
+			term.visible = true;
+			var black = Gdk.RGBA ();
+			black.parse ("black");
+			term.set_color_cursor (black);
+			term.button_press_event.connect (on_term_button_press_event);
+			term.key_press_event.connect (on_term_key_press_event);
+			// creating pty for term
+			try {
+				pty = term.pty_new_sync (Vte.PtyFlags.NO_HELPER);
+			} catch (Error e) {
+				stderr.printf ("Error: %s\n", e.message);
+			}
+			// add term in a grid with a scrollbar
+			term_window = new Gtk.ScrolledWindow (null, term.vadjustment);
+			term_window.expand = true;
+			term_window.visible = true;
+			term_window.propagate_natural_height = true;
+			term_window.add (term);
+			// connect to signal
+			emit_action.connect (display_action);
+			emit_action_progress.connect (display_action_progress);
+			emit_hook_progress.connect (display_hook_progress);
+			emit_script_output.connect (show_in_term);
+			emit_warning.connect ((msg) => {
+				warning_textbuffer.append (msg + "\n");
+			});
+			emit_error.connect (display_error);
+			refresh_finished.connect (on_refresh_finished);
+			finished.connect (on_finished);
+			sysupgrade_finished.connect (on_finished);
+			start_generating_mirrors_list.connect (start_progressbar_pulse);
+			generate_mirrors_list_finished.connect (reset_progress_box);
+			start_building.connect (start_progressbar_pulse);
+			stop_building.connect (stop_progressbar_pulse);
+			// notify
+			Notify.init (dgettext (null, "Package Manager"));
+			// flags
+			flags = (1 << 4); //Alpm.TransFlag.CASCADE
+			if (database.config.recurse) {
+				flags |= (1 << 5); //Alpm.TransFlag.RECURSE
+			}
+		}
+
+		bool on_term_button_press_event (Gdk.EventButton event) {
+			// Check if right mouse button was clicked
+			if (event.type == Gdk.EventType.BUTTON_PRESS && event.button == 3) {
+				if (term.get_has_selection ()) {
+					var right_click_menu = new Gtk.Menu ();
+					var copy_item = new Gtk.MenuItem.with_label (dgettext (null, "Copy"));
+					copy_item.activate.connect (() => {term.copy_clipboard ();});
+					right_click_menu.append (copy_item);
+					right_click_menu.show_all ();
+					right_click_menu.popup_at_pointer (event);
+					return true;
+				}
+			}
+			return false;
+		}
+
+		bool on_term_key_press_event (Gdk.EventKey event) {
+			// Check if Ctrl + c keys were pressed
+			if (((event.state & Gdk.ModifierType.CONTROL_MASK) != 0) && (Gdk.keyval_name (event.keyval) == "c")) {
+				term.copy_clipboard ();
+				return true;
+			}
+			return false;
+		}
+
+		void show_in_term (string message) {
+			term.set_pty (pty);
+			try {
+				Process.spawn_async (null, {"echo", message}, null, SpawnFlags.SEARCH_PATH, pty.child_setup, null);
+			} catch (SpawnError e) {
+				stderr.printf ("SpawnError: %s\n", e.message);
+			}
+		}
+
+		protected override async int run_cmd_line (string[] args, string working_directory, Cancellable cancellable) {
+			int status = 1;
+			term.set_pty (pty);
+			var launcher = new SubprocessLauncher (SubprocessFlags.NONE);
+			launcher.set_cwd (working_directory);
+			launcher.set_environ (Environ.get ());
+			launcher.set_child_setup (pty.child_setup);
+			try {
+				Subprocess process = launcher.spawnv (args);
+				try {
+					yield process.wait_async (cancellable);
+					if (process.get_if_exited ()) {
+						status = process.get_exit_status ();
+					}
+				} catch (Error e) {
+					// cancelled
+					process.send_signal (Posix.Signal.INT);
+					process.send_signal (Posix.Signal.KILL);
+				}
+			} catch (Error e) {
+				stderr.printf ("Error: %s\n", e.message);
+			}
+			return status;
+		}
+
+		void display_action (string action) {
+			if (action != current_action) {
+				current_action = action;
+				show_in_term (action);
+				progress_box.action_label.label = action;
+				progress_box.progressbar.fraction = 0;
+				progress_box.progressbar.text = "";
+			}
+		}
+
+		void display_action_progress (string action, string status, double progress) {
+			if (action != current_action) {
+				current_action = action;
+				show_in_term (action);
+				progress_box.action_label.label = action;
+			}
+			progress_box.progressbar.fraction = progress;
+			progress_box.progressbar.text = status;
+		}
+
+		void display_hook_progress (string action, string details, string status, double progress) {
+			if (action != current_action) {
+				current_action = action;
+				show_in_term (action);
+				progress_box.action_label.label = action;
+			}
+			show_in_term (details);
+			progress_box.progressbar.fraction = progress;
+			progress_box.progressbar.text = status;
+		}
+
+		public void reset_progress_box () {
+			current_action = "";
+			progress_box.action_label.label = "";
+			stop_progressbar_pulse ();
+			progress_box.progressbar.fraction = 0;
+			progress_box.progressbar.text = "";
+		}
+
+		public void start_progressbar_pulse () {
+			stop_progressbar_pulse ();
+			pulse_timeout_id = Timeout.add (500, (GLib.SourceFunc) progress_box.progressbar.pulse);
+		}
+
+		public void stop_progressbar_pulse () {
+			if (pulse_timeout_id != 0) {
+				Source.remove (pulse_timeout_id);
+				pulse_timeout_id = 0;
+				progress_box.progressbar.fraction = 0;
+			}
+		}
+
+		protected override int choose_provider (string depend, string[] providers) {
+			var choose_provider_dialog = new ChooseProviderDialog (application_window);
+			choose_provider_dialog.title = dgettext (null, "Choose a provider for %s").printf (depend);
+			unowned Gtk.Box box = choose_provider_dialog.get_content_area ();
+			Gtk.RadioButton? last_radiobutton = null;
+			Gtk.RadioButton? first_radiobutton = null;
+			foreach (unowned string provider in providers) {
+				var radiobutton = new Gtk.RadioButton.with_label_from_widget (last_radiobutton, provider);
+				radiobutton.visible = true;
+				// active first provider
+				if (last_radiobutton == null) {
+					radiobutton.active = true;
+					first_radiobutton = radiobutton;
+				}
+				last_radiobutton = radiobutton;
+				box.add (radiobutton);
+			}
+			choose_provider_dialog.run ();
+			// get active provider
+			int index = 0;
+			// list is given in reverse order so reverse it !
+			SList<unowned Gtk.RadioButton> list = last_radiobutton.get_group ().copy ();
+			list.reverse ();
+			foreach (var radiobutton in list) {
+				if (radiobutton.active) {
+					break;
+				}
+				index++;
+			}
+			choose_provider_dialog.destroy ();
+			return index;
+		}
+
+		protected override bool ask_confirmation (TransactionSummary summary) {
+			show_warnings (true);
+			uint64 dsize = 0;
+			transaction_summary.remove_all ();
+			transaction_sum_dialog.sum_list.clear ();
+			var iter = Gtk.TreeIter ();
+			if (summary.to_remove.length > 0) {
+				foreach (unowned AlpmPackage infos in summary.to_remove) {
+					transaction_summary.add (infos.name);
+					transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
+												1, infos.name,
+												2, infos.version);
+				}
+				Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
+				int pos = (path.get_indices ()[0]) - (summary.to_remove.length - 1);
+				transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
+				transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To remove") + ":"));
+			}
+			if (summary.aur_conflicts_to_remove.length > 0) {
+				// do not add type enum because it is just infos
+				foreach (unowned AlpmPackage infos in summary.aur_conflicts_to_remove) {
+					transaction_summary.add (infos.name);
+					transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
+												1, infos.name,
+												2, infos.version);
+				}
+				Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
+				int pos = (path.get_indices ()[0]) - (summary.aur_conflicts_to_remove.length - 1);
+				transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
+				transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To remove") + ":"));
+			}
+			if (summary.to_downgrade.length > 0) {
+				foreach (unowned AlpmPackage infos in summary.to_downgrade) {
+					dsize += infos.download_size;
+					transaction_summary.add (infos.name);
+					transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
+												1, infos.name,
+												2, infos.version,
+												3, "(%s)".printf (infos.installed_version));
+				}
+				Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
+				int pos = (path.get_indices ()[0]) - (summary.to_downgrade.length - 1);
+				transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
+				transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To downgrade") + ":"));
+			}
+			if (summary.to_build.length > 0) {
+				foreach (unowned AURPackage infos in summary.to_build) {
+					transaction_summary.add (infos.name);
+					transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
+												1, infos.name,
+												2, infos.version);
+				}
+				Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
+				int pos = (path.get_indices ()[0]) - (summary.to_build.length - 1);
+				transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
+				transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To build") + ":"));
+			}
+			if (summary.to_install.length > 0) {
+				foreach (unowned AlpmPackage infos in summary.to_install) {
+					dsize += infos.download_size;
+					transaction_summary.add (infos.name);
+					transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
+												1, infos.name,
+												2, infos.version);
+				}
+				Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
+				int pos = (path.get_indices ()[0]) - (summary.to_install.length - 1);
+				transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
+				transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To install") + ":"));
+			}
+			if (summary.to_reinstall.length > 0) {
+				foreach (unowned AlpmPackage infos in summary.to_reinstall) {
+					dsize += infos.download_size;
+					transaction_summary.add (infos.name);
+					transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
+												1, infos.name,
+												2, infos.version);
+				}
+				Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
+				int pos = (path.get_indices ()[0]) - (summary.to_reinstall.length - 1);
+				transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
+				transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To reinstall") + ":"));
+			}
+			if (summary.to_upgrade.length > 0) {
+				if (!no_confirm_upgrade) {
+					foreach (unowned AlpmPackage infos in summary.to_upgrade) {
+						dsize += infos.download_size;
+						transaction_summary.add (infos.name);
+						transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
+													1, infos.name,
+													2, infos.version,
+													3, "(%s)".printf (infos.installed_version));
+					}
+					Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
+					int pos = (path.get_indices ()[0]) - (summary.to_upgrade.length - 1);
+					transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
+					transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To upgrade") + ":"));
+				}
+			}
+			if (dsize == 0) {
+				transaction_sum_dialog.top_label.visible = false;
+			} else {
+				transaction_sum_dialog.top_label.set_markup ("<b>%s: %s</b>".printf (dgettext (null, "Total download size"), format_size (dsize)));
+				transaction_sum_dialog.top_label.visible = true;
+			}
+			if (transaction_sum_dialog.run () == Gtk.ResponseType.OK) {
+				transaction_sum_dialog.hide ();
+				return true;
+			} else {
+				transaction_sum_dialog.hide ();
+				transaction_summary.remove_all ();
+			}
+			return false;
+		}
+
+		void show_warnings (bool block) {
+			if (warning_textbuffer.len > 0) {
+				var flags = Gtk.DialogFlags.MODAL;
+				int use_header_bar;
+				Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header_bar);
+				if (use_header_bar == 1) {
+					flags |= Gtk.DialogFlags.USE_HEADER_BAR;
+				}
+				var dialog = new Gtk.Dialog.with_buttons (dgettext (null, "Warning"),
+														application_window,
+														flags);
+				dialog.border_width = 6;
+				dialog.icon_name = "system-software-install";
+				dialog.deletable = false;
+				unowned Gtk.Widget widget = dialog.add_button (dgettext (null, "_Close"), Gtk.ResponseType.CLOSE);
+				widget.can_focus = true;
+				widget.has_focus = true;
+				widget.can_default = true;
+				widget.has_default = true;
+				var scrolledwindow = new Gtk.ScrolledWindow (null, null);
+				var label = new Gtk.Label (warning_textbuffer.str);
+				label.selectable = true;
+				label.margin = 12;
+				scrolledwindow.visible = true;
+				label.visible = true;
+				scrolledwindow.add (label);
+				scrolledwindow.expand = true;
+				unowned Gtk.Box box = dialog.get_content_area ();
+				box.add (scrolledwindow);
+				dialog.default_width = 600;
+				dialog.default_height = 300;
+				if (block) {
+					dialog.run ();
+					dialog.destroy ();
+				} else {
+					dialog.show ();
+					dialog.response.connect (() => {
+						dialog.destroy ();
+					});
+				}
+				warning_textbuffer = new StringBuilder ();
+			}
+		}
+
+		public void display_error (string message, string[] details) {
+			reset_progress_box ();
+			var flags = Gtk.DialogFlags.MODAL;
+			int use_header_bar;
+			Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header_bar);
+			if (use_header_bar == 1) {
+				flags |= Gtk.DialogFlags.USE_HEADER_BAR;
+			}
+			var dialog = new Gtk.Dialog.with_buttons (message,
+													application_window,
+													flags);
+			dialog.border_width = 6;
+			dialog.icon_name = "system-software-install";
+			var textbuffer = new StringBuilder ();
+			if (details.length != 0) {
+				show_in_term (message + ":");
+				foreach (unowned string detail in details) {
+					show_in_term (detail);
+					textbuffer.append (detail + "\n");
+				}
+			} else {
+				show_in_term (message);
+				textbuffer.append (message);
+			}
+			dialog.deletable = false;
+			unowned Gtk.Widget widget = dialog.add_button (dgettext (null, "_Close"), Gtk.ResponseType.CLOSE);
+			widget.can_focus = true;
+			widget.has_focus = true;
+			widget.can_default = true;
+			widget.has_default = true;
+			var scrolledwindow = new Gtk.ScrolledWindow (null, null);
+			var label = new Gtk.Label (textbuffer.str);
+			label.selectable = true;
+			label.margin = 12;
+			scrolledwindow.visible = true;
+			label.visible = true;
+			scrolledwindow.add (label);
+			scrolledwindow.expand = true;
+			unowned Gtk.Box box = dialog.get_content_area ();
+			box.add (scrolledwindow);
+			dialog.default_width = 600;
+			dialog.default_height = 300;
+			dialog.show ();
+			dialog.response.connect (() => {
+				dialog.destroy ();
+			});
+			Timeout.add (1000, () => {
+				try {
+					var notification = new Notify.Notification (dgettext (null, "Package Manager"),
+																message,
+																"system-software-update");
+					notification.show ();
+				} catch (Error e) {
+					stderr.printf ("Notify Error: %s", e.message);
+				}
+				return false;
+			});
+		}
+
+		void on_refresh_finished (bool success) {
+			reset_progress_box ();
+			show_in_term ("");
+		}
+
+		void on_finished (bool success) {
+			if (success) {
+				try {
+					var notification = new Notify.Notification (dgettext (null, "Package Manager"),
+																dgettext (null, "Transaction successfully finished"),
+																"system-software-update");
+					notification.show ();
+				} catch (Error e) {
+					stderr.printf ("Notify Error: %s", e.message);
+				}
+			}
+			transaction_summary.remove_all ();
+			reset_progress_box ();
+			show_in_term ("");
+			show_warnings (false);
+		}
+	}
+}
diff --git a/src/transaction.vala b/src/transaction.vala
index 0dd63783..07321a44 100644
--- a/src/transaction.vala
+++ b/src/transaction.vala
@@ -18,44 +18,6 @@
  */
 
 namespace Pamac {
-	[DBus (name = "org.manjaro.pamac.user")]
-	interface UserDaemon : Object {
-		public abstract void enable_appstream () throws Error;
-		public abstract void refresh_handle () throws Error;
-		public abstract string[] get_mirrors_countries () throws Error;
-		public abstract string get_mirrors_choosen_country () throws Error;
-		public abstract string get_lockfile () throws Error;
-		public abstract AlpmPackage get_installed_pkg (string pkgname) throws Error;
-		public abstract bool get_checkspace () throws Error;
-		public abstract string[] get_ignorepkgs () throws Error;
-		public abstract bool should_hold (string pkgname) throws Error;
-		public abstract uint get_pkg_reason (string pkgname) throws Error;
-		public abstract uint get_pkg_origin (string pkgname) throws Error;
-		public abstract async AlpmPackage[] get_installed_pkgs () throws Error;
-		public abstract async AlpmPackage[] get_installed_apps () throws Error;
-		public abstract async AlpmPackage[] get_explicitly_installed_pkgs () throws Error;
-		public abstract async AlpmPackage[] get_foreign_pkgs () throws Error;
-		public abstract async AlpmPackage[] get_orphans () throws Error;
-		public abstract AlpmPackage find_installed_satisfier (string depstring) throws Error;
-		public abstract AlpmPackage get_sync_pkg (string pkgname) throws Error;
-		public abstract AlpmPackage find_sync_satisfier (string depstring) throws Error;
-		public abstract async AlpmPackage[] search_pkgs (string search_string) throws Error;
-		public abstract async AURPackage[] search_in_aur (string search_string) throws Error;
-		public abstract async AlpmPackage[] get_category_pkgs (string category) throws Error;
-		public abstract string[] get_repos_names () throws Error;
-		public abstract async AlpmPackage[] get_repo_pkgs (string repo) throws Error;
-		public abstract string[] get_groups_names () throws Error;
-		public abstract async AlpmPackage[] get_group_pkgs (string groupname) throws Error;
-		public abstract AlpmPackageDetails get_pkg_details (string pkgname, string app_name) throws Error;
-		public abstract string[] get_pkg_files (string pkgname) throws Error;
-		public abstract async AURPackageDetails get_aur_details (string pkgname) throws Error;
-		public abstract string[] get_pkg_uninstalled_optdeps (string pkgname) throws Error;
-		public abstract void start_get_updates (bool check_aur_updates, bool refresh_files_dbs) throws Error;
-		[DBus (no_reply = true)]
-		public abstract void quit () throws Error;
-		public signal void emit_get_updates_progress (uint percent);
-		public signal void get_updates_finished (Updates updates);
-	}
 	[DBus (name = "org.manjaro.pamac.system")]
 	interface SystemDaemon : Object {
 		public abstract void set_environment_variables (HashTable<string,string> variables) throws Error;
@@ -79,7 +41,7 @@ namespace Pamac {
 		public abstract void start_get_updates (bool check_aur_updates) throws Error;
 		[DBus (no_reply = true)]
 		public abstract void quit () throws Error;
-		public signal void get_updates_finished (Updates updates);
+		public signal void get_updates_finished (UpdatesPriv updates);
 		public signal void emit_event (uint primary_event, uint secondary_event, string[] details);
 		public signal void emit_providers (string depend, string[] providers);
 		public signal void emit_progress (uint progress, string pkgname, uint percent, uint n_targets, uint current_target);
@@ -100,198 +62,114 @@ namespace Pamac {
 	}
 
 	public class Transaction: Object {
-
 		enum Type {
-			STANDARD = (1 << 0),
-			UPDATE = (1 << 1),
-			BUILD = (1 << 2)
+			INSTALL = (1 << 0),
+			REMOVE = (1 << 1),
+			UPDATE = (1 << 2),
+			BUILD = (1 << 3)
 		}
-
-		public enum Mode {
-			MANAGER,
-			INSTALLER
-		}
-
-		UserDaemon user_daemon;
 		SystemDaemon system_daemon;
-
-		public Mode mode;
-		Pamac.Config pamac_config;
-		public bool check_aur_updates { get { return pamac_config.check_aur_updates; } }
-		public bool enable_aur { get { return pamac_config.enable_aur; }  }
-		public unowned GLib.HashTable<string,string> environment_variables { get {return pamac_config.environment_variables; } }
-		public bool no_update_hide_icon { get { return pamac_config.no_update_hide_icon; } }
-		public bool download_updates { get { return pamac_config.download_updates; } }
-		public bool recurse { get { return pamac_config.recurse; } }
-		public uint64 refresh_period { get { return pamac_config.refresh_period; } }
-		public string aur_build_dir { get { return pamac_config.aur_build_dir; } }
-		public uint64 keep_num_pkgs { get { return pamac_config.keep_num_pkgs; } }
-		public bool rm_only_uninstalled { get { return pamac_config.rm_only_uninstalled; } }
-
-		//Alpm.TransFlag
-		int flags;
-
-		public GenericSet<string?> to_install;
-		public GenericSet<string?> to_remove;
-		public GenericSet<string?> to_load;
-		public GenericSet<string?> to_build;
-		public GenericSet<string?> to_update;
+		// run transaction data
+		string current_action;
+		string current_status;
+		double current_progress;
+		string current_filename;
+		bool sysupgrade_after_trans;
+		bool no_confirm_commit;
+		bool enable_downgrade;
+		bool sysupgrading;
+		string[] to_install_first;
+		string[] temporary_ignorepkgs;
+		string[] overwrite_files;
+		// building data
 		Queue<string> to_build_queue;
 		string[] aur_pkgs_to_install;
-		GenericSet<string?> previous_to_install;
-		GenericSet<string?> previous_to_remove;
-		public GenericSet<string?> transaction_summary;
-		public GenericSet<string?> temporary_ignorepkgs;
-		public GLib.File lockfile;
-
+		bool building;
+		Cancellable build_cancellable;
+		// download data
+		Timer timer;
 		uint64 total_download;
 		uint64 already_downloaded;
-		string previous_textbar;
-		float previous_percent;
-		string previous_filename;
-		uint pulse_timeout_id;
-		bool sysupgrade_after_trans;
-		bool enable_downgrade;
-		bool no_confirm_commit;
-		bool building;
 		uint64 previous_xfered;
 		uint64 download_rate;
 		uint64 rates_nb;
-		Timer timer;
-		bool success;
-		StringBuilder warning_textbuffer;
-
-		//dialogs
-		public string[] preferences_available_countries;
-		TransactionSumDialog transaction_sum_dialog;
-		public ProgressBox progress_box;
-		Vte.Terminal term;
-		Vte.Pty pty;
-		Cancellable build_cancellable;
-		public Gtk.ScrolledWindow term_window;
-		//parent window
-		public Gtk.ApplicationWindow? application_window { get; private set; }
 
+		// transaction options
+		public Database database { get; construct set; }
+		public int flags { get; set; } //Alpm.TransFlag
+		public bool no_confirm_upgrade { get; set; }
+
+		public signal void emit_action (string action);
+		public signal void emit_action_progress (string action, string status, double progress);
+		public signal void emit_hook_progress (string action, string details, string status, double progress);
+		public signal void emit_script_output (string message);
+		public signal void emit_warning (string message);
+		public signal void emit_error (string message, string[] details);
 		public signal void start_downloading ();
 		public signal void stop_downloading ();
 		public signal void start_building ();
 		public signal void stop_building ();
 		public signal void important_details_outpout (bool must_show);
+		public signal void refresh_finished (bool success);
 		public signal void finished (bool success);
+		public signal void sysupgrade_finished (bool success);
 		public signal void set_pkgreason_finished ();
 		public signal void write_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon,
 														bool enable_aur, string aur_build_dir, bool check_aur_updates,
 														bool download_updates);
 		public signal void write_alpm_config_finished (bool checkspace);
-		public signal void generate_mirrors_list ();
+		public signal void start_generating_mirrors_list ();
 		public signal void generate_mirrors_list_finished ();
-		public signal void run_preferences_dialog_finished ();
-		public signal void get_updates_progress (uint percent);
-		public signal void get_updates_finished (Updates updates);
 
-		public Transaction (Gtk.ApplicationWindow? application_window) {
-			mode = Mode.MANAGER;
-			pamac_config = new Pamac.Config ("/etc/pamac.conf");
-			flags = (1 << 4); //Alpm.TransFlag.CASCADE
-			if (pamac_config.recurse) {
-				flags |= (1 << 5); //Alpm.TransFlag.RECURSE
-			}
-			to_install = new GenericSet<string?> (str_hash, str_equal);
-			to_remove = new GenericSet<string?> (str_hash, str_equal);
-			to_load = new GenericSet<string?> (str_hash, str_equal);
-			to_build = new GenericSet<string?> (str_hash, str_equal);
-			to_update = new GenericSet<string?> (str_hash, str_equal);
-			to_build_queue = new Queue<string> ();
-			previous_to_install = new GenericSet<string?> (str_hash, str_equal);
-			previous_to_remove = new GenericSet<string?> (str_hash, str_equal);
-			transaction_summary = new GenericSet<string?> (str_hash, str_equal);
-			temporary_ignorepkgs = new GenericSet<string?> (str_hash, str_equal);
-			connecting_user_daemon ();
-			get_lockfile ();
-			//creating dialogs
-			this.application_window = application_window;
-			preferences_available_countries = {};
-			transaction_sum_dialog = new TransactionSumDialog (application_window);
-			progress_box = new ProgressBox ();
-			progress_box.progressbar.text = "";
-			//creating terminal
-			term = new Vte.Terminal ();
-			term.set_scrollback_lines (-1);
-			term.expand = true;
-			term.visible = true;
-			var black = Gdk.RGBA ();
-			black.parse ("black");
-			term.set_color_cursor (black);
-			term.button_press_event.connect (on_term_button_press_event);
-			term.key_press_event.connect (on_term_key_press_event);
-			// creating pty for term
-			try {
-				pty = term.pty_new_sync (Vte.PtyFlags.NO_HELPER);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			// add term in a grid with a scrollbar
-			term_window = new Gtk.ScrolledWindow (null, term.vadjustment);
-			term_window.expand = true;
-			term_window.visible = true;
-			term_window.propagate_natural_height = true;
-			term_window.add (term);
-			build_cancellable = new Cancellable ();
-			// progress data
-			previous_textbar = "";
-			previous_filename = "";
+		public Transaction (Database database) {
+			Object (database: database);
+		}
+
+		construct {
+			// transaction options
+			flags = 0;
+			enable_downgrade = false;
+			no_confirm_upgrade = false;
+			// run transaction data
+			current_action = "";
+			current_status = "";
+			current_filename = "";
 			sysupgrade_after_trans = false;
 			no_confirm_commit = false;
+			sysupgrading = false;
+			to_install_first = {};
+			temporary_ignorepkgs = {};
+			overwrite_files = {};
+			// building data
+			to_build_queue = new Queue<string> ();
+			build_cancellable = new Cancellable ();
 			building = false;
+			// download data
 			timer = new Timer ();
-			success = false;
-			warning_textbuffer = new StringBuilder ();
-			// notify
-			Notify.init (dgettext (null, "Package Manager"));
 		}
 
-		public void run_preferences_dialog () {
-			check_authorization.begin ((obj, res) => {
-				bool authorized = check_authorization.end (res);
-				if (authorized) {
-					var preferences_dialog = new PreferencesDialog (this);
-					preferences_dialog.run ();
-					preferences_dialog.destroy ();
-					while (Gtk.events_pending ()) {
-						Gtk.main_iteration ();
-					}
-				}
-				run_preferences_dialog_finished ();
-			});
+		// destruction
+		~Transaction () {
+			stop_daemon ();
 		}
 
-		public ErrorInfos get_current_error () {
-			try {
-				return system_daemon.get_current_error ();
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				return ErrorInfos ();
-			}
+		protected virtual bool ask_confirmation (TransactionSummary summary) {
+			// no confirm
+			return true;
 		}
 
-		public string[] get_mirrors_countries () {
-			string[] countries = {};
-			try {
-				countries = user_daemon.get_mirrors_countries ();
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return countries;
+		protected virtual int choose_provider (string depend, string[] providers) {
+			// choose first provider
+			return 0;
 		}
 
-		public string get_mirrors_choosen_country () {
-			string country = "";
+		ErrorInfos get_current_error () {
 			try {
-				country = user_daemon.get_mirrors_choosen_country ();
+				return system_daemon.get_current_error ();
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
+				stderr.printf ("get_current_error: %s\n", e.message);
+				return ErrorInfos ();
 			}
-			return country;
 		}
 
 		public bool get_lock () {
@@ -300,7 +178,7 @@ namespace Pamac {
 			try {
 				locked = system_daemon.get_lock ();
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
+				stderr.printf ("get_lock: %s\n", e.message);
 			}
 			return locked;
 		}
@@ -310,12 +188,12 @@ namespace Pamac {
 			try {
 				unlocked = system_daemon.unlock ();
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
+				stderr.printf ("unlock: %s\n", e.message);
 			}
 			return unlocked;
 		}
 
-		async bool check_authorization () {
+		public async bool check_authorization () {
 			SourceFunc callback = check_authorization.callback;
 			bool authorized = false;
 			ulong handler_id = system_daemon.get_authorization_finished.connect ((authorized_) => {
@@ -325,7 +203,7 @@ namespace Pamac {
 			try {
 				system_daemon.start_get_authorization ();
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
+				stderr.printf ("start_get_authorization: %s\n", e.message);
 			}
 			yield;
 			system_daemon.disconnect (handler_id);
@@ -334,119 +212,32 @@ namespace Pamac {
 
 		public void start_write_pamac_config (HashTable<string,Variant> new_pamac_conf) {
 			try {
-				system_daemon.write_pamac_config_finished.connect (on_write_pamac_config_finished);
 				system_daemon.start_write_pamac_config (new_pamac_conf);
+				system_daemon.write_pamac_config_finished.connect (on_write_pamac_config_finished);
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				system_daemon.write_pamac_config_finished.disconnect (on_write_pamac_config_finished);
+				stderr.printf ("start_write_pamac_config: %s\n", e.message);
 			}
 		}
 
 		public void start_write_alpm_config (HashTable<string,Variant> new_alpm_conf) {
 			try {
-				system_daemon.write_alpm_config_finished.connect (on_write_alpm_config_finished);
 				system_daemon.start_write_alpm_config (new_alpm_conf);
+				system_daemon.write_alpm_config_finished.connect (on_write_alpm_config_finished);
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				system_daemon.write_alpm_config_finished.disconnect (on_write_alpm_config_finished);
-			}
-		}
-
-		bool on_term_button_press_event (Gdk.EventButton event) {
-			// Check if right mouse button was clicked
-			if (event.type == Gdk.EventType.BUTTON_PRESS && event.button == 3) {
-				if (term.get_has_selection ()) {
-					var right_click_menu = new Gtk.Menu ();
-					var copy_item = new Gtk.MenuItem.with_label (dgettext (null, "Copy"));
-					copy_item.activate.connect (() => {term.copy_clipboard ();});
-					right_click_menu.append (copy_item);
-					right_click_menu.show_all ();
-					right_click_menu.popup_at_pointer (event);
-					return true;
-				}
-			}
-			return false;
-		}
-
-		bool on_term_key_press_event (Gdk.EventKey event) {
-			// Check if Ctrl + c keys were pressed
-			if (((event.state & Gdk.ModifierType.CONTROL_MASK) != 0) && (Gdk.keyval_name (event.keyval) == "c")) {
-				term.copy_clipboard ();
-				return true;
-			}
-			return false;
-		}
-
-		void show_in_term (string message) {
-			term.set_pty (pty);
-			try {
-				Process.spawn_async (null, {"echo", message}, null, SpawnFlags.SEARCH_PATH, pty.child_setup, null);
-			} catch (SpawnError e) {
-				stderr.printf ("SpawnError: %s\n", e.message);
-			}
-		}
-
-		async int spawn_in_term (string[] args, string? working_directory = null) {
-			int status = 1;
-			term.set_pty (pty);
-			var launcher = new SubprocessLauncher (SubprocessFlags.NONE);
-			launcher.set_cwd (working_directory);
-			launcher.set_environ (Environ.get ());
-			launcher.set_child_setup (pty.child_setup);
-			try {
-				Subprocess process = launcher.spawnv (args);
-				try {
-					yield process.wait_async (build_cancellable);
-					if (process.get_if_exited ()) {
-						status = process.get_exit_status ();
-					}
-				} catch (Error e) {
-					// cancelled
-					process.send_signal (Posix.Signal.INT);
-					process.send_signal (Posix.Signal.KILL);
-				}
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return status;
-		}
-
-		void reset_progress_box (string action) {
-			show_in_term (action);
-			progress_box.action_label.label = action;
-			stop_progressbar_pulse ();
-			progress_box.progressbar.fraction = 0;
-			progress_box.progressbar.text = "";
-		}
-
-		public void start_progressbar_pulse () {
-			stop_progressbar_pulse ();
-			pulse_timeout_id = Timeout.add (500, (GLib.SourceFunc) progress_box.progressbar.pulse);
-		}
-
-		public void stop_progressbar_pulse () {
-			if (pulse_timeout_id != 0) {
-				Source.remove (pulse_timeout_id);
-				pulse_timeout_id = 0;
-				progress_box.progressbar.fraction = 0;
+				stderr.printf ("start_write_alpm_config: %s\n", e.message);
 			}
 		}
 
 		public void start_generate_mirrors_list (string country) {
-			string action = dgettext (null, "Refreshing mirrors list") + "...";
-			reset_progress_box (action);
-			start_progressbar_pulse ();
+			emit_action (dgettext (null, "Refreshing mirrors list") + "...");
 			important_details_outpout (false);
-			generate_mirrors_list ();
+			start_generating_mirrors_list ();
 			try {
+				system_daemon.start_generate_mirrors_list (country);
 				system_daemon.generate_mirrors_list_data.connect (on_generate_mirrors_list_data);
 				system_daemon.generate_mirrors_list_finished.connect (on_generate_mirrors_list_finished);
-				system_daemon.start_generate_mirrors_list (country);
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				stop_progressbar_pulse ();
-				system_daemon.generate_mirrors_list_data.disconnect (on_generate_mirrors_list_data);
-				system_daemon.generate_mirrors_list_finished.disconnect (on_generate_mirrors_list_finished);
+				stderr.printf ("start_generate_mirrors_list: %s\n", e.message);
 			}
 		}
 
@@ -454,17 +245,16 @@ namespace Pamac {
 			try {
 				system_daemon.clean_cache (keep_nb, only_uninstalled);
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
+				stderr.printf ("clean_cache: %s\n", e.message);
 			}
 		}
 
 		public void start_set_pkgreason (string pkgname, uint reason) {
 			try {
-				system_daemon.set_pkgreason_finished.connect (on_set_pkgreason_finished);
 				system_daemon.start_set_pkgreason (pkgname, reason);
+				system_daemon.set_pkgreason_finished.connect (on_set_pkgreason_finished);
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				system_daemon.set_pkgreason_finished.disconnect (on_set_pkgreason_finished);
+				stderr.printf ("start_set_pkgreason: %s\n", e.message);
 			}
 		}
 
@@ -472,678 +262,182 @@ namespace Pamac {
 			check_authorization.begin ((obj, res) => {
 				bool authorized = check_authorization.end (res);
 				if (authorized) {
-					string action = dgettext (null, "Synchronizing package databases") + "...";
-					reset_progress_box (action);
+					emit_action (dgettext (null, "Synchronizing package databases") + "...");
 					connecting_system_daemon ();
 					connecting_dbus_signals ();
 					try {
-						system_daemon.refresh_finished.connect (on_refresh_finished);
 						system_daemon.start_refresh (force);
+						system_daemon.refresh_finished.connect (on_refresh_finished);
+						start_downloading ();
 					} catch (Error e) {
-						stderr.printf ("Error: %s\n", e.message);
-						system_daemon.refresh_finished.disconnect (on_refresh_finished);
-						success = false;
-						finish_transaction ();
+						stderr.printf ("start_refresh: %s\n", e.message);
+						on_refresh_finished (false);
 					}
 				} else {
-					success = false;
-					finish_transaction ();
+					on_refresh_finished (false);
 				}
 			});
 		}
 
-		public void refresh_handle () {
-			try {
-				user_daemon.refresh_handle ();
-				get_lockfile ();
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-		}
-
-		void get_lockfile () {
-			try {
-				lockfile = GLib.File.new_for_path (user_daemon.get_lockfile ());
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				//try standard lock file
-				lockfile = GLib.File.new_for_path ("var/lib/pacman/db.lck");
-			}
-		}
-
-		public bool get_checkspace () {
-			bool checkspace = false;
-			try {
-				checkspace = user_daemon.get_checkspace ();
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return checkspace;
-		}
-
-		public string[] get_ignorepkgs () {
-			string[] ignorepkgs = {};
-			try {
-				ignorepkgs = user_daemon.get_ignorepkgs ();
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return ignorepkgs;
-		}
-
-		public AlpmPackage get_installed_pkg (string pkgname) {
-			try {
-				return user_daemon.get_installed_pkg (pkgname);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				return AlpmPackage () {
-					name = "",
-					version = "",
-					desc = "",
-					repo = ""
-				};
-			}
-		}
-
-		public AlpmPackage find_installed_satisfier (string depstring) {
-			try {
-				return user_daemon.find_installed_satisfier (depstring);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				return AlpmPackage () {
-					name = "",
-					version = "",
-					desc = "",
-					repo = ""
-				};
-			}
-		}
-
-		public bool should_hold (string pkgname) {
-			bool should_hold = false;
-			try {
-				should_hold = user_daemon.should_hold (pkgname);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return should_hold;
-		}
-
-		public uint get_pkg_reason (string pkgname) {
-			uint reason = 0;
-			try {
-				reason = user_daemon.get_pkg_reason (pkgname);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return reason;
-		}
-
-		public uint get_pkg_origin (string pkgname) {
-			uint origin = 0;
-			try {
-				origin = user_daemon.get_pkg_origin (pkgname);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return origin;
-		}
-
-		public async AlpmPackage[] get_installed_pkgs () {
-			AlpmPackage[] pkgs = {};
-			try {
-				pkgs = yield user_daemon.get_installed_pkgs ();
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return pkgs;
-		}
-
-		public async AlpmPackage[] get_installed_apps () {
-			AlpmPackage[] pkgs = {};
-			try {
-				pkgs = yield user_daemon.get_installed_apps ();
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return pkgs;
-		}
-
-		public async AlpmPackage[] get_explicitly_installed_pkgs () {
-			AlpmPackage[] pkgs = {};
-			try {
-				pkgs = yield user_daemon.get_explicitly_installed_pkgs ();
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return pkgs;
-		}
-
-		public async AlpmPackage[] get_foreign_pkgs () {
-			AlpmPackage[] pkgs = {};
-			try {
-				pkgs = yield user_daemon.get_foreign_pkgs ();
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return pkgs;
-		}
-
-		public async AlpmPackage[] get_orphans () {
-			AlpmPackage[] pkgs = {};
-			try {
-				pkgs = yield user_daemon.get_orphans ();
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return pkgs;
-		}
-
-		public AlpmPackage get_sync_pkg (string pkgname) {
-			try {
-				return user_daemon.get_sync_pkg (pkgname);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				return AlpmPackage () {
-					name = "",
-					version = "",
-					desc = "",
-					repo = ""
-				};
-			}
-		}
-
-		public AlpmPackage find_sync_satisfier (string depstring) {
-			try {
-				return user_daemon.find_sync_satisfier (depstring);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				return AlpmPackage () {
-					name = "",
-					version = "",
-					desc = "",
-					repo = ""
-				};
-			}
-		}
-
-		public async AlpmPackage[] search_pkgs (string search_string) {
-			AlpmPackage[] pkgs = {};
-			try {
-				pkgs = yield user_daemon.search_pkgs (search_string);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return pkgs;
-		}
-
-		public async AURPackage[] search_in_aur (string search_string) {
-			AURPackage[] pkgs = {};
-			try {
-				pkgs = yield user_daemon.search_in_aur (search_string);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return pkgs;
-		}
-
-		public async AlpmPackage[] get_category_pkgs (string category) {
-			AlpmPackage[] pkgs = {};
-			try {
-				pkgs = yield user_daemon.get_category_pkgs (category);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return pkgs;
-		}
-
-		public string[] get_repos_names () {
-			string[] repos_names = {};
-			try {
-				repos_names = user_daemon.get_repos_names ();
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return repos_names;
-		}
-
-		public async AlpmPackage[] get_repo_pkgs (string repo) {
-			AlpmPackage[] pkgs = {};
-			try {
-				pkgs = yield user_daemon.get_repo_pkgs (repo);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return pkgs;
-		}
-
-		public string[] get_groups_names () {
-			string[] groups_names = {};
-			try {
-				groups_names = user_daemon.get_groups_names ();
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return groups_names;
-		}
-
-		public async AlpmPackage[] get_group_pkgs (string group_name) {
-			AlpmPackage[] pkgs = {};
-			try {
-				pkgs = yield user_daemon.get_group_pkgs (group_name);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return pkgs;
-		}
-
-		public string[] get_pkg_uninstalled_optdeps (string pkgname) {
-			string[] optdeps = {};
-			try {
-				optdeps = user_daemon.get_pkg_uninstalled_optdeps (pkgname);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return optdeps;
-		}
-
-		public AlpmPackageDetails get_pkg_details (string pkgname, string app_name) {
-			try {
-				return user_daemon.get_pkg_details (pkgname, app_name);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				return AlpmPackageDetails () {
-					name = "",
-					version = "",
-					desc = "",
-					repo = "",
-					url = "",
-					packager = "",
-					builddate = "",
-					installdate = "",
-					reason = "",
-					has_signature = ""
-				};
-			}
-		}
-
-		public string[] get_pkg_files (string pkgname) {
-			try {
-				return user_daemon.get_pkg_files (pkgname);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				return {};
-			}
-		}
-
-		public async AURPackageDetails get_aur_details (string pkgname) {
-			var pkg = AURPackageDetails () {
-				name = "",
-				version = "",
-				desc = "",
-				packagebase = "",
-				url = "",
-				maintainer = ""
-			};
-			try {
-				pkg = yield user_daemon.get_aur_details (pkgname);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			return pkg;
-		}
-
-		public void start_get_updates () {
-			user_daemon.emit_get_updates_progress.connect (on_emit_get_updates_progress);
-			user_daemon.get_updates_finished.connect (on_get_updates_finished);
-			try {
-				user_daemon.start_get_updates (pamac_config.enable_aur && pamac_config.check_aur_updates, false);
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				success = false;
-				finish_transaction ();
-			}
-		}
-
 		void start_get_updates_for_sysupgrade () {
-			system_daemon.get_updates_finished.connect (on_get_updates_for_sysupgrade_finished);
 			try {
-				system_daemon.start_get_updates (pamac_config.enable_aur && pamac_config.check_aur_updates);
+				system_daemon.start_get_updates (database.config.check_aur_updates);
+				system_daemon.get_updates_finished.connect (on_get_updates_for_sysupgrade_finished);
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				success = false;
-				finish_transaction ();
+				stderr.printf ("start_get_updates: %s\n", e.message);
+				finish_transaction (false);
 			}
 		}
 
-		void sysupgrade_real (bool enable_downgrade) {
-			progress_box.progressbar.fraction = 0;
-			string[] temporary_ignorepkgs_ = {};
-			string[] to_build_ = {};
-			foreach (unowned string name in to_build) {
-				to_build_ += name;
-			}
-			foreach (unowned string pkgname in temporary_ignorepkgs) {
-				temporary_ignorepkgs_ += pkgname;
-			}
+		void sysupgrade_real (string[] to_build) {
 			connecting_system_daemon ();
 			connecting_dbus_signals ();
 			try {
 				// this will respond with trans_prepare_finished signal
-				system_daemon.start_sysupgrade_prepare (enable_downgrade, temporary_ignorepkgs_, to_build_, {});
+				system_daemon.start_sysupgrade_prepare (enable_downgrade, temporary_ignorepkgs, to_build, overwrite_files);
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				success = false;
-				finish_transaction ();
+				stderr.printf ("start_sysupgrade_prepare: %s\n", e.message);
+				finish_transaction (false);
 			}
 		}
 
-		public void sysupgrade (bool enable_downgrade) {
+		public void start_sysupgrade (bool enable_downgrade, string[] temporary_ignorepkgs, string[] overwrite_files) {
 			this.enable_downgrade = enable_downgrade;
-			string action = dgettext (null, "Starting full system upgrade") + "...";
-			reset_progress_box (action);
+			this.temporary_ignorepkgs = temporary_ignorepkgs;
+			this.overwrite_files = overwrite_files;
+			sysupgrading = true;
+			emit_action (dgettext (null, "Starting full system upgrade") + "...");
 			start_get_updates_for_sysupgrade ();
 		}
 
-		void on_emit_get_updates_progress (uint percent) {
-			get_updates_progress (percent);
-		}
-
-		void on_get_updates_finished (Updates updates) {
-			user_daemon.emit_get_updates_progress.disconnect (on_emit_get_updates_progress);
-			user_daemon.get_updates_finished.disconnect (on_get_updates_finished);
-			get_updates_finished (updates);
-		}
-
-		void on_get_updates_for_sysupgrade_finished (Updates updates) {
+		void on_get_updates_for_sysupgrade_finished (UpdatesPriv updates) {
 			system_daemon.get_updates_finished.disconnect (on_get_updates_for_sysupgrade_finished);
 			// get syncfirst updates
-			if (updates.is_syncfirst) {
-				clear_lists ();
+			if (updates.syncfirst) {
 				sysupgrade_after_trans = true;
-				no_confirm_commit = true;
+				to_install_first = {};
 				foreach (unowned AlpmPackage infos in updates.repos_updates) {
-					to_install.add (infos.name);
+					to_install_first += infos.name;
+				}
+				string[] to_build = {};
+				foreach (unowned AURPackage infos in updates.aur_updates) {
+					if (!(infos.name in temporary_ignorepkgs)) {
+						to_build += infos.name;
+					}
 				}
 				// run as a standard transaction
-				run ();
+				sysupgrade_real (to_build);
 			} else {
 				if (updates.aur_updates.length != 0) {
-					clear_lists ();
+					string[] to_build = {};
 					foreach (unowned AURPackage infos in updates.aur_updates) {
 						if (!(infos.name in temporary_ignorepkgs)) {
-							to_build.add (infos.name);
+							to_build += infos.name;
 						}
 					}
 					if (updates.repos_updates.length != 0) {
-						sysupgrade_real (enable_downgrade);
+						sysupgrade_real (to_build);
 					} else {
 						// only aur updates
 						// run as a standard transaction
-						run ();
+						start ({}, {}, {}, to_build, overwrite_files);
 					}
 				} else {
 					if (updates.repos_updates.length != 0) {
-						sysupgrade_real (enable_downgrade);
+						sysupgrade_real ({});
 					} else {
-						finish_transaction ();
-						stop_progressbar_pulse ();
+						finish_transaction (true);
 					}
 				}
 			}
 		}
 
-		public void clear_lists () {
-			to_install.remove_all ();
-			to_remove.remove_all ();
-			to_build.remove_all ();
-			to_load.remove_all ();
-		}
-
-		void clear_previous_lists () {
-			previous_to_install.remove_all ();
-			previous_to_remove.remove_all ();
-		}
-
-		void start_trans_prepare (int transflags, string[] to_install, string[] to_remove, string[] to_load, string[] to_build) {
+		void start_trans_prepare (string[] to_install, string[] to_remove, string[] to_load, string[] to_build) {
 			try {
-				system_daemon.start_trans_prepare (transflags, to_install, to_remove, to_load, to_build, {});
+				system_daemon.start_trans_prepare (flags, to_install, to_remove, to_load, to_build, overwrite_files);
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-				stop_progressbar_pulse ();
-				success = false;
-				finish_transaction ();
+				stderr.printf ("start_trans_prepare: %s\n", e.message);
+				finish_transaction (false);
 			}
 		}
 
-		public void run () {
-			string action = dgettext (null, "Preparing") + "...";
-			reset_progress_box (action);
-			start_progressbar_pulse ();
-			string[] to_install_ = {};
-			string[] to_remove_ = {};
-			string[] to_load_ = {};
-			string[] to_build_ = {};
-			foreach (unowned string name in to_install) {
-				to_install_ += name;
-			}
-			foreach (unowned string name in to_remove) {
-				to_remove_ += name;
-			}
-			foreach (unowned string path in to_load) {
-				to_load_ += path;
-			}
-			foreach (unowned string name in to_build) {
-				to_build_ += name;
-			}
+		public void start (string[] to_install, string[] to_remove, string[] to_load, string[] to_build, string[] overwrite_files) {
+			this.overwrite_files = overwrite_files;
+			emit_action (dgettext (null, "Preparing") + "...");
 			connecting_system_daemon ();
 			connecting_dbus_signals ();
-			start_trans_prepare (flags, to_install_, to_remove_, to_load_, to_build_);
+			start_trans_prepare (to_install, to_remove, to_load, to_build);
 		}
 
-		void choose_provider (string depend, string[] providers) {
-			var choose_provider_dialog = new ChooseProviderDialog (application_window);
-			choose_provider_dialog.title = dgettext (null, "Choose a provider for %s").printf (depend);
-			unowned Gtk.Box box = choose_provider_dialog.get_content_area ();
-			Gtk.RadioButton? last_radiobutton = null;
-			Gtk.RadioButton? first_radiobutton = null;
-			foreach (unowned string provider in providers) {
-				var radiobutton = new Gtk.RadioButton.with_label_from_widget (last_radiobutton, provider);
-				radiobutton.visible = true;
-				// active first provider
-				if (last_radiobutton == null) {
-					radiobutton.active = true;
-					first_radiobutton = radiobutton;
-				}
-				last_radiobutton = radiobutton;
-				box.add (radiobutton);
-			}
-			choose_provider_dialog.run ();
-			// get active provider
-			int index = 0;
-			// list is given in reverse order so reverse it !
-			SList<unowned Gtk.RadioButton> list = last_radiobutton.get_group ().copy ();
-			list.reverse ();
-			foreach (var radiobutton in list) {
-				if (radiobutton.active) {
-					try {
-						system_daemon.choose_provider (index);
-					} catch (Error e) {
-						stderr.printf ("Error: %s\n", e.message);
-					}
+		void start_commit () {
+			if (to_install_first.length > 0) {
+				release ();
+				to_build_queue.clear ();
+				no_confirm_commit = true;
+				start_trans_prepare (to_install_first, {}, {}, {});
+				to_install_first = {};
+			} else {
+				try {
+					system_daemon.start_trans_commit ();
+				} catch (Error e) {
+					stderr.printf ("start_trans_commit: %s\n", e.message);
+					finish_transaction (false);
 				}
-				index++;
-			}
-			choose_provider_dialog.destroy ();
-			while (Gtk.events_pending ()) {
-				Gtk.main_iteration ();
 			}
 		}
 
-		Type set_transaction_sum () {
-			// return 0 if transaction_sum is empty, 2, if there are only aur updates, 1 otherwise
-			Type type = 0;
-			uint64 dsize = 0;
-			transaction_summary.remove_all ();
-			var summary = TransactionSummary ();
-			transaction_sum_dialog.sum_list.clear ();
+		public virtual async int run_cmd_line (string[] args, string working_directory, Cancellable cancellable) {
+			int status = 1;
+			var launcher = new SubprocessLauncher (SubprocessFlags.STDOUT_PIPE | SubprocessFlags.STDERR_MERGE);
+			launcher.set_cwd (working_directory);
+			launcher.set_environ (Environ.get ());
 			try {
-				summary = system_daemon.get_transaction_summary ();
-			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
-			}
-			var iter = Gtk.TreeIter ();
-			if (summary.to_remove.length > 0) {
-				type |= Type.STANDARD;
-				foreach (unowned AlpmPackage infos in summary.to_remove) {
-					transaction_summary.add (infos.name);
-					transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
-												1, infos.name,
-												2, infos.version);
-				}
-				Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
-				int pos = (path.get_indices ()[0]) - (summary.to_remove.length - 1);
-				transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
-				transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To remove") + ":"));
-			}
-			if (summary.aur_conflicts_to_remove.length > 0) {
-				// do not add type enum because it is just infos
-				foreach (unowned AlpmPackage infos in summary.aur_conflicts_to_remove) {
-					transaction_summary.add (infos.name);
-					transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
-												1, infos.name,
-												2, infos.version);
-				}
-				Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
-				int pos = (path.get_indices ()[0]) - (summary.aur_conflicts_to_remove.length - 1);
-				transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
-				transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To remove") + ":"));
-			}
-			if (summary.to_downgrade.length > 0) {
-				type |= Type.STANDARD;
-				foreach (unowned AlpmPackage infos in summary.to_downgrade) {
-					dsize += infos.download_size;
-					transaction_summary.add (infos.name);
-					transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
-												1, infos.name,
-												2, infos.version,
-												3, "(%s)".printf (infos.installed_version));
-				}
-				Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
-				int pos = (path.get_indices ()[0]) - (summary.to_downgrade.length - 1);
-				transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
-				transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To downgrade") + ":"));
-			}
-			if (summary.to_build.length > 0) {
-				type |= Type.BUILD;
-				// populate build queue
-				foreach (unowned string name in summary.aur_pkgbases_to_build) {
-					to_build_queue.push_tail (name);
-				}
-				aur_pkgs_to_install = {};
-				foreach (unowned AURPackage infos in summary.to_build) {
-					aur_pkgs_to_install += infos.name;
-					transaction_summary.add (infos.name);
-					transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
-												1, infos.name,
-												2, infos.version);
-				}
-				Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
-				int pos = (path.get_indices ()[0]) - (summary.to_build.length - 1);
-				transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
-				transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To build") + ":"));
-			}
-			if (summary.to_install.length > 0) {
-				type |= Type.STANDARD;
-				foreach (unowned AlpmPackage infos in summary.to_install) {
-					dsize += infos.download_size;
-					transaction_summary.add (infos.name);
-					transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
-												1, infos.name,
-												2, infos.version);
-				}
-				Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
-				int pos = (path.get_indices ()[0]) - (summary.to_install.length - 1);
-				transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
-				transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To install") + ":"));
-			}
-			if (summary.to_reinstall.length > 0) {
-				type |= Type.STANDARD;
-				foreach (unowned AlpmPackage infos in summary.to_reinstall) {
-					dsize += infos.download_size;
-					transaction_summary.add (infos.name);
-					transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
-												1, infos.name,
-												2, infos.version);
+				Subprocess process = launcher.spawnv (args);
+				var dis = new DataInputStream (process.get_stdout_pipe ());
+				string? line;
+				while ((line = yield dis.read_line_async (Priority.DEFAULT, cancellable)) != null) {
+					emit_script_output (line);
 				}
-				Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
-				int pos = (path.get_indices ()[0]) - (summary.to_reinstall.length - 1);
-				transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
-				transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To reinstall") + ":"));
-			}
-			if (summary.to_upgrade.length > 0) {
-				type |= Type.UPDATE;
-				if (mode == Mode.INSTALLER) {
-					foreach (unowned AlpmPackage infos in summary.to_upgrade) {
-						dsize += infos.download_size;
-						transaction_summary.add (infos.name);
-						transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
-													1, infos.name,
-													2, infos.version,
-													3, "(%s)".printf (infos.installed_version));
+				try {
+					yield process.wait_async (cancellable);
+					if (process.get_if_exited ()) {
+						status = process.get_exit_status ();
 					}
-					Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter);
-					int pos = (path.get_indices ()[0]) - (summary.to_upgrade.length - 1);
-					transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos));
-					transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To upgrade") + ":"));
+				} catch (Error e) {
+					// cancelled
+					process.send_signal (Posix.Signal.INT);
+					process.send_signal (Posix.Signal.KILL);
 				}
-			}
-			if (dsize == 0) {
-				transaction_sum_dialog.top_label.visible = false;
-			} else {
-				transaction_sum_dialog.top_label.set_markup ("<b>%s: %s</b>".printf (dgettext (null, "Total download size"), format_size (dsize)));
-				transaction_sum_dialog.top_label.visible = true;
-			}
-			return type;
-		}
-
-		void start_commit () {
-			try {
-				system_daemon.start_trans_commit ();
 			} catch (Error e) {
 				stderr.printf ("Error: %s\n", e.message);
-				success = false;
-				finish_transaction ();
 			}
+			return status;
 		}
 
-		async void build_aur_packages () {
+		async void build_next_aur_package () {
 			string pkgname = to_build_queue.pop_head ();
-			string action = dgettext (null, "Building %s").printf (pkgname) + "...";
-			reset_progress_box (action);
+			emit_action (dgettext (null, "Building %s").printf (pkgname) + "...");
 			build_cancellable.reset ();
-			start_progressbar_pulse ();
 			important_details_outpout (false);
-			to_build.remove_all ();
 			string [] built_pkgs = {};
 			int status = 1;
 			string builddir;
-			if (aur_build_dir == "/tmp") {
+			if (database.config.aur_build_dir == "/tmp") {
 				builddir = "/tmp/pamac-build-%s".printf (Environment.get_user_name ());
 			} else {
-				builddir = aur_build_dir;
+				builddir = database.config.aur_build_dir;
 			}
-			status = yield spawn_in_term ({"mkdir", "-p", builddir});
+			status = yield run_cmd_line ({"mkdir", "-p", builddir}, "/", build_cancellable);
 			if (status == 0) {
-				status = yield spawn_in_term ({"rm", "-rf", pkgname}, builddir);
+				status = yield run_cmd_line ({"rm", "-rf", pkgname}, builddir, build_cancellable);
 				if (!build_cancellable.is_cancelled ()) {
 					if (status == 0) {
 						building = true;
 						start_building ();
-						status = yield spawn_in_term ({"git", "clone", "https://aur.archlinux.org/%s.git".printf (pkgname)}, builddir);
+						status = yield run_cmd_line ({"git", "clone", "https://aur.archlinux.org/%s.git".printf (pkgname)}, builddir, build_cancellable);
 						if (status == 0) {
 							string pkgdir = "%s/%s".printf (builddir, pkgname);
-							status = yield spawn_in_term ({"makepkg", "-cf"}, pkgdir);
+							status = yield run_cmd_line ({"makepkg", "-cf"}, pkgdir, build_cancellable);
 							building = false;
 							if (status == 0) {
 								// get built pkgs path
@@ -1187,16 +481,12 @@ namespace Pamac {
 			building = false;
 			if (status == 0 && built_pkgs.length > 0) {
 				no_confirm_commit = true;
-				show_in_term ("");
-				stop_progressbar_pulse ();
-				start_trans_prepare (flags, {}, {}, built_pkgs, {});
+				emit_script_output ("");
+				start_trans_prepare ({}, {}, built_pkgs, {});
 			} else {
 				important_details_outpout (true);
-				to_load.remove_all ();
 				to_build_queue.clear ();
-				stop_progressbar_pulse ();
-				success = false;
-				finish_transaction ();
+				finish_transaction (false);
 			}
 		}
 
@@ -1207,117 +497,104 @@ namespace Pamac {
 				try {
 					system_daemon.trans_cancel ();
 				} catch (Error e) {
-					stderr.printf ("Error: %s\n", e.message);
+					stderr.printf ("trans_cancel: %s\n", e.message);
 				}
 			}
-			show_in_term ("\n" + dgettext (null, "Transaction cancelled") + ".\n");
-			progress_box.action_label.label = "";
-			warning_textbuffer = new StringBuilder ();
+			emit_script_output ("");
+			emit_action (dgettext (null, "Transaction cancelled") + ".");
+			emit_script_output ("");
 		}
 
 		public void release () {
 			try {
 				system_daemon.trans_release ();
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
+				stderr.printf ("trans_release: %s\n", e.message);
 			}
-			warning_textbuffer = new StringBuilder ();
 		}
 
 		public void stop_daemon () {
 			try {
-				user_daemon.quit ();
 				if (system_daemon != null) {
 					system_daemon.quit ();
 				}
 			} catch (Error e) {
-				stderr.printf ("Error: %s\n", e.message);
+				stderr.printf ("quit: %s\n", e.message);
 			}
 		}
 
 		void on_emit_event (uint primary_event, uint secondary_event, string[] details) {
-			string? action = null;
-			string? detailed_action = null;
 			switch (primary_event) {
 				case 1: //Alpm.Event.Type.CHECKDEPS_START
-					action = dgettext (null, "Checking dependencies") + "...";
+					emit_action (dgettext (null, "Checking dependencies") + "...");
 					break;
 				case 3: //Alpm.Event.Type.FILECONFLICTS_START
-					action = dgettext (null, "Checking file conflicts") + "...";
+					current_action = dgettext (null, "Checking file conflicts") + "...";
 					break;
 				case 5: //Alpm.Event.Type.RESOLVEDEPS_START
-					action = dgettext (null, "Resolving dependencies") + "...";
+					emit_action (dgettext (null, "Resolving dependencies") + "...");
 					break;
 				case 7: //Alpm.Event.Type.INTERCONFLICTS_START
-					action = dgettext (null, "Checking inter-conflicts") + "...";
+					emit_action (dgettext (null, "Checking inter-conflicts") + "...");
 					break;
 				case 11: //Alpm.Event.Type.PACKAGE_OPERATION_START
 					switch (secondary_event) {
 						// special case handle differently
 						case 1: //Alpm.Package.Operation.INSTALL
-							previous_filename = details[0];
-							string msg = dgettext (null, "Installing %s").printf (details[0]) + "...";
-							progress_box.action_label.label = msg;
-							show_in_term (dgettext (null, "Installing %s").printf ("%s (%s)".printf (details[0], details[1])) + "...");
+							current_filename = details[0];
+							current_action = dgettext (null, "Installing %s").printf ("%s (%s)".printf (details[0], details[1])) + "...";
 							break;
 						case 2: //Alpm.Package.Operation.UPGRADE
-							previous_filename = details[0];
-							string msg = dgettext (null, "Upgrading %s").printf (details[0]) + "...";
-							progress_box.action_label.label = msg;
-							show_in_term (dgettext (null, "Upgrading %s").printf ("%s (%s -> %s)".printf (details[0], details[1], details[2])) + "...");
+							current_filename = details[0];
+							current_action = dgettext (null, "Upgrading %s").printf ("%s (%s -> %s)".printf (details[0], details[1], details[2])) + "...";
 							break;
 						case 3: //Alpm.Package.Operation.REINSTALL
-							previous_filename = details[0];
-							string msg = dgettext (null, "Reinstalling %s").printf (details[0]) + "...";
-							progress_box.action_label.label = msg;
-							show_in_term (dgettext (null, "Reinstalling %s").printf ("%s (%s)".printf (details[0], details[1])) + "...");
+							current_filename = details[0];
+							current_action = dgettext (null, "Reinstalling %s").printf ("%s (%s)".printf (details[0], details[1])) + "...";
 							break;
 						case 4: //Alpm.Package.Operation.DOWNGRADE
-							previous_filename = details[0];
-							string msg = dgettext (null, "Downgrading %s").printf (details[0]) + "...";
-							progress_box.action_label.label = msg;
-							show_in_term (dgettext (null, "Downgrading %s").printf ("%s (%s -> %s)".printf (details[0], details[1], details[2])) + "...");
+							current_filename = details[0];
+							current_action = dgettext (null, "Downgrading %s").printf ("%s (%s -> %s)".printf (details[0], details[1], details[2])) + "...";
 							break;
 						case 5: //Alpm.Package.Operation.REMOVE
-							previous_filename = details[0];
-							string msg = dgettext (null, "Removing %s").printf (details[0]) + "...";
-							progress_box.action_label.label = msg;
-							show_in_term (dgettext (null, "Removing %s").printf ("%s (%s)".printf (details[0], details[1])) + "...");
+							current_filename = details[0];
+							current_action = dgettext (null, "Removing %s").printf ("%s (%s)".printf (details[0], details[1])) + "...";
 							break;
 					}
 					break;
 				case 13: //Alpm.Event.Type.INTEGRITY_START
-					action = dgettext (null, "Checking integrity") + "...";
+					current_action = dgettext (null, "Checking integrity") + "...";
 					break;
 				case 15: //Alpm.Event.Type.LOAD_START
-					action = dgettext (null, "Loading packages files") + "...";
+					current_action = dgettext (null, "Loading packages files") + "...";
 					break;
 				case 17: //Alpm.Event.Type.DELTA_INTEGRITY_START
-					action = dgettext (null, "Checking delta integrity") + "...";
+					emit_action (dgettext (null, "Checking delta integrity") + "...");
 					break;
 				case 19: //Alpm.Event.Type.DELTA_PATCHES_START
-					action = dgettext (null, "Applying deltas") + "...";
+					emit_action (dgettext (null, "Applying deltas") + "...");
 					break;
 				case 21: //Alpm.Event.Type.DELTA_PATCH_START
-					detailed_action = dgettext (null, "Generating %s with %s").printf (details[0], details[1]) + "...";
+					emit_script_output (dgettext (null, "Generating %s with %s").printf (details[0], details[1]) + "...");
 					break;
 				case 22: //Alpm.Event.Type.DELTA_PATCH_DONE
-					detailed_action = dgettext (null, "Generation succeeded") + "...";
+					emit_script_output (dgettext (null, "Generation succeeded") + ".");
 					break;
 				case 23: //Alpm.Event.Type.DELTA_PATCH_FAILED
-					detailed_action = dgettext (null, "Generation failed") + "...";
+					emit_script_output (dgettext (null, "Generation failed") + ".");
 					break;
 				case 24: //Alpm.Event.Type.SCRIPTLET_INFO
 					// hooks output are also emitted as SCRIPTLET_INFO
-					if (previous_filename != "") {
-						progress_box.action_label.label = dgettext (null, "Configuring %s").printf (previous_filename) + "...";
+					if (current_filename != "") {
+						emit_action (dgettext (null, "Configuring %s").printf (current_filename) + "...");
+						current_filename = "";
 					}
-					detailed_action = details[0].replace ("\n", "");
+					emit_script_output (details[0].replace ("\n", ""));
 					important_details_outpout (false);
 					break;
 				case 25: //Alpm.Event.Type.RETRIEVE_START
 					start_downloading ();
-					action = dgettext (null, "Downloading") + "...";
+					emit_action (dgettext (null, "Downloading") + "...");
 					break;
 				case 26: //Alpm.Event.Type.RETRIEVE_DONE
 				case 27: //Alpm.Event.Type.RETRIEVE_FAILED
@@ -1325,89 +602,89 @@ namespace Pamac {
 					break;
 				case 28: //Alpm.Event.Type.PKGDOWNLOAD_START
 					// special case handle differently
-					show_in_term (dgettext (null, "Downloading %s").printf (details[0]) + "...");
 					string name_version_release = details[0].slice (0, details[0].last_index_of_char ('-'));
 					string name_version = name_version_release.slice (0, name_version_release.last_index_of_char ('-'));
 					string name = name_version.slice (0, name_version.last_index_of_char ('-'));
-					progress_box.action_label.label = dgettext (null, "Downloading %s").printf (name) + "...";
+					string version_release = details[0].replace (name + "-", "").replace (".pkg.tar.xz", "");
+					current_action = dgettext (null, "Downloading %s").printf ("%s (%s)".printf (name, version_release)) + "...";
 					break;
 				case 31: //Alpm.Event.Type.DISKSPACE_START
-					action = dgettext (null, "Checking available disk space") + "...";
+					current_action = dgettext (null, "Checking available disk space") + "...";
 					break;
 				case 33: //Alpm.Event.Type.OPTDEP_REMOVAL
-					detailed_action = dgettext (null, "%s optionally requires %s").printf (details[0], details[1]);
-					warning_textbuffer.append (detailed_action + "\n");
+					emit_warning (dgettext (null, "%s optionally requires %s").printf (details[0], details[1]));
 					break;
 				case 34: //Alpm.Event.Type.DATABASE_MISSING
-					detailed_action = dgettext (null, "Database file for %s does not exist").printf (details[0]);
+					emit_script_output (dgettext (null, "Database file for %s does not exist").printf (details[0]) + ".");
 					break;
 				case 35: //Alpm.Event.Type.KEYRING_START
-					action = dgettext (null, "Checking keyring") + "...";
+					current_action = dgettext (null, "Checking keyring") + "...";
 					break;
 				case 37: //Alpm.Event.Type.KEY_DOWNLOAD_START
-					action = dgettext (null, "Downloading required keys") + "...";
+					emit_action (dgettext (null, "Downloading required keys") + "...");
 					break;
 				case 39: //Alpm.Event.Type.PACNEW_CREATED
-					detailed_action = dgettext (null, "%s installed as %s.pacnew").printf (details[0], details[0]);
+					emit_script_output (dgettext (null, "%s installed as %s.pacnew").printf (details[0], details[0])+ ".");
 					break;
 				case 40: //Alpm.Event.Type.PACSAVE_CREATED
-					detailed_action = dgettext (null, "%s installed as %s.pacsave").printf (details[0], details[0]);
+					emit_script_output (dgettext (null, "%s installed as %s.pacsave").printf (details[0], details[0])+ ".");
 					break;
 				case 41: //Alpm.Event.Type.HOOK_START
 					switch (secondary_event) {
 						case 1: //Alpm.HookWhen.PRE_TRANSACTION
-							action = dgettext (null, "Running pre-transaction hooks") + "...";
+							current_action = dgettext (null, "Running pre-transaction hooks") + "...";
 							break;
 						case 2: //Alpm.HookWhen.POST_TRANSACTION
-							previous_filename = "";
-							action = dgettext (null, "Running post-transaction hooks") + "...";
+							current_filename = "";
+							current_action = dgettext (null, "Running post-transaction hooks") + "...";
 							break;
 						default:
 							break;
 					}
 					break;
 				case 43: // Alpm.Event.Type.HOOK_RUN_START
-					float fraction = (float) int.parse (details[2]) / int.parse (details[3]);
-					if (fraction != previous_percent) {
-						previous_percent = fraction;
-						progress_box.progressbar.fraction = fraction;
+					double progress = (double) int.parse (details[2]) / int.parse (details[3]);
+					string status = "%s/%s".printf (details[2], details[3]);
+					bool changed = false;
+					if (progress != current_progress) {
+						current_progress = progress;
+						changed = true;
 					}
-					string textbar = "%s/%s".printf (details[2], details[3]);
-					if (textbar != previous_textbar) {
-						previous_textbar = textbar;
-						progress_box.progressbar.text = textbar;
+					if (status != current_status) {
+						current_status = status;
+						changed = true;
 					}
-					if (details[1] != "") {
-						detailed_action = details[1];
-					} else {
-						detailed_action = details[0];
+					if (changed) {
+						if (details[1] != "") {
+							emit_hook_progress (current_action, details[1], current_status, current_progress);
+						} else {
+							emit_hook_progress (current_action, details[0], current_status, current_progress);
+						}
 					}
 					break;
 				default:
 					break;
 			}
-			if (action != null) {
-				progress_box.action_label.label = action;
-				show_in_term (action);
-			}
-			if (detailed_action != null) {
-				show_in_term (detailed_action);
-			}
 		}
 
 		void on_emit_providers (string depend, string[] providers) {
-			choose_provider (depend, providers);
+			int index = choose_provider (depend, providers);
+			try {
+				system_daemon.choose_provider (index);
+			} catch (Error e) {
+				stderr.printf ("choose_provider: %s\n", e.message);
+			}
 		}
 
 		void on_emit_progress (uint progress, string pkgname, uint percent, uint n_targets, uint current_target) {
-			float fraction;
+			double fraction;
 			switch (progress) {
 				case 0: //Alpm.Progress.ADD_START
 				case 1: //Alpm.Progress.UPGRADE_START
 				case 2: //Alpm.Progress.DOWNGRADE_START
 				case 3: //Alpm.Progress.REINSTALL_START
 				case 4: //Alpm.Progress.REMOVE_START
-					fraction = ((float) (current_target - 1) / n_targets) + ((float) percent / (100 * n_targets));
+					fraction = ((double) (current_target - 1) / n_targets) + ((double) percent / (100 * n_targets));
 					break;
 				case 5: //Alpm.Progress.CONFLICTS_START
 				case 6: //Alpm.Progress.DISKSPACE_START
@@ -1415,29 +692,35 @@ namespace Pamac {
 				case 8: //Alpm.Progress.LOAD_START
 				case 9: //Alpm.Progress.KEYRING_START
 				default:
-					fraction = (float) percent / 100;
+					fraction = (double) percent / 100;
 					break;
 			}
-			string textbar = "%lu/%lu".printf (current_target, n_targets);
-			if (textbar != previous_textbar) {
-				previous_textbar = textbar;
-				progress_box.progressbar.text = textbar;
+			string status = "%lu/%lu".printf (current_target, n_targets);
+			bool changed = false;
+			if (fraction != current_progress) {
+				current_progress = fraction;
+				changed = true;
+			}
+			if (status != current_status) {
+				current_status = status;
+				changed = true;
 			}
-			if (fraction != previous_percent) {
-				previous_percent = fraction;
-				progress_box.progressbar.fraction = fraction;
+			if (changed) {
+				if (current_action != "") {
+					emit_action_progress (current_action, current_status, current_progress);
+				}
 			}
 		}
 
 		void on_emit_download (string filename, uint64 xfered, uint64 total) {
 			var text = new StringBuilder ();
-			float fraction;
+			double fraction;
 			if (total_download > 0) {
 				if (xfered == 0) {
 					// start download pkg is handled by Alpm.Event.Type.PKGDOWNLOAD_START
 					previous_xfered = 0;
-					fraction = previous_percent;
-					text.append (previous_textbar);
+					fraction = current_progress;
+					text.append (current_status);
 					timer.start ();
 				} else {
 					if (timer.elapsed () > 0.1) {
@@ -1446,7 +729,7 @@ namespace Pamac {
 					}
 					previous_xfered = xfered;
 					uint64 downloaded_total = xfered + already_downloaded;
-					fraction = (float) downloaded_total / total_download;
+					fraction = (double) downloaded_total / total_download;
 					if (fraction <= 1) {
 						text.append ("%s/%s  ".printf (format_size (xfered + already_downloaded), format_size (total_download)));
 						uint64 remaining_seconds = 0;
@@ -1467,7 +750,7 @@ namespace Pamac {
 						text.append ("%s".printf (format_size (xfered + already_downloaded)));
 					}
 					if (xfered == total) {
-						previous_filename = "";
+						current_filename = "";
 						already_downloaded += total;
 					} else {
 						timer.start ();
@@ -1481,20 +764,19 @@ namespace Pamac {
 					fraction = 0;
 					timer.start ();
 					if (filename.has_suffix (".db") || filename.has_suffix (".files")) {
-						string action = dgettext (null, "Refreshing %s").printf (filename) + "...";
-						reset_progress_box (action);
+						current_action = dgettext (null, "Refreshing %s").printf (filename) + "...";
 					}
 				} else if (xfered == total) {
 					timer.stop ();
 					fraction = 1;
-					previous_filename = "";
+					current_filename = "";
 				} else {
 					if (timer.elapsed () > 0.1) {
 						download_rate = ((download_rate * rates_nb) + (uint64) ((xfered - previous_xfered) / timer.elapsed ())) / (rates_nb + 1);
 						rates_nb++;
 					}
 					previous_xfered = xfered;
-					fraction = (float) xfered / total;
+					fraction = (double) xfered / total;
 					if (fraction <= 1) {
 						text.append ("%s/%s  ".printf (format_size (xfered), format_size (total)));
 						uint64 remaining_seconds = 0;
@@ -1518,27 +800,25 @@ namespace Pamac {
 					timer.start ();
 				}
 			}
-			if (fraction != previous_percent) {
-				previous_percent = fraction;
-				progress_box.progressbar.fraction = fraction;
+			if (fraction != current_progress) {
+				current_progress = fraction;
 			}
-			if (text.str != previous_textbar) {
-				previous_textbar = text.str;
-				progress_box.progressbar.text = text.str;
+			if (text.str != current_status) {
+				current_status = text.str;
 			}
+			emit_action_progress (current_action, current_status, current_progress);
 		}
 
 		void on_emit_totaldownload (uint64 total) {
 			download_rate = 0;
 			rates_nb = 0;
-			previous_percent = 0;
-			previous_textbar = "";
+			current_progress = 0;
+			current_status = "";
 			total_download = total;
 			//  this is emitted at the end of the total download 
 			// with the value 0 so stop our timer
 			if (total == 0) {
 				timer.stop ();
-				progress_box.progressbar.text = "";
 			}
 		}
 
@@ -1546,343 +826,198 @@ namespace Pamac {
 			// msg ends with \n
 			string? line = null;
 			if (level == 1) { //Alpm.LogLevel.ERROR
-				if (previous_filename != "") {
-					line = dgettext (null, "Error") + ": " + previous_filename + ": " + msg;
+				if (current_filename != "") {
+					line = dgettext (null, "Error") + ": " + current_filename + ": " + msg;
 				} else {
 					line = dgettext (null, "Error") + ": " + msg;
 				}
 				important_details_outpout (false);
+				emit_error (line.replace ("\n", ""), {});
 			} else if (level == (1 << 1)) { //Alpm.LogLevel.WARNING
 				// do not show warning when manjaro-system remove db.lck
-				if (previous_filename != "manjaro-system") {
-					if (previous_filename != "") {
-						line = dgettext (null, "Warning") + ": " + previous_filename + ": " + msg;
+				if (current_filename != "manjaro-system") {
+					if (current_filename != "") {
+						line = dgettext (null, "Warning") + ": " + current_filename + ": " + msg;
 					} else {
 						line = dgettext (null, "Warning") + ": " + msg;
 					}
-					warning_textbuffer.append (msg);
-				}
-			}
-			if (line != null) {
-				show_in_term (line.replace ("\n", ""));
-			}
-		}
-
-		void show_warnings (bool block = true) {
-			if (warning_textbuffer.len > 0) {
-				var flags = Gtk.DialogFlags.MODAL;
-				int use_header_bar;
-				Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header_bar);
-				if (use_header_bar == 1) {
-					flags |= Gtk.DialogFlags.USE_HEADER_BAR;
+					emit_warning (line.replace ("\n", ""));
 				}
-				var dialog = new Gtk.Dialog.with_buttons (dgettext (null, "Warning"),
-														application_window,
-														flags);
-				dialog.border_width = 6;
-				dialog.icon_name = "system-software-install";
-				dialog.deletable = false;
-				unowned Gtk.Widget widget = dialog.add_button (dgettext (null, "_Close"), Gtk.ResponseType.CLOSE);
-				widget.can_focus = true;
-				widget.has_focus = true;
-				widget.can_default = true;
-				widget.has_default = true;
-				var scrolledwindow = new Gtk.ScrolledWindow (null, null);
-				var label = new Gtk.Label (warning_textbuffer.str);
-				label.selectable = true;
-				label.margin = 12;
-				scrolledwindow.visible = true;
-				label.visible = true;
-				scrolledwindow.add (label);
-				scrolledwindow.expand = true;
-				unowned Gtk.Box box = dialog.get_content_area ();
-				box.add (scrolledwindow);
-				dialog.default_width = 600;
-				dialog.default_height = 300;
-				if (block) {
-					dialog.run ();
-					dialog.destroy ();
-				} else {
-					dialog.show ();
-					dialog.response.connect (() => {
-						dialog.destroy ();
-					});
-				}
-				warning_textbuffer = new StringBuilder ();
 			}
 		}
 
-		public void display_error (string message, string[] details) {
-			var flags = Gtk.DialogFlags.MODAL;
-			int use_header_bar;
-			Gtk.Settings.get_default ().get ("gtk-dialogs-use-header", out use_header_bar);
-			if (use_header_bar == 1) {
-				flags |= Gtk.DialogFlags.USE_HEADER_BAR;
-			}
-			var dialog = new Gtk.Dialog.with_buttons (message,
-													application_window,
-													flags);
-			dialog.border_width = 6;
-			dialog.icon_name = "system-software-install";
-			var textbuffer = new StringBuilder ();
-			if (details.length != 0) {
-				show_in_term (message + ":");
-				foreach (unowned string detail in details) {
-					show_in_term (detail);
-					textbuffer.append (detail + "\n");
-				}
-			} else {
-				show_in_term (message);
-				textbuffer.append (message);
-			}
-			dialog.deletable = false;
-			unowned Gtk.Widget widget = dialog.add_button (dgettext (null, "_Close"), Gtk.ResponseType.CLOSE);
-			widget.can_focus = true;
-			widget.has_focus = true;
-			widget.can_default = true;
-			widget.has_default = true;
-			var scrolledwindow = new Gtk.ScrolledWindow (null, null);
-			var label = new Gtk.Label (textbuffer.str);
-			label.selectable = true;
-			label.margin = 12;
-			scrolledwindow.visible = true;
-			label.visible = true;
-			scrolledwindow.add (label);
-			scrolledwindow.expand = true;
-			unowned Gtk.Box box = dialog.get_content_area ();
-			box.add (scrolledwindow);
-			dialog.default_width = 600;
-			dialog.default_height = 300;
-			dialog.show ();
-			dialog.response.connect (() => {
-				dialog.destroy ();
-			});
-			Timeout.add (1000, () => {
-				try {
-					var notification = new Notify.Notification (dgettext (null, "Package Manager"),
-																message,
-																"system-software-update");
-					notification.show ();
-				} catch (Error e) {
-					stderr.printf ("Notify Error: %s", e.message);
-				}
-				return false;
-			});
-		}
-
 		void handle_error (ErrorInfos error) {
 			if (error.message != "") {
-				reset_progress_box ("");
-				display_error (error.message, error.details);
+				emit_error (error.message, error.details);
 			}
-			finish_transaction ();
+			finish_transaction (false);
 		}
 
-		void finish_transaction () {
+		void finish_transaction (bool success) {
 			disconnecting_dbus_signals ();
-			transaction_summary.remove_all ();
-			reset_progress_box ("");
-			if (success) {
-				try {
-					var notification = new Notify.Notification (dgettext (null, "Package Manager"),
-																dgettext (null, "Transaction successfully finished"),
-																"system-software-update");
-					notification.show ();
-				} catch (Error e) {
-					stderr.printf ("Notify Error: %s", e.message);
-				}
+			database.refresh ();
+			if (sysupgrading) {
+				sysupgrade_finished (success);
+				sysupgrading = false;
+			} else {
+				finished (success);
 			}
-			finished (success);
-			success = false;
 		}
 
 		void on_refresh_finished (bool success) {
-			stop_progressbar_pulse ();
-			this.success = success;
-			if (success) {
-				finished (success);
-				reset_progress_box ("");
-				success = false;
-			} else {
-				handle_error (get_current_error ());
+			stop_downloading ();
+			if (!success) {
+				var error = get_current_error ();
+				if (error.message != "") {
+					emit_error (error.message, error.details);
+				}
 			}
-			previous_filename = "";
+			current_filename = "";
 			disconnecting_dbus_signals ();
 			system_daemon.refresh_finished.disconnect (on_refresh_finished);
+			database.refresh ();
+			refresh_finished (success);
 		}
 
 		void on_trans_prepare_finished (bool success) {
-			stop_progressbar_pulse ();
-			this.success = success;
 			if (success) {
-				show_warnings ();
-				Type type = set_transaction_sum ();
-				if (mode != Mode.INSTALLER && (no_confirm_commit || type == Type.UPDATE)) {
-					// no_confirm_commit or only updates
-					to_install.remove_all ();
+				var summary = TransactionSummary ();
+				try {
+					summary = system_daemon.get_transaction_summary ();
+				} catch (Error e) {
+					stderr.printf ("get_transaction_summary: %s\n", e.message);
+				}
+				Type type = 0;
+				if ((summary.to_install.length
+					+ summary.to_downgrade.length
+					+ summary.to_reinstall.length) > 0) {
+					type |= Type.INSTALL;
+				}
+				if (summary.to_remove.length > 0) {
+					type |= Type.REMOVE;
+				}
+				if (summary.to_upgrade.length > 0) {
+					type |= Type.UPDATE;
+				}
+				if (summary.to_build.length > 0) {
+					type |= Type.BUILD;
+					// populate build queue
+					foreach (unowned string name in summary.aur_pkgbases_to_build) {
+						to_build_queue.push_tail (name);
+					}
+					aur_pkgs_to_install = {};
+					foreach (unowned AURPackage infos in summary.to_build) {
+						aur_pkgs_to_install += infos.name;
+					}
+				}
+				if (no_confirm_commit
+					|| (no_confirm_upgrade && ((type & Type.REMOVE) == 0))) {
 					start_commit ();
 				} else if (type != 0) {
-					if (transaction_sum_dialog.run () == Gtk.ResponseType.OK) {
-						transaction_sum_dialog.hide ();
-						while (Gtk.events_pending ()) {
-							Gtk.main_iteration ();
-						}
+					if (ask_confirmation (summary)) {
 						if (type == Type.BUILD) {
 							// there only AUR packages to build
 							release ();
 							on_trans_commit_finished (true);
 						} else {
-							// backup to_install and to_remove
-							foreach (unowned string name in to_install) {
-								previous_to_install.add (name);
-							}
-							foreach (unowned string name in to_remove) {
-								previous_to_remove.add (name);
-							}
-							to_install.remove_all ();
-							to_remove.remove_all ();
 							start_commit ();
 						}
 					} else {
-						transaction_sum_dialog.hide ();
-						unowned string action = dgettext (null, "Transaction cancelled");
-						show_in_term (action + ".\n");
-						progress_box.action_label.label = action;
+						emit_action (dgettext (null, "Transaction cancelled") + ".");
 						release ();
-						transaction_summary.remove_all ();
 						to_build_queue.clear ();
 						sysupgrade_after_trans = false;
-						this.success = false;
-						finish_transaction ();
+						finish_transaction (false);
 					}
 				} else {
 					//var err = ErrorInfos ();
 					//err.message = dgettext (null, "Nothing to do") + "\n";
-					show_in_term (dgettext (null, "Nothing to do") + ".\n");
+					emit_action (dgettext (null, "Nothing to do") + ".");
 					release ();
-					clear_lists ();
-					finish_transaction ();
+					finish_transaction (true);
 					//handle_error (err);
 				}
 			} else {
-				to_load.remove_all ();
-				warning_textbuffer = new StringBuilder ();
 				handle_error (get_current_error ());
 			}
 		}
 
 		void on_trans_commit_finished (bool success) {
-			this.success = success;
-			// needed before build_aur_packages and remove_makedeps
+			// needed before build_aur_packages
 			no_confirm_commit = false;
 			if (success) {
-				show_warnings (false);
-				to_load.remove_all ();
 				if (to_build_queue.get_length () != 0) {
-					show_in_term ("");
-					clear_previous_lists ();
+					emit_script_output ("");
 					check_authorization.begin ((obj, res) => {
 						bool authorized = check_authorization.end (res);
 						if (authorized) {
-							build_aur_packages.begin ();
+							build_next_aur_package.begin ();
 						} else {
 							to_build_queue.clear ();
 							on_trans_commit_finished (false);
 						}
 					});
 				} else {
-					clear_previous_lists ();
 					if (sysupgrade_after_trans) {
 						sysupgrade_after_trans = false;
+						no_confirm_commit = true;
 						disconnecting_dbus_signals ();
-						sysupgrade (false);
+						start_sysupgrade (enable_downgrade, temporary_ignorepkgs, {});
 					} else {
-						unowned string action = dgettext (null, "Transaction successfully finished");
-						show_in_term (action + ".\n");
-						progress_box.action_label.label = action;
-						finish_transaction ();
+						emit_action (dgettext (null, "Transaction successfully finished") + ".");
+						finish_transaction (true);
 					}
 				}
 			} else {
-				// if it is an authentication or a download error, database was not modified
 				var err = get_current_error ();
-				if (err.message == dgettext (null, "Authentication failed")
-					|| err.no == 54) { //Alpm.Errno.EXTERNAL_DOWNLOAD
-					// recover old pkgnames
-					foreach (unowned string name in previous_to_install) {
-						to_install.add (name);
-					}
-					foreach (unowned string name in previous_to_remove) {
-						to_remove.add (name);
-					}
-				} else {
-					to_load.remove_all ();
-				}
-				clear_previous_lists ();
 				to_build_queue.clear ();
-				warning_textbuffer = new StringBuilder ();
 				handle_error (err);
 			}
 			total_download = 0;
 			already_downloaded = 0;
-			previous_filename = "";
+			current_filename = "";
 		}
 
 		void on_set_pkgreason_finished () {
 			system_daemon.set_pkgreason_finished.disconnect (on_set_pkgreason_finished);
+			database.refresh ();
 			set_pkgreason_finished ();
 		}
 
 		void on_write_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon,
-												bool enable_aur, string aur_build_dir, bool check_aur_updates) {
+											bool enable_aur, string aur_build_dir, bool check_aur_updates,
+											bool download_updates) {
 			system_daemon.write_pamac_config_finished.disconnect (on_write_pamac_config_finished);
-			pamac_config.reload ();
-			flags = (1 << 4); //Alpm.TransFlag.CASCADE
-			if (pamac_config.recurse) {
-				flags |= (1 << 5); //Alpm.TransFlag.RECURSE
-			}
+			database.config.reload ();
 			write_pamac_config_finished (recurse, refresh_period, no_update_hide_icon,
 										enable_aur, aur_build_dir, check_aur_updates,
 										download_updates);
 		}
 
 		void on_write_alpm_config_finished (bool checkspace) {
-			refresh_handle ();
 			system_daemon.write_alpm_config_finished.disconnect (on_write_alpm_config_finished);
+			database.refresh ();
 			write_alpm_config_finished (checkspace);
 		}
 
 		void on_generate_mirrors_list_data (string line) {
-			show_in_term (line);
+			emit_script_output (line);
 		}
 
 		void on_generate_mirrors_list_finished () {
-			refresh_handle ();
 			system_daemon.generate_mirrors_list_data.disconnect (on_generate_mirrors_list_data);
 			system_daemon.generate_mirrors_list_finished.disconnect (on_generate_mirrors_list_finished);
-			reset_progress_box ("");
 			generate_mirrors_list_finished ();
 		}
 
-		void connecting_user_daemon () {
-			if (user_daemon == null) {
-				try {
-					user_daemon = Bus.get_proxy_sync (BusType.SESSION, "org.manjaro.pamac.user", "/org/manjaro/pamac/user");
-					user_daemon.enable_appstream ();
-				} catch (Error e) {
-					stderr.printf ("Error: %s\n", e.message);
-				}
-			}
-		}
-
 		void connecting_system_daemon () {
 			if (system_daemon == null) {
 				try {
 					system_daemon = Bus.get_proxy_sync (BusType.SYSTEM, "org.manjaro.pamac.system", "/org/manjaro/pamac/system");
 					// Set environment variables
-					system_daemon.set_environment_variables (pamac_config.environment_variables);
+					system_daemon.set_environment_variables (database.config.environment_variables);
 				} catch (Error e) {
-					stderr.printf ("Error: %s\n", e.message);
+					stderr.printf ("set_environment_variables: %s\n", e.message);
 				}
 			}
 		}
diff --git a/src/tray.vala b/src/tray.vala
index 42bc10c9..61513b88 100644
--- a/src/tray.vala
+++ b/src/tray.vala
@@ -86,7 +86,7 @@ namespace Pamac {
 				try {
 					system_daemon = Bus.get_proxy_sync (BusType.SYSTEM, "org.manjaro.pamac.system", "/org/manjaro/pamac/system");
 					// Set environment variables
-					var pamac_config = new Pamac.Config ("/etc/pamac.conf");
+					var pamac_config = new Config ("/etc/pamac.conf");
 					system_daemon.set_environment_variables (pamac_config.environment_variables);
 					system_daemon.download_updates_finished.connect (on_download_updates_finished);
 				} catch (Error e) {
@@ -150,7 +150,7 @@ namespace Pamac {
 		public abstract void set_icon_visible (bool visible);
 
 		bool check_updates () {
-			var pamac_config = new Pamac.Config ("/etc/pamac.conf");
+			var pamac_config = new Config ("/etc/pamac.conf");
 			if (pamac_config.refresh_period != 0) {
 				try {
 					user_daemon.start_get_updates (pamac_config.enable_aur && pamac_config.check_aur_updates, true);
@@ -163,7 +163,7 @@ namespace Pamac {
 
 		void on_get_updates_finished (Updates updates) {
 			updates_nb = updates.repos_updates.length + updates.aur_updates.length;
-			var pamac_config = new Pamac.Config ("/etc/pamac.conf");
+			var pamac_config = new Config ("/etc/pamac.conf");
 			if (updates_nb == 0) {
 				set_icon (noupdate_icon_name);
 				set_tooltip (noupdate_info);
@@ -297,7 +297,7 @@ namespace Pamac {
 			Intl.textdomain ("pamac");
 			Intl.setlocale (LocaleCategory.ALL, "");
 
-			var pamac_config = new Pamac.Config ("/etc/pamac.conf");
+			var pamac_config = new Config ("/etc/pamac.conf");
 			// if refresh period is 0, just return so tray will exit
 			if (pamac_config.refresh_period == 0) {
 				return;
diff --git a/src/updates_priv.vala b/src/updates_priv.vala
new file mode 100644
index 00000000..b3ce3bb5
--- /dev/null
+++ b/src/updates_priv.vala
@@ -0,0 +1,26 @@
+/*
+ *  pamac-vala
+ *
+ *  Copyright (C) 2018 Guillaume Benoit <guillaume@manjaro.org>
+ *
+ *  This program 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 get of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Pamac {
+	struct UpdatesPriv {
+		bool syncfirst;
+		AlpmPackage[] repos_updates;
+		AURPackage[] aur_updates;
+	}
+}
diff --git a/src/user_daemon.vala b/src/user_daemon.vala
index 12ce4e7a..e0ad8ff5 100644
--- a/src/user_daemon.vala
+++ b/src/user_daemon.vala
@@ -420,11 +420,11 @@ namespace Pamac {
 			return pkgs;
 		}
 
-		public async AlpmPackage[] get_installed_pkgs () throws Error {
-			return get_installed_pkgs_sync ();
+		public async AlpmPackage[] get_installed_pkgs_async () throws Error {
+			return get_installed_pkgs ();
 		}
 
-		public AlpmPackage[] get_installed_pkgs_sync () throws Error {
+		public AlpmPackage[] get_installed_pkgs () throws Error {
 			AlpmPackage[] pkgs = {};
 			unowned Alpm.List<unowned Alpm.Package> pkgcache = alpm_handle.localdb.pkgcache;
 			while (pkgcache != null) {
@@ -437,7 +437,11 @@ namespace Pamac {
 			return pkgs;
 		}
 
-		public async AlpmPackage[] get_installed_apps () throws Error {
+		public async AlpmPackage[] get_installed_apps_async () throws Error {
+			return get_installed_apps ();
+		}
+
+		public AlpmPackage[] get_installed_apps () throws Error {
 			AlpmPackage[] pkgs = {};
 			app_store.get_apps ().foreach ((app) => {
 				unowned string pkgname = app.get_pkgname_default ();
@@ -463,7 +467,11 @@ namespace Pamac {
 			return pkgs;
 		}
 
-		public async AlpmPackage[] get_explicitly_installed_pkgs () throws Error {
+		public async AlpmPackage[] get_explicitly_installed_pkgs_async () throws Error {
+			return get_explicitly_installed_pkgs ();
+		}
+
+		public AlpmPackage[] get_explicitly_installed_pkgs () throws Error {
 			AlpmPackage[] pkgs = {};
 			unowned Alpm.List<unowned Alpm.Package> pkgcache = alpm_handle.localdb.pkgcache;
 			while (pkgcache != null) {
@@ -478,11 +486,11 @@ namespace Pamac {
 			return pkgs;
 		}
 
-		public async AlpmPackage[] get_foreign_pkgs () throws Error {
-			return get_foreign_pkgs_sync ();
+		public async AlpmPackage[] get_foreign_pkgs_async () throws Error {
+			return get_foreign_pkgs ();
 		}
 
-		public AlpmPackage[] get_foreign_pkgs_sync () throws Error {
+		public AlpmPackage[] get_foreign_pkgs() throws Error {
 			AlpmPackage[] pkgs = {};
 			unowned Alpm.List<unowned Alpm.Package> pkgcache = alpm_handle.localdb.pkgcache;
 			while (pkgcache != null) {
@@ -508,11 +516,11 @@ namespace Pamac {
 			return pkgs;
 		}
 
-		public async AlpmPackage[] get_orphans () throws Error {
-			return get_orphans_sync ();
+		public async AlpmPackage[] get_orphans_async () throws Error {
+			return get_orphans ();
 		}
 
-		public AlpmPackage[] get_orphans_sync () throws Error {
+		public AlpmPackage[] get_orphans () throws Error {
 			AlpmPackage[] pkgs = {};
 			unowned Alpm.List<unowned Alpm.Package> pkgcache = alpm_handle.localdb.pkgcache;
 			while (pkgcache != null) {
@@ -627,11 +635,11 @@ namespace Pamac {
 			return result;
 		}
 
-		public async AlpmPackage[] search_pkgs (string search_string) throws Error {
-			return search_pkgs_sync (search_string);
+		public async AlpmPackage[] search_pkgs_async (string search_string) throws Error {
+			return search_pkgs (search_string);
 		}
 
-		public AlpmPackage[] search_pkgs_sync (string search_string) throws Error {
+		public AlpmPackage[] search_pkgs(string search_string) throws Error {
 			AlpmPackage[] pkgs = {};
 			Alpm.List<unowned Alpm.Package> alpm_pkgs = search_all_dbs (search_string);
 			unowned Alpm.List<unowned Alpm.Package> list = alpm_pkgs;
@@ -661,7 +669,7 @@ namespace Pamac {
 			};
 		}
 
-		public async AURPackage[] search_in_aur (string search_string) throws Error {
+		public async AURPackage[] search_in_aur_async (string search_string) throws Error {
 			if (!aur_search_results.contains (search_string)) {
 				Json.Array pkgs = yield AUR.search (search_string.split (" "));
 				aur_search_results.insert (search_string, pkgs);
@@ -678,7 +686,7 @@ namespace Pamac {
 			return result;
 		}
 
-		public async AURPackageDetails get_aur_details (string pkgname) throws Error {
+		public async AURPackageDetails get_aur_details_async (string pkgname) throws Error {
 			string name = "";
 			string version = "";
 			string desc = "";
@@ -834,11 +842,11 @@ namespace Pamac {
 			return repos_names;
 		}
 
-		public async AlpmPackage[] get_repo_pkgs (string repo) throws Error {
-			return get_repo_pkgs_sync (repo);
+		public async AlpmPackage[] get_repo_pkgs_async (string repo) throws Error {
+			return get_repo_pkgs (repo);
 		}
 
-		public AlpmPackage[] get_repo_pkgs_sync (string repo) throws Error {
+		public AlpmPackage[] get_repo_pkgs (string repo) throws Error {
 			AlpmPackage[] pkgs = {};
 			unowned Alpm.List<unowned Alpm.DB> syncdbs = alpm_handle.syncdbs;
 			while (syncdbs != null) {
@@ -922,11 +930,11 @@ namespace Pamac {
 			return result;
 		}
 
-		public async AlpmPackage[] get_group_pkgs (string groupname) throws Error {
-			return get_group_pkgs_sync (groupname);
+		public async AlpmPackage[] get_group_pkgs_async (string groupname) throws Error {
+			return get_group_pkgs (groupname);
 		}
 
-		public AlpmPackage[] get_group_pkgs_sync (string groupname) throws Error {
+		public AlpmPackage[] get_group_pkgs (string groupname) throws Error {
 			AlpmPackage[] pkgs = {};
 			Alpm.List<unowned Alpm.Package> alpm_pkgs = group_pkgs (groupname);
 			unowned Alpm.List<unowned Alpm.Package> list = alpm_pkgs;
@@ -940,7 +948,11 @@ namespace Pamac {
 			return pkgs;
 		}
 
-		public async AlpmPackage[] get_category_pkgs (string category) throws Error {
+		public async AlpmPackage[] get_category_pkgs_async (string category) throws Error {
+			return get_category_pkgs (category);
+		}
+
+		public AlpmPackage[] get_category_pkgs (string category) throws Error {
 			AlpmPackage[] pkgs = {};
 			app_store.get_apps ().foreach ((app) => {
 				app.get_categories ().foreach ((cat_name) => {
diff --git a/src/version.vala b/src/version.vala
index 4e33643c..89b6ebad 100644
--- a/src/version.vala
+++ b/src/version.vala
@@ -1 +1 @@
-const string VERSION = "6.5.0";
+const string VERSION = "6.9.0";
-- 
GitLab