summaryrefslogtreecommitdiff
path: root/community/packagekit
diff options
context:
space:
mode:
authorParabola <dev@list.parabolagnulinux.org>2011-04-05 14:26:38 +0000
committerParabola <dev@list.parabolagnulinux.org>2011-04-05 14:26:38 +0000
commit415856bdd4f48ab4f2732996f0bae58595092bbe (patch)
treeede2018b591f6dfb477fe9341ba17b9bc000fab9 /community/packagekit
Tue Apr 5 14:26:38 UTC 2011
Diffstat (limited to 'community/packagekit')
-rw-r--r--community/packagekit/PKGBUILD93
-rw-r--r--community/packagekit/alpm.patch11693
-rw-r--r--community/packagekit/packagekit.install11
3 files changed, 11797 insertions, 0 deletions
diff --git a/community/packagekit/PKGBUILD b/community/packagekit/PKGBUILD
new file mode 100644
index 000000000..410da5d19
--- /dev/null
+++ b/community/packagekit/PKGBUILD
@@ -0,0 +1,93 @@
+# $Id: PKGBUILD 43963 2011-04-01 10:59:14Z jconder $
+# Maintainer: Jonathan Conder <jonno.conder@gmail.com>
+pkgbase='packagekit'
+pkgname=('packagekit' 'packagekit-qt' 'packagekit-python')
+pkgver=0.6.13
+pkgrel=2
+pkgdesc="A system designed to make installation and updates of packages easier."
+arch=('i686' 'x86_64')
+url="http://www.packagekit.org"
+license=('GPL')
+makedepends=('dbus-glib' 'gobject-introspection' 'gtk-doc' 'intltool'
+ 'networkmanager' 'pacman' 'pm-utils' 'polkit' 'python2' 'qt'
+ 'sqlite3')
+options=('!libtool')
+source=("http://www.packagekit.org/releases/PackageKit-$pkgver.tar.bz2"
+ 'alpm.patch')
+sha256sums=('cec67a54cd615163402b1e5100a6a9be0bd1838896d6183407b4d9274de47249'
+ '777b1cda90f8cc78eb5cf651d47b5c7b6f183a34b98ad0d93945c76973bd29de')
+
+build() {
+ cd "$srcdir/PackageKit-$pkgver"
+
+ patch -Np1 -i "$srcdir/alpm.patch"
+
+ # TODO: change to Makefile.in's and configure
+ sed -i 's@SUBDIRS = test@SUBDIRS =@' 'backends/Makefile.am'
+ sed -i 's@python @python2 @' 'lib/python/packagekit/Makefile.am'
+
+ export PYTHON=/usr/bin/python2
+ ./autogen.sh --prefix=/usr \
+ --sysconfdir=/etc \
+ --localstatedir=/var \
+ --libexecdir=/usr/lib/PackageKit \
+ --disable-static \
+ --disable-gtk-doc \
+ --disable-tests \
+ --disable-local \
+ --disable-browser-plugin \
+ --disable-gstreamer-plugin \
+ --disable-gtk-module \
+ --disable-command-not-found \
+ --disable-cron \
+ --disable-debuginfo-install \
+ --enable-pm-utils \
+ --disable-dummy \
+ --enable-alpm \
+ --with-default-backend=alpm
+ make
+}
+
+package_packagekit() {
+ backup=('var/lib/PackageKit/transactions.db'
+ 'etc/PackageKit/alpm.d/pacman.conf'
+ 'etc/PackageKit/alpm.d/repos.list')
+ depends=('dbus-glib' 'pacman>=3.5.0' 'pacman<3.6.0' 'polkit'
+ 'shared-mime-info' 'sqlite3')
+ optdepends=('networkmanager')
+ install='packagekit.install'
+
+ cd "$srcdir/PackageKit-$pkgver"
+
+ make DESTDIR="$pkgdir" install
+
+ rm -rf "$pkgdir/usr/include/PackageKit/packagekit-qt"
+ rm -rf "$pkgdir/usr/lib/libpackagekit-qt.so"*
+ rm -rf "$pkgdir/usr/lib/pkgconfig/packagekit-qt.pc"
+ rm -rf "$pkgdir/usr/share/cmake"
+
+ rm -rf "$pkgdir/usr/lib/python"*
+ rm -rf "$pkgdir/usr/share/PackageKit/website"
+
+ mv "$pkgdir/etc/bash_completion.d/pk-completion.bash" \
+ "$pkgdir/etc/bash_completion.d/pkcon"
+ touch "$pkgdir/var/log/PackageKit"
+}
+
+package_packagekit-qt() {
+ depends=('packagekit' 'qt')
+ pkgdesc=('Qt bindings for PackageKit')
+
+ cd "$srcdir/PackageKit-$pkgver/lib/packagekit-qt"
+
+ make DESTDIR="$pkgdir" install
+}
+
+package_packagekit-python() {
+ depends=('packagekit' 'python2')
+ pkgdesc=('Python bindings for PackageKit')
+
+ cd "$srcdir/PackageKit-$pkgver/lib/python"
+
+ make DESTDIR="$pkgdir" install
+}
diff --git a/community/packagekit/alpm.patch b/community/packagekit/alpm.patch
new file mode 100644
index 000000000..cc415ce9d
--- /dev/null
+++ b/community/packagekit/alpm.patch
@@ -0,0 +1,11693 @@
+diff --git a/backends/Makefile.am b/backends/Makefile.am
+index 3d53950..ba378df 100644
+--- a/backends/Makefile.am
++++ b/backends/Makefile.am
+@@ -32,10 +32,6 @@ if BACKEND_TYPE_OPKG
+ SUBDIRS += opkg
+ endif
+
+-if BACKEND_TYPE_PACMAN
+-SUBDIRS += pacman
+-endif
+-
+ if BACKEND_TYPE_RAZOR
+ SUBDIRS += razor
+ endif
+diff --git a/backends/alpm/Makefile.am b/backends/alpm/Makefile.am
+index 15749dc..a664b2c 100644
+--- a/backends/alpm/Makefile.am
++++ b/backends/alpm/Makefile.am
+@@ -1,10 +1,54 @@
+-INCLUDES = \
+- -DG_LOG_DOMAIN=\"PackageKit-Alpm\"
++PK_BACKEND_CONFIG_FILE = $(confdir)/pacman.conf
++PK_BACKEND_GROUP_FILE = $(confdir)/groups.list
++PK_BACKEND_REPO_FILE = $(confdir)/repos.list
++
++PK_BACKEND_DEFAULT_PATH = "/bin:/usr/bin:/sbin:/usr/sbin"
++PK_BACKEND_DEFAULT_ROOT = "/"
++PK_BACKEND_DEFAULT_DBPATH = $(localstatedir)/lib/pacman
++PK_BACKEND_DEFAULT_CACHEDIR = $(localstatedir)/cache/pacman/pkg
++PK_BACKEND_DEFAULT_LOGFILE = $(localstatedir)/log/pacman.log
++
++ALPM_CACHE_PATH = $(localstatedir)/lib/pacman/sync
++ALPM_PACKAGE_URL = "http://www.archlinux.org/packages/%s/%s/%s/"
++
++DEFS = -DPK_BACKEND_CONFIG_FILE=\"$(PK_BACKEND_CONFIG_FILE)\" \
++ -DPK_BACKEND_GROUP_FILE=\"$(PK_BACKEND_GROUP_FILE)\" \
++ -DPK_BACKEND_REPO_FILE=\"$(PK_BACKEND_REPO_FILE)\" \
++ -DPK_BACKEND_DEFAULT_PATH=\"$(PK_BACKEND_DEFAULT_PATH)\" \
++ -DPK_BACKEND_DEFAULT_ROOT=\"$(PK_BACKEND_DEFAULT_ROOT)\" \
++ -DPK_BACKEND_DEFAULT_DBPATH=\"$(PK_BACKEND_DEFAULT_DBPATH)\" \
++ -DPK_BACKEND_DEFAULT_CACHEDIR=\"$(PK_BACKEND_DEFAULT_CACHEDIR)\" \
++ -DPK_BACKEND_DEFAULT_LOGFILE=\"$(PK_BACKEND_DEFAULT_LOGFILE)\" \
++ -DALPM_CACHE_PATH=\"$(ALPM_CACHE_PATH)\" \
++ -DALPM_PACKAGE_URL=\"$(ALPM_PACKAGE_URL)\" \
++ -DG_LOG_DOMAIN=\"PackageKit-alpm\"
++
++confdir = $(PK_CONF_DIR)/alpm.d
++conf_DATA = groups.list \
++ pacman.conf \
++ repos.list
+
+ plugindir = $(PK_PLUGIN_DIR)
+ plugin_LTLIBRARIES = libpk_backend_alpm.la
+-libpk_backend_alpm_la_SOURCES = pk-backend-alpm.c
+-libpk_backend_alpm_la_LIBADD = $(PK_PLUGIN_LIBS) -lalpm
+-libpk_backend_alpm_la_LDFLAGS = -module -avoid-version
+-libpk_backend_alpm_la_CFLAGS = $(PK_PLUGIN_CFLAGS) $(WARNINGFLAGS_C)
+
++libpk_backend_alpm_la_SOURCES = pk-backend-alpm.c \
++ pk-backend-config.c \
++ pk-backend-databases.c \
++ pk-backend-depends.c \
++ pk-backend-error.c \
++ pk-backend-groups.c \
++ pk-backend-install.c \
++ pk-backend-packages.c \
++ pk-backend-remove.c \
++ pk-backend-search.c \
++ pk-backend-sync.c \
++ pk-backend-transaction.c \
++ pk-backend-update.c
++libpk_backend_alpm_la_LIBADD = $(PK_PLUGIN_LIBS) \
++ -lalpm
++libpk_backend_alpm_la_LDFLAGS = -module \
++ -avoid-version
++libpk_backend_alpm_la_CFLAGS = $(PK_PLUGIN_CFLAGS) \
++ $(WARNINGFLAGS_C)
++
++EXTRA_DIST = $(conf_DATA) $(libpk_backend_alpm_la_SOURCES:.c=.h)
+diff --git a/backends/alpm/TODO b/backends/alpm/TODO
+deleted file mode 100644
+index 04a827f..0000000
+--- a/backends/alpm/TODO
++++ /dev/null
+@@ -1,4 +0,0 @@
+-
+-* Fix cache refreshing. Currently throws 'unexpected error'
+-* Improve error handling by using macros. Currently 50% is very similiar error handling code.
+-* Handle transaction progress and events in the callback functions.
+diff --git a/backends/alpm/groups.list b/backends/alpm/groups.list
+new file mode 100644
+index 0000000..b2c02ae
+--- /dev/null
++++ b/backends/alpm/groups.list
+@@ -0,0 +1,65 @@
++adesklet-desklets desktop-other
++base system
++base-devel programming
++bmp-io-plugins multimedia
++bmp-plugins multimedia
++cegcc programming
++compiz desktop-other
++compiz-fusion desktop-other
++compiz-fusion-gtk desktop-gnome
++compiz-fusion-kde desktop-kde
++compiz-gnome desktop-gnome
++compiz-gtk desktop-gnome
++compiz-kde desktop-kde
++e17-extra-svn desktop-other
++e17-libs-svn desktop-other
++e17-svn desktop-other
++fprint other
++gimp-help other
++gimp-plugins other
++gnome desktop-gnome
++gnome-extra desktop-gnome
++gnustep-core desktop-other
++google-gadgets desktop-other
++gstreamer0.10-plugins multimedia
++kde desktop-kde
++kdeaccessibility desktop-kde
++kdeadmin desktop-kde
++kdeartwork desktop-kde
++kdebase desktop-kde
++kdeedu desktop-kde
++kde-extragear desktop-kde
++kdegames desktop-kde
++kdegraphics desktop-kde
++kde-l10n desktop-kde
++kde-meta desktop-kde
++kdemultimedia desktop-kde
++kdenetwork desktop-kde
++kdepim desktop-kde
++kdeplasma-addons desktop-kde
++kdesdk desktop-kde
++kdetoys desktop-kde
++kdeutils desktop-kde
++kdewebdev desktop-kde
++koffice desktop-kde
++ladspa-plugins multimedia
++lib32 other
++lxde other
++qtcurve desktop-kde
++rox-desktop desktop-other
++telepathy other
++texlive-lang other
++texlive-lang-doc other
++texlive-most other
++texlive-most-doc other
++thunderbird-i18n other
++thunderbird-spell-i18n other
++vim-plugins other
++xfce4 desktop-xfce
++xfce4-goodies desktop-xfce
++xmms-effect-plugins multimedia
++xmms-io-plugins multimedia
++xmms-plugins multimedia
++xorg desktop-other
++xorg-input-drivers desktop-other
++xorg-video-drivers desktop-other
+diff --git a/backends/alpm/pacman.conf b/backends/alpm/pacman.conf
+new file mode 100644
+index 0000000..8fdef09
+--- /dev/null
++++ b/backends/alpm/pacman.conf
+@@ -0,0 +1,12 @@
++# PackageKit configuration for the alpm backend
++# See the pacman.conf(5) manpage for option and repository directives.
++
++[options]
++
++# Use default pacman configuration initially
++#
++Include = /etc/pacman.conf
++
++# Prevent PackageKit from removing itself
++#
++HoldPkg = packagekit
+diff --git a/backends/alpm/pk-backend-alpm.c b/backends/alpm/pk-backend-alpm.c
+index 5513d8d..0077329 100644
+--- a/backends/alpm/pk-backend-alpm.c
++++ b/backends/alpm/pk-backend-alpm.c
+@@ -1,7 +1,8 @@
+ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+@@ -20,1678 +21,361 @@
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+-#define _GNU_SOURCE
++#include <config.h>
++#include <glib/gstdio.h>
++#include <sys/utsname.h>
+
+-#define ALPM_CONFIG_PATH "/etc/pacman.conf"
++#include "pk-backend-alpm.h"
++#include "pk-backend-databases.h"
++#include "pk-backend-error.h"
++#include "pk-backend-groups.h"
+
+-#define ALPM_ROOT "/"
+-#define ALPM_DBPATH "/var/lib/pacman"
+-#define ALPM_CACHEDIR "/var/cache/pacman/pkg"
+-#define ALPM_LOGFILE "/var/log/pacman.log"
++PkBackend *backend = NULL;
++GCancellable *cancellable = NULL;
++static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+-#define ALPM_PKG_EXT ".pkg.tar.gz"
+-#define ALPM_LOCAL_DB_ALIAS "installed"
++pmdb_t *localdb = NULL;
+
+-#define ALPM_PROGRESS_UPDATE_INTERVAL 400
++gchar *xfercmd = NULL;
++alpm_list_t *holdpkgs = NULL;
++alpm_list_t *syncfirsts = NULL;
+
+-#include <gmodule.h>
+-#include <glib.h>
+-#include <string.h>
+-#include <pk-backend.h>
+-
+-#include <alpm.h>
+-#include <alpm_list.h>
+-
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <string.h>
+-#include <ctype.h>
+-
+-PkBackend *backend_instance = NULL;
+-
+-GHashTable *group_map;
+-
+-alpm_list_t *syncfirst = NULL;
+-alpm_list_t *holdpkg = NULL;
+-
+-alpm_list_t *downloaded_files = NULL;
+-gchar *current_file = NULL;
+-
+-off_t trans_xfered;
+-off_t trans_total;
+-
+-int trans_subprogress;
+-
+-typedef enum {
+- PK_ALPM_SEARCH_TYPE_NULL,
+- PK_ALPM_SEARCH_TYPE_RESOLVE,
+- PK_ALPM_SEARCH_TYPE_NAME,
+- PK_ALPM_SEARCH_TYPE_DETAILS,
+- PK_ALPM_SEARCH_TYPE_GROUP,
+- PK_ALPM_SEARCH_TYPE_PROVIDES
+-} PkAlpmSearchType;
+-
+-static int
+-pkg_cmp (pmpkg_t *pkg1, pmpkg_t *pkg2) {
+- int comparison;
+- /* check for no package */
+- if (pkg1 == NULL)
+- return -1;
+- if (pkg2 == NULL)
+- return 1;
+- /* compare package names */
+- comparison = g_strcmp0 (alpm_pkg_get_name (pkg1), alpm_pkg_get_name (pkg2));
+- if (comparison != 0)
+- return comparison;
+- /* compare package versions */
+- comparison = alpm_pkg_vercmp (alpm_pkg_get_version (pkg1), alpm_pkg_get_version (pkg2));
+- if (comparison != 0)
+- return comparison;
+- /* packages are equal */
+- return 0;
+-}
+-
+-/* temporary commented to not produce compilation errors :) */
+-/*
+-static gboolean
+-pkg_equal (pmpkg_t *p1, pmpkg_t *p2)
+-{
+- if (g_strcmp0 (alpm_pkg_get_name (p1), alpm_pkg_get_name (p2)) != 0)
+- return FALSE;
+- if (g_strcmp0 (alpm_pkg_get_version (p1), alpm_pkg_get_version (p2)) != 0)
+- return FALSE;
+- return TRUE;
+-}
+-*/
+-
+-static gboolean
+-pkg_equals_to (pmpkg_t *pkg, const gchar *name, const gchar *version)
+-{
+- if (pkg == NULL)
+- return FALSE;
+- if (g_strcmp0 (alpm_pkg_get_name (pkg), name) != 0)
+- return FALSE;
+- if (version != NULL)
+- if (g_strcmp0 (alpm_pkg_get_version (pkg), version) != 0)
+- return FALSE;
+- return TRUE;
+-}
+-
+-static gchar *
+-pkg_to_package_id_str (pmpkg_t *pkg, const gchar *repo)
+-{
+- gchar *arch = (gchar *) alpm_pkg_get_arch (pkg);
+- if (arch == NULL)
+- arch = (gchar *) "unknown";
+-
+- return pk_package_id_build (alpm_pkg_get_name (pkg), alpm_pkg_get_version (pkg), arch, repo);
+-}
+-
+-static pmpkg_t *
+-pkg_from_package_id (const gchar *package_id)
+-{
+- pmdb_t *repo = NULL;
+- pmpkg_t *result;
+- gchar **package_id_data = pk_package_id_split (package_id);
+-
+- /* do all this fancy stuff */
+- if (g_strcmp0 (ALPM_LOCAL_DB_ALIAS, package_id_data[PK_PACKAGE_ID_DATA]) == 0)
+- repo = alpm_option_get_localdb ();
+- else {
+- alpm_list_t *iterator;
+- for (iterator = alpm_option_get_syncdbs (); iterator; iterator = alpm_list_next (iterator)) {
+- repo = alpm_list_getdata (iterator);
+- if (g_strcmp0 (alpm_db_get_name (repo), package_id_data[PK_PACKAGE_ID_DATA]) == 0)
+- break;
+- }
+- }
+-
+- if (repo != NULL) {
+- pmpkg_t *pkg = alpm_db_get_pkg (repo, package_id_data[PK_PACKAGE_ID_NAME]);
+- if (pkg_equals_to (pkg, package_id_data[PK_PACKAGE_ID_NAME], package_id_data[PK_PACKAGE_ID_VERSION]))
+- result = pkg;
+- else
+- result = NULL;
+- } else
+- result = NULL;
+-
+- g_strfreev (package_id_data);
+-
+- return result;
+-}
+-
+-static void
+-emit_package (PkBackend *backend, pmpkg_t *pkg, const gchar *repo, PkInfoEnum info)
+-{
+- gchar *package_id_str;
+-
+- g_debug ("alpm: emitting package with name %s", alpm_pkg_get_name (pkg));
+-
+- package_id_str = pkg_to_package_id_str (pkg, repo);
+- pk_backend_package (backend, info, package_id_str, alpm_pkg_get_desc (pkg));
+- g_free (package_id_str);
+-}
+-
+-static void
+-cb_trans_evt (pmtransevt_t event, void *data1, void *data2)
+-{
+- gchar **package_ids;
+-
+- /* TODO: add more code here */
+- switch (event) {
+- case PM_TRANS_EVT_REMOVE_START:
+- pk_backend_set_allow_cancel (backend_instance, FALSE);
+-
+- /* reset transaction subprogress */
+- trans_subprogress = -1;
+-
+- emit_package (backend_instance, data1, ALPM_LOCAL_DB_ALIAS, PK_INFO_ENUM_REMOVING);
+- break;
+- case PM_TRANS_EVT_ADD_START:
+- pk_backend_set_allow_cancel (backend_instance, FALSE);
+-
+- /* reset transaction subprogress */
+- trans_subprogress = -1;
+-
+- pk_backend_set_status (backend_instance, PK_STATUS_ENUM_INSTALL);
+-
+- package_ids = pk_backend_get_strv (backend_instance, "package_ids");
+- if (package_ids != NULL) {
+- unsigned int iterator;
+-
+- /* search for package in package_ids */
+- gchar *package_id_needle = pkg_to_package_id_str (data1, "");
+-
+- g_debug ("needle is %s", package_id_needle);
+- for (iterator = 0; iterator < g_strv_length (package_ids); ++iterator)
+- if (strstr (package_ids[iterator], package_id_needle) != NULL) {
+- pk_backend_package (backend_instance, PK_INFO_ENUM_INSTALLING, package_ids[iterator], alpm_pkg_get_desc (data1));
+- break;
+- }
+-
+- g_free (package_id_needle);
+- } else
+- /* we are installing a local file */
+- emit_package (backend_instance, data1, "local", PK_INFO_ENUM_INSTALLING);
+-
+- break;
+- case PM_TRANS_EVT_UPGRADE_START:
+- pk_backend_set_allow_cancel (backend_instance, FALSE);
+-
+- /* reset transaction subprogress */
+- trans_subprogress = -1;
+-
+- emit_package (backend_instance, data1, ALPM_LOCAL_DB_ALIAS, PK_INFO_ENUM_UPDATING);
+- break;
+- default: g_debug ("alpm: event %i happened", event);
+- }
+-}
+-
+-static void
+-cb_trans_conv (pmtransconv_t conv, void *data1, void *data2, void *data3, int *response)
+-{
+- /* TODO: check if some code needs to be placed there */
+-}
+-
+-static void
+-cb_trans_progress (pmtransprog_t event, const char *pkgname, int percent, int howmany, int current)
++gchar *
++pk_backend_get_description (PkBackend *self)
+ {
+- if (trans_subprogress != percent) {
+- /* avoid duplicates */
+- trans_subprogress = percent;
++ g_return_val_if_fail (self != NULL, NULL);
+
+- if (event == PM_TRANS_PROGRESS_ADD_START || event == PM_TRANS_PROGRESS_UPGRADE_START || event == PM_TRANS_PROGRESS_REMOVE_START) {
+- int trans_percent;
+-
+- g_debug ("alpm: transaction percentage for %s is %i", pkgname, percent);
+- trans_percent = (int) ((float) ((current - 1) * 100 + percent)) / ((float) (howmany * 100)) * 100;
+- pk_backend_set_sub_percentage ((PkBackend *) backend_instance, percent);
+- pk_backend_set_percentage ((PkBackend *) backend_instance, trans_percent);
+- }
+- }
++ return g_strdup ("alpm");
+ }
+
+-static void
+-cb_dl_progress (const char *filename, off_t file_xfered, off_t file_total)
++gchar *
++pk_backend_get_author (PkBackend *self)
+ {
+- int file_percent;
+- int trans_percent;
+-
+- if (g_str_has_suffix (filename, ALPM_PKG_EXT)) {
+- if (g_strcmp0 (filename, current_file) != 0) {
+- alpm_list_t *repos;
+- alpm_list_t *packages;
+- pmpkg_t *current_pkg = NULL;
+- const gchar *repo_name = NULL;
+-
+- g_free (current_file);
+- current_file = g_strdup (filename);
+-
+- /* iterate repos */
+- for (repos = alpm_option_get_syncdbs (); current_pkg == NULL && repos; repos = alpm_list_next (repos)) {
+- pmdb_t *db = alpm_list_getdata (repos);
+-
+- /* iterate pkgs */
+- for (packages = alpm_db_get_pkgcache (db); current_pkg == NULL && packages; packages = alpm_list_next (packages)) {
+- pmpkg_t *pkg = alpm_list_getdata (packages);
+-
+- /* compare package information with file name */
+- gchar *needle = g_strjoin ("-", alpm_pkg_get_name (pkg), alpm_pkg_get_version (pkg), NULL);
+- if (needle != NULL && strcmp (needle, "") != 0)
+- g_debug ("matching %s with %s", filename, needle);
+- if (g_str_has_prefix (filename, needle)) {
+- current_pkg = pkg;
+- repo_name = alpm_db_get_name (db);
+- }
+- g_free (needle);
+- }
+- }
+-
+- if (current_pkg != NULL)
+- emit_package (backend_instance, current_pkg, repo_name, PK_INFO_ENUM_DOWNLOADING);
+- }
+- }
++ g_return_val_if_fail (self != NULL, NULL);
+
+- file_percent = (int) ((float) file_xfered) / ((float) file_total) * 100;
+- trans_percent = (int) ((float) (trans_xfered + file_xfered)) / ((float) trans_total) * 100;
+- pk_backend_set_sub_percentage ((PkBackend *) backend_instance, file_percent);
+- pk_backend_set_percentage ((PkBackend *) backend_instance, trans_percent);
+-
+- if (file_xfered == file_total) {
+- downloaded_files = alpm_list_add (downloaded_files, g_strdup (filename));
+- trans_xfered = trans_xfered + file_total;
+- }
++ return g_strdup ("Jonathan Conder <jonno.conder@gmail.com>");
+ }
+
+-static void
+-cb_dl_total (off_t total)
+-{
+- trans_total = total;
+- /* zero total size means that download is finished, so clear trans_xfered */
+- if (total == 0)
+- trans_xfered = 0;
+-}
+-
+-/**
+- * strtrim:
+- * Trim whitespaces and newlines from a string
+- */
+-static char *
+-strtrim (char *str)
+-{
+- char *pch = str;
+-
+- if (str == NULL || *str == '\0')
+- /* string is empty, so we're done. */
+- return (str);
+-
+- while (isspace (*pch))
+- pch++;
+-
+- if (pch != str)
+- memmove (str, pch, (strlen (pch) + 1));
+-
+- /* check if there wasn't anything but whitespace in the string. */
+- if (*str == '\0')
+- return (str);
+-
+- pch = (str + (strlen (str) - 1));
+-
+- while (isspace (*pch))
+- pch--;
+-
+- *++pch = '\0';
+-
+- return (str);
+-}
+-
+-/**
+- * _strnadd:
+- * Helper function for strreplace
+- */
+-static void
+-_strnadd (char **str, const char *append, unsigned int count)
+-{
+- if (*str)
+- *str = realloc (*str, strlen (*str) + count + 1);
+- else
+- *str = calloc (sizeof (char), count + 1);
+-
+- strncat (*str, append, count);
+-}
+-
+-/**
+- * strreplace:
+- * Replace all occurences of 'needle' with 'replace' in 'str', returning
+- * a new string (must be free'd)
+- */
+-static char *
+-strreplace (const char *str, const char *needle, const char *replace)
+-{
+- const char *p, *q;
+- char *newstr = NULL;
+- unsigned int needlesz = strlen (needle), replacesz = strlen (replace);
+-
+- p = q = str;
+-
+- while (1) {
+- q = strstr (p, needle);
+- if (!q) {
+- /* not found */
+- if (*p) /* add the rest of 'p' */
+- _strnadd (&newstr, p, strlen (p));
+-
+- break;
+- } else { /* found match */
+- if (q > p) /* add chars between this occurance and last occurance, if any */
+- _strnadd (&newstr, p, q - p);
+-
+- _strnadd (&newstr, replace, replacesz);
+- p = q + needlesz;
+- }
+- }
+-
+- return newstr;
+-}
+-
+-/**
+- * set_repeating_option:
+- * Add repeating options such as NoExtract, NoUpgrade, etc to alpm settings.
+- * @param ptr a pointer to the start of the multiple options
+- * @param option the string (friendly) name of the option, used for messages
+- * @param optionfunc a function pointer to an alpm_option_add_* function
+- */
+-static void
+-set_repeating_option (const char *ptr, const char *option, void (*optionfunc) (const char*))
+-{
+- char *p = (char*) ptr;
+- char *q;
+-
+- while ((q = strchr (p, ' '))) {
+- *q = '\0';
+- (*optionfunc) (p);
+- g_debug ("config: %s: %s", option, p);
+- p = q;
+- p++;
+- }
+- (*optionfunc) (p);
+- g_debug ("config: %s: %s", option, p);
+-}
+-
+-/**
+- * option_add_syncfirst:
+- * Add package name to SyncFirst list
+- * @param name name of the package to be added
+- */
+-static void
+-option_add_syncfirst (const char *name) {
+- syncfirst = alpm_list_add (syncfirst, strdup (name));
+-}
+-
+-/**
+- * option_add_holdpkg:
+- * Add package name to HoldPkg list
+- * @param name name of the package to be added
+- */
+-static void
+-option_add_holdpkg (const char *name) {
+- holdpkg = alpm_list_add (holdpkg, strdup (name));
+-}
+-
+-/**
+- * parse_config:
+- * Parse config file and set all the needed options
+- * Based heavily on the pacman source code
+- * @param file full name of config file
+- * @param givensection section to start from
+- * @param givendb db to start from
+- */
+-static int
+-parse_config (const char *file, const char *givensection, pmdb_t * const givendb)
+-{
+- FILE *fp = NULL;
+- char line[PATH_MAX + 1];
+- int linenum = 0;
+- char *ptr, *section = NULL;
+- pmdb_t *db = NULL;
+-
+- /* set default options */
+- alpm_option_set_root (ALPM_ROOT);
+- alpm_option_set_dbpath (ALPM_DBPATH);
+- alpm_option_add_cachedir (ALPM_CACHEDIR);
+- alpm_option_set_logfile (ALPM_LOGFILE);
+-
+- fp = fopen (file, "r");
+- if (fp == NULL) {
+- g_error ("config file %s could not be read", file);
+- return 1;
+- }
+-
+- /* if we are passed a section, use it as our starting point */
+- if (givensection != NULL)
+- section = strdup (givensection);
+-
+- /* if we are passed a db, use it as our starting point */
+- if (givendb != NULL)
+- db = givendb;
+-
+- while (fgets (line, PATH_MAX, fp)) {
+- linenum++;
+- strtrim (line);
+-
+- if (strlen (line) == 0 || line[0] == '#')
+- continue;
+-
+- if ((ptr = strchr (line, '#')))
+- *ptr = '\0';
+-
+- if (line[0] == '[' && line[strlen (line) - 1] == ']') {
+- /* new config section, skip the '[' */
+- ptr = line;
+- ptr++;
+- if (section)
+- free (section);
+-
+- section = strdup (ptr);
+- section[strlen (section) - 1] = '\0';
+- g_debug ("config: new section '%s'", section);
+- if (!strlen (section)) {
+- g_debug ("config file %s, line %d: bad section name", file, linenum);
+- return 1;
+- }
+-
+- /* if we are not looking at the options section, register a db */
+- if (g_strcmp0 (section, "options") != 0)
+- db = alpm_db_register_sync (section);
+- } else {
+- /* directive */
+- char *key;
+- key = line;
+- ptr = line;
+- /* strsep modifies the 'line' string: 'key \0 ptr' */
+- strsep (&ptr, "=");
+- strtrim (key);
+- strtrim (ptr);
+-
+- if (key == NULL) {
+- g_error ("config file %s, line %d: syntax error in config file - missing key.", file, linenum);
+- return 1;
+- }
+- if (section == NULL) {
+- g_error ("config file %s, line %d: all directives must belong to a section.", file, linenum);
+- return 1;
+- }
+-
+- if (ptr == NULL && g_strcmp0 (section, "options") == 0) {
+- /* directives without settings, all in [options] */
+- if (g_strcmp0 (key, "UseSyslog") == 0) {
+- alpm_option_set_usesyslog (1);
+- g_debug ("config: usesyslog");
+- } else if (g_strcmp0 (key, "UseDelta") == 0) {
+- alpm_option_set_usedelta (1);
+- g_debug ("config: usedelta");
+- } else if (g_strcmp0 (key, "ILoveCandy") != 0 && g_strcmp0 (key, "ShowSize") != 0 && g_strcmp0 (key, "TotalDownload") != 0 && g_strcmp0 (key, "NoPassiveFTP") != 0) {
+- g_warning ("config file %s, line %d: directive '%s' not recognized.", file, linenum, key);
+- }
+- } else {
+- /* directives with settings */
+- if (g_strcmp0 (key, "Include") == 0) {
+- g_debug ("config: including %s", ptr);
+- parse_config (ptr, section, db);
+- /* Ignore include failures... assume non-critical */
+- } else if (g_strcmp0 (section, "options") == 0) {
+- if (g_strcmp0 (key, "NoUpgrade") == 0) {
+- set_repeating_option (ptr, "NoUpgrade", alpm_option_add_noupgrade);
+- } else if (g_strcmp0 (key, "NoExtract") == 0) {
+- set_repeating_option (ptr, "NoExtract", alpm_option_add_noextract);
+- } else if (g_strcmp0 (key, "IgnorePkg") == 0) {
+- set_repeating_option (ptr, "IgnorePkg", alpm_option_add_ignorepkg);
+- } else if (g_strcmp0 (key, "IgnoreGroup") == 0) {
+- set_repeating_option (ptr, "IgnoreGroup", alpm_option_add_ignoregrp);
+- } else if (g_strcmp0 (key, "HoldPkg") == 0) {
+- set_repeating_option (ptr, "HoldPkg", option_add_holdpkg);
+- } else if (g_strcmp0 (key, "SyncFirst") == 0) {
+- set_repeating_option (ptr, "SyncFirst", option_add_syncfirst);
+- } else if (g_strcmp0 (key, "DBPath") == 0) {
+- alpm_option_set_dbpath (ptr);
+- } else if (g_strcmp0 (key, "CacheDir") == 0) {
+- if (alpm_option_add_cachedir (ptr) != 0) {
+- g_error ("problem adding cachedir '%s' (%s)", ptr, alpm_strerrorlast ());
+- return 1;
+- }
+- g_debug ("config: cachedir: %s", ptr);
+- } else if (g_strcmp0 (key, "RootDir") == 0) {
+- alpm_option_set_root (ptr);
+- g_debug ("config: rootdir: %s", ptr);
+- } else if (g_strcmp0 (key, "LogFile") == 0) {
+- alpm_option_set_logfile (ptr);
+- g_debug ("config: logfile: %s", ptr);
+- } else if (g_strcmp0 (key, "XferCommand") != 0 && g_strcmp0 (key, "CleanMethod") != 0) {
+- g_warning ("config file %s, line %d: directive '%s' not recognized.", file, linenum, key);
+- }
+- } else if (g_strcmp0 (key, "Server") == 0) {
+- /* let's attempt a replacement for the current repo */
+- char *server = strreplace (ptr, "$repo", section);
+-
+- if (alpm_db_setserver (db, server) != 0) {
+- /* pm_errno is set by alpm_db_setserver */
+- g_error ("config file %s, line %d: could not add server URL to database (%s).", file, linenum, alpm_strerrorlast ());
+- free (server);
+- return 1;
+- }
+- free (server);
+- } else {
+- g_warning ("config file %s, line %d: directive '%s' not recognized.", file, linenum, key);
+- }
+- }
+- }
+- }
+-
+- fclose (fp);
+- if (section)
+- free (section);
+-
+- g_debug ("config: finished parsing %s", file);
+- return 0;
+-}
+-
+-/**
+- * backend_initialize:
+- */
+-static void
+-backend_initialize (PkBackend *backend)
+-{
+- /* initialize backend_instance for use in callback functions */
+- backend_instance = backend;
+-
+- g_debug ("alpm: initializing backend");
+-
+- if (alpm_initialize () == -1) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_FAILED_INITIALIZATION, "Failed to initialize package manager");
+- g_debug ("alpm: %s", alpm_strerror (pm_errno));
+- return;
+- }
+-
+- /* read options from config file */
+- if (parse_config (ALPM_CONFIG_PATH, NULL, NULL) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_FAILED_CONFIG_PARSING, "Failed to parse config file");
+- alpm_release ();
+- return;
+- }
+-
+- if (alpm_db_register_local () == NULL) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_REPO_NOT_AVAILABLE, "Failed to load local database");
+- g_debug ("alpm: %s", alpm_strerror (pm_errno));
+- alpm_release ();
+- return;
+- }
+-
+- alpm_option_set_dlcb (cb_dl_progress);
+- alpm_option_set_totaldlcb (cb_dl_total);
+-
+- /* fill in group mapping */
+- group_map = g_hash_table_new (g_str_hash, g_str_equal);
+- g_hash_table_insert (group_map, (gchar *) "gnome", (gchar *) "desktop-gnome");
+- g_hash_table_insert (group_map, (gchar *) "gnome-extra", (gchar *) "desktop-gnome");
+- g_hash_table_insert (group_map, (gchar *) "compiz-gnome", (gchar *) "desktop-gnome");
+- g_hash_table_insert (group_map, (gchar *) "kde", (gchar *) "desktop-kde");
+- g_hash_table_insert (group_map, (gchar *) "compiz-kde", (gchar *) "desktop-kde");
+- g_hash_table_insert (group_map, (gchar *) "compiz-fusion-kde", (gchar *) "desktop-kde");
+- g_hash_table_insert (group_map, (gchar *) "lxde", (gchar *) "desktop-other");
+- g_hash_table_insert (group_map, (gchar *) "rox-desktop", (gchar *) "desktop-other");
+- g_hash_table_insert (group_map, (gchar *) "e17-cvs", (gchar *) "desktop-other");
+- g_hash_table_insert (group_map, (gchar *) "e17-extra-cvs", (gchar *) "desktop-other");
+- g_hash_table_insert (group_map, (gchar *) "e17-libs-cvs", (gchar *) "desktop-other");
+- g_hash_table_insert (group_map, (gchar *) "xfce4", (gchar *) "desktop-xfce");
+- g_hash_table_insert (group_map, (gchar *) "xfce4-goodies", (gchar *) "desktop-xfce");
+- g_hash_table_insert (group_map, (gchar *) "bmp-io-plugins", (gchar *) "multimedia");
+- g_hash_table_insert (group_map, (gchar *) "bmp-plugins", (gchar *) "multimedia");
+- g_hash_table_insert (group_map, (gchar *) "bmp-visualization-plugins", (gchar *) "multimedia");
+- g_hash_table_insert (group_map, (gchar *) "gstreamer0.10-plugins", (gchar *) "multimedia");
+- g_hash_table_insert (group_map, (gchar *) "ladspa-plugins", (gchar *) "multimedia");
+- g_hash_table_insert (group_map, (gchar *) "pvr", (gchar *) "multimedia");
+- g_hash_table_insert (group_map, (gchar *) "mythtv-extras", (gchar *) "multimedia");
+- g_hash_table_insert (group_map, (gchar *) "xmms-effect-plugins", (gchar *) "multimedia");
+- g_hash_table_insert (group_map, (gchar *) "xmms-io-plugins", (gchar *) "multimedia");
+- g_hash_table_insert (group_map, (gchar *) "xmms-plugins", (gchar *) "multimedia");
+- g_hash_table_insert (group_map, (gchar *) "base-devel", (gchar *) "programming");
+- g_hash_table_insert (group_map, (gchar *) "texlive-lang", (gchar *) "publishing");
+- g_hash_table_insert (group_map, (gchar *) "texlive-lang-doc", (gchar *) "publishing");
+- g_hash_table_insert (group_map, (gchar *) "texlive-most", (gchar *) "publishing");
+- g_hash_table_insert (group_map, (gchar *) "texlive-most-doc", (gchar *) "publishing");
+- g_hash_table_insert (group_map, (gchar *) "texlive-most-svn", (gchar *) "publishing");
+- g_hash_table_insert (group_map, (gchar *) "base", (gchar *) "system");
+-
+- g_debug ("alpm: ready to go");
+-}
+-
+-/**
+- * backend_destroy:
+- */
+-static void
+-backend_destroy (PkBackend *backend)
+-{
+- g_hash_table_destroy (group_map);
+-
+- if (alpm_release () == -1) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_FAILED_FINALISE, "Failed to release package manager");
+- g_debug ("alpm: %s", alpm_strerror (pm_errno));
+- }
+-}
+-
+-/**
+- * backend_get_groups:
+- */
+-static PkBitfield
+-backend_get_groups (PkBackend *backend)
+-{
+- return pk_bitfield_from_enums (
+- PK_GROUP_ENUM_DESKTOP_GNOME,
+- PK_GROUP_ENUM_DESKTOP_KDE,
+- PK_GROUP_ENUM_DESKTOP_OTHER,
+- PK_GROUP_ENUM_DESKTOP_XFCE,
+- PK_GROUP_ENUM_MULTIMEDIA,
+- PK_GROUP_ENUM_OTHER,
+- PK_GROUP_ENUM_PROGRAMMING,
+- PK_GROUP_ENUM_PUBLISHING,
+- PK_GROUP_ENUM_SYSTEM,
+- -1);
+-}
+-
+-/**
+- * backend_get_filters:
+- */
+-static PkBitfield
+-backend_get_filters (PkBackend *backend)
+-{
+- return pk_bitfield_from_enums (PK_FILTER_ENUM_INSTALLED, -1);
+-}
+-
+-/**
+- * backend_get_mime_types:
+- */
+-static gchar *
+-backend_get_mime_types (PkBackend *backend)
+-{
+- return g_strdup ("application/x-compressed-tar");
+-}
+-
+-/**
+- * backend_cancel:
+- **/
+-static void
+-backend_cancel (PkBackend *backend)
+-{
+- pk_backend_set_status (backend, PK_STATUS_ENUM_CANCEL);
+-}
+-
+-/**
+- * backend_download_packages_thread:
+- */
+ static gboolean
+-backend_download_packages_thread (PkBackend *backend)
++pk_backend_spawn (PkBackend *self, const gchar *command)
+ {
+- gchar **package_ids = pk_backend_get_strv (backend, "package_ids");
+- const gchar *directory = pk_backend_get_string (backend, "directory");
+- unsigned int iterator;
+- alpm_list_t *list_iterator;
+- alpm_list_t *cachedirs = NULL;
+- alpm_list_t *data = NULL;
+-
+- g_debug ("alpm: downloading packages to %s", directory);
+-
+- /* old cachedirs list automatically gets freed in alpm, so make a copy */
+- for (list_iterator = alpm_option_get_cachedirs (); list_iterator; list_iterator = alpm_list_next (list_iterator))
+- cachedirs = alpm_list_add (cachedirs, g_strdup (alpm_list_getdata (list_iterator)));
+- /* set new download destination */
+- alpm_option_set_cachedirs (NULL);
+- alpm_option_add_cachedir (directory);
+-
+- /* create a new transaction */
+- if (alpm_trans_init (PM_TRANS_FLAG_NODEPS | PM_TRANS_FLAG_DOWNLOADONLY, cb_trans_evt, cb_trans_conv, cb_trans_progress) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- pk_backend_finished (backend);
+- return FALSE;
+- }
++ int status;
++ GError *error = NULL;
+
+- /* add targets to the transaction */
+- for (iterator = 0; iterator < g_strv_length (package_ids); ++iterator) {
+- gchar **package_id_data = pk_package_id_split (package_ids[iterator]);
+-
+- if (alpm_sync_target (package_id_data[PK_PACKAGE_ID_NAME]) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- alpm_trans_release ();
+- pk_backend_finished (backend);
+- return FALSE;
+- }
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (command != NULL, FALSE);
+
+- g_strfreev (package_id_data);
++ if (!g_spawn_command_line_sync (command, NULL, NULL, &status, &error)) {
++ g_warning ("could not spawn command: %s", error->message);
++ g_error_free (error);
++ return FALSE;
+ }
+
+- /* prepare and commit transaction */
+- if (alpm_trans_prepare (&data) != 0 || alpm_trans_commit (&data) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- alpm_trans_release ();
+- pk_backend_finished (backend);
++ if (WIFEXITED (status) == 0) {
++ g_warning ("command did not execute correctly");
+ return FALSE;
+ }
+
+- alpm_trans_release ();
+-
+- /* emit downloaded packages */
+- for (list_iterator = downloaded_files; list_iterator; list_iterator = alpm_list_next (list_iterator)) {
+- gchar *package_id = NULL;
+- gchar *filename;
+-
+- /* TODO: optimize this? split-then-join isn't good */
+- for (iterator = 0; package_id == NULL && iterator < g_strv_length (package_ids); ++iterator) {
+- gchar **package_id_data = pk_package_id_split (package_ids[iterator]);
+- gchar *needle = g_strjoin ("-", package_id_data[PK_PACKAGE_ID_NAME], package_id_data[PK_PACKAGE_ID_VERSION], NULL);
+-
+- if (needle != NULL && strcmp (needle, "") != 0)
+- g_debug ("matching %s with %s", (char *) alpm_list_getdata (list_iterator), needle);
+- if (g_str_has_prefix ((char *) alpm_list_getdata (list_iterator), needle))
+- package_id = package_ids[iterator];
+-
+- g_free (needle);
+- g_strfreev (package_id_data);
+- }
+-
+- filename = g_build_filename (directory, alpm_list_getdata (list_iterator), NULL);
+- pk_backend_files (backend, package_id, filename);
+- g_free (filename);
+-
+- /* clean up list data */
+- g_free (alpm_list_getdata (list_iterator));
++ if (WEXITSTATUS (status) != EXIT_SUCCESS) {
++ gint code = WEXITSTATUS (status);
++ g_warning ("command returned error code %d", code);
++ return FALSE;
+ }
+- alpm_list_free (downloaded_files);
+
+- /* return cachedirs back */
+- alpm_option_set_cachedirs (cachedirs);
+-
+- pk_backend_finished (backend);
+ return TRUE;
+ }
+
+-/**
+- * backend_download_packages:
+- */
+-static void
+-backend_download_packages (PkBackend *backend, gchar **package_ids, const gchar *directory)
+-{
+- pk_backend_set_status (backend, PK_STATUS_ENUM_DOWNLOAD);
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
+-
+- pk_backend_thread_create (backend, backend_download_packages_thread);
+-}
+-
+-/**
+- * backend_get_depends:
+- */
+-static void
+-backend_get_depends (PkBackend *backend, PkBitfield filters, gchar **package_ids, gboolean recursive)
++gint
++pk_backend_fetchcb (const gchar *url, const gchar *path, gint force)
+ {
+- unsigned int iterator;
++ GRegex *xo, *xi;
++ gchar *oldpwd, *basename, *file, *part;
++ gchar *tempcmd = NULL, *finalcmd = NULL;
++ gint result = 0;
+
+- pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_allow_cancel (backend, FALSE);
++ g_return_val_if_fail (url != NULL, -1);
++ g_return_val_if_fail (path != NULL, -1);
++ g_return_val_if_fail (xfercmd != NULL, -1);
++ g_return_val_if_fail (backend != NULL, -1);
+
+- for (iterator = 0; iterator < g_strv_length (package_ids); ++iterator) {
+- alpm_list_t *list_iterator;
+-
+- pmpkg_t *pkg = pkg_from_package_id (package_ids[iterator]);
+- if (pkg == NULL) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, alpm_strerrorlast ());
+- pk_backend_finished (backend);
+- return;
+- }
+-
+- for (list_iterator = alpm_pkg_get_depends (pkg); list_iterator; list_iterator = alpm_list_next (list_iterator)) {
+- pmdepend_t *dep = alpm_list_getdata (list_iterator);
+- pmpkg_t *dep_pkg;
+- gboolean found = FALSE;
+-
+- if (!pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED)) {
+- /* search in sync dbs */
+- alpm_list_t *db_iterator;
+- for (db_iterator = alpm_option_get_syncdbs (); found == FALSE && db_iterator; db_iterator = alpm_list_next (db_iterator)) {
+- pmdb_t *syncdb = alpm_list_getdata (db_iterator);
+-
+- g_debug ("alpm: searching for %s in %s", alpm_dep_get_name (dep), alpm_db_get_name (syncdb));
+-
+- dep_pkg = alpm_db_get_pkg (syncdb, alpm_dep_get_name (dep));
+- if (dep_pkg && alpm_depcmp (dep_pkg, dep) && pkg_cmp (dep_pkg, alpm_db_get_pkg (alpm_option_get_localdb (), alpm_dep_get_name (dep))) != 0) {
+- found = TRUE;
+- emit_package (backend, dep_pkg, alpm_db_get_name (syncdb), PK_INFO_ENUM_AVAILABLE);
+- }
+- }
+- }
+-
+- if (!pk_bitfield_contain (filters, PK_FILTER_ENUM_NOT_INSTALLED)) {
+- g_debug ("alpm: searching for %s in local db", alpm_dep_get_name (dep));
+-
+- /* search in local db */
+- dep_pkg = alpm_db_get_pkg (alpm_option_get_localdb (), alpm_dep_get_name (dep));
+- if (dep_pkg && alpm_depcmp (dep_pkg, dep)) {
+- found = TRUE;
+- emit_package (backend, dep_pkg, ALPM_LOCAL_DB_ALIAS, PK_INFO_ENUM_INSTALLED);
+- }
+- }
+- }
++ oldpwd = g_get_current_dir ();
++ if (g_chdir (path) < 0) {
++ g_warning ("could not find or read directory %s", path);
++ g_free (oldpwd);
++ return -1;
+ }
+
+- pk_backend_finished (backend);
+-}
+-
+-/**
+- * backend_get_details:
+- */
+-static void
+-backend_get_details (PkBackend *backend, gchar **package_ids)
+-{
+- unsigned int iterator;
+-
+- pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_allow_cancel (backend, FALSE);
+-
+- for (iterator = 0; iterator < g_strv_length (package_ids); ++iterator) {
+- alpm_list_t *licenses_list;
+- GString *licenses_str;
+- gchar *licenses;
+-
+- pmpkg_t *pkg = pkg_from_package_id (package_ids[iterator]);
+- if (pkg == NULL) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_REPO_NOT_FOUND, alpm_strerrorlast ());
+- pk_backend_finished (backend);
+- return;
+- }
+-
+- licenses_list = alpm_pkg_get_licenses (pkg);
+- if (licenses_list == NULL)
+- licenses_str = g_string_new ("unknown");
+- else {
+- alpm_list_t *list_iterator;
+-
+- licenses_str = g_string_new ("");
+- for (list_iterator = licenses_list; list_iterator; list_iterator = alpm_list_next (list_iterator)) {
+- if (list_iterator != licenses_list)
+- g_string_append (licenses_str, ", ");
+- g_string_append (licenses_str, (char *) alpm_list_getdata (list_iterator));
+- }
+- }
+-
+- /* get licenses_str content to licenses array */
+- licenses = g_string_free (licenses_str, FALSE);
++ xo = g_regex_new ("%o", 0, 0, NULL);
++ xi = g_regex_new ("%u", 0, 0, NULL);
+
+- /* return details */
+- pk_backend_details (backend, package_ids[iterator], licenses, PK_GROUP_ENUM_OTHER, alpm_pkg_get_desc (pkg), alpm_pkg_get_url (pkg), alpm_pkg_get_size (pkg));
++ basename = g_path_get_basename (url);
++ file = g_strconcat (path, basename, NULL);
++ part = g_strconcat (file, ".part", NULL);
+
+- /* free licenses array as we no longer need it */
+- g_free (licenses);
++ if (force != 0 && g_file_test (part, G_FILE_TEST_EXISTS)) {
++ g_unlink (part);
+ }
+-
+- pk_backend_finished (backend);
+-}
+-
+-/**
+- * backend_get_files:
+- */
+-static void
+-backend_get_files (PkBackend *backend, gchar **package_ids)
+-{
+- unsigned int iterator;
+-
+- pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_allow_cancel (backend, FALSE);
+-
+- for (iterator = 0; iterator < g_strv_length (package_ids); ++iterator) {
+- alpm_list_t *files_list;
+- GString *files_str;
+- gchar *files;
+-
+- pmpkg_t *pkg = pkg_from_package_id (package_ids[iterator]);
+- if (pkg == NULL) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_REPO_NOT_FOUND, alpm_strerrorlast ());
+- pk_backend_finished (backend);
+- return;
+- }
+-
+- files_list = alpm_pkg_get_files (pkg);
+- files_str = g_string_new ("");
+- if (files_list != NULL) {
+- alpm_list_t *list_iterator;
+-
+- for (list_iterator = files_list; list_iterator; list_iterator = alpm_list_next (list_iterator)) {
+- if (list_iterator != files_list)
+- g_string_append (files_str, ";");
+- g_string_append (files_str, alpm_option_get_root ());
+- g_string_append (files_str, (char *) alpm_list_getdata (list_iterator));
+- }
+- }
+- files = g_string_free (files_str, FALSE);
+-
+- pk_backend_files (backend, package_ids[iterator], files);
++ if (force != 0 && g_file_test (file, G_FILE_TEST_EXISTS)) {
++ g_unlink (file);
+ }
+
+- pk_backend_finished (backend);
+-}
+-
+-static void
+-backend_search (PkBackend *backend, pmdb_t *repo, const gchar *needle, PkAlpmSearchType search_type) {
+- /* package cache */
+- alpm_list_t *pkg_cache;
+-
+- /* utility variables */
+- alpm_list_t *iterator;
+- const gchar *repo_name;
+- PkInfoEnum info;
+- gboolean match;
+- gboolean repo_is_local;
+-
+- if (repo == alpm_option_get_localdb ()) {
+- repo_name = ALPM_LOCAL_DB_ALIAS;
+- info = PK_INFO_ENUM_INSTALLED;
+- repo_is_local = TRUE;
+- } else {
+- repo_name = alpm_db_get_name (repo);
+- info = PK_INFO_ENUM_AVAILABLE;
+- repo_is_local = FALSE;
++ tempcmd = g_regex_replace_literal (xo, xfercmd, -1, 0, part, 0, NULL);
++ if (tempcmd == NULL) {
++ result = -1;
++ goto out;
+ }
+
+- /* get package cache for specified repo */
+- pkg_cache = alpm_db_get_pkgcache (repo);
+-
+- /* iterate package cache */
+- for (iterator = pkg_cache; iterator; iterator = alpm_list_next (iterator)) {
+- pmpkg_t *pkg = alpm_list_getdata (iterator);
+-
+- switch (search_type) {
+- alpm_list_t *provides;
+- alpm_list_t *groups;
+-
+- case PK_ALPM_SEARCH_TYPE_NULL:
+- match = TRUE;
+- break;
+- case PK_ALPM_SEARCH_TYPE_RESOLVE:
+- match = g_strcmp0 (alpm_pkg_get_name (pkg), needle) == 0;
+- break;
+- case PK_ALPM_SEARCH_TYPE_NAME:
+- match = strstr (alpm_pkg_get_name (pkg), needle) != NULL;
+- break;
+- case PK_ALPM_SEARCH_TYPE_DETAILS:
+- /* workaround for buggy packages with no description */
+- if (alpm_pkg_get_desc (pkg) == NULL)
+- match = FALSE;
+- else
+- /* TODO: strcasestr is a non-standard extension, replace it? */
+- match = strcasestr (alpm_pkg_get_desc (pkg), needle) != NULL;
+- break;
+- case PK_ALPM_SEARCH_TYPE_GROUP:
+- match = FALSE;
+- /* iterate groups */
+- for (groups = alpm_pkg_get_groups (pkg); groups && !match; groups = alpm_list_next (groups)) {
+- gchar *group = (gchar *) g_hash_table_lookup (group_map, (char *) alpm_list_getdata (groups));
+- if (group == NULL)
+- group = (gchar *) "other";
+- match = (g_strcmp0 (group, needle) == 0);
+- }
+- break;
+- case PK_ALPM_SEARCH_TYPE_PROVIDES:
+- match = FALSE;
+- /* iterate provides */
+- for (provides = alpm_pkg_get_provides (pkg); provides && !match; provides = alpm_list_next (provides))
+- match = (g_strcmp0 (needle, alpm_list_getdata (provides)) == 0);
+- break;
+- default:
+- match = FALSE;
+- }
++ finalcmd = g_regex_replace_literal (xi, tempcmd, -1, 0, url, 0, NULL);
++ if (finalcmd == NULL) {
++ result = -1;
++ goto out;
++ }
+
+- if (match && (repo_is_local || pkg_cmp (pkg, alpm_db_get_pkg (alpm_option_get_localdb (), alpm_pkg_get_name (pkg))) != 0)) {
+- /* we found what we wanted */
+- emit_package (backend, pkg, repo_name, info);
++ if (!pk_backend_spawn (backend, finalcmd)) {
++ result = -1;
++ goto out;
++ } else if (g_strrstr (xfercmd, "%o") != NULL) {
++ /* using .part filename */
++ if (g_rename (part, file) < 0) {
++ g_warning ("could not rename %s", part);
++ result = -1;
++ goto out;
+ }
+ }
+-}
+
+-/**
+- * backend_search_values:
+- */
+-static void
+-backend_search_values (PkBackend *backend, pmdb_t *repo, gchar **values, PkAlpmSearchType search_type) {
+- unsigned int iterator;
++out:
++ g_free (finalcmd);
++ g_free (tempcmd);
+
+- for (iterator = 0; iterator < g_strv_length (values); ++iterator)
+- backend_search (backend, repo, values[iterator], search_type);
+-}
+-
+-/**
+- * backend_get_packages_thread:
+- */
+-static gboolean
+-backend_get_packages_thread (PkBackend *backend)
+-{
+- PkBitfield filters = pk_backend_get_uint (backend, "filters");
+-
+- gboolean search_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED);
+- gboolean search_not_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_NOT_INSTALLED);
++ g_free (part);
++ g_free (file);
++ g_free (basename);
+
+- if (!search_not_installed) {
+- /* search in local db */
+- backend_search (backend, alpm_option_get_localdb (), NULL, PK_ALPM_SEARCH_TYPE_NULL);
+- }
+-
+- if (!search_installed) {
+- /* search in sync repos */
+- alpm_list_t *repos;
+- /* iterate repos */
+- for (repos = alpm_option_get_syncdbs (); repos; repos = alpm_list_next (repos))
+- backend_search (backend, alpm_list_getdata (repos), NULL, PK_ALPM_SEARCH_TYPE_NULL);
+- }
++ g_regex_unref (xi);
++ g_regex_unref (xo);
+
+- pk_backend_finished (backend);
+- return TRUE;
+-}
++ g_chdir (oldpwd);
++ g_free (oldpwd);
+
+-/**
+- * backend_get_packages:
+- */
+-static void
+-backend_get_packages (PkBackend *backend, PkBitfield filters)
+-{
+- pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
+-
+- pk_backend_thread_create (backend, backend_get_packages_thread);
++ return result;
+ }
+
+-/**
+- * backend_get_repo_list:
+- */
+ static void
+-backend_get_repo_list (PkBackend *backend, PkBitfield filters)
++pk_backend_logcb (pmloglevel_t level, const gchar *format, va_list args)
+ {
+- alpm_list_t *list_iterator;
+-
+- pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
++ gchar *output;
+
+- /* iterate on repo list */
+- for (list_iterator = alpm_option_get_syncdbs (); list_iterator; list_iterator = alpm_list_next (list_iterator)) {
+- pmdb_t *db = alpm_list_getdata (list_iterator);
++ g_return_if_fail (backend != NULL);
+
+- pk_backend_repo_detail (backend, alpm_db_get_name (db), alpm_db_get_name (db), TRUE);
++ if (format != NULL && format[0] != '\0') {
++ output = g_strdup_vprintf (format, args);
++ } else {
++ return;
+ }
+
+- pk_backend_finished (backend);
+-}
+-
+-/**
+- * backend_get_update_detail:
+- */
+-static void
+-backend_get_update_detail (PkBackend *backend, gchar **package_ids)
+-{
+- unsigned int iterator;
+-
+- pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_allow_cancel (backend, FALSE);
+-
+- for (iterator = 0; iterator < g_strv_length (package_ids); ++iterator) {
+- /* TODO: add changelog code here */
+- gchar **package_id_data = pk_package_id_split (package_ids[iterator]);
+-
+- pmpkg_t *installed_pkg = alpm_db_get_pkg (alpm_option_get_localdb (), package_id_data[PK_PACKAGE_ID_NAME]);
++ /* report important output to PackageKit */
++ switch (level) {
++ case PM_LOG_DEBUG:
++ case PM_LOG_FUNCTION:
++ g_debug ("%s", output);
++ break;
+
+- gchar *installed_package_id = installed_pkg ? pkg_to_package_id_str (installed_pkg, ALPM_LOCAL_DB_ALIAS) : NULL;
+- pk_backend_update_detail (backend, package_ids[iterator], installed_package_id, "", "", "", "", PK_RESTART_ENUM_NONE,
+- installed_pkg ? "Update to latest available version" : "Install as a dependency for another update",
+- NULL, PK_UPDATE_STATE_ENUM_UNKNOWN, NULL, NULL);
+- g_free (installed_package_id);
++ case PM_LOG_WARNING:
++ g_warning ("%s", output);
++ pk_backend_output (backend, output);
++ break;
+
+- g_strfreev (package_id_data);
++ default:
++ g_warning ("%s", output);
++ break;
+ }
+
+- pk_backend_finished (backend);
++ g_free (output);
+ }
+
+-/**
+- * backend_get_updates:
+- */
+-static void
+-backend_get_updates (PkBackend *backend, PkBitfield filters)
++static gboolean
++pk_backend_initialize_alpm (PkBackend *self, GError **error)
+ {
+- alpm_list_t *list_iterator;
+-
+- pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_allow_cancel (backend, FALSE);
+-
+- /* iterate through list of installed packages to find update for each */
+- for (list_iterator = alpm_db_get_pkgcache (alpm_option_get_localdb ()); list_iterator; list_iterator = alpm_list_next (list_iterator)) {
+- alpm_list_t *db_iterator;
+-
+- pmpkg_t *pkg = alpm_list_getdata (list_iterator);
++ struct utsname un;
++ gchar *user_agent;
+
+- for (db_iterator = alpm_option_get_syncdbs (); db_iterator; db_iterator = alpm_list_next (db_iterator)) {
+- pmdb_t *db = alpm_list_getdata (db_iterator);
+- pmpkg_t *repo_pkg = alpm_db_get_pkg (db, alpm_pkg_get_name (pkg));
++ g_return_val_if_fail (self != NULL, FALSE);
+
+- if (repo_pkg != NULL && alpm_pkg_vercmp (alpm_pkg_get_version (pkg), alpm_pkg_get_version (repo_pkg)) < 0) {
+- gchar *package_id_str = pkg_to_package_id_str (repo_pkg, alpm_db_get_name (db));
+- pk_backend_package (backend, PK_INFO_ENUM_NORMAL, package_id_str, alpm_pkg_get_desc (repo_pkg));
+- g_free (package_id_str);
++ /* PATH might have been nuked by D-Bus */
++ g_setenv ("PATH", PK_BACKEND_DEFAULT_PATH, FALSE);
+
+- break;
+- }
+- }
+- }
+-
+- pk_backend_finished (backend);
+-}
++ uname (&un);
++ user_agent = g_strdup_printf ("%s/%s (%s %s) libalpm/%s",
++ PACKAGE_TARNAME, PACKAGE_VERSION,
++ un.sysname, un.machine, alpm_version ());
++ g_setenv ("HTTP_USER_AGENT", user_agent, FALSE);
++ g_free (user_agent);
+
+-/**
+- * backend_install_files_thread:
+- */
+-static gboolean
+-backend_install_files_thread (PkBackend *backend)
+-{
+- unsigned int iterator;
+- alpm_list_t *data = NULL;
+-
+- gchar **full_paths = pk_backend_get_strv (backend, "full_paths");
+-
+- /* create a new transaction */
+- if (alpm_trans_init (0, cb_trans_evt, cb_trans_conv, cb_trans_progress) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- pk_backend_finished (backend);
++ g_debug ("initializing");
++ if (alpm_initialize () < 0) {
++ g_set_error_literal (error, ALPM_ERROR, pm_errno,
++ alpm_strerrorlast ());
+ return FALSE;
+ }
+
+- /* add targets to the transaction */
+- for (iterator = 0; iterator < g_strv_length (full_paths); ++iterator) {
+- if (alpm_add_target (full_paths[iterator]) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- alpm_trans_release ();
+- pk_backend_finished (backend);
+- return FALSE;
+- } else
+- g_debug ("alpm: %s added to transaction queue", full_paths[iterator]);
+- }
+-
+- /* prepare and commit transaction */
+- if (alpm_trans_prepare (&data) != 0 || alpm_trans_commit (&data) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- alpm_trans_release ();
+- pk_backend_finished (backend);
+- return FALSE;
++ backend = self;
++ localdb = alpm_option_get_localdb ();
++ if (localdb == NULL) {
++ g_set_error (error, ALPM_ERROR, pm_errno, "[%s]: %s", "local",
++ alpm_strerrorlast ());
+ }
+
+- alpm_trans_release ();
++ /* set some sane defaults */
++ alpm_option_set_logcb (pk_backend_logcb);
++ alpm_option_set_root (PK_BACKEND_DEFAULT_ROOT);
++ alpm_option_set_dbpath (PK_BACKEND_DEFAULT_DBPATH);
++ alpm_option_set_logfile (PK_BACKEND_DEFAULT_LOGFILE);
+
+- pk_backend_finished (backend);
+ return TRUE;
+ }
+
+-/**
+- * backend_install_files:
+- */
+ static void
+-backend_install_files (PkBackend *backend, gboolean only_trusted, gchar **full_paths)
+-{
+- pk_backend_set_status (backend, PK_STATUS_ENUM_INSTALL);
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
+-
+- pk_backend_thread_create (backend, backend_install_files_thread);
+-}
+-
+-/**
+- * backend_install_packages_thread:
+- */
+-static gboolean
+-backend_install_packages_thread (PkBackend *backend)
++pk_backend_destroy_alpm (PkBackend *self)
+ {
+- unsigned int iterator;
+- alpm_list_t *data = NULL;
+-
+- /* FIXME: support only_trusted */
+- gchar **package_ids = pk_backend_get_strv (backend, "package_ids");
+-
+- /* create a new transaction */
+- if (alpm_trans_init (0, cb_trans_evt, cb_trans_conv, cb_trans_progress) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- pk_backend_finished (backend);
+- return FALSE;
+- }
+-
+- /* add targets to the transaction */
+- for (iterator = 0; iterator < g_strv_length (package_ids); ++iterator) {
+- gchar **package_id_data = pk_package_id_split (package_ids[iterator]);
++ g_return_if_fail (self != NULL);
+
+- if (alpm_sync_target (package_id_data[PK_PACKAGE_ID_NAME]) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
++ if (backend != NULL) {
++ if (alpm_trans_get_flags () != -1) {
+ alpm_trans_release ();
+- pk_backend_finished (backend);
+- return FALSE;
+ }
+-
+- g_strfreev (package_id_data);
+- }
+-
+- /* prepare and commit transaction */
+- if (alpm_trans_prepare (&data) != 0 || alpm_trans_commit (&data) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- alpm_trans_release ();
+- pk_backend_finished (backend);
+- return FALSE;
++ alpm_release ();
++ backend = NULL;
+ }
+
+- alpm_trans_release ();
+-
+- pk_backend_finished (backend);
+- return TRUE;
+-}
+-
+-/**
+- * backend_install_packages:
+- */
+-static void
+-backend_install_packages (PkBackend *backend, gboolean only_trusted, gchar **package_ids)
+-{
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
+-
+- pk_backend_thread_create (backend, backend_install_packages_thread);
++ FREELIST (syncfirsts);
++ FREELIST (holdpkgs);
++ g_free (xfercmd);
+ }
+
+-/**
+- * backend_refresh_cache_thread:
+- */
+-static gboolean
+-backend_refresh_cache_thread (PkBackend *backend)
++void
++pk_backend_initialize (PkBackend *self)
+ {
+- alpm_list_t *list_iterator;
++ GError *error = NULL;
+
+- if (alpm_trans_init (PM_TRANS_FLAG_NOSCRIPTLET, cb_trans_evt, cb_trans_conv, cb_trans_progress) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- pk_backend_finished (backend);
+- return FALSE;
+- }
++ g_return_if_fail (self != NULL);
+
+- for (list_iterator = alpm_option_get_syncdbs (); list_iterator; list_iterator = alpm_list_next (list_iterator)) {
+- pmdb_t *db = (pmdb_t *) alpm_list_getdata (list_iterator);
+- if (alpm_db_update (FALSE, db) == -1) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- pk_backend_finished (backend);
+- return FALSE;
+- }
++ if (!pk_backend_initialize_alpm (self, &error) ||
++ !pk_backend_initialize_databases (self, &error) ||
++ !pk_backend_initialize_groups (self, &error)) {
++ g_error ("%s", error->message);
++ g_error_free (error);
+ }
+-
+- alpm_trans_release ();
+-
+- pk_backend_finished (backend);
+- return TRUE;
+ }
+
+-/**
+- * backend_refresh_cache:
+- */
+-static void
+-backend_refresh_cache (PkBackend *backend, gboolean force)
++void
++pk_backend_destroy (PkBackend *self)
+ {
+- if (!pk_backend_is_online (backend)) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Can not refresh cache in offline mode");
+- pk_backend_finished (backend);
+- return;
+- }
+-
+- pk_backend_set_status (backend, PK_STATUS_ENUM_REFRESH_CACHE);
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
++ g_return_if_fail (self != NULL);
+
+- pk_backend_thread_create (backend, backend_refresh_cache_thread);
++ pk_backend_destroy_groups (self);
++ pk_backend_destroy_databases (self);
++ pk_backend_destroy_alpm (self);
+ }
+
+-/**
+- * backend_remove_packages_thread:
+- */
+-static gboolean
+-backend_remove_packages_thread (PkBackend *backend)
++PkBitfield
++pk_backend_get_filters (PkBackend *self)
+ {
+- unsigned int iterator;
+- alpm_list_t *list_iterator = NULL;
+- alpm_list_t *data = NULL;
+- gchar *holdpkgs = NULL;
+-
+- gchar **package_ids = pk_backend_get_strv (backend, "package_ids");
+- gboolean allow_deps = pk_backend_get_bool (backend, "allow_deps");
+- gboolean autoremove = pk_backend_get_bool (backend, "autoremove");
+-
+- pmtransflag_t flags = 0;
+- if (allow_deps)
+- flags |= PM_TRANS_FLAG_CASCADE;
+- if (autoremove)
+- flags |= PM_TRANS_FLAG_RECURSE;
+-
+- /* create a new transaction */
+- if (alpm_trans_init (flags, cb_trans_evt, cb_trans_conv, cb_trans_progress) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- pk_backend_finished (backend);
+- return FALSE;
+- }
+-
+- /* add targets to the transaction */
+- for (iterator = 0; iterator < g_strv_length (package_ids); ++iterator) {
+- gchar **package_id_data = pk_package_id_split (package_ids[iterator]);
+-
+- if (alpm_remove_target (package_id_data[PK_PACKAGE_ID_NAME]) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- alpm_trans_release ();
+- pk_backend_finished (backend);
+- return FALSE;
+- }
+-
+- g_strfreev (package_id_data);
+- }
+-
+- /* prepare transaction */
+- if (alpm_trans_prepare (&data) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- alpm_trans_release ();
+- pk_backend_finished (backend);
+- return FALSE;
+- }
++ g_return_val_if_fail (self != NULL, 0);
+
+- /* search for HoldPkg's in target list */
+- for (list_iterator = alpm_trans_get_remove (); list_iterator; list_iterator = alpm_list_next (list_iterator)) {
+- pmpkg_t *pkg = alpm_list_getdata (list_iterator);
+- const gchar *pkgname = alpm_pkg_get_name (pkg);
+-
+- if (alpm_list_find_str (holdpkg, pkgname) != NULL) {
+- if (holdpkgs == NULL)
+- holdpkgs = g_strdup (pkgname);
+- else {
+- gchar *new_holdpkgs = g_strdup_printf ("%s, %s", holdpkgs, pkgname);
+- g_free (holdpkgs);
+- holdpkgs = new_holdpkgs;
+- }
+- }
+- }
+-
+- /* pacman just asks for confirmation, but here we fail to be safe */
+- if (holdpkgs != NULL) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_CANNOT_REMOVE_SYSTEM_PACKAGE, "The following packages are designated HoldPkg: %s", holdpkgs);
+- free (holdpkgs);
+- alpm_trans_release ();
+- pk_backend_finished (backend);
+- return FALSE;
+- }
+-
+- /* commit transaction */
+- if (alpm_trans_commit (&data) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- alpm_trans_release ();
+- pk_backend_finished (backend);
+- return FALSE;
+- }
+-
+- alpm_trans_release ();
+-
+- pk_backend_finished (backend);
+- return TRUE;
++ return pk_bitfield_from_enums (PK_FILTER_ENUM_INSTALLED, -1);
+ }
+
+-/**
+- * backend_remove_packages:
+- */
+-static void
+-backend_remove_packages (PkBackend *backend, gchar **package_ids, gboolean allow_deps, gboolean autoremove)
++gchar *
++pk_backend_get_mime_types (PkBackend *self)
+ {
+- pk_backend_set_status (backend, PK_STATUS_ENUM_REMOVE);
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
++ g_return_val_if_fail (self != NULL, NULL);
+
+- pk_backend_thread_create (backend, backend_remove_packages_thread);
++ /* packages currently use .pkg.tar.gz and .pkg.tar.xz */
++ return g_strdup ("application/x-compressed-tar;"
++ "application/x-xz-compressed-tar");
+ }
+
+-/**
+- * backend_resolve_thread:
+- */
+-static gboolean
+-backend_resolve_thread (PkBackend *backend)
++void
++pk_backend_run (PkBackend *self, PkStatusEnum status, PkBackendThreadFunc func)
+ {
+- unsigned int iterator;
+-
+- gchar **package_ids = pk_backend_get_strv (backend, "package_ids");
+- PkBitfield filters = pk_backend_get_uint (backend, "filters");
+-
+- gboolean search_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED);
+- gboolean search_not_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_NOT_INSTALLED);
+-
+- for (iterator = 0; iterator < g_strv_length (package_ids); ++iterator) {
+- if (pk_package_id_check (package_ids[iterator])) {
+- /* skip all the db iterations and so on - we already know everything */
+- pmpkg_t *pkg = pkg_from_package_id (package_ids[iterator]);
+-
+- if (pkg != NULL) {
+- gchar **package_id_data = pk_package_id_split (package_ids[iterator]);
+-
+- if (!search_not_installed && g_strcmp0 (package_id_data[PK_PACKAGE_ID_DATA], ALPM_LOCAL_DB_ALIAS) == 0)
+- emit_package (backend, pkg, ALPM_LOCAL_DB_ALIAS, PK_INFO_ENUM_INSTALLED);
+-
+- if (!search_installed && g_strcmp0 (package_id_data[PK_PACKAGE_ID_DATA], ALPM_LOCAL_DB_ALIAS) != 0)
+- emit_package (backend, pkg, package_id_data[PK_PACKAGE_ID_DATA], PK_INFO_ENUM_INSTALLED);
+-
+- g_strfreev (package_id_data);
+- }
+- } else {
+- /* good old way with backend_search */
+- /* TODO: check, is it still needed? */
+- if (!search_not_installed) {
+- /* search in local db */
+- backend_search (backend, alpm_option_get_localdb (), package_ids[iterator], PK_ALPM_SEARCH_TYPE_RESOLVE);
+- }
+-
+- if (!search_installed) {
+- /* search in sync repos */
+- alpm_list_t *repos;
+- /* iterate repos */
+- for (repos = alpm_option_get_syncdbs (); repos; repos = alpm_list_next (repos))
+- backend_search (backend, alpm_list_getdata (repos), package_ids[iterator], PK_ALPM_SEARCH_TYPE_RESOLVE);
+- }
+- }
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (func != NULL);
++
++ g_static_mutex_lock (&mutex);
++
++ if (cancellable != NULL) {
++ g_warning ("cancellable was not NULL");
++ g_object_unref (cancellable);
+ }
++ cancellable = g_cancellable_new ();
+
+- pk_backend_finished (backend);
+- return TRUE;
+-}
++ g_static_mutex_unlock (&mutex);
+
+-/**
+- * backend_resolve:
+- */
+-static void
+-backend_resolve (PkBackend *backend, PkBitfield filters, gchar **package_ids)
+-{
+- pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
++ pk_backend_set_allow_cancel (self, TRUE);
+
+- pk_backend_thread_create (backend, backend_resolve_thread);
++ pk_backend_set_status (self, status);
++ pk_backend_thread_create (self, func);
+ }
+
+-/**
+- * backend_search_thread:
+- */
+-static gboolean
+-backend_search_thread (PkBackend *backend)
++void
++pk_backend_cancel (PkBackend *self)
+ {
+- gchar **values = pk_backend_get_strv (backend, "values");
+- PkBitfield filters = pk_backend_get_uint (backend, "filters");
+- PkAlpmSearchType search_type = pk_backend_get_uint (backend, "search-type");
+-
+- gboolean search_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED);
+- gboolean search_not_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_NOT_INSTALLED);
++ g_return_if_fail (self != NULL);
+
+- if (!search_not_installed) {
+- /* search in local db */
+- backend_search_values (backend, alpm_option_get_localdb (), values, search_type);
+- }
++ g_static_mutex_lock (&mutex);
+
+- if (!search_installed) {
+- /* search in sync repos */
+- alpm_list_t *repos;
+- /* iterate repos */
+- for (repos = alpm_option_get_syncdbs (); repos; repos = alpm_list_next (repos))
+- backend_search_values (backend, alpm_list_getdata (repos), values, search_type);
++ if (cancellable != NULL) {
++ g_cancellable_cancel (cancellable);
+ }
+
+- pk_backend_finished (backend);
+- return TRUE;
++ g_static_mutex_unlock (&mutex);
+ }
+
+-/**
+- * backend_search_details:
+- */
+-static void
+-backend_search_details (PkBackend *backend, PkBitfield filters, gchar **values)
++gboolean
++pk_backend_cancelled (PkBackend *self)
+ {
+- pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
+- pk_backend_set_uint (backend, "search-type", PK_ALPM_SEARCH_TYPE_DETAILS);
+- pk_backend_set_strv (backend, "values", values);
++ gboolean cancelled;
+
+- pk_backend_thread_create (backend, backend_search_thread);
+-}
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (cancellable != NULL, FALSE);
+
+-/**
+- * backend_search_groups:
+- */
+-static void
+-backend_search_groups (PkBackend *backend, PkBitfield filters, gchar **values)
+-{
+- pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
+- pk_backend_set_uint (backend, "search-type", PK_ALPM_SEARCH_TYPE_GROUP);
+- pk_backend_set_strv (backend, "values", values);
++ g_static_mutex_lock (&mutex);
+
+- pk_backend_thread_create (backend, backend_search_thread);
+-}
++ cancelled = g_cancellable_is_cancelled (cancellable);
+
+-/**
+- * backend_search_names:
+- */
+-static void
+-backend_search_names (PkBackend *backend, PkBitfield filters, gchar **values)
+-{
+- pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
+- pk_backend_set_uint (backend, "search-type", PK_ALPM_SEARCH_TYPE_NAME);
+- pk_backend_set_strv (backend, "values", values);
++ g_static_mutex_unlock (&mutex);
+
+- pk_backend_thread_create (backend, backend_search_thread);
++ return cancelled;
+ }
+
+-/**
+- * backend_update_packages:
+- */
+-static void
+-backend_update_packages (PkBackend *backend, gboolean only_trusted, gchar **package_ids)
++gboolean
++pk_backend_finish (PkBackend *self, GError *error)
+ {
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
++ gboolean cancelled = FALSE;
+
+- pk_backend_thread_create (backend, backend_install_packages_thread);
+-}
++ g_return_val_if_fail (self != NULL, FALSE);
+
+-/**
+- * backend_update_system_thread:
+- */
+-static gboolean
+-backend_update_system_thread (PkBackend *backend)
+-{
+- alpm_list_t *data = NULL;
+-
+- /* FIXME: support only_trusted */
++ pk_backend_set_allow_cancel (self, FALSE);
+
+- /* create a new transaction */
+- if (alpm_trans_init (0, cb_trans_evt, cb_trans_conv, cb_trans_progress) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- pk_backend_finished (backend);
+- return FALSE;
+- }
++ g_static_mutex_lock (&mutex);
+
+- /* set action, prepare and commit transaction */
+- if (alpm_sync_sysupgrade (FALSE) != 0 || alpm_trans_prepare (&data) != 0 || alpm_trans_commit (&data) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_TRANSACTION_ERROR, alpm_strerrorlast ());
+- alpm_trans_release ();
+- pk_backend_finished (backend);
+- return FALSE;
++ if (cancellable != NULL) {
++ cancelled = g_cancellable_is_cancelled (cancellable);
++ g_object_unref (cancellable);
++ cancellable = NULL;
+ }
+
+- alpm_trans_release ();
++ g_static_mutex_unlock (&mutex);
+
+- pk_backend_finished (backend);
+- return TRUE;
+-}
+-
+-/**
+- * backend_update_system:
+- */
+-static void
+-backend_update_system (PkBackend *backend, gboolean only_trusted)
+-{
+- pk_backend_thread_create (backend, backend_update_system_thread);
+-}
++ if (error != NULL) {
++ pk_backend_error (self, error);
++ g_error_free (error);
++ }
+
+-/**
+- * backend_what_provides:
+- */
+-static void
+-backend_what_provides (PkBackend *backend, PkBitfield filters, PkProvidesEnum provides, gchar **values)
+-{
+- pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
+- pk_backend_set_uint (backend, "search-type", PK_ALPM_SEARCH_TYPE_PROVIDES);
+- pk_backend_set_strv (backend, "values", values);
++ if (cancelled) {
++ pk_backend_set_status (self, PK_STATUS_ENUM_CANCEL);
++ }
+
+- pk_backend_thread_create (backend, backend_search_thread);
++ pk_backend_thread_finished (self);
++ return (error == NULL);
+ }
+-
+-/* FIXME: port this away from PK_BACKEND_OPTIONS */
+-PK_BACKEND_OPTIONS (
+- "alpm", /* description */
+- "Valeriy Lyasotskiy <onestep@ukr.net>", /* author */
+- backend_initialize, /* initialize */
+- backend_destroy, /* destroy */
+- backend_get_groups, /* get_groups */
+- backend_get_filters, /* get_filters */
+- NULL, /* get_roles */
+- backend_get_mime_types, /* get_mime_types */
+- backend_cancel, /* cancel */
+- backend_download_packages, /* download_packages */
+- NULL, /* get_categories */
+- backend_get_depends, /* get_depends */
+- backend_get_details, /* get_details */
+- NULL, /* get_distro_upgrades */
+- backend_get_files, /* get_files */
+- backend_get_packages, /* get_packages */
+- backend_get_repo_list, /* get_repo_list */
+- NULL, /* get_requires */
+- backend_get_update_detail, /* get_update_detail */
+- backend_get_updates, /* get_updates */
+- backend_install_files, /* install_files */
+- backend_install_packages, /* install_packages */
+- NULL, /* install_signature */
+- backend_refresh_cache, /* refresh_cache */
+- backend_remove_packages, /* remove_packages */
+- NULL, /* repo_enable */
+- NULL, /* repo_set_data */
+- backend_resolve, /* resolve */
+- NULL, /* rollback */
+- backend_search_details, /* search_details */
+- NULL, /* search_files */
+- backend_search_groups, /* search_groups */
+- backend_search_names, /* search_names */
+- backend_update_packages, /* update_packages */
+- backend_update_system, /* update_system */
+- backend_what_provides, /* what_provides */
+- NULL, /* simulate_install_files */
+- NULL, /* simulate_install_packages */
+- NULL, /* simulate_remove_packages */
+- NULL, /* simulate_update_packages */
+- NULL, /* upgrade_system */
+- NULL, /* transaction_start */
+- NULL /* transaction_stop */
+-);
+diff --git a/backends/alpm/pk-backend-alpm.h b/backends/alpm/pk-backend-alpm.h
+new file mode 100644
+index 0000000..23a2724
+--- /dev/null
++++ b/backends/alpm/pk-backend-alpm.h
+@@ -0,0 +1,47 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alpm.h>
++#include <gio/gio.h>
++#include <pk-backend.h>
++
++extern PkBackend *backend;
++extern GCancellable *cancellable;
++
++extern pmdb_t *localdb;
++
++extern gchar *xfercmd;
++extern alpm_list_t *holdpkgs;
++extern alpm_list_t *syncfirsts;
++
++gint pk_backend_fetchcb (const gchar *url, const gchar *path,
++ gint force);
++
++void pk_backend_run (PkBackend *self, PkStatusEnum status,
++ PkBackendThreadFunc func);
++
++void pk_backend_cancel (PkBackend *self);
++
++gboolean pk_backend_cancelled (PkBackend *self);
++
++gboolean pk_backend_finish (PkBackend *self, GError *error);
+diff --git a/backends/alpm/pk-backend-config.c b/backends/alpm/pk-backend-config.c
+new file mode 100644
+index 0000000..21a4c54
+--- /dev/null
++++ b/backends/alpm/pk-backend-config.c
+@@ -0,0 +1,775 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alpm.h>
++#include <glob.h>
++#include <string.h>
++#include <sys/utsname.h>
++
++#include "pk-backend-alpm.h"
++#include "pk-backend-config.h"
++#include "pk-backend-error.h"
++
++typedef struct {
++ gboolean checkspace, ilovecandy, showsize, totaldl, usedelta, usesyslog;
++
++ gchar *arch, *cleanmethod, *dbpath, *logfile, *root, *xfercmd;
++
++ alpm_list_t *cachedirs, *holdpkgs, *ignoregrps, *ignorepkgs,
++ *noextracts, *noupgrades, *syncfirsts;
++
++ alpm_list_t *repos;
++ GHashTable *servers;
++ GRegex *xrepo, *xarch;
++} PkBackendConfig;
++
++static PkBackendConfig *
++pk_backend_config_new (void)
++{
++ PkBackendConfig *config = g_new0 (PkBackendConfig, 1);
++ config->servers = g_hash_table_new_full (g_str_hash, g_str_equal,
++ g_free, NULL);
++ config->xrepo = g_regex_new ("\\$repo", 0, 0, NULL);
++ config->xarch = g_regex_new ("\\$arch", 0, 0, NULL);
++ return config;
++}
++
++static void
++pk_backend_config_list_free (alpm_list_t *list)
++{
++ alpm_list_free_inner (list, g_free);
++ alpm_list_free (list);
++}
++
++static gboolean
++pk_backend_config_servers_free (gpointer repo, gpointer list, gpointer data)
++{
++ pk_backend_config_list_free ((alpm_list_t *) list);
++ return TRUE;
++}
++
++static void
++pk_backend_config_free (PkBackendConfig *config)
++{
++ g_return_if_fail (config != NULL);
++
++ g_free (config->arch);
++ g_free (config->cleanmethod);
++ g_free (config->dbpath);
++ g_free (config->logfile);
++ g_free (config->root);
++ g_free (config->xfercmd);
++
++ FREELIST (config->cachedirs);
++ FREELIST (config->holdpkgs);
++ FREELIST (config->ignoregrps);
++ FREELIST (config->ignorepkgs);
++ FREELIST (config->noextracts);
++ FREELIST (config->noupgrades);
++ FREELIST (config->syncfirsts);
++
++ pk_backend_config_list_free (config->repos);
++ g_hash_table_foreach_remove (config->servers,
++ pk_backend_config_servers_free, NULL);
++ g_hash_table_unref (config->servers);
++ g_regex_unref (config->xrepo);
++ g_regex_unref (config->xarch);
++}
++
++static void
++pk_backend_config_set_checkspace (PkBackendConfig *config)
++{
++ g_return_if_fail (config != NULL);
++
++ config->checkspace = TRUE;
++}
++
++static void
++pk_backend_config_set_ilovecandy (PkBackendConfig *config)
++{
++ g_return_if_fail (config != NULL);
++
++ config->ilovecandy = TRUE;
++}
++
++static void
++pk_backend_config_set_showsize (PkBackendConfig *config)
++{
++ g_return_if_fail (config != NULL);
++
++ config->showsize = TRUE;
++}
++
++static void
++pk_backend_config_set_totaldl (PkBackendConfig *config)
++{
++ g_return_if_fail (config != NULL);
++
++ config->totaldl = TRUE;
++}
++
++static void
++pk_backend_config_set_usedelta (PkBackendConfig *config)
++{
++ g_return_if_fail (config != NULL);
++
++ config->usedelta = TRUE;
++}
++
++static void
++pk_backend_config_set_usesyslog (PkBackendConfig *config)
++{
++ g_return_if_fail (config != NULL);
++
++ config->usesyslog = TRUE;
++}
++
++typedef struct {
++ const gchar *name;
++ void (*func) (PkBackendConfig *config);
++} PkBackendConfigBoolean;
++
++/* keep this in alphabetical order */
++static const PkBackendConfigBoolean pk_backend_config_boolean_options[] = {
++ { "CheckSpace", pk_backend_config_set_checkspace },
++ { "ILoveCandy", pk_backend_config_set_ilovecandy },
++ { "ShowSize", pk_backend_config_set_showsize },
++ { "TotalDownload", pk_backend_config_set_totaldl },
++ { "UseDelta", pk_backend_config_set_usedelta },
++ { "UseSyslog", pk_backend_config_set_usesyslog },
++ { NULL, NULL }
++};
++
++static gboolean
++pk_backend_config_set_boolean (PkBackendConfig *config, const gchar *option)
++{
++ gsize i;
++
++ g_return_val_if_fail (config != NULL, FALSE);
++ g_return_val_if_fail (option != NULL, FALSE);
++
++ for (i = 0;; ++i) {
++ const gchar *name = pk_backend_config_boolean_options[i].name;
++ gint cmp = g_strcmp0 (option, name);
++
++ if (name == NULL || cmp < 0) {
++ return FALSE;
++ } else if (cmp == 0) {
++ pk_backend_config_boolean_options[i].func (config);
++ return TRUE;
++ }
++ }
++}
++
++static void
++pk_backend_config_add_cachedir (PkBackendConfig *config, const gchar *path)
++{
++ gsize length;
++ gchar *cachedir;
++
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (path != NULL);
++
++ /* allocate normally */
++ length = strlen (path) + 1;
++ cachedir = malloc (length * sizeof (gchar));
++ g_strlcpy (cachedir, path, length);
++ config->cachedirs = alpm_list_add (config->cachedirs, cachedir);
++}
++
++static void
++pk_backend_config_set_arch (PkBackendConfig *config, const gchar *arch)
++{
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (arch != NULL);
++
++ g_free (config->arch);
++ if (g_strcmp0 (arch, "auto") == 0) {
++ struct utsname un;
++ uname (&un);
++ config->arch = g_strdup (un.machine);
++ } else {
++ config->arch = g_strdup (arch);
++ }
++}
++
++static void
++pk_backend_config_set_cleanmethod (PkBackendConfig *config, const gchar *method)
++{
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (method != NULL);
++
++ g_free (config->cleanmethod);
++ config->cleanmethod = g_strdup (method);
++}
++
++static void
++pk_backend_config_set_dbpath (PkBackendConfig *config, const gchar *path)
++{
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (path != NULL);
++
++ g_free (config->dbpath);
++ config->dbpath = g_strdup (path);
++}
++
++static void
++pk_backend_config_set_logfile (PkBackendConfig *config, const gchar *filename)
++{
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (filename != NULL);
++
++ g_free (config->logfile);
++ config->logfile = g_strdup (filename);
++}
++
++static void
++pk_backend_config_set_root (PkBackendConfig *config, const gchar *path)
++{
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (path != NULL);
++
++ g_free (config->root);
++ config->root = g_strdup (path);
++}
++
++static void
++pk_backend_config_set_xfercmd (PkBackendConfig *config, const gchar *command)
++{
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (command != NULL);
++
++ g_free (config->xfercmd);
++ config->xfercmd = g_strdup (command);
++}
++
++typedef struct {
++ const gchar *name;
++ void (*func) (PkBackendConfig *config, const gchar *s);
++} PkBackendConfigString;
++
++/* keep this in alphabetical order */
++static const PkBackendConfigString pk_backend_config_string_options[] = {
++ { "Architecture", pk_backend_config_set_arch },
++ { "CacheDir", pk_backend_config_add_cachedir },
++ { "CleanMethod", pk_backend_config_set_cleanmethod },
++ { "DBPath", pk_backend_config_set_dbpath },
++ { "LogFile", pk_backend_config_set_logfile },
++ { "RootDir", pk_backend_config_set_root },
++ { "XferCommand", pk_backend_config_set_xfercmd },
++ { NULL, NULL }
++};
++
++static gboolean
++pk_backend_config_set_string (PkBackendConfig *config, const gchar *option,
++ const gchar *s)
++{
++ gsize i;
++
++ g_return_val_if_fail (config != NULL, FALSE);
++ g_return_val_if_fail (option != NULL, FALSE);
++ g_return_val_if_fail (s != NULL, FALSE);
++
++ for (i = 0;; ++i) {
++ const gchar *name = pk_backend_config_string_options[i].name;
++ gint cmp = g_strcmp0 (option, name);
++
++ if (name == NULL || cmp < 0) {
++ return FALSE;
++ } else if (cmp == 0) {
++ pk_backend_config_string_options[i].func (config, s);
++ return TRUE;
++ }
++ }
++}
++
++static void
++pk_backend_config_add_holdpkg (PkBackendConfig *config, gchar *package)
++{
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (package != NULL);
++
++ config->holdpkgs = alpm_list_add (config->holdpkgs, package);
++}
++
++static void
++pk_backend_config_add_ignoregrp (PkBackendConfig *config, gchar *group)
++{
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (group != NULL);
++
++ config->ignoregrps = alpm_list_add (config->ignoregrps, group);
++}
++
++static void
++pk_backend_config_add_ignorepkg (PkBackendConfig *config, gchar *package)
++{
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (package != NULL);
++
++ config->ignorepkgs = alpm_list_add (config->ignorepkgs, package);
++}
++
++static void
++pk_backend_config_add_noextract (PkBackendConfig *config, gchar *filename)
++{
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (filename != NULL);
++
++ config->noextracts = alpm_list_add (config->noextracts, filename);
++}
++
++static void
++pk_backend_config_add_noupgrade (PkBackendConfig *config, gchar *filename)
++{
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (filename != NULL);
++
++ config->noupgrades = alpm_list_add (config->noupgrades, filename);
++}
++
++static void
++pk_backend_config_add_syncfirst (PkBackendConfig *config, gchar *package)
++{
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (package != NULL);
++
++ config->syncfirsts = alpm_list_add (config->syncfirsts, package);
++}
++
++typedef struct {
++ const gchar *name;
++ void (*func) (PkBackendConfig *config, gchar *value);
++} PkBackendConfigList;
++
++/* keep this in alphabetical order */
++static const PkBackendConfigList pk_backend_config_list_options[] = {
++ { "HoldPkg", pk_backend_config_add_holdpkg },
++ { "IgnoreGroup", pk_backend_config_add_ignoregrp },
++ { "IgnorePkg", pk_backend_config_add_ignorepkg },
++ { "NoExtract", pk_backend_config_add_noextract },
++ { "NoUpgrade", pk_backend_config_add_noupgrade },
++ { "SyncFirst", pk_backend_config_add_syncfirst },
++ { NULL, NULL }
++};
++
++static void
++pk_backend_config_list_add (PkBackendConfig *config, gsize option,
++ const gchar *list)
++{
++ gchar *str;
++
++ for (str = strchr (list, ' '); str != NULL; str = strchr (list, ' ')) {
++ /* allocate normally */
++ gchar *value = malloc ((++str - list) * sizeof (gchar));
++ g_strlcpy (value, list, str - list);
++ pk_backend_config_list_options[option].func (config, value);
++ list = str;
++ }
++ pk_backend_config_list_options[option].func (config, strdup (list));
++}
++
++static gboolean
++pk_backend_config_set_list (PkBackendConfig *config, const gchar *option,
++ const gchar *list)
++{
++ gsize i;
++
++ g_return_val_if_fail (config != NULL, FALSE);
++ g_return_val_if_fail (option != NULL, FALSE);
++ g_return_val_if_fail (list != NULL, FALSE);
++
++ for (i = 0;; ++i) {
++ const gchar *name = pk_backend_config_list_options[i].name;
++ gint cmp = g_strcmp0 (option, name);
++
++ if (name == NULL || cmp < 0) {
++ return FALSE;
++ } else if (cmp == 0) {
++ pk_backend_config_list_add (config, i, list);
++ return TRUE;
++ }
++ }
++}
++
++static void
++pk_backend_config_add_repo (PkBackendConfig *config, const gchar *repo)
++{
++ g_return_if_fail (config != NULL);
++ g_return_if_fail (repo != NULL);
++
++ if (alpm_list_find_str (config->repos, repo) == NULL) {
++ config->repos = alpm_list_add (config->repos, g_strdup (repo));
++ }
++}
++
++static gboolean
++pk_backend_config_repo_add_server (PkBackendConfig *config, const gchar *repo,
++ const gchar *value, GError **e)
++{
++ alpm_list_t *list;
++ gchar *url;
++
++ g_return_val_if_fail (config != NULL, FALSE);
++ g_return_val_if_fail (repo != NULL, FALSE);
++ g_return_val_if_fail (alpm_list_find_str (config->repos, repo) != NULL,
++ FALSE);
++ g_return_val_if_fail (value != NULL, FALSE);
++
++ url = g_regex_replace_literal (config->xrepo, value, -1, 0, repo, 0, e);
++ if (url == NULL) {
++ return FALSE;
++ }
++
++ if (config->arch != NULL) {
++ gchar *temp = url;
++ url = g_regex_replace_literal (config->xarch, temp, -1, 0,
++ config->arch, 0, e);
++ g_free (temp);
++
++ if (url == NULL) {
++ return FALSE;
++ }
++ } else if (strstr (url, "$arch") != NULL) {
++ g_set_error (e, ALPM_ERROR, PM_ERR_CONFIG_INVALID,
++ "url contained $arch, which is not set");
++ }
++
++ list = (alpm_list_t *) g_hash_table_lookup (config->servers, repo);
++ list = alpm_list_add (list, url);
++ g_hash_table_insert (config->servers, g_strdup (repo), list);
++
++ return TRUE;
++}
++
++static gboolean
++pk_backend_config_parse (PkBackendConfig *config, const gchar *filename,
++ gchar *section, GError **error)
++{
++ GFile *file;
++ GFileInputStream *is;
++ GDataInputStream *input;
++
++ gchar *key, *str, *line = NULL;
++ guint num = 1;
++
++ GError *e = NULL;
++
++ g_return_val_if_fail (config != NULL, FALSE);
++ g_return_val_if_fail (filename != NULL, FALSE);
++
++ file = g_file_new_for_path (filename);
++ is = g_file_read (file, NULL, &e);
++
++ if (is == NULL) {
++ g_propagate_error (error, e);
++ g_object_unref (file);
++ return FALSE;
++ }
++
++ input = g_data_input_stream_new (G_INPUT_STREAM (is));
++ section = g_strdup (section);
++
++ for (;; g_free (line), ++num) {
++ line = g_data_input_stream_read_line (input, NULL, NULL, &e);
++
++ if (line != NULL) {
++ g_strstrip (line);
++ } else {
++ break;
++ }
++
++ /* skip empty lines */
++ if (*line == '\0' || *line == '#') {
++ continue;
++ }
++
++ /* remove trailing comments */
++ for (str = line; *str != '\0' && *str != '#'; ++str);
++ *str-- = '\0';
++
++ /* change sections */
++ if (*line == '[' && *str == ']') {
++ *str = '\0';
++ str = line + 1;
++
++ if (*str == '\0') {
++ g_set_error (&e, ALPM_ERROR,
++ PM_ERR_CONFIG_INVALID,
++ "empty section name");
++ break;
++ }
++
++ g_free (section);
++ section = g_strdup (str);
++
++ if (g_strcmp0 (section, "options") != 0) {
++ pk_backend_config_add_repo (config, section);
++ }
++
++ continue;
++ }
++
++ /* parse a directive */
++ if (section == NULL) {
++ g_set_error (&e, ALPM_ERROR, PM_ERR_CONFIG_INVALID,
++ "directive must belong to a section");
++ break;
++ }
++
++ str = line;
++ key = strsep (&str, "=");
++ g_strchomp (key);
++ if (str != NULL) {
++ g_strchug (str);
++ }
++
++ if (str == NULL) {
++ /* set a boolean directive */
++ if (g_strcmp0 (section, "options") == 0 &&
++ pk_backend_config_set_boolean (config, key)) {
++ continue;
++ }
++ /* report error below */
++ } else if (g_strcmp0 (key, "Include") == 0) {
++ gsize i;
++ glob_t match = { 0 };
++
++ /* ignore globbing errors */
++ if (glob (str, GLOB_NOCHECK, NULL, &match) != 0) {
++ continue;
++ }
++
++ /* parse the files that matched */
++ for (i = 0; i < match.gl_pathc; ++i) {
++ if (!pk_backend_config_parse (config,
++ match.gl_pathv[i],
++ section, &e)) {
++ break;
++ }
++ }
++
++ globfree (&match);
++ if (e != NULL) {
++ break;
++ } else {
++ continue;
++ }
++ } else if (g_strcmp0 (section, "options") == 0) {
++ /* set a string or list directive */
++ if (pk_backend_config_set_string (config, key, str) ||
++ pk_backend_config_set_list (config, key, str)) {
++ continue;
++ }
++ /* report error below */
++ } else if (g_strcmp0 (key, "Server") == 0) {
++ if (!pk_backend_config_repo_add_server (config, section,
++ str, &e)) {
++ break;
++ } else {
++ continue;
++ }
++ }
++
++ /* report errors from above */
++ g_set_error (&e, ALPM_ERROR, PM_ERR_CONFIG_INVALID,
++ "unrecognised directive '%s'", key);
++ break;
++ }
++
++ g_free (section);
++
++ g_object_unref (input);
++ g_object_unref (is);
++ g_object_unref (file);
++
++ if (e != NULL) {
++ g_propagate_prefixed_error (error, e, "%s:%u", filename, num);
++ return FALSE;
++ } else {
++ return TRUE;
++ }
++}
++
++static gboolean
++pk_backend_config_configure_paths (PkBackendConfig *config, GError **error)
++{
++ g_return_val_if_fail (config != NULL, FALSE);
++
++ if (config->root == NULL) {
++ config->root = g_strdup (PK_BACKEND_DEFAULT_ROOT);
++ }
++
++ if (alpm_option_set_root (config->root) < 0) {
++ g_set_error (error, ALPM_ERROR, pm_errno, "RootDir: %s",
++ alpm_strerrorlast ());
++ return FALSE;
++ }
++
++ if (config->dbpath == NULL) {
++ config->dbpath = g_strconcat (alpm_option_get_root (),
++ PK_BACKEND_DEFAULT_DBPATH + 1,
++ NULL);
++ }
++
++ if (alpm_option_set_dbpath (config->dbpath) < 0) {
++ g_set_error (error, ALPM_ERROR, pm_errno, "DBPath: %s",
++ alpm_strerrorlast ());
++ return FALSE;
++ }
++
++ if (config->logfile == NULL) {
++ config->logfile = g_strconcat (alpm_option_get_root (),
++ PK_BACKEND_DEFAULT_LOGFILE + 1,
++ NULL);
++ }
++
++ alpm_option_set_logfile (config->logfile);
++
++ if (config->cachedirs == NULL) {
++ gchar *path = g_strconcat (alpm_option_get_root (),
++ PK_BACKEND_DEFAULT_CACHEDIR + 1,
++ NULL);
++ config->cachedirs = alpm_list_add (NULL, path);
++ }
++
++ /* alpm takes ownership */
++ alpm_option_set_cachedirs (config->cachedirs);
++ config->cachedirs = NULL;
++
++ return TRUE;
++}
++
++static gboolean
++pk_backend_config_configure_repos (PkBackendConfig *config, GError **error)
++{
++ const alpm_list_t *i;
++
++ g_return_val_if_fail (config != NULL, FALSE);
++
++ for (i = alpm_option_get_syncdbs (); i != NULL; i = i->next) {
++ if (alpm_db_unregister (i->data) < 0) {
++ g_set_error_literal (error, ALPM_ERROR, pm_errno,
++ alpm_strerrorlast ());
++ return FALSE;
++ }
++ }
++
++ for (i = config->repos; i != NULL; i = i->next) {
++ const gchar *key;
++ gpointer value;
++ pmdb_t *db;
++ alpm_list_t *j;
++
++ key = (const gchar *) i->data;
++ value = g_hash_table_lookup (config->servers, key);
++
++ db = alpm_db_register_sync (key);
++ if (db == NULL) {
++ g_set_error (error, ALPM_ERROR, pm_errno, "[%s]: %s",
++ key, alpm_strerrorlast ());
++ return FALSE;
++ }
++
++ for (j = (alpm_list_t *) value; j != NULL; j = j->next) {
++ alpm_db_setserver (db, (const gchar *) j->data);
++ }
++ }
++
++ return TRUE;
++}
++
++static gboolean
++pk_backend_config_configure_alpm (PkBackendConfig *config, GError **error)
++{
++ g_return_val_if_fail (config != NULL, FALSE);
++
++ if (!pk_backend_config_configure_paths (config, error)) {
++ return FALSE;
++ }
++
++ alpm_option_set_checkspace (config->checkspace);
++ alpm_option_set_usedelta (config->usedelta);
++ alpm_option_set_usesyslog (config->usesyslog);
++ alpm_option_set_arch (config->arch);
++
++ /* backend takes ownership */
++ g_free (xfercmd);
++ xfercmd = config->xfercmd;
++ config->xfercmd = NULL;
++
++ if (xfercmd != NULL) {
++ alpm_option_set_fetchcb (pk_backend_fetchcb);
++ } else {
++ alpm_option_set_fetchcb (NULL);
++ }
++
++ /* backend takes ownership */
++ FREELIST (holdpkgs);
++ holdpkgs = config->holdpkgs;
++ config->holdpkgs = NULL;
++
++ /* backend takes ownership */
++ FREELIST (syncfirsts);
++ syncfirsts = config->syncfirsts;
++ config->syncfirsts = NULL;
++
++ /* alpm takes ownership */
++ alpm_option_set_ignoregrps (config->ignoregrps);
++ config->ignoregrps = NULL;
++
++ /* alpm takes ownership */
++ alpm_option_set_ignorepkgs (config->ignorepkgs);
++ config->ignorepkgs = NULL;
++
++ /* alpm takes ownership */
++ alpm_option_set_noextracts (config->noextracts);
++ config->noextracts = NULL;
++
++ /* alpm takes ownership */
++ alpm_option_set_noupgrades (config->noupgrades);
++ config->noupgrades = NULL;
++
++ if (!pk_backend_config_configure_repos (config, error)) {
++ return FALSE;
++ }
++
++ return TRUE;
++}
++
++gboolean
++pk_backend_configure (const gchar *filename, GError **error)
++{
++ PkBackendConfig *config;
++ gboolean result;
++
++ g_return_val_if_fail (filename != NULL, FALSE);
++
++ config = pk_backend_config_new ();
++
++ result = pk_backend_config_parse (config, filename, NULL, error) &&
++ pk_backend_config_configure_alpm (config, error);
++
++ pk_backend_config_free (config);
++ return result;
++}
+diff --git a/backends/alpm/pk-backend-config.h b/backends/alpm/pk-backend-config.h
+new file mode 100644
+index 0000000..cb8b8dc
+--- /dev/null
++++ b/backends/alpm/pk-backend-config.h
+@@ -0,0 +1,26 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <glib.h>
++
++gboolean pk_backend_configure (const gchar *filename, GError **error);
+diff --git a/backends/alpm/pk-backend-databases.c b/backends/alpm/pk-backend-databases.c
+new file mode 100644
+index 0000000..f6ab06e
+--- /dev/null
++++ b/backends/alpm/pk-backend-databases.c
+@@ -0,0 +1,346 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include "pk-backend-alpm.h"
++#include "pk-backend-config.h"
++#include "pk-backend-databases.h"
++#include "pk-backend-error.h"
++
++static GHashTable *disabled = NULL;
++
++static GHashTable *
++disabled_repos_new (GError **error)
++{
++ GHashTable *table;
++ GFile *file;
++
++ GFileInputStream *is;
++ GDataInputStream *input;
++
++ GError *e = NULL;
++
++ g_debug ("reading disabled repos from %s", PK_BACKEND_REPO_FILE);
++ file = g_file_new_for_path (PK_BACKEND_REPO_FILE);
++ is = g_file_read (file, NULL, &e);
++
++ if (is == NULL) {
++ g_object_unref (file);
++ g_propagate_error (error, e);
++ return NULL;
++ }
++
++ table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
++ input = g_data_input_stream_new (G_INPUT_STREAM (is));
++
++ /* read disabled repos line by line, ignoring comments */
++ while (TRUE) {
++ gchar *line;
++
++ line = g_data_input_stream_read_line (input, NULL, NULL, &e);
++
++ if (line != NULL) {
++ g_strstrip (line);
++ } else {
++ break;
++ }
++
++ if (*line == '\0' || *line == '#') {
++ g_free (line);
++ continue;
++ }
++
++ g_hash_table_insert (table, line, GINT_TO_POINTER (1));
++ }
++
++ g_object_unref (input);
++ g_object_unref (is);
++ g_object_unref (file);
++
++ if (e != NULL) {
++ g_hash_table_unref (table);
++ g_propagate_error (error, e);
++ return NULL;
++ } else {
++ return table;
++ }
++}
++
++static void
++disabled_repos_free (GHashTable *table)
++{
++ GHashTableIter iter;
++ GFile *file;
++
++ GFileOutputStream *os;
++ GDataOutputStream *output;
++
++ const gchar *line;
++
++ g_return_if_fail (table != NULL);
++
++ g_debug ("storing disabled repos in %s", PK_BACKEND_REPO_FILE);
++ file = g_file_new_for_path (PK_BACKEND_REPO_FILE);
++ os = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL);
++
++ if (os == NULL) {
++ g_object_unref (file);
++ g_hash_table_unref (table);
++ return;
++ }
++
++ g_hash_table_iter_init (&iter, table);
++ output = g_data_output_stream_new (G_OUTPUT_STREAM (os));
++
++ /* write all disabled repos line by line */
++ while (g_hash_table_iter_next (&iter, (gpointer *) &line, NULL) &&
++ g_data_output_stream_put_string (output, line, NULL, NULL) &&
++ g_data_output_stream_put_byte (output, '\n', NULL, NULL));
++
++ g_object_unref (output);
++ g_object_unref (os);
++ g_object_unref (file);
++
++ g_hash_table_unref (table);
++}
++
++static gboolean
++disabled_repos_configure (GHashTable *table, GError **error)
++{
++ const alpm_list_t *i;
++
++ g_debug ("reading config from %s", PK_BACKEND_CONFIG_FILE);
++
++ /* read configuration from pacman.conf file */
++ if (!pk_backend_configure (PK_BACKEND_CONFIG_FILE, error)) {
++ return FALSE;
++ }
++
++ /* disable disabled repos */
++ for (i = alpm_option_get_syncdbs (); i != NULL;) {
++ pmdb_t *db = (pmdb_t *) i->data;
++ const gchar *repo = alpm_db_get_name (db);
++
++ if (g_hash_table_lookup (table, repo) == NULL) {
++ /* repo is not disabled */
++ i = i->next;
++ continue;
++ }
++
++ if (alpm_db_unregister (db) < 0) {
++ g_set_error (error, ALPM_ERROR, pm_errno, "[%s]: %s",
++ repo, alpm_strerrorlast ());
++ return FALSE;
++ }
++
++ /* start again because the list gets invalidated */
++ i = alpm_option_get_syncdbs ();
++ }
++
++ return TRUE;
++}
++
++gboolean
++pk_backend_initialize_databases (PkBackend *self, GError **error)
++{
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ disabled = disabled_repos_new (error);
++ if (disabled == NULL) {
++ return FALSE;
++ }
++
++ if (!disabled_repos_configure (disabled, error)) {
++ return FALSE;
++ }
++
++ return TRUE;
++}
++
++void
++pk_backend_destroy_databases (PkBackend *self)
++{
++ g_return_if_fail (self != NULL);
++
++ if (disabled != NULL) {
++ disabled_repos_free (disabled);
++ }
++}
++
++static gboolean
++pk_backend_repo_info (PkBackend *self, const gchar *repo, gboolean enabled)
++{
++ gchar *description;
++ gboolean result;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (repo != NULL, FALSE);
++
++ description = g_strdup_printf ("[%s]", repo);
++ result = pk_backend_repo_detail (self, repo, description, enabled);
++ g_free (description);
++
++ return result;
++}
++
++static gboolean
++pk_backend_get_repo_list_thread (PkBackend *self)
++{
++ const alpm_list_t *i;
++ GHashTableIter iter;
++ gpointer key, value;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (disabled != NULL, FALSE);
++
++ /* emit enabled repos */
++ for (i = alpm_option_get_syncdbs (); i != NULL; i = i->next) {
++ pmdb_t *db = (pmdb_t *) i->data;
++ const gchar *repo = alpm_db_get_name (db);
++
++ if (pk_backend_cancelled (self)) {
++ goto out;
++ } else {
++ pk_backend_repo_info (self, repo, TRUE);
++ }
++ }
++
++ /* emit disabled repos */
++ g_hash_table_iter_init (&iter, disabled);
++ while (g_hash_table_iter_next (&iter, &key, &value)) {
++ const gchar *repo = (const gchar *) key;
++
++ if (pk_backend_cancelled (self)) {
++ goto out;
++ } else {
++ pk_backend_repo_info (self, repo, FALSE);
++ }
++ }
++
++out:
++ return pk_backend_finish (self, NULL);
++}
++
++void
++pk_backend_get_repo_list (PkBackend *self, PkBitfield filters)
++{
++ g_return_if_fail (self != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY,
++ pk_backend_get_repo_list_thread);
++}
++
++static gboolean
++pk_backend_repo_enable_thread (PkBackend *self)
++{
++ const gchar *repo;
++
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (disabled != NULL, FALSE);
++
++ repo = pk_backend_get_string (self, "repo_id");
++
++ g_return_val_if_fail (repo != NULL, FALSE);
++
++ if (g_hash_table_remove (disabled, repo)) {
++ /* reload configuration to preserve ordering */
++ if (disabled_repos_configure (disabled, &error)) {
++ pk_backend_repo_list_changed (self);
++ }
++ } else {
++ int code = PM_ERR_DB_NOT_NULL;
++ g_set_error (&error, ALPM_ERROR, code, "[%s]: %s",
++ repo, alpm_strerror (code));
++ }
++
++ if (error != NULL) {
++ pk_backend_error (self, error);
++ g_error_free (error);
++ }
++
++ pk_backend_thread_finished (self);
++ return (error == NULL);
++}
++
++static gboolean
++pk_backend_repo_disable_thread (PkBackend *self)
++{
++ const alpm_list_t *i;
++ const gchar *repo;
++
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (disabled != NULL, FALSE);
++
++ repo = pk_backend_get_string (self, "repo_id");
++
++ g_return_val_if_fail (repo != NULL, FALSE);
++
++ for (i = alpm_option_get_syncdbs (); i != NULL; i = i->next) {
++ pmdb_t *db = (pmdb_t *) i->data;
++ const gchar *name = alpm_db_get_name (db);
++
++ if (g_strcmp0 (repo, name) == 0) {
++ if (alpm_db_unregister (db) < 0) {
++ g_set_error (&error, ALPM_ERROR, pm_errno,
++ "[%s]: %s", repo,
++ alpm_strerrorlast ());
++ } else {
++ g_hash_table_insert (disabled, g_strdup (repo),
++ GINT_TO_POINTER (1));
++ }
++ break;
++ }
++ }
++
++ if (i == NULL) {
++ int code = PM_ERR_DB_NULL;
++ g_set_error (&error, ALPM_ERROR, code, "[%s]: %s", repo,
++ alpm_strerror (code));
++ }
++
++ if (error != NULL) {
++ pk_backend_error (self, error);
++ g_error_free (error);
++ }
++
++ pk_backend_thread_finished (self);
++ return (error == NULL);
++}
++
++void
++pk_backend_repo_enable (PkBackend *self, const gchar *repo_id, gboolean enabled)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (repo_id != NULL);
++
++ pk_backend_set_status (self, PK_STATUS_ENUM_QUERY);
++
++ if (enabled) {
++ pk_backend_thread_create (self, pk_backend_repo_enable_thread);
++ } else {
++ pk_backend_thread_create (self, pk_backend_repo_disable_thread);
++ }
++}
+diff --git a/backends/alpm/pk-backend-databases.h b/backends/alpm/pk-backend-databases.h
+new file mode 100644
+index 0000000..f9eb2f9
+--- /dev/null
++++ b/backends/alpm/pk-backend-databases.h
+@@ -0,0 +1,30 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alpm.h>
++#include <pk-backend.h>
++
++gboolean pk_backend_initialize_databases (PkBackend *self,
++ GError **error);
++
++void pk_backend_destroy_databases (PkBackend *self);
+diff --git a/backends/alpm/pk-backend-depends.c b/backends/alpm/pk-backend-depends.c
+new file mode 100644
+index 0000000..8bb8567
+--- /dev/null
++++ b/backends/alpm/pk-backend-depends.c
+@@ -0,0 +1,269 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alpm.h>
++#include <pk-backend.h>
++
++#include "pk-backend-alpm.h"
++#include "pk-backend-depends.h"
++#include "pk-backend-error.h"
++#include "pk-backend-packages.h"
++
++static pmpkg_t *
++alpm_list_find_pkg (const alpm_list_t *pkgs, const gchar *name)
++{
++ g_return_val_if_fail (name != NULL, NULL);
++
++ for (; pkgs != NULL; pkgs = pkgs->next) {
++ if (g_strcmp0 (name, alpm_pkg_get_name (pkgs->data)) == 0) {
++ return pkgs->data;
++ }
++ }
++
++ return NULL;
++}
++
++static alpm_list_t *
++pk_backend_find_provider (PkBackend *self, alpm_list_t *pkgs,
++ const gchar *depend, GError **error)
++{
++ PkBitfield filters;
++ gboolean recursive, skip_local, skip_remote;
++
++ pmpkg_t *provider;
++ alpm_list_t *pkgcache, *syncdbs;
++
++ g_return_val_if_fail (self != NULL, pkgs);
++ g_return_val_if_fail (depend != NULL, pkgs);
++ g_return_val_if_fail (localdb != NULL, pkgs);
++
++ recursive = pk_backend_get_bool (self, "recursive");
++ filters = pk_backend_get_uint (self, "filters");
++ skip_local = pk_bitfield_contain (filters,
++ PK_FILTER_ENUM_NOT_INSTALLED);
++ skip_remote = pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED);
++
++ if (alpm_find_satisfier (pkgs, depend) != NULL) {
++ return pkgs;
++ }
++
++ /* look for local dependencies */
++ pkgcache = alpm_db_get_pkgcache (localdb);
++ provider = alpm_find_satisfier (pkgcache, depend);
++
++ if (provider != NULL) {
++ if (!skip_local) {
++ pk_backend_pkg (self, provider, PK_INFO_ENUM_INSTALLED);
++ /* assume later dependencies will also be local */
++ if (recursive) {
++ pkgs = alpm_list_add (pkgs, provider);
++ }
++ }
++
++ return pkgs;
++ }
++
++ /* look for remote dependencies */
++ syncdbs = alpm_option_get_syncdbs ();
++ provider = alpm_find_dbs_satisfier (syncdbs, depend);
++
++ if (provider != NULL) {
++ if (!skip_remote) {
++ pk_backend_pkg (self, provider, PK_INFO_ENUM_AVAILABLE);
++ }
++ /* keep looking for local dependencies */
++ if (recursive) {
++ pkgs = alpm_list_add (pkgs, provider);
++ }
++ } else {
++ int code = PM_ERR_UNSATISFIED_DEPS;
++ g_set_error (error, ALPM_ERROR, code, "%s: %s", depend,
++ alpm_strerror (code));
++ }
++
++ return pkgs;
++}
++
++static alpm_list_t *
++pk_backend_find_requirer (PkBackend *self, alpm_list_t *pkgs, const gchar *name,
++ GError **error)
++{
++ pmpkg_t *requirer;
++
++ g_return_val_if_fail (self != NULL, pkgs);
++ g_return_val_if_fail (name != NULL, pkgs);
++ g_return_val_if_fail (localdb != NULL, pkgs);
++
++ if (alpm_list_find_pkg (pkgs, name) != NULL) {
++ return pkgs;
++ }
++
++ /* look for local requirers */
++ requirer = alpm_db_get_pkg (localdb, name);
++
++ if (requirer != NULL) {
++ pk_backend_pkg (self, requirer, PK_INFO_ENUM_INSTALLED);
++ if (pk_backend_get_bool (self, "recursive")) {
++ pkgs = alpm_list_add (pkgs, requirer);
++ }
++ } else {
++ int code = PM_ERR_PKG_NOT_FOUND;
++ g_set_error (error, ALPM_ERROR, code, "%s: %s", name,
++ alpm_strerror (code));
++ }
++
++ return pkgs;
++}
++
++static gboolean
++pk_backend_get_depends_thread (PkBackend *self)
++{
++ gchar **packages;
++ alpm_list_t *i, *pkgs = NULL;
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ packages = pk_backend_get_strv (self, "package_ids");
++
++ g_return_val_if_fail (packages != NULL, FALSE);
++
++ /* construct an initial package list */
++ for (; *packages != NULL; ++packages) {
++ pmpkg_t *pkg;
++
++ if (pk_backend_cancelled (self)) {
++ break;
++ }
++
++ pkg = pk_backend_find_pkg (self, *packages, &error);
++ if (pkg == NULL) {
++ break;
++ }
++
++ pkgs = alpm_list_add (pkgs, pkg);
++ }
++
++ /* package list might be modified along the way but that is ok */
++ for (i = pkgs; i != NULL; i = i->next) {
++ const alpm_list_t *depends;
++
++ if (pk_backend_cancelled (self) || error != NULL) {
++ break;
++ }
++
++ depends = alpm_pkg_get_depends (i->data);
++ for (; depends != NULL; depends = depends->next) {
++ gchar *depend;
++
++ if (pk_backend_cancelled (self) || error != NULL) {
++ break;
++ }
++
++ depend = alpm_dep_compute_string (depends->data);
++ pkgs = pk_backend_find_provider (self, pkgs, depend,
++ &error);
++ g_free (depend);
++ }
++ }
++
++ alpm_list_free (pkgs);
++ return pk_backend_finish (self, NULL);
++}
++
++static gboolean
++pk_backend_get_requires_thread (PkBackend *self)
++{
++ gchar **packages;
++ alpm_list_t *i, *pkgs = NULL;
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ packages = pk_backend_get_strv (self, "package_ids");
++
++ g_return_val_if_fail (packages != NULL, FALSE);
++
++ /* construct an initial package list */
++ for (; *packages != NULL; ++packages) {
++ pmpkg_t *pkg;
++
++ if (pk_backend_cancelled (self)) {
++ break;
++ }
++
++ pkg = pk_backend_find_pkg (self, *packages, &error);
++ if (pkg == NULL) {
++ break;
++ }
++
++ pkgs = alpm_list_add (pkgs, pkg);
++ }
++
++ /* package list might be modified along the way but that is ok */
++ for (i = pkgs; i != NULL; i = i->next) {
++ alpm_list_t *requiredby;
++
++ if (pk_backend_cancelled (self) || error != NULL) {
++ break;
++ }
++
++ requiredby = alpm_pkg_compute_requiredby (i->data);
++ for (; requiredby != NULL; requiredby = requiredby->next) {
++ if (pk_backend_cancelled (self) || error != NULL) {
++ break;
++ }
++
++ pkgs = pk_backend_find_requirer (self, pkgs,
++ requiredby->data,
++ &error);
++ }
++
++ FREELIST (requiredby);
++ }
++
++ alpm_list_free (pkgs);
++ return pk_backend_finish (self, error);
++}
++
++void
++pk_backend_get_depends (PkBackend *self, PkBitfield filters,
++ gchar **package_ids, gboolean recursive)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (package_ids != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY,
++ pk_backend_get_depends_thread);
++}
++
++void
++pk_backend_get_requires (PkBackend *self, PkBitfield filters,
++ gchar **package_ids, gboolean recursive)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (package_ids != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY,
++ pk_backend_get_requires_thread);
++}
+diff --git a/backends/alpm/pk-backend-depends.h b/backends/alpm/pk-backend-depends.h
+new file mode 100644
+index 0000000..368965a
+--- /dev/null
++++ b/backends/alpm/pk-backend-depends.h
+@@ -0,0 +1,22 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
+diff --git a/backends/alpm/pk-backend-error.c b/backends/alpm/pk-backend-error.c
+new file mode 100644
+index 0000000..6383175
+--- /dev/null
++++ b/backends/alpm/pk-backend-error.c
+@@ -0,0 +1,203 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alpm.h>
++
++#include "pk-backend-error.h"
++
++static void
++pk_backend_output_locked (PkBackend *self)
++{
++ gchar *output;
++
++ g_return_if_fail (self != NULL);
++
++ output = g_strdup_printf ("If you are certain no other package manager "
++ "is running, you can remove %s\n",
++ alpm_option_get_lockfile ());
++ pk_backend_output (self, output);
++ g_free (output);
++}
++
++void
++pk_backend_error (PkBackend *self, GError *error)
++{
++ PkErrorEnum code = PK_ERROR_ENUM_UNKNOWN;
++
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (error != NULL);
++
++ if (error->domain == ALPM_ERROR) {
++ switch (error->code) {
++ case PM_ERR_MEMORY:
++ case PM_ERR_SYSTEM:
++ code = PK_ERROR_ENUM_OOM;
++ break;
++
++ case PM_ERR_BADPERMS:
++ code = PK_ERROR_ENUM_NOT_AUTHORIZED;
++ break;
++
++ case PM_ERR_NOT_A_FILE:
++ case PM_ERR_NOT_A_DIR:
++ code = PK_ERROR_ENUM_FILE_NOT_FOUND;
++ break;
++
++ case PM_ERR_WRONG_ARGS:
++ case PM_ERR_HANDLE_NULL:
++ case PM_ERR_DB_NULL:
++ case PM_ERR_TRANS_NULL:
++ case PM_ERR_TRANS_NOT_INITIALIZED:
++ case PM_ERR_TRANS_NOT_PREPARED:
++ case PM_ERR_TRANS_NOT_LOCKED:
++ case PM_ERR_INVALID_REGEX:
++ code = PK_ERROR_ENUM_INTERNAL_ERROR;
++ break;
++
++ case PM_ERR_DISK_SPACE:
++ code = PK_ERROR_ENUM_NO_SPACE_ON_DEVICE;
++ break;
++
++ case PM_ERR_HANDLE_NOT_NULL:
++ case PM_ERR_DB_NOT_NULL:
++ case PM_ERR_TRANS_NOT_NULL:
++ code = PK_ERROR_ENUM_FAILED_INITIALIZATION;
++ break;
++
++ case PM_ERR_HANDLE_LOCK:
++ code = PK_ERROR_ENUM_CANNOT_GET_LOCK;
++ pk_backend_output_locked (self);
++ break;
++
++ case PM_ERR_DB_OPEN:
++ case PM_ERR_DB_NOT_FOUND:
++ case PM_ERR_PKG_REPO_NOT_FOUND:
++ code = PK_ERROR_ENUM_REPO_NOT_FOUND;
++ break;
++
++ case PM_ERR_DB_CREATE:
++ code = PK_ERROR_ENUM_CANNOT_WRITE_REPO_CONFIG;
++ break;
++
++ case PM_ERR_DB_VERSION:
++ case PM_ERR_DB_REMOVE:
++ code = PK_ERROR_ENUM_REPO_CONFIGURATION_ERROR;
++ break;
++
++ case PM_ERR_DB_WRITE:
++ code = PK_ERROR_ENUM_REPO_NOT_AVAILABLE;
++ break;
++
++ case PM_ERR_SERVER_BAD_URL:
++ code = PK_ERROR_ENUM_REPO_CONFIGURATION_ERROR;
++ break;
++
++ case PM_ERR_SERVER_NONE:
++ code = PK_ERROR_ENUM_NO_MORE_MIRRORS_TO_TRY;
++ break;
++
++ case PM_ERR_TRANS_DUP_TARGET:
++ case PM_ERR_TRANS_ABORT:
++ code = PK_ERROR_ENUM_TRANSACTION_ERROR;
++ break;
++
++ case PM_ERR_TRANS_TYPE:
++ code = PK_ERROR_ENUM_CANNOT_CANCEL;
++ break;
++
++ case PM_ERR_PKG_NOT_FOUND:
++ code = PK_ERROR_ENUM_PACKAGE_NOT_FOUND;
++ break;
++
++ case PM_ERR_PKG_IGNORED:
++ code = PK_ERROR_ENUM_PACKAGE_INSTALL_BLOCKED;
++ break;
++
++ case PM_ERR_PKG_INVALID:
++ case PM_ERR_PKG_OPEN:
++ case PM_ERR_PKG_INVALID_NAME:
++ case PM_ERR_DLT_INVALID:
++ code = PK_ERROR_ENUM_INVALID_PACKAGE_FILE;
++ break;
++
++ case PM_ERR_PKG_CANT_REMOVE:
++ code = PK_ERROR_ENUM_PACKAGE_FAILED_TO_REMOVE;
++ break;
++
++ case PM_ERR_PKG_INVALID_ARCH:
++ code = PK_ERROR_ENUM_INCOMPATIBLE_ARCHITECTURE;
++ break;
++
++ case PM_ERR_DLT_PATCHFAILED:
++ code = PK_ERROR_ENUM_PACKAGE_FAILED_TO_BUILD;
++ break;
++
++ case PM_ERR_UNSATISFIED_DEPS:
++ code = PK_ERROR_ENUM_DEP_RESOLUTION_FAILED;
++ break;
++
++ case PM_ERR_CONFLICTING_DEPS:
++ code = PK_ERROR_ENUM_PACKAGE_CONFLICTS;
++ break;
++
++ case PM_ERR_FILE_CONFLICTS:
++ code = PK_ERROR_ENUM_FILE_CONFLICTS;
++ break;
++
++ case PM_ERR_RETRIEVE:
++ case PM_ERR_LIBFETCH:
++ case PM_ERR_EXTERNAL_DOWNLOAD:
++ code = PK_ERROR_ENUM_PACKAGE_DOWNLOAD_FAILED;
++ break;
++
++ case PM_ERR_LIBARCHIVE:
++ code = PK_ERROR_ENUM_LOCAL_INSTALL_FAILED;
++ break;
++
++ case PM_ERR_CONFIG_INVALID:
++ code = PK_ERROR_ENUM_CANNOT_REMOVE_SYSTEM_PACKAGE;
++ break;
++
++ case PM_ERR_PKG_HELD:
++ code = PK_ERROR_ENUM_CANNOT_REMOVE_SYSTEM_PACKAGE;
++ break;
++ }
++ }
++
++ pk_backend_error_code (self, code, "%s", error->message);
++}
++
++void
++pk_backend_output (PkBackend *self, const gchar *output)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (output != NULL);
++
++ pk_backend_message (self, PK_MESSAGE_ENUM_UNKNOWN, "%s", output);
++}
++
++GQuark
++alpm_error_quark (void)
++{
++ return g_quark_from_static_string ("alpm-error-quark");
++}
+diff --git a/backends/alpm/pk-backend-error.h b/backends/alpm/pk-backend-error.h
+new file mode 100644
+index 0000000..b01b06d
+--- /dev/null
++++ b/backends/alpm/pk-backend-error.h
+@@ -0,0 +1,37 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <pk-backend.h>
++
++#define ALPM_ERROR (alpm_error_quark ())
++
++enum {
++ PM_ERR_CONFIG_INVALID = 0x10000,
++ PM_ERR_PKG_HELD
++};
++
++void pk_backend_error (PkBackend *self, GError *error);
++
++void pk_backend_output (PkBackend *self, const gchar *output);
++
++GQuark alpm_error_quark (void);
+diff --git a/backends/alpm/pk-backend-groups.c b/backends/alpm/pk-backend-groups.c
+new file mode 100644
+index 0000000..59e304d
+--- /dev/null
++++ b/backends/alpm/pk-backend-groups.c
+@@ -0,0 +1,153 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <gio/gio.h>
++#include <string.h>
++
++#include "pk-backend-groups.h"
++
++static GHashTable *grps = NULL;
++static PkBitfield groups = 0;
++
++static GHashTable *
++group_map_new (GError **error)
++{
++ GHashTable *map;
++ GFile *file;
++
++ GFileInputStream *is;
++ GDataInputStream *input;
++
++ GError *e = NULL;
++
++ g_debug ("reading group map from %s", PK_BACKEND_GROUP_FILE);
++ file = g_file_new_for_path (PK_BACKEND_GROUP_FILE);
++ is = g_file_read (file, NULL, &e);
++
++ if (is == NULL) {
++ g_object_unref (file);
++ g_propagate_error (error, e);
++ return NULL;
++ }
++
++ map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
++ input = g_data_input_stream_new (G_INPUT_STREAM (is));
++
++ /* read groups line by line, ignoring comments */
++ while (TRUE) {
++ PkGroupEnum group;
++ gchar *key, *value;
++
++ value = g_data_input_stream_read_line (input, NULL, NULL, &e);
++
++ if (value != NULL) {
++ g_strstrip (value);
++ } else {
++ break;
++ }
++
++ if (*value == '\0' || *value == '#') {
++ g_free (value);
++ continue;
++ }
++
++ /* line format: grp (space|tab)+ group */
++ key = strsep (&value, " ");
++ g_strchomp (key);
++
++ if (value == NULL) {
++ /* safe to cast as it is never freed or modified */
++ value = (gchar *) "other";
++ group = PK_GROUP_ENUM_OTHER;
++ } else {
++ g_strchug (value);
++ group = pk_group_enum_from_string (value);
++ }
++
++ if (group != PK_GROUP_ENUM_UNKNOWN) {
++ /* key and value are allocated together */
++ g_hash_table_replace (map, key, value);
++ pk_bitfield_add (groups, group);
++ }
++ }
++
++ g_object_unref (input);
++ g_object_unref (is);
++ g_object_unref (file);
++
++ if (e != NULL) {
++ g_hash_table_unref (map);
++ g_propagate_error (error, e);
++ return NULL;
++ } else {
++ return map;
++ }
++}
++
++gboolean
++pk_backend_initialize_groups (PkBackend *self, GError **error)
++{
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ grps = group_map_new (error);
++
++ return (grps != NULL);
++}
++
++void
++pk_backend_destroy_groups (PkBackend *self)
++{
++ g_return_if_fail (self != NULL);
++
++ if (grps != NULL) {
++ g_hash_table_unref (grps);
++ }
++}
++
++const gchar *
++alpm_pkg_get_group (pmpkg_t *pkg)
++{
++ const alpm_list_t *i;
++
++ g_return_val_if_fail (pkg != NULL, NULL);
++ g_return_val_if_fail (grps != NULL, NULL);
++
++ /* use the first group that we recognise */
++ for (i = alpm_pkg_get_groups (pkg); i != NULL; i = i->next) {
++ gpointer value = g_hash_table_lookup (grps, i->data);
++
++ if (value != NULL) {
++ return (const gchar *) value;
++ }
++ }
++
++ return "other";
++}
++
++PkBitfield
++pk_backend_get_groups (PkBackend *self)
++{
++ g_return_val_if_fail (self != NULL, 0);
++
++ return groups;
++}
+diff --git a/backends/alpm/pk-backend-groups.h b/backends/alpm/pk-backend-groups.h
+new file mode 100644
+index 0000000..28dcf65
+--- /dev/null
++++ b/backends/alpm/pk-backend-groups.h
+@@ -0,0 +1,32 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alpm.h>
++#include <pk-backend.h>
++
++gboolean pk_backend_initialize_groups (PkBackend *self,
++ GError **error);
++
++void pk_backend_destroy_groups (PkBackend *self);
++
++const gchar *alpm_pkg_get_group (pmpkg_t *pkg);
+diff --git a/backends/alpm/pk-backend-install.c b/backends/alpm/pk-backend-install.c
+new file mode 100644
+index 0000000..65a6c11
+--- /dev/null
++++ b/backends/alpm/pk-backend-install.c
+@@ -0,0 +1,124 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alpm.h>
++#include <pk-backend.h>
++
++#include "pk-backend-alpm.h"
++#include "pk-backend-error.h"
++#include "pk-backend-install.h"
++#include "pk-backend-transaction.h"
++
++static gint
++alpm_add_file (const gchar *filename)
++{
++ pmpkg_t *pkg;
++
++ g_return_val_if_fail (filename != NULL, -1);
++
++ if (alpm_pkg_load (filename, 1, &pkg) < 0) {
++ return -1;
++ }
++
++ if (alpm_add_pkg (pkg) < 0) {
++ alpm_pkg_free (pkg);
++ return -1;
++ }
++
++ return 0;
++}
++
++static gboolean
++pk_backend_transaction_add_targets (PkBackend *self, GError **error)
++{
++ gchar **paths;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ paths = pk_backend_get_strv (self, "full_paths");
++
++ g_return_val_if_fail (paths != NULL, FALSE);
++
++ for (; *paths != NULL; ++paths) {
++ if (alpm_add_file (*paths) < 0) {
++ g_set_error (error, ALPM_ERROR, pm_errno, "%s: %s",
++ *paths, alpm_strerrorlast ());
++ return FALSE;
++ }
++ }
++
++ return TRUE;
++}
++
++static gboolean
++pk_backend_simulate_install_files_thread (PkBackend *self)
++{
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ if (pk_backend_transaction_initialize (self, 0, &error) &&
++ pk_backend_transaction_add_targets (self, &error) &&
++ pk_backend_transaction_simulate (self, &error)) {
++ pk_backend_transaction_packages (self);
++ }
++
++ return pk_backend_transaction_finish (self, error);
++}
++
++static gboolean
++pk_backend_install_files_thread (PkBackend *self)
++{
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ if (pk_backend_transaction_initialize (self, 0, &error) &&
++ pk_backend_transaction_add_targets (self, &error) &&
++ pk_backend_transaction_simulate (self, &error)) {
++ pk_backend_transaction_commit (self, &error);
++ }
++
++ return pk_backend_transaction_finish (self, error);
++}
++
++void
++pk_backend_simulate_install_files (PkBackend *self, gchar **paths)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (paths != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_SETUP,
++ pk_backend_simulate_install_files_thread);
++}
++
++void
++pk_backend_install_files (PkBackend *self, gboolean only_trusted,
++ gchar **full_paths)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (full_paths != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_SETUP,
++ pk_backend_install_files_thread);
++}
+diff --git a/backends/alpm/pk-backend-install.h b/backends/alpm/pk-backend-install.h
+new file mode 100644
+index 0000000..368965a
+--- /dev/null
++++ b/backends/alpm/pk-backend-install.h
+@@ -0,0 +1,22 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
+diff --git a/backends/alpm/pk-backend-packages.c b/backends/alpm/pk-backend-packages.c
+new file mode 100644
+index 0000000..e9a7c94
+--- /dev/null
++++ b/backends/alpm/pk-backend-packages.c
+@@ -0,0 +1,363 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include "pk-backend-alpm.h"
++#include "pk-backend-error.h"
++#include "pk-backend-groups.h"
++#include "pk-backend-packages.h"
++
++gchar *
++alpm_pkg_build_id (pmpkg_t *pkg)
++{
++ const gchar *name, *version, *arch, *repo;
++ pmdb_t *db;
++
++ g_return_val_if_fail (pkg != NULL, NULL);
++ g_return_val_if_fail (localdb != NULL, NULL);
++
++ name = alpm_pkg_get_name (pkg);
++ version = alpm_pkg_get_version (pkg);
++
++ arch = alpm_pkg_get_arch (pkg);
++ if (arch == NULL) {
++ arch = "any";
++ }
++
++ db = alpm_pkg_get_db (pkg);
++ /* TODO: check */
++ if (db == NULL || db == localdb) {
++ repo = "installed";
++ } else {
++ repo = alpm_db_get_name (db);
++ }
++
++ return pk_package_id_build (name, version, arch, repo);
++}
++
++void
++pk_backend_pkg (PkBackend *self, pmpkg_t *pkg, PkInfoEnum info)
++{
++ gchar *package;
++
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (pkg != NULL);
++
++ package = alpm_pkg_build_id (pkg);
++ pk_backend_package (self, info, package, alpm_pkg_get_desc (pkg));
++ g_free (package);
++}
++
++pmpkg_t *
++pk_backend_find_pkg (PkBackend *self, const gchar *package_id, GError **error)
++{
++ gchar **package;
++ const gchar *repo_id;
++ pmdb_t *db = NULL;
++ pmpkg_t *pkg;
++
++ g_return_val_if_fail (self != NULL, NULL);
++ g_return_val_if_fail (package_id != NULL, NULL);
++ g_return_val_if_fail (localdb != NULL, NULL);
++
++ package = pk_package_id_split (package_id);
++ repo_id = package[PK_PACKAGE_ID_DATA];
++
++ /* find the database to search in */
++ if (g_strcmp0 (repo_id, "installed") == 0) {
++ db = localdb;
++ } else {
++ const alpm_list_t *i;
++ for (i = alpm_option_get_syncdbs (); i != NULL; i = i->next) {
++ const gchar *repo = alpm_db_get_name (i->data);
++
++ if (g_strcmp0 (repo, repo_id) == 0) {
++ db = i->data;
++ break;
++ }
++ }
++ }
++
++ if (db != NULL) {
++ pkg = alpm_db_get_pkg (db, package[PK_PACKAGE_ID_NAME]);
++ } else {
++ pkg = NULL;
++ }
++
++ if (pkg != NULL) {
++ const gchar *version = alpm_pkg_get_version (pkg);
++ if (g_strcmp0 (version, package[PK_PACKAGE_ID_VERSION]) != 0) {
++ pkg = NULL;
++ }
++ }
++
++ if (pkg == NULL) {
++ int code = PM_ERR_PKG_NOT_FOUND;
++ g_set_error (error, ALPM_ERROR, code, "%s: %s", package_id,
++ alpm_strerror (code));
++ }
++ g_strfreev (package);
++ return pkg;
++}
++
++static gboolean
++pk_backend_resolve_package (PkBackend *self, const gchar *package,
++ GError **error)
++{
++ pmpkg_t *pkg;
++
++ PkBitfield filters;
++ gboolean skip_local, skip_remote;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (package != NULL, FALSE);
++ g_return_val_if_fail (localdb != NULL, FALSE);
++
++ pkg = pk_backend_find_pkg (self, package, error);
++ if (pkg == NULL) {
++ return FALSE;
++ }
++
++ filters = pk_backend_get_uint (self, "filters");
++ skip_local = pk_bitfield_contain (filters,
++ PK_FILTER_ENUM_NOT_INSTALLED);
++ skip_remote = pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED);
++
++ if (alpm_pkg_get_db (pkg) == localdb) {
++ if (!skip_local) {
++ pk_backend_pkg (self, pkg, PK_INFO_ENUM_INSTALLED);
++ }
++ } else {
++ if (!skip_remote) {
++ pk_backend_pkg (self, pkg, PK_INFO_ENUM_AVAILABLE);
++ }
++ }
++
++ return TRUE;
++}
++
++static gboolean
++pk_backend_resolve_name (PkBackend *self, const gchar *name, GError **error)
++{
++ pmpkg_t *pkg;
++ int code;
++
++ PkBitfield filters;
++ gboolean skip_local, skip_remote;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (name != NULL, FALSE);
++ g_return_val_if_fail (localdb != NULL, FALSE);
++
++ filters = pk_backend_get_uint (self, "filters");
++ skip_local = pk_bitfield_contain (filters,
++ PK_FILTER_ENUM_NOT_INSTALLED);
++ skip_remote = pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED);
++
++ pkg = alpm_db_get_pkg (localdb, name);
++ if (pkg != NULL) {
++ if (!skip_local) {
++ pk_backend_pkg (self, pkg, PK_INFO_ENUM_INSTALLED);
++ return TRUE;
++ }
++ } else if (!skip_remote) {
++ const alpm_list_t *i;
++ for (i = alpm_option_get_syncdbs (); i != NULL; i = i->next) {
++ pkg = alpm_db_get_pkg (i->data, name);
++ if (pkg != NULL) {
++ pk_backend_pkg (self, pkg,
++ PK_INFO_ENUM_AVAILABLE);
++ return TRUE;
++ }
++ }
++ }
++
++ code = PM_ERR_PKG_NOT_FOUND;
++ g_set_error (error, ALPM_ERROR, code, "%s: %s", name,
++ alpm_strerror (code));
++ return FALSE;
++}
++
++static gboolean
++pk_backend_resolve_thread (PkBackend *self)
++{
++ gchar **packages;
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ packages = pk_backend_get_strv (self, "package_ids");
++
++ g_return_val_if_fail (packages != NULL, FALSE);
++
++ for (; *packages != NULL; ++packages) {
++ if (pk_backend_cancelled (self)) {
++ break;
++ }
++
++ /* find a package with the given id or name */
++ if (pk_package_id_check (*packages)) {
++ if (!pk_backend_resolve_package (self, *packages,
++ &error)) {
++ break;
++ }
++ } else {
++ if (!pk_backend_resolve_name (self, *packages,
++ &error)) {
++ break;
++ }
++ }
++ }
++
++ return pk_backend_finish (self, error);
++}
++
++void
++pk_backend_resolve (PkBackend *self, PkBitfield filters, gchar **package_ids)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (package_ids != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY, pk_backend_resolve_thread);
++}
++
++static gboolean
++pk_backend_get_details_thread (PkBackend *self)
++{
++ gchar **packages;
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (localdb != NULL, FALSE);
++
++ packages = pk_backend_get_strv (self, "package_ids");
++
++ g_return_val_if_fail (packages != NULL, FALSE);
++
++ for (; *packages != NULL; ++packages) {
++ pmpkg_t *pkg;
++ const alpm_list_t *i;
++
++ GString *licenses;
++ PkGroupEnum group;
++ const gchar *desc, *url;
++ gulong size;
++
++ if (pk_backend_cancelled (self)) {
++ break;
++ }
++
++ pkg = pk_backend_find_pkg (self, *packages, &error);
++ if (pkg == NULL) {
++ break;
++ }
++
++ licenses = g_string_new ("");
++ i = alpm_pkg_get_licenses (pkg);
++ for (; i != NULL; i = i->next) {
++ /* assume OR although it may not be correct */
++ g_string_append_printf (licenses, " or %s",
++ (const gchar *) i->data);
++ }
++ if (licenses->len == 0) {
++ g_string_append (licenses, " or Unknown");
++ }
++
++ group = pk_group_enum_from_string (alpm_pkg_get_group (pkg));
++ desc = alpm_pkg_get_desc (pkg);
++ url = alpm_pkg_get_url (pkg);
++
++ if (alpm_pkg_get_db (pkg) == localdb) {
++ size = alpm_pkg_get_isize (pkg);
++ } else {
++ size = alpm_pkg_download_size (pkg);
++ }
++
++ pk_backend_details (self, *packages, licenses->str + 4, group,
++ desc, url, size);
++ g_string_free (licenses, TRUE);
++ }
++
++ return pk_backend_finish (self, error);
++}
++
++void
++pk_backend_get_details (PkBackend *self, gchar **package_ids)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (package_ids != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY,
++ pk_backend_get_details_thread);
++}
++
++static gboolean
++pk_backend_get_files_thread (PkBackend *self)
++{
++ gchar **packages;
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ packages = pk_backend_get_strv (self, "package_ids");
++
++ g_return_val_if_fail (packages != NULL, FALSE);
++
++ for (; *packages != NULL; ++packages) {
++ pmpkg_t *pkg;
++ const alpm_list_t *i;
++
++ GString *files;
++ const gchar *root;
++
++ if (pk_backend_cancelled (self)) {
++ break;
++ }
++
++ pkg = pk_backend_find_pkg (self, *packages, &error);
++ if (pkg == NULL) {
++ break;
++ }
++
++ files = g_string_new ("");
++ root = alpm_option_get_root ();
++ for (i = alpm_pkg_get_files (pkg); i != NULL; i = i->next) {
++ g_string_append_printf (files, ";%s%s", root,
++ (const gchar *) i->data);
++ }
++
++ pk_backend_files (self, *packages, files->str + 1);
++ g_string_free (files, TRUE);
++ }
++
++ return pk_backend_finish (self, error);
++}
++
++void
++pk_backend_get_files (PkBackend *self, gchar **package_ids)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (package_ids != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY,
++ pk_backend_get_files_thread);
++}
+diff --git a/backends/alpm/pk-backend-packages.h b/backends/alpm/pk-backend-packages.h
+new file mode 100644
+index 0000000..4b2d7f8
+--- /dev/null
++++ b/backends/alpm/pk-backend-packages.h
+@@ -0,0 +1,33 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alpm.h>
++#include <pk-backend.h>
++
++gchar *alpm_pkg_build_id (pmpkg_t *pkg);
++
++void pk_backend_pkg (PkBackend *self, pmpkg_t *pkg,
++ PkInfoEnum info);
++
++pmpkg_t *pk_backend_find_pkg (PkBackend *self, const gchar *package_id,
++ GError **error);
+diff --git a/backends/alpm/pk-backend-remove.c b/backends/alpm/pk-backend-remove.c
+new file mode 100644
+index 0000000..03329b1
+--- /dev/null
++++ b/backends/alpm/pk-backend-remove.c
+@@ -0,0 +1,167 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alpm.h>
++#include <pk-backend.h>
++
++#include "pk-backend-alpm.h"
++#include "pk-backend-error.h"
++#include "pk-backend-remove.h"
++#include "pk-backend-transaction.h"
++
++static gint
++alpm_remove_local (const gchar *name)
++{
++ pmpkg_t *pkg;
++
++ g_return_val_if_fail (name != NULL, -1);
++ g_return_val_if_fail (localdb != NULL, -1);
++
++ pkg = alpm_db_get_pkg (localdb, name);
++ if (pkg == NULL) {
++ pm_errno = PM_ERR_PKG_NOT_FOUND;
++ return -1;
++ }
++
++ return alpm_remove_pkg (pkg);
++}
++
++static gboolean
++pk_backend_transaction_remove_targets (PkBackend *self, GError **error)
++{
++ gchar **packages;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ packages = pk_backend_get_strv (self, "package_ids");
++
++ g_return_val_if_fail (packages != NULL, FALSE);
++
++ for (; *packages != NULL; ++packages) {
++ gchar **package = pk_package_id_split (*packages);
++ gchar *name = package[PK_PACKAGE_ID_NAME];
++
++ if (alpm_remove_local (name) < 0) {
++ g_set_error (error, ALPM_ERROR, pm_errno, "%s: %s",
++ name, alpm_strerrorlast ());
++ g_strfreev (package);
++ return FALSE;
++ }
++
++ g_strfreev (package);
++ }
++
++ return TRUE;
++}
++
++static gboolean
++pk_backend_transaction_remove_simulate (PkBackend *self, GError **error)
++{
++ const alpm_list_t *i;
++
++ if (!pk_backend_transaction_simulate (self, error)) {
++ return FALSE;
++ }
++
++ for (i = alpm_trans_get_remove (); i != NULL; i = i->next) {
++ const gchar *name = alpm_pkg_get_name (i->data);
++ if (alpm_list_find_str (holdpkgs, name)) {
++ g_set_error (error, ALPM_ERROR, PM_ERR_PKG_HELD,
++ "%s: %s", name,
++ "could not remove HoldPkg");
++ return FALSE;
++ }
++ }
++
++ return TRUE;
++}
++
++static gboolean
++pk_backend_simulate_remove_packages_thread (PkBackend *self)
++{
++ pmtransflag_t flags = PM_TRANS_FLAG_CASCADE;
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ /* remove unneeded packages that were required by those to be removed */
++ if (pk_backend_get_bool (self, "autoremove")) {
++ flags |= PM_TRANS_FLAG_RECURSE;
++ }
++
++ if (pk_backend_transaction_initialize (self, flags, &error) &&
++ pk_backend_transaction_remove_targets (self, &error) &&
++ pk_backend_transaction_remove_simulate (self, &error)) {
++ pk_backend_transaction_packages (self);
++ }
++
++ return pk_backend_transaction_finish (self, error);
++}
++
++static gboolean
++pk_backend_remove_packages_thread (PkBackend *self)
++{
++ pmtransflag_t flags = 0;
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ /* remove packages that depend on those to be removed */
++ if (pk_backend_get_bool (self, "allow_deps")) {
++ flags |= PM_TRANS_FLAG_CASCADE;
++ }
++ /* remove unneeded packages that were required by those to be removed */
++ if (pk_backend_get_bool (self, "autoremove")) {
++ flags |= PM_TRANS_FLAG_RECURSE;
++ }
++
++ if (pk_backend_transaction_initialize (self, flags, &error) &&
++ pk_backend_transaction_remove_targets (self, &error) &&
++ pk_backend_transaction_remove_simulate (self, &error)) {
++ pk_backend_transaction_commit (self, &error);
++ }
++
++ return pk_backend_transaction_finish (self, error);
++}
++
++void
++pk_backend_simulate_remove_packages (PkBackend *self, gchar **package_ids,
++ gboolean autoremove)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (package_ids != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_SETUP,
++ pk_backend_simulate_remove_packages_thread);
++}
++
++void
++pk_backend_remove_packages (PkBackend *self, gchar **package_ids,
++ gboolean allow_deps, gboolean autoremove)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (package_ids != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_SETUP,
++ pk_backend_remove_packages_thread);
++}
+diff --git a/backends/alpm/pk-backend-remove.h b/backends/alpm/pk-backend-remove.h
+new file mode 100644
+index 0000000..368965a
+--- /dev/null
++++ b/backends/alpm/pk-backend-remove.h
+@@ -0,0 +1,22 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
+diff --git a/backends/alpm/pk-backend-search.c b/backends/alpm/pk-backend-search.c
+new file mode 100644
+index 0000000..592472d
+--- /dev/null
++++ b/backends/alpm/pk-backend-search.c
+@@ -0,0 +1,450 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alpm.h>
++#include <pk-backend.h>
++#include <string.h>
++
++#include "pk-backend-alpm.h"
++#include "pk-backend-groups.h"
++#include "pk-backend-packages.h"
++#include "pk-backend-search.h"
++
++static gpointer
++pk_backend_pattern_needle (const gchar *needle, GError **error)
++{
++ return (gpointer) needle;
++}
++
++static gpointer
++pk_backend_pattern_regex (const gchar *needle, GError **error)
++{
++ gchar *pattern;
++ GRegex *regex;
++
++ g_return_val_if_fail (needle != NULL, NULL);
++
++ pattern = g_regex_escape_string (needle, -1);
++ regex = g_regex_new (pattern, G_REGEX_CASELESS, 0, error);
++ g_free (pattern);
++
++ return regex;
++}
++
++static gpointer
++pk_backend_pattern_chroot (const gchar *needle, GError **error)
++{
++ g_return_val_if_fail (needle != NULL, NULL);
++
++ if (G_IS_DIR_SEPARATOR (*needle)) {
++ const gchar *file = needle, *root = alpm_option_get_root ();
++
++ /* adjust needle to the correct prefix */
++ for (; *file == *root; ++file, ++root) {
++ if (*root == '\0') {
++ needle = file - 1;
++ break;
++ } else if (*file == '\0') {
++ break;
++ }
++ }
++ }
++
++ return (gpointer) needle;
++}
++
++static gboolean
++pk_backend_match_all (pmpkg_t *pkg, gpointer pattern)
++{
++ g_return_val_if_fail (pkg != NULL, FALSE);
++ g_return_val_if_fail (pattern != NULL, FALSE);
++
++ /* match all packages */
++ return TRUE;
++}
++
++static gboolean
++pk_backend_match_details (pmpkg_t *pkg, GRegex *regex)
++{
++ const gchar *desc;
++ pmdb_t *db;
++ const alpm_list_t *i;
++
++ g_return_val_if_fail (pkg != NULL, FALSE);
++ g_return_val_if_fail (regex != NULL, FALSE);
++
++ /* match the name first... */
++ if (g_regex_match (regex, alpm_pkg_get_name (pkg), 0, NULL)) {
++ return TRUE;
++ }
++
++ /* ... then the description... */
++ desc = alpm_pkg_get_desc (pkg);
++ if (desc != NULL && g_regex_match (regex, desc, 0, NULL)) {
++ return TRUE;
++ }
++
++ /* ... then the database... */
++ db = alpm_pkg_get_db (pkg);
++ if (db != NULL && g_regex_match (regex, alpm_db_get_name (db),
++ G_REGEX_MATCH_ANCHORED, NULL)) {
++ return TRUE;
++ }
++
++ /* ... then the licenses */
++ for (i = alpm_pkg_get_licenses (pkg); i != NULL; i = i->next) {
++ if (g_regex_match (regex, i->data, G_REGEX_MATCH_ANCHORED,
++ NULL)) {
++ return TRUE;
++ }
++ }
++
++ return FALSE;
++}
++
++static gboolean
++pk_backend_match_file (pmpkg_t *pkg, const gchar *needle)
++{
++ const alpm_list_t *i;
++
++ g_return_val_if_fail (pkg != NULL, FALSE);
++ g_return_val_if_fail (needle != NULL, FALSE);
++
++ /* match any file the package contains */
++ if (G_IS_DIR_SEPARATOR (*needle)) {
++ for (i = alpm_pkg_get_files (pkg); i != NULL; i = i->next) {
++ /* match the full path of file */
++ if (g_strcmp0 (i->data, needle + 1) == 0) {
++ return TRUE;
++ }
++ }
++ } else {
++ for (i = alpm_pkg_get_files (pkg); i != NULL; i = i->next) {
++ const gchar *file = strrchr (i->data, G_DIR_SEPARATOR);
++ if (file == NULL) {
++ file = i->data;
++ } else {
++ ++file;
++ }
++
++ /* match the basename of file */
++ if (g_strcmp0 (file, needle) == 0) {
++ return TRUE;
++ }
++ }
++ }
++
++ return FALSE;
++}
++
++static gboolean
++pk_backend_match_group (pmpkg_t *pkg, const gchar *needle)
++{
++ g_return_val_if_fail (pkg != NULL, FALSE);
++ g_return_val_if_fail (needle != NULL, FALSE);
++
++ /* match the group the package is in */
++ return g_strcmp0 (needle, alpm_pkg_get_group (pkg)) == 0;
++}
++
++static gboolean
++pk_backend_match_name (pmpkg_t *pkg, GRegex *regex)
++{
++ g_return_val_if_fail (pkg != NULL, FALSE);
++ g_return_val_if_fail (regex != NULL, FALSE);
++
++ /* match the name of the package */
++ return g_regex_match (regex, alpm_pkg_get_name (pkg), 0, NULL);
++}
++
++static gboolean
++pk_backend_match_provides (pmpkg_t *pkg, gpointer pattern)
++{
++ /* TODO: implement GStreamer codecs, Pango fonts, etc. */
++ const alpm_list_t *i;
++
++ g_return_val_if_fail (pkg != NULL, FALSE);
++ g_return_val_if_fail (pattern != NULL, FALSE);
++
++ /* match features provided by package */
++ for (i = alpm_pkg_get_provides (pkg); i != NULL; i = i->next) {
++ const gchar *needle = pattern, *name = i->data;
++
++ for (; *needle == *name; ++needle, ++name) {
++ if (*needle == '\0') {
++ if (*name == '\0' || *name == '=') {
++ return TRUE;
++ } else {
++ break;
++ }
++ }
++ }
++ }
++
++ return FALSE;
++}
++
++typedef enum {
++ SEARCH_TYPE_ALL,
++ SEARCH_TYPE_DETAILS,
++ SEARCH_TYPE_FILES,
++ SEARCH_TYPE_GROUP,
++ SEARCH_TYPE_NAME,
++ SEARCH_TYPE_PROVIDES,
++ SEARCH_TYPE_LAST
++} SearchType;
++
++typedef gpointer (*PatternFunc) (const gchar *needle, GError **error);
++typedef gboolean (*MatchFunc) (pmpkg_t *pkg, gpointer pattern);
++
++static PatternFunc pattern_funcs[] = {
++ pk_backend_pattern_needle,
++ pk_backend_pattern_regex,
++ pk_backend_pattern_chroot,
++ pk_backend_pattern_needle,
++ pk_backend_pattern_regex,
++ pk_backend_pattern_needle
++};
++
++static GDestroyNotify pattern_frees[] = {
++ NULL,
++ (GDestroyNotify) g_regex_unref,
++ NULL,
++ NULL,
++ (GDestroyNotify) g_regex_unref,
++ NULL
++};
++
++static MatchFunc match_funcs[] = {
++ pk_backend_match_all,
++ (MatchFunc) pk_backend_match_details,
++ (MatchFunc) pk_backend_match_file,
++ (MatchFunc) pk_backend_match_group,
++ (MatchFunc) pk_backend_match_name,
++ pk_backend_match_provides
++};
++
++static gboolean
++alpm_pkg_is_local (pmpkg_t *pkg)
++{
++ pmpkg_t *local;
++
++ g_return_val_if_fail (pkg != NULL, FALSE);
++ g_return_val_if_fail (localdb != NULL, FALSE);
++
++ /* find an installed package with the same name */
++ local = alpm_db_get_pkg (localdb, alpm_pkg_get_name (pkg));
++ if (local == NULL) {
++ return FALSE;
++ }
++
++ /* make sure the installed version is the same */
++ if (alpm_pkg_vercmp (alpm_pkg_get_version (local),
++ alpm_pkg_get_version (pkg)) != 0) {
++ return FALSE;
++ }
++
++ /* make sure the installed arch is the same */
++ if (g_strcmp0 (alpm_pkg_get_arch (local),
++ alpm_pkg_get_arch (pkg)) != 0) {
++ return FALSE;
++ }
++
++ return TRUE;
++}
++
++static void
++pk_backend_search_db (PkBackend *self, pmdb_t *db, MatchFunc match,
++ const alpm_list_t *patterns)
++{
++ const alpm_list_t *i, *j;
++
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (db != NULL);
++ g_return_if_fail (match != NULL);
++
++ /* emit packages that match all search terms */
++ for (i = alpm_db_get_pkgcache (db); i != NULL; i = i->next) {
++ if (pk_backend_cancelled (self)) {
++ break;
++ }
++
++ for (j = patterns; j != NULL; j = j->next) {
++ if (!match (i->data, j->data)) {
++ break;
++ }
++ }
++
++ /* all search terms matched */
++ if (j == NULL) {
++ if (db == localdb) {
++ pk_backend_pkg (self, i->data,
++ PK_INFO_ENUM_INSTALLED);
++ } else if (!alpm_pkg_is_local (i->data)) {
++ pk_backend_pkg (self, i->data,
++ PK_INFO_ENUM_AVAILABLE);
++ }
++ }
++ }
++}
++
++static gboolean
++pk_backend_search_thread (PkBackend *self)
++{
++ gchar **needles;
++ SearchType type;
++
++ PatternFunc pattern_func;
++ GDestroyNotify pattern_free;
++ MatchFunc match_func;
++
++ PkBitfield filters;
++ gboolean skip_local, skip_remote;
++
++ const alpm_list_t *i;
++ alpm_list_t *patterns = NULL;
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (localdb != NULL, FALSE);
++
++ needles = pk_backend_get_strv (self, "search");
++ type = pk_backend_get_uint (self, "search-type");
++
++ g_return_val_if_fail (needles != NULL, FALSE);
++ g_return_val_if_fail (type < SEARCH_TYPE_LAST, FALSE);
++
++ pattern_func = pattern_funcs[type];
++ pattern_free = pattern_frees[type];
++ match_func = match_funcs[type];
++
++ g_return_val_if_fail (pattern_func != NULL, FALSE);
++ g_return_val_if_fail (match_func != NULL, FALSE);
++
++ filters = pk_backend_get_uint (self, "filters");
++ skip_local = pk_bitfield_contain (filters,
++ PK_FILTER_ENUM_NOT_INSTALLED);
++ skip_remote = pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED);
++
++ /* convert search terms to the pattern requested */
++ for (; *needles != NULL; ++needles) {
++ gpointer pattern = pattern_func (*needles, &error);
++
++ if (pattern == NULL) {
++ goto out;
++ }
++
++ patterns = alpm_list_add (patterns, pattern);
++ }
++
++ /* find installed packages first */
++ if (!skip_local) {
++ pk_backend_search_db (self, localdb, match_func, patterns);
++ }
++
++ if (skip_remote) {
++ goto out;
++ }
++
++ for (i = alpm_option_get_syncdbs (); i != NULL; i = i->next) {
++ if (pk_backend_cancelled (self)) {
++ break;
++ }
++
++ pk_backend_search_db (self, i->data, match_func, patterns);
++ }
++
++out:
++ if (pattern_free != NULL) {
++ alpm_list_free_inner (patterns, pattern_free);
++ }
++ alpm_list_free (patterns);
++ return pk_backend_finish (self, error);
++}
++
++void
++pk_backend_get_packages (PkBackend *self, PkBitfield filters)
++{
++ g_return_if_fail (self != NULL);
++
++ /* provide a dummy needle */
++ pk_backend_set_strv (self, "search", g_strsplit ("", ";", 0));
++
++ pk_backend_set_uint (self, "search-type", SEARCH_TYPE_ALL);
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY, pk_backend_search_thread);
++}
++
++void
++pk_backend_search_details (PkBackend *self, PkBitfield filters, gchar **values)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (values != NULL);
++
++ pk_backend_set_uint (self, "search-type", SEARCH_TYPE_DETAILS);
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY, pk_backend_search_thread);
++}
++
++void
++pk_backend_search_files (PkBackend *self, PkBitfield filters, gchar **values)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (values != NULL);
++
++ /* speed up search by restricting it to local database */
++ pk_bitfield_add (filters, PK_FILTER_ENUM_INSTALLED);
++ pk_backend_set_uint (self, "filters", filters);
++
++ pk_backend_set_uint (self, "search-type", SEARCH_TYPE_FILES);
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY, pk_backend_search_thread);
++}
++
++void
++pk_backend_search_groups (PkBackend *self, PkBitfield filters, gchar **values)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (values != NULL);
++
++ pk_backend_set_uint (self, "search-type", SEARCH_TYPE_GROUP);
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY, pk_backend_search_thread);
++}
++
++void
++pk_backend_search_names (PkBackend *self, PkBitfield filters, gchar **values)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (values != NULL);
++
++ pk_backend_set_uint (self, "search-type", SEARCH_TYPE_NAME);
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY, pk_backend_search_thread);
++}
++
++void
++pk_backend_what_provides (PkBackend *self, PkBitfield filters,
++ PkProvidesEnum provides, gchar **values)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (values != NULL);
++
++ pk_backend_set_uint (self, "search-type", SEARCH_TYPE_PROVIDES);
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY, pk_backend_search_thread);
++}
+diff --git a/backends/alpm/pk-backend-search.h b/backends/alpm/pk-backend-search.h
+new file mode 100644
+index 0000000..368965a
+--- /dev/null
++++ b/backends/alpm/pk-backend-search.h
+@@ -0,0 +1,22 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
+diff --git a/backends/alpm/pk-backend-sync.c b/backends/alpm/pk-backend-sync.c
+new file mode 100644
+index 0000000..7147514
+--- /dev/null
++++ b/backends/alpm/pk-backend-sync.c
+@@ -0,0 +1,283 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alpm.h>
++#include <pk-backend.h>
++#include <string.h>
++
++#include "pk-backend-alpm.h"
++#include "pk-backend-error.h"
++#include "pk-backend-sync.h"
++#include "pk-backend-transaction.h"
++
++static gint
++alpm_add_dbtarget (const gchar *repo, const gchar *name)
++{
++ const alpm_list_t *i;
++ pmpkg_t *pkg;
++
++ g_return_val_if_fail (repo != NULL, -1);
++ g_return_val_if_fail (name != NULL, -1);
++
++ for (i = alpm_option_get_syncdbs (); i != NULL; i = i->next) {
++ if (g_strcmp0 (alpm_db_get_name (i->data), repo) == 0) {
++ break;
++ }
++ }
++
++ if (i == NULL) {
++ pm_errno = PM_ERR_DB_NOT_FOUND;
++ return -1;
++ }
++
++ pkg = alpm_db_get_pkg (i->data, name);
++ if (pkg == NULL) {
++ pm_errno = PM_ERR_PKG_NOT_FOUND;
++ return -1;
++ }
++
++ return alpm_add_pkg (pkg);
++}
++
++static gboolean
++pk_backend_transaction_sync_targets (PkBackend *self, GError **error)
++{
++ gchar **packages;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ packages = pk_backend_get_strv (self, "package_ids");
++
++ g_return_val_if_fail (packages != NULL, FALSE);
++
++ for (; *packages != NULL; ++packages) {
++ gchar **package = pk_package_id_split (*packages);
++ gchar *repo = package[PK_PACKAGE_ID_DATA];
++ gchar *name = package[PK_PACKAGE_ID_NAME];
++
++ if (alpm_add_dbtarget (repo, name) < 0) {
++ g_set_error (error, ALPM_ERROR, pm_errno, "%s/%s: %s",
++ repo, name, alpm_strerrorlast ());
++ g_strfreev (package);
++ return FALSE;
++ }
++
++ g_strfreev (package);
++ }
++
++ return TRUE;
++}
++
++static gboolean
++pk_backend_download_packages_thread (PkBackend *self)
++{
++ alpm_list_t *cachedirs;
++ const gchar *directory;
++ pmtransflag_t flags = 0;
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ directory = pk_backend_get_string (self, "directory");
++
++ g_return_val_if_fail (directory != NULL, FALSE);
++
++ /* download files to a PackageKit directory */
++ cachedirs = alpm_list_strdup (alpm_option_get_cachedirs ());
++ alpm_option_set_cachedirs (alpm_list_add (NULL, strdup (directory)));
++
++ flags |= PM_TRANS_FLAG_NODEPS;
++ flags |= PM_TRANS_FLAG_NOCONFLICTS;
++ flags |= PM_TRANS_FLAG_DOWNLOADONLY;
++
++ if (pk_backend_transaction_initialize (self, flags, &error) &&
++ pk_backend_transaction_sync_targets (self, &error) &&
++ pk_backend_transaction_simulate (self, &error)) {
++ pk_backend_transaction_commit (self, &error);
++ }
++
++ alpm_option_set_cachedirs (cachedirs);
++
++ return pk_backend_transaction_finish (self, error);
++}
++
++void
++pk_backend_download_packages (PkBackend *self, gchar **package_ids,
++ const gchar *directory)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (package_ids != NULL);
++ g_return_if_fail (directory != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_SETUP,
++ pk_backend_download_packages_thread);
++}
++
++static gboolean
++pk_backend_simulate_install_packages_thread (PkBackend *self)
++{
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ if (pk_backend_transaction_initialize (self, 0, &error) &&
++ pk_backend_transaction_sync_targets (self, &error) &&
++ pk_backend_transaction_simulate (self, &error)) {
++ pk_backend_transaction_packages (self);
++ }
++
++ return pk_backend_transaction_finish (self, error);
++}
++
++static gboolean
++pk_backend_install_packages_thread (PkBackend *self)
++{
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ if (pk_backend_transaction_initialize (self, 0, &error) &&
++ pk_backend_transaction_sync_targets (self, &error) &&
++ pk_backend_transaction_simulate (self, &error)) {
++ pk_backend_transaction_commit (self, &error);
++ }
++
++ return pk_backend_transaction_finish (self, error);
++}
++
++void
++pk_backend_simulate_install_packages (PkBackend *self, gchar **package_ids)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (package_ids != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_SETUP,
++ pk_backend_simulate_install_packages_thread);
++}
++
++void
++pk_backend_install_packages (PkBackend *self, gboolean only_trusted,
++ gchar **package_ids)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (package_ids != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_SETUP,
++ pk_backend_install_packages_thread);
++}
++
++static gboolean
++pk_backend_replaces_dependencies (PkBackend *self, pmpkg_t *pkg)
++{
++ const alpm_list_t *i, *replaces;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (pkg != NULL, FALSE);
++
++ replaces = alpm_pkg_get_replaces (pkg);
++ for (i = alpm_trans_get_remove (); i != NULL; i = i->next) {
++ pmpkg_t *rpkg = (pmpkg_t *) i->data;
++ const gchar *rname = alpm_pkg_get_name (rpkg);
++
++ if (pk_backend_cancelled (self)) {
++ return FALSE;
++ } else if (alpm_list_find_str (replaces, rname) == NULL) {
++ continue;
++ }
++
++ if (alpm_pkg_get_reason (rpkg) == PM_PKG_REASON_EXPLICIT) {
++ return FALSE;
++ }
++ }
++
++ return TRUE;
++}
++
++static gboolean
++pk_backend_update_packages_thread (PkBackend *self)
++{
++ const alpm_list_t *i;
++ alpm_list_t *asdeps = NULL;
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (localdb != NULL, FALSE);
++
++ if (!pk_backend_transaction_initialize (self, 0, &error) ||
++ !pk_backend_transaction_sync_targets (self, &error) ||
++ !pk_backend_transaction_simulate (self, &error)) {
++ goto out;
++ }
++
++ /* change the install reason of packages that replace dependencies */
++ for (i = alpm_trans_get_add (); i != NULL; i = i->next) {
++ pmpkg_t *pkg = (pmpkg_t *) i->data;
++ const gchar *name = alpm_pkg_get_name (pkg);
++
++ if (pk_backend_cancelled (self)) {
++ goto out;
++ } else if (alpm_db_get_pkg (localdb, name) != NULL) {
++ continue;
++ }
++
++ if (pk_backend_replaces_dependencies (self, pkg)) {
++ asdeps = alpm_list_add (asdeps, g_strdup (name));
++ }
++ }
++
++ if (!pk_backend_transaction_commit (self, &error)) {
++ goto out;
++ }
++
++ for (i = asdeps; i != NULL; i = i->next) {
++ const gchar *name = (const gchar *) i->data;
++ alpm_db_set_pkgreason (localdb, name, PM_PKG_REASON_DEPEND);
++ }
++
++out:
++ alpm_list_free_inner (asdeps, g_free);
++ alpm_list_free (asdeps);
++
++ return pk_backend_transaction_finish (self, error);
++}
++
++void
++pk_backend_simulate_update_packages (PkBackend *self, gchar **package_ids)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (package_ids != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_SETUP,
++ pk_backend_simulate_install_packages_thread);
++}
++
++void
++pk_backend_update_packages (PkBackend *self, gboolean only_trusted,
++ gchar **package_ids)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (package_ids != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_SETUP,
++ pk_backend_update_packages_thread);
++}
+diff --git a/backends/alpm/pk-backend-sync.h b/backends/alpm/pk-backend-sync.h
+new file mode 100644
+index 0000000..368965a
+--- /dev/null
++++ b/backends/alpm/pk-backend-sync.h
+@@ -0,0 +1,22 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
+diff --git a/backends/alpm/pk-backend-transaction.c b/backends/alpm/pk-backend-transaction.c
+new file mode 100644
+index 0000000..f919309
+--- /dev/null
++++ b/backends/alpm/pk-backend-transaction.c
+@@ -0,0 +1,916 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include "pk-backend-alpm.h"
++#include "pk-backend-error.h"
++#include "pk-backend-packages.h"
++#include "pk-backend-transaction.h"
++
++static off_t dcomplete = 0;
++static off_t dtotal = 0;
++
++static pmpkg_t *dpkg = NULL;
++static GString *dfiles = NULL;
++
++static gchar *
++pk_backend_resolve_path (PkBackend *self, const gchar *basename)
++{
++ const gchar *dirname;
++
++ g_return_val_if_fail (self != NULL, NULL);
++ g_return_val_if_fail (basename != NULL, NULL);
++
++ dirname = pk_backend_get_string (self, "directory");
++
++ g_return_val_if_fail (dirname != NULL, NULL);
++
++ return g_build_filename (dirname, basename, NULL);
++}
++
++static gboolean
++alpm_pkg_has_basename (pmpkg_t *pkg, const gchar *basename)
++{
++ const alpm_list_t *i;
++
++ g_return_val_if_fail (pkg != NULL, FALSE);
++ g_return_val_if_fail (basename != NULL, FALSE);
++
++ if (g_strcmp0 (alpm_pkg_get_filename (pkg), basename) == 0) {
++ return TRUE;
++ }
++
++ if (alpm_option_get_usedelta () == 0) {
++ return FALSE;
++ }
++
++ for (i = alpm_pkg_get_deltas (pkg); i != NULL; i = i->next) {
++ const gchar *patch = alpm_delta_get_filename (i->data);
++
++ if (g_strcmp0 (patch, basename) == 0) {
++ return TRUE;
++ }
++ }
++
++ return FALSE;
++}
++
++static void
++pk_backend_transaction_download_end (PkBackend *self)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (dpkg != NULL);
++
++ pk_backend_pkg (self, dpkg, PK_INFO_ENUM_FINISHED);
++
++ /* tell DownloadPackages what files were downloaded */
++ if (dfiles != NULL) {
++ gchar *package_id;
++
++ package_id = alpm_pkg_build_id (dpkg);
++
++ pk_backend_files (self, package_id, dfiles->str);
++
++ g_free (package_id);
++ g_string_free (dfiles, TRUE);
++ }
++
++ dpkg = NULL;
++ dfiles = NULL;
++}
++
++static void
++pk_backend_transaction_download_start (PkBackend *self, const gchar *basename)
++{
++ gchar *path;
++ const alpm_list_t *i;
++
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (basename != NULL);
++
++ /* continue or finish downloading the current package */
++ if (dpkg != NULL) {
++ if (alpm_pkg_has_basename (dpkg, basename)) {
++ if (dfiles != NULL) {
++ path = pk_backend_resolve_path (self, basename);
++ g_string_append_printf (dfiles, ";%s", path);
++ g_free (path);
++ }
++
++ return;
++ } else {
++ pk_backend_transaction_download_end (self);
++ dpkg = NULL;
++ }
++ }
++
++ /* figure out what the next package is */
++ for (i = alpm_trans_get_add (); i != NULL; i = i->next) {
++ pmpkg_t *pkg = (pmpkg_t *) i->data;
++
++ if (alpm_pkg_has_basename (pkg, basename)) {
++ dpkg = pkg;
++ break;
++ }
++ }
++
++ if (dpkg == NULL) {
++ return;
++ }
++
++ pk_backend_pkg (self, dpkg, PK_INFO_ENUM_DOWNLOADING);
++
++ /* start collecting files for the new package */
++ if (pk_backend_get_role (self) == PK_ROLE_ENUM_DOWNLOAD_PACKAGES) {
++ path = pk_backend_resolve_path (self, basename);
++ dfiles = g_string_new (path);
++ g_free (path);
++ }
++}
++
++static void
++pk_backend_transaction_totaldlcb (off_t total)
++{
++ g_return_if_fail (backend != NULL);
++
++ if (dtotal > 0 && dpkg != NULL) {
++ pk_backend_transaction_download_end (backend);
++ }
++
++ dcomplete = 0;
++ dtotal = total;
++}
++
++static void
++pk_backend_transaction_dlcb (const gchar *basename, off_t complete, off_t total)
++{
++ guint percentage = 100, sub_percentage = 100;
++
++ g_return_if_fail (basename != NULL);
++ g_return_if_fail (complete <= total);
++ g_return_if_fail (backend != NULL);
++
++ if (total > 0) {
++ sub_percentage = complete * 100 / total;
++ }
++
++ if (dtotal > 0) {
++ percentage = (dcomplete + complete) * 100 / dtotal;
++ } else if (dtotal < 0) {
++ /* database files */
++ percentage = (dcomplete * 100 + sub_percentage) / -dtotal;
++
++ if (complete == total) {
++ complete = total = 1;
++ } else {
++ complete = total + 1;
++ }
++ }
++
++ if (complete == 0) {
++ g_debug ("downloading file %s", basename);
++ pk_backend_set_status (backend, PK_STATUS_ENUM_DOWNLOAD);
++ pk_backend_transaction_download_start (backend, basename);
++ } else if (complete == total) {
++ dcomplete += complete;
++ }
++
++ pk_backend_set_sub_percentage (backend, sub_percentage);
++ pk_backend_set_percentage (backend, percentage);
++}
++
++static void
++pk_backend_transaction_progress_cb (pmtransprog_t type, const gchar *target,
++ gint percent, gsize targets, gsize current)
++{
++ static gint recent = 101;
++ gsize overall = percent + (current - 1) * 100;
++
++ /* TODO: revert when fixed upstream */
++ if (type == PM_TRANS_PROGRESS_CONFLICTS_START ||
++ type == PM_TRANS_PROGRESS_DISKSPACE_START ||
++ type == PM_TRANS_PROGRESS_INTEGRITY_START) {
++ if (current < targets) {
++ overall = percent + current++ * 100;
++ }
++ }
++
++ if (current < 1 || targets < current) {
++ g_warning ("TODO: CURRENT/TARGETS FAILED for %d", type);
++ }
++
++ g_return_if_fail (target != NULL);
++ g_return_if_fail (0 <= percent && percent <= 100);
++ g_return_if_fail (1 <= current && current <= targets);
++ g_return_if_fail (backend != NULL);
++
++ /* update transaction progress */
++ switch (type) {
++ case PM_TRANS_PROGRESS_ADD_START:
++ case PM_TRANS_PROGRESS_UPGRADE_START:
++ case PM_TRANS_PROGRESS_REMOVE_START:
++ case PM_TRANS_PROGRESS_CONFLICTS_START:
++ case PM_TRANS_PROGRESS_DISKSPACE_START:
++ case PM_TRANS_PROGRESS_INTEGRITY_START:
++ if (percent == recent) {
++ break;
++ }
++
++ pk_backend_set_sub_percentage (backend, percent);
++ pk_backend_set_percentage (backend, overall / targets);
++ recent = percent;
++
++ g_debug ("%d%% of %s complete (%zu of %zu)", percent,
++ target, current, targets);
++ break;
++
++ default:
++ g_warning ("unknown progress type %d", type);
++ break;
++ }
++}
++
++static void
++pk_backend_install_ignorepkg (PkBackend *self, pmpkg_t *pkg, gint *result)
++{
++ gchar *output;
++
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (pkg != NULL);
++ g_return_if_fail (result != NULL);
++
++ switch (pk_backend_get_role (self)) {
++ case PK_ROLE_ENUM_INSTALL_PACKAGES:
++ output = g_strdup_printf ("%s: was not ignored\n",
++ alpm_pkg_get_name (pkg));
++ pk_backend_output (self, output);
++ g_free (output);
++
++ case PK_ROLE_ENUM_DOWNLOAD_PACKAGES:
++ case PK_ROLE_ENUM_SIMULATE_INSTALL_PACKAGES:
++ *result = 1;
++ break;
++
++ default:
++ *result = 0;
++ break;
++ }
++}
++
++static void
++pk_backend_select_provider (PkBackend *self, pmdepend_t *dep,
++ const alpm_list_t *providers)
++{
++ gchar *output;
++
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (dep != NULL);
++ g_return_if_fail (providers != NULL);
++
++ output = g_strdup_printf ("provider package was selected "
++ "(%s provides %s)\n",
++ alpm_pkg_get_name (providers->data),
++ alpm_dep_get_name (dep));
++ pk_backend_output (self, output);
++ g_free (output);
++}
++
++static void
++pk_backend_transaction_conv_cb (pmtransconv_t question, gpointer data1,
++ gpointer data2, gpointer data3, gint *result)
++{
++ g_return_if_fail (result != NULL);
++ g_return_if_fail (backend != NULL);
++
++ switch (question) {
++ case PM_TRANS_CONV_INSTALL_IGNOREPKG:
++ pk_backend_install_ignorepkg (backend, data1, result);
++ break;
++
++ case PM_TRANS_CONV_REPLACE_PKG:
++ case PM_TRANS_CONV_CONFLICT_PKG:
++ case PM_TRANS_CONV_CORRUPTED_PKG:
++ case PM_TRANS_CONV_LOCAL_NEWER:
++ /* these actions are mostly harmless */
++ g_debug ("safe question %d", question);
++ *result = 1;
++ break;
++
++ case PM_TRANS_CONV_REMOVE_PKGS:
++ g_debug ("unsafe question %d", question);
++ *result = 0;
++ break;
++
++ case PM_TRANS_CONV_SELECT_PROVIDER:
++ pk_backend_select_provider (backend, data1, data2);
++ *result = 0;
++ break;
++
++ default:
++ g_warning ("unknown question %d", question);
++ break;
++ }
++}
++
++static void
++pk_backend_transaction_dep_resolve (PkBackend *self)
++{
++ g_return_if_fail (self != NULL);
++
++ pk_backend_set_status (self, PK_STATUS_ENUM_DEP_RESOLVE);
++}
++
++static void
++pk_backend_transaction_test_commit (PkBackend *self)
++{
++ g_return_if_fail (self != NULL);
++
++ pk_backend_set_status (self, PK_STATUS_ENUM_TEST_COMMIT);
++}
++
++static void
++pk_backend_transaction_add_start (PkBackend *self, pmpkg_t *pkg)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (pkg != NULL);
++
++ pk_backend_set_status (self, PK_STATUS_ENUM_INSTALL);
++ pk_backend_pkg (self, pkg, PK_INFO_ENUM_INSTALLING);
++}
++
++static void
++pk_backend_transaction_add_done (PkBackend *self, pmpkg_t *pkg)
++{
++ const gchar *name, *version;
++ const alpm_list_t *i, *optdepends;
++
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (pkg != NULL);
++
++ name = alpm_pkg_get_name (pkg);
++ version = alpm_pkg_get_version (pkg);
++
++ alpm_logaction ("installed %s (%s)\n", name, version);
++ pk_backend_pkg (self, pkg, PK_INFO_ENUM_FINISHED);
++
++ optdepends = alpm_pkg_get_optdepends (pkg);
++ if (optdepends != NULL) {
++ GString *depends = g_string_new ("");
++
++ g_string_append_printf (depends,
++ "Optional dependencies for %s:\n",
++ name);
++
++ for (i = optdepends; i != NULL; i = i->next) {
++ g_string_append_printf (depends, "%s\n",
++ (const gchar *) i->data);
++ }
++
++ pk_backend_output (self, depends->str);
++ g_string_free (depends, TRUE);
++ }
++}
++
++static void
++pk_backend_transaction_remove_start (PkBackend *self, pmpkg_t *pkg)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (pkg != NULL);
++
++ pk_backend_set_status (self, PK_STATUS_ENUM_REMOVE);
++ pk_backend_pkg (self, pkg, PK_INFO_ENUM_REMOVING);
++}
++
++static void
++pk_backend_transaction_remove_done (PkBackend *self, pmpkg_t *pkg)
++{
++ const gchar *name, *version;
++
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (pkg != NULL);
++
++ name = alpm_pkg_get_name (pkg);
++ version = alpm_pkg_get_version (pkg);
++
++ alpm_logaction ("removed %s (%s)\n", name, version);
++ pk_backend_pkg (self, pkg, PK_INFO_ENUM_FINISHED);
++}
++
++static void
++pk_backend_transaction_upgrade_start (PkBackend *self, pmpkg_t *pkg,
++ pmpkg_t *old)
++{
++ PkRoleEnum role;
++ PkStatusEnum state;
++ PkInfoEnum info;
++
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (pkg != NULL);
++
++ role = pk_backend_get_role (self);
++ if (role == PK_ROLE_ENUM_INSTALL_FILES ||
++ role == PK_ROLE_ENUM_SIMULATE_INSTALL_FILES) {
++ state = PK_STATUS_ENUM_INSTALL;
++ info = PK_INFO_ENUM_INSTALLING;
++ } else {
++ state = PK_STATUS_ENUM_UPDATE;
++ info = PK_INFO_ENUM_UPDATING;
++ }
++
++ pk_backend_set_status (self, state);
++ pk_backend_pkg (self, pkg, info);
++}
++
++static void
++pk_backend_transaction_upgrade_done (PkBackend *self, pmpkg_t *pkg,
++ pmpkg_t *old)
++{
++ const gchar *name, *pre, *post;
++ const alpm_list_t *i;
++ alpm_list_t *optdepends;
++
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (pkg != NULL);
++ g_return_if_fail (old != NULL);
++
++ name = alpm_pkg_get_name (pkg);
++ pre = alpm_pkg_get_version (old);
++ post = alpm_pkg_get_version (pkg);
++
++ alpm_logaction ("upgraded %s (%s -> %s)\n", name, pre, post);
++ pk_backend_pkg (self, pkg, PK_INFO_ENUM_FINISHED);
++
++ optdepends = alpm_list_diff (alpm_pkg_get_optdepends (pkg),
++ alpm_pkg_get_optdepends (old),
++ (alpm_list_fn_cmp) g_strcmp0);
++ if (optdepends != NULL) {
++ GString *depends = g_string_new ("");
++
++ g_string_append_printf (depends,
++ "New optional dependencies for %s\n",
++ name);
++
++ for (i = optdepends; i != NULL; i = i->next) {
++ g_string_append_printf (depends, "%s\n",
++ (const gchar *) i->data);
++ }
++
++ pk_backend_output (self, depends->str);
++
++ g_string_free (depends, TRUE);
++ alpm_list_free (optdepends);
++ }
++}
++
++static void
++pk_backend_transaction_event_cb (pmtransevt_t event, gpointer data,
++ gpointer old)
++{
++ g_return_if_fail (backend != NULL);
++
++ /* figure out the backend status and package info */
++ switch (event) {
++ case PM_TRANS_EVT_CHECKDEPS_START:
++ case PM_TRANS_EVT_RESOLVEDEPS_START:
++ pk_backend_transaction_dep_resolve (backend);
++ break;
++
++ case PM_TRANS_EVT_FILECONFLICTS_START:
++ case PM_TRANS_EVT_INTERCONFLICTS_START:
++ case PM_TRANS_EVT_INTEGRITY_START:
++ case PM_TRANS_EVT_DELTA_INTEGRITY_START:
++ case PM_TRANS_EVT_DISKSPACE_START:
++ pk_backend_transaction_test_commit (backend);
++ break;
++
++ case PM_TRANS_EVT_ADD_START:
++ pk_backend_transaction_add_start (backend, data);
++ break;
++
++ case PM_TRANS_EVT_ADD_DONE:
++ pk_backend_transaction_add_done (backend, data);
++ break;
++
++ case PM_TRANS_EVT_REMOVE_START:
++ pk_backend_transaction_remove_start (backend, data);
++ break;
++
++ case PM_TRANS_EVT_REMOVE_DONE:
++ pk_backend_transaction_remove_done (backend, data);
++ break;
++
++ case PM_TRANS_EVT_UPGRADE_START:
++ pk_backend_transaction_upgrade_start (backend, data,
++ old);
++ break;
++
++ case PM_TRANS_EVT_UPGRADE_DONE:
++ pk_backend_transaction_upgrade_done (backend, data,
++ old);
++ break;
++
++ case PM_TRANS_EVT_SCRIPTLET_INFO:
++ pk_backend_output (backend, data);
++ break;
++
++ default:
++ g_debug ("unhandled event %d", event);
++ break;
++ }
++}
++
++static void
++transaction_cancelled_cb (GCancellable *object, gpointer data)
++{
++ g_return_if_fail (data != NULL);
++
++ alpm_trans_interrupt ();
++}
++
++gboolean
++pk_backend_transaction_initialize (PkBackend *self, pmtransflag_t flags,
++ GError **error)
++{
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (cancellable != NULL, FALSE);
++
++ if (alpm_trans_init (flags, pk_backend_transaction_event_cb,
++ pk_backend_transaction_conv_cb,
++ pk_backend_transaction_progress_cb) < 0) {
++ g_set_error_literal (error, ALPM_ERROR, pm_errno,
++ alpm_strerrorlast ());
++ return FALSE;
++ }
++
++ alpm_option_set_dlcb (pk_backend_transaction_dlcb);
++ alpm_option_set_totaldlcb (pk_backend_transaction_totaldlcb);
++
++ g_cancellable_connect (cancellable,
++ G_CALLBACK (transaction_cancelled_cb),
++ self, NULL);
++
++ return TRUE;
++}
++
++static gchar *
++alpm_pkg_build_list (const alpm_list_t *i)
++{
++ GString *list;
++
++ if (i == NULL) {
++ return NULL;
++ } else {
++ list = g_string_new ("");
++ }
++
++ for (; i != NULL; i = i->next) {
++ g_string_append_printf (list, "%s, ",
++ alpm_pkg_get_name (i->data));
++ }
++
++ g_string_truncate (list, list->len - 2);
++ return g_string_free (list, FALSE);
++}
++
++static gchar *
++alpm_miss_build_list (const alpm_list_t *i)
++{
++ GString *list;
++
++ if (i == NULL) {
++ return NULL;
++ } else {
++ list = g_string_new ("");
++ }
++
++ for (; i != NULL; i = i->next) {
++ pmdepend_t *dep = alpm_miss_get_dep (i->data);
++ gchar *depend = alpm_dep_compute_string (dep);
++ g_string_append_printf (list, "%s <- %s, ", depend,
++ alpm_miss_get_target (i->data));
++ free (depend);
++ }
++
++ g_string_truncate (list, list->len - 2);
++ return g_string_free (list, FALSE);
++}
++
++static void
++alpm_dep_free (gpointer dep)
++{
++ /* TODO: remove when implemented in libalpm */
++ free ((gpointer) alpm_dep_get_name (dep));
++ free ((gpointer) alpm_dep_get_version (dep));
++ free (dep);
++}
++
++static void
++alpm_miss_free (gpointer miss)
++{
++ /* TODO: remove when implemented in libalpm */
++ const gchar *temp = alpm_miss_get_causingpkg (miss);
++ if (temp != NULL) {
++ free ((gpointer) temp);
++ }
++
++ free ((gpointer) alpm_miss_get_target (miss));
++ alpm_dep_free (alpm_miss_get_dep (miss));
++ free (miss);
++}
++
++static gchar *
++alpm_conflict_build_list (const alpm_list_t *i)
++{
++ GString *list;
++
++ if (i == NULL) {
++ return NULL;
++ } else {
++ list = g_string_new ("");
++ }
++
++ for (; i != NULL; i = i->next) {
++ const gchar *first = alpm_conflict_get_package1 (i->data);
++ const gchar *second = alpm_conflict_get_package2 (i->data);
++ const gchar *reason = alpm_conflict_get_reason (i->data);
++
++ if (g_strcmp0 (first, reason) == 0 ||
++ g_strcmp0 (second, reason) == 0) {
++ g_string_append_printf (list, "%s <-> %s, ", first,
++ second);
++ } else {
++ g_string_append_printf (list, "%s <-> %s (%s), ", first,
++ second, reason);
++ }
++ }
++
++ g_string_truncate (list, list->len - 2);
++ return g_string_free (list, FALSE);
++}
++
++static void
++alpm_conflict_free (gpointer conflict)
++{
++ /* TODO: remove when implemented in libalpm */
++ free ((gpointer) alpm_conflict_get_package1 (conflict));
++ free ((gpointer) alpm_conflict_get_package2 (conflict));
++ free ((gpointer) alpm_conflict_get_reason (conflict));
++ free (conflict);
++}
++
++static gchar *
++alpm_fileconflict_build_list (const alpm_list_t *i)
++{
++ GString *list;
++
++ if (i == NULL) {
++ return NULL;
++ } else {
++ list = g_string_new ("");
++ }
++
++ for (; i != NULL; i = i->next) {
++ const gchar *target = alpm_fileconflict_get_target (i->data);
++ const gchar *file = alpm_fileconflict_get_file (i->data);
++ const gchar *ctarget = alpm_fileconflict_get_ctarget (i->data);
++ if (*ctarget != '\0') {
++ g_string_append_printf (list, "%s <-> %s (%s), ",
++ target, ctarget, file);
++ } else {
++ g_string_append_printf (list, "%s (%s), ", target,
++ file);
++ }
++ }
++
++ g_string_truncate (list, list->len - 2);
++ return g_string_free (list, FALSE);
++}
++
++static void
++alpm_fileconflict_free (gpointer conflict)
++{
++ /* TODO: remove when implemented in libalpm */
++ const gchar *temp = alpm_fileconflict_get_ctarget (conflict);
++ if (*temp != '\0') {
++ free ((gpointer) temp);
++ }
++
++ free ((gpointer) alpm_fileconflict_get_target (conflict));
++ free ((gpointer) alpm_fileconflict_get_file (conflict));
++ free (conflict);
++}
++
++gboolean
++pk_backend_transaction_simulate (PkBackend *self, GError **error)
++{
++ alpm_list_t *data = NULL;
++ gchar *prefix;
++
++ if (alpm_trans_prepare (&data) >= 0) {
++ return TRUE;
++ }
++
++ switch (pm_errno) {
++ case PM_ERR_PKG_INVALID_ARCH:
++ prefix = alpm_pkg_build_list (data);
++ alpm_list_free (data);
++ break;
++
++ case PM_ERR_UNSATISFIED_DEPS:
++ prefix = alpm_miss_build_list (data);
++ alpm_list_free_inner (data, alpm_miss_free);
++ alpm_list_free (data);
++ break;
++
++ case PM_ERR_CONFLICTING_DEPS:
++ prefix = alpm_conflict_build_list (data);
++ alpm_list_free_inner (data, alpm_conflict_free);
++ alpm_list_free (data);
++ break;
++
++ case PM_ERR_FILE_CONFLICTS:
++ prefix = alpm_fileconflict_build_list (data);
++ alpm_list_free_inner (data, alpm_fileconflict_free);
++ alpm_list_free (data);
++ break;
++
++ default:
++ prefix = NULL;
++ if (data != NULL) {
++ g_warning ("unhandled error %d", pm_errno);
++ }
++ break;
++ }
++
++ if (prefix != NULL) {
++ g_set_error (error, ALPM_ERROR, pm_errno, "%s: %s", prefix,
++ alpm_strerrorlast ());
++ g_free (prefix);
++ } else {
++ g_set_error_literal (error, ALPM_ERROR, pm_errno,
++ alpm_strerrorlast ());
++ }
++
++ return FALSE;
++}
++
++void
++pk_backend_transaction_packages (PkBackend *self)
++{
++ const alpm_list_t *i;
++ PkInfoEnum info;
++
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (localdb != NULL);
++
++ /* emit packages that would have been installed */
++ for (i = alpm_trans_get_add (); i != NULL; i = i->next) {
++ if (pk_backend_cancelled (self)) {
++ break;
++ } else {
++ const gchar *name = alpm_pkg_get_name (i->data);
++
++ if (alpm_db_get_pkg (localdb, name) != NULL) {
++ info = PK_INFO_ENUM_UPDATING;
++ } else {
++ info = PK_INFO_ENUM_INSTALLING;
++ }
++
++ pk_backend_pkg (self, i->data, info);
++ }
++ }
++
++ switch (pk_backend_get_role (self)) {
++ case PK_ROLE_ENUM_SIMULATE_UPDATE_PACKAGES:
++ info = PK_INFO_ENUM_OBSOLETING;
++ break;
++
++ default:
++ info = PK_INFO_ENUM_REMOVING;
++ break;
++ }
++
++ /* emit packages that would have been removed */
++ for (i = alpm_trans_get_remove (); i != NULL; i = i->next) {
++ if (pk_backend_cancelled (self)) {
++ break;
++ } else {
++ pk_backend_pkg (self, i->data, info);
++ }
++ }
++}
++
++static gchar *
++alpm_string_build_list (const alpm_list_t *i)
++{
++ GString *list;
++
++ if (i == NULL) {
++ return NULL;
++ } else {
++ list = g_string_new ("");
++ }
++
++ for (; i != NULL; i = i->next) {
++ g_string_append_printf (list, "%s, ", (const gchar *) i->data);
++ }
++
++ g_string_truncate (list, list->len - 2);
++ return g_string_free (list, FALSE);
++}
++
++gboolean
++pk_backend_transaction_commit (PkBackend *self, GError **error)
++{
++ alpm_list_t *data = NULL;
++ gchar *prefix;
++
++ if (pk_backend_cancelled (self)) {
++ return TRUE;
++ }
++
++ pk_backend_set_allow_cancel (self, FALSE);
++ pk_backend_set_status (self, PK_STATUS_ENUM_RUNNING);
++
++ if (alpm_trans_commit (&data) >= 0) {
++ return TRUE;
++ }
++
++ switch (pm_errno) {
++ case PM_ERR_FILE_CONFLICTS:
++ prefix = alpm_fileconflict_build_list (data);
++ alpm_list_free_inner (data, alpm_fileconflict_free);
++ alpm_list_free (data);
++ break;
++
++ case PM_ERR_PKG_INVALID:
++ case PM_ERR_DLT_INVALID:
++ prefix = alpm_string_build_list (data);
++ alpm_list_free (data);
++ break;
++
++ default:
++ prefix = NULL;
++ if (data != NULL) {
++ g_warning ("unhandled error %d", pm_errno);
++ }
++ break;
++ }
++
++ if (prefix != NULL) {
++ g_set_error (error, ALPM_ERROR, pm_errno, "%s: %s", prefix,
++ alpm_strerrorlast ());
++ g_free (prefix);
++ } else {
++ g_set_error_literal (error, ALPM_ERROR, pm_errno,
++ alpm_strerrorlast ());
++ }
++
++ return FALSE;
++}
++
++gboolean
++pk_backend_transaction_end (PkBackend *self, GError **error)
++{
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ alpm_option_set_dlcb (NULL);
++ alpm_option_set_totaldlcb (NULL);
++
++ if (alpm_trans_release () < 0) {
++ g_set_error_literal (error, ALPM_ERROR, pm_errno,
++ alpm_strerrorlast ());
++ return FALSE;
++ }
++
++ return TRUE;
++}
++
++gboolean
++pk_backend_transaction_finish (PkBackend *self, GError *error)
++{
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ pk_backend_transaction_end (self, (error == NULL) ? &error : NULL);
++
++ return pk_backend_finish (self, error);
++}
+diff --git a/backends/alpm/pk-backend-transaction.h b/backends/alpm/pk-backend-transaction.h
+new file mode 100644
+index 0000000..7bc1af0
+--- /dev/null
++++ b/backends/alpm/pk-backend-transaction.h
+@@ -0,0 +1,43 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alpm.h>
++#include <pk-backend.h>
++
++gboolean pk_backend_transaction_initialize (PkBackend *self,
++ pmtransflag_t flags,
++ GError **error);
++
++gboolean pk_backend_transaction_simulate (PkBackend *self,
++ GError **error);
++
++void pk_backend_transaction_packages (PkBackend *self);
++
++gboolean pk_backend_transaction_commit (PkBackend *self,
++ GError **error);
++
++gboolean pk_backend_transaction_end (PkBackend *self,
++ GError **error);
++
++gboolean pk_backend_transaction_finish (PkBackend *self,
++ GError *error);
+diff --git a/backends/alpm/pk-backend-update.c b/backends/alpm/pk-backend-update.c
+new file mode 100644
+index 0000000..a281953
+--- /dev/null
++++ b/backends/alpm/pk-backend-update.c
+@@ -0,0 +1,443 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alpm.h>
++#include <glib/gstdio.h>
++#include <pk-backend.h>
++#include <string.h>
++#include <sys/stat.h>
++
++#include "pk-backend-alpm.h"
++#include "pk-backend-error.h"
++#include "pk-backend-packages.h"
++#include "pk-backend-transaction.h"
++#include "pk-backend-update.h"
++
++static gchar *
++alpm_pkg_build_replaces (pmpkg_t *pkg)
++{
++ const alpm_list_t *i;
++ GString *string = NULL;
++
++ g_return_val_if_fail (pkg != NULL, NULL);
++ g_return_val_if_fail (localdb != NULL, NULL);
++
++ /* make a list of the packages that package replaces */
++ for (i = alpm_pkg_get_replaces (pkg); i != NULL; i = i->next) {
++ pmpkg_t *replaces = alpm_db_get_pkg (localdb, i->data);
++
++ if (replaces != NULL) {
++ gchar *package = alpm_pkg_build_id (replaces);
++ if (string == NULL) {
++ string = g_string_new (package);
++ } else {
++ g_string_append_printf (string, "&%s", package);
++ }
++ g_free (package);
++ }
++ }
++
++ if (string != NULL) {
++ return g_string_free (string, FALSE);
++ } else {
++ return NULL;
++ }
++}
++
++static gchar *
++alpm_pkg_build_urls (pmpkg_t *pkg)
++{
++ GString *string = g_string_new ("");
++#ifdef ALPM_PACKAGE_URL
++ const gchar *name, *arch, *repo, *url;
++#else
++ const gchar *url;
++#endif
++
++ g_return_val_if_fail (pkg != NULL, NULL);
++
++ /* grab the URL of the package... */
++ url = alpm_pkg_get_url (pkg);
++ if (url != NULL) {
++ g_string_append_printf (string, "%s;Package website;", url);
++ }
++
++#ifdef ALPM_PACKAGE_URL
++ /* ... and construct the distro URL if possible */
++ name = alpm_pkg_get_name (pkg);
++ arch = alpm_pkg_get_arch (pkg);
++ repo = alpm_db_get_name (alpm_pkg_get_db (pkg));
++
++ g_string_append_printf (string, ALPM_PACKAGE_URL ";Distribution page;",
++ repo, arch, name);
++#endif
++
++ g_string_truncate (string, string->len - 1);
++ return g_string_free (string, FALSE);
++}
++
++static gboolean
++alpm_pkg_same_pkgver (pmpkg_t *a, pmpkg_t *b)
++{
++ const gchar *version_a, *version_b, *last_a, *last_b;
++ gsize length_a, length_b;
++
++ g_return_val_if_fail (a != NULL, (b == NULL));
++ g_return_val_if_fail (b != NULL, FALSE);
++
++ version_a = alpm_pkg_get_version (a);
++ version_b = alpm_pkg_get_version (b);
++
++ last_a = strrchr (version_a, '-');
++ last_b = strrchr (version_b, '-');
++
++ if (last_a != NULL) {
++ length_a = last_a - version_a;
++ } else {
++ length_a = strlen (version_a);
++ }
++
++ if (last_b != NULL) {
++ length_b = last_b - version_b;
++ } else {
++ length_b = strlen (version_b);
++ }
++
++ if (length_a != length_b) {
++ return FALSE;
++ } else {
++ return strncmp (version_a, version_b, length_a) == 0;
++ }
++}
++
++static gboolean
++pk_backend_get_update_detail_thread (PkBackend *self)
++{
++ gchar **packages;
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (localdb != NULL, FALSE);
++
++ packages = pk_backend_get_strv (self, "package_ids");
++
++ g_return_val_if_fail (packages != NULL, FALSE);
++
++ /* collect details about updates */
++ for (; *packages != NULL; ++packages) {
++ pmpkg_t *pkg, *old;
++ pmdb_t *db;
++
++ gchar *upgrades, *replaces, *urls;
++ const gchar *reason;
++
++ PkRestartEnum restart;
++ PkUpdateStateEnum state;
++
++ GTimeVal built = { 0 }, installed = { 0 };
++ gchar *issued, *updated;
++
++ if (pk_backend_cancelled (self)) {
++ break;
++ }
++
++ pkg = pk_backend_find_pkg (self, *packages, &error);
++ if (pkg == NULL) {
++ break;
++ }
++
++ old = alpm_db_get_pkg (localdb, alpm_pkg_get_name (pkg));
++ if (old != NULL) {
++ upgrades = alpm_pkg_build_id (old);
++ if (alpm_pkg_same_pkgver (pkg, old)) {
++ reason = "Update to a newer release";
++ } else {
++ reason = "Update to a new upstream version";
++ }
++ } else {
++ upgrades = NULL;
++ reason = "Install to replace an older package";
++ }
++
++ db = alpm_pkg_get_db (pkg);
++ replaces = alpm_pkg_build_replaces (pkg);
++ urls = alpm_pkg_build_urls (pkg);
++
++ if (g_str_has_prefix (alpm_pkg_get_name (pkg), "kernel")) {
++ restart = PK_RESTART_ENUM_SYSTEM;
++ } else {
++ restart = PK_RESTART_ENUM_NONE;
++ }
++
++ if (g_str_has_suffix (alpm_db_get_name (db), "testing")) {
++ state = PK_UPDATE_STATE_ENUM_TESTING;
++ } else {
++ state = PK_UPDATE_STATE_ENUM_STABLE;
++ }
++
++ built.tv_sec = alpm_pkg_get_builddate (pkg);
++ if (built.tv_sec > 0) {
++ issued = g_time_val_to_iso8601 (&built);
++ } else {
++ issued = NULL;
++ }
++
++ if (upgrades != NULL) {
++ installed.tv_sec = alpm_pkg_get_installdate (old);
++ if (installed.tv_sec > 0) {
++ updated = g_time_val_to_iso8601 (&installed);
++ } else {
++ updated = NULL;
++ }
++ } else {
++ updated = NULL;
++ }
++
++ pk_backend_update_detail (self, *packages, upgrades, replaces,
++ urls, NULL, NULL, restart, reason,
++ NULL, state, issued, updated);
++
++ g_free (issued);
++ g_free (updated);
++
++ g_free (urls);
++ g_free (replaces);
++ g_free (upgrades);
++ }
++
++ return pk_backend_finish (self, error);
++}
++
++void
++pk_backend_get_update_detail (PkBackend *self, gchar **package_ids)
++{
++ g_return_if_fail (self != NULL);
++ g_return_if_fail (package_ids != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY,
++ pk_backend_get_update_detail_thread);
++}
++
++static gboolean
++pk_backend_update_databases (PkBackend *self, gint force, GError **error) {
++ alpm_cb_download dlcb;
++ alpm_cb_totaldl totaldlcb;
++ const alpm_list_t *i;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ if (!pk_backend_transaction_initialize (self, 0, error)) {
++ return FALSE;
++ }
++
++ alpm_logaction ("synchronizing package lists\n");
++
++ dlcb = alpm_option_get_dlcb ();
++ totaldlcb = alpm_option_get_totaldlcb ();
++
++ /* set total size to minus the number of databases */
++ i = alpm_option_get_syncdbs ();
++ totaldlcb (-alpm_list_count (i));
++
++ for (; i != NULL; i = i->next) {
++ gint result;
++
++ if (pk_backend_cancelled (self)) {
++ /* pretend to be finished */
++ i = NULL;
++ break;
++ }
++
++ result = alpm_db_update (force, i->data);
++
++ if (result > 0) {
++ /* fake the download when already up to date */
++ dlcb ("", 1, 1);
++ } else if (result < 0) {
++ g_set_error (error, ALPM_ERROR, pm_errno, "[%s]: %s",
++ alpm_db_get_name (i->data),
++ alpm_strerrorlast ());
++ break;
++ }
++ }
++
++ totaldlcb (0);
++
++ if (i == NULL) {
++ return pk_backend_transaction_end (self, error);
++ } else {
++ pk_backend_transaction_end (self, NULL);
++ return FALSE;
++ }
++}
++
++static gboolean
++alpm_pkg_is_ignorepkg (pmpkg_t *pkg)
++{
++ const alpm_list_t *ignorepkgs, *ignoregrps, *i;
++
++ g_return_val_if_fail (pkg != NULL, TRUE);
++
++ ignorepkgs = alpm_option_get_ignorepkgs ();
++ if (alpm_list_find_str (ignorepkgs, alpm_pkg_get_name (pkg)) != NULL) {
++ return TRUE;
++ }
++
++ ignoregrps = alpm_option_get_ignoregrps ();
++ for (i = alpm_pkg_get_groups (pkg); i != NULL; i = i->next) {
++ if (alpm_list_find_str (ignoregrps, i->data) != NULL) {
++ return TRUE;
++ }
++ }
++
++ return FALSE;
++}
++
++static gboolean
++alpm_pkg_is_syncfirst (pmpkg_t *pkg)
++{
++ g_return_val_if_fail (pkg != NULL, FALSE);
++
++ if (alpm_list_find_str (syncfirsts, alpm_pkg_get_name (pkg)) != NULL) {
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++static pmpkg_t *
++alpm_pkg_find_update (pmpkg_t *pkg, const alpm_list_t *dbs)
++{
++ const gchar *name;
++ const alpm_list_t *i;
++
++ g_return_val_if_fail (pkg != NULL, NULL);
++
++ name = alpm_pkg_get_name (pkg);
++
++ for (; dbs != NULL; dbs = dbs->next) {
++ pmpkg_t *update = alpm_db_get_pkg (dbs->data, name);
++
++ if (update != NULL) {
++ if (alpm_pkg_vercmp (alpm_pkg_get_version (update),
++ alpm_pkg_get_version (pkg)) > 0) {
++ return update;
++ } else {
++ return NULL;
++ }
++ }
++
++ i = alpm_db_get_pkgcache (dbs->data);
++ for (; i != NULL; i = i->next) {
++ if (alpm_list_find_str (alpm_pkg_get_replaces (i->data),
++ name) != NULL) {
++ return i->data;
++ }
++ }
++ }
++
++ return NULL;
++}
++
++static gboolean
++pk_backend_get_updates_thread (PkBackend *self)
++{
++ struct stat cache;
++ time_t one_hour_ago;
++ const alpm_list_t *i, *syncdbs;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++ g_return_val_if_fail (localdb != NULL, FALSE);
++
++ time (&one_hour_ago);
++ one_hour_ago -= 60 * 60;
++
++ /* refresh databases if they are older than an hour */
++ if (g_stat (ALPM_CACHE_PATH, &cache) < 0 ||
++ cache.st_mtime < one_hour_ago) {
++ GError *error = NULL;
++ /* show updates even if the databases could not be updated */
++ if (!pk_backend_update_databases (self, 0, &error)) {
++ g_warning ("%s", error->message);
++ }
++ } else {
++ g_debug ("databases have been refreshed recently");
++ }
++
++ /* find outdated and replacement packages */
++ syncdbs = alpm_option_get_syncdbs ();
++ for (i = alpm_db_get_pkgcache (localdb); i != NULL; i = i->next) {
++ pmpkg_t *upgrade = alpm_pkg_find_update (i->data, syncdbs);
++
++ if (pk_backend_cancelled (self)) {
++ break;
++ } else if (upgrade != NULL) {
++ PkInfoEnum info;
++
++ if (alpm_pkg_is_ignorepkg (upgrade)) {
++ info = PK_INFO_ENUM_BLOCKED;
++ } else if (alpm_pkg_is_syncfirst (upgrade)) {
++ info = PK_INFO_ENUM_IMPORTANT;
++ } else {
++ info = PK_INFO_ENUM_NORMAL;
++ }
++
++ pk_backend_pkg (self, upgrade, info);
++ }
++ }
++
++ return pk_backend_finish (self, NULL);
++}
++
++void
++pk_backend_get_updates (PkBackend *self, PkBitfield filters)
++{
++ g_return_if_fail (self != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_QUERY,
++ pk_backend_get_updates_thread);
++}
++
++static gboolean
++pk_backend_refresh_cache_thread (PkBackend *self)
++{
++ gint force;
++ GError *error = NULL;
++
++ g_return_val_if_fail (self != NULL, FALSE);
++
++ /* download databases even if they are older than current */
++ force = (gint) pk_backend_get_bool (self, "force");
++
++ pk_backend_update_databases (self, force, &error);
++ return pk_backend_finish (self, error);
++}
++
++void
++pk_backend_refresh_cache (PkBackend *self, gboolean force)
++{
++ g_return_if_fail (self != NULL);
++
++ pk_backend_run (self, PK_STATUS_ENUM_SETUP,
++ pk_backend_refresh_cache_thread);
++}
+diff --git a/backends/alpm/pk-backend-update.h b/backends/alpm/pk-backend-update.h
+new file mode 100644
+index 0000000..368965a
+--- /dev/null
++++ b/backends/alpm/pk-backend-update.h
+@@ -0,0 +1,22 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
++ * Copyright (C) 2008-2010 Valeriy Lyasotskiy <onestep@ukr.net>
++ * Copyright (C) 2010-2011 Jonathan Conder <jonno.conder@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * 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 2 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 copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
+diff --git a/backends/alpm/repos.list b/backends/alpm/repos.list
+new file mode 100644
+index 0000000..191d31d
+--- /dev/null
++++ b/backends/alpm/repos.list
+@@ -0,0 +1 @@
++# Generated by PackageKit
+diff --git a/backends/pacman/Makefile.am b/backends/pacman/Makefile.am
+deleted file mode 100644
+index 9ea0217..0000000
+--- a/backends/pacman/Makefile.am
++++ /dev/null
+@@ -1,53 +0,0 @@
+-INCLUDES = \
+- -DG_LOG_DOMAIN=\"PackageKit-Pacman\"
+-
+-PACMAN_CONFIG_FILE = $(confdir)/pacman.conf
+-PACMAN_GROUP_LIST = $(confdir)/groups.list
+-PACMAN_REPO_LIST = $(confdir)/repos.list
+-PACMAN_REPO_LIST_HEADER = "\# Generated by $(PACKAGE_NAME) - DO NOT MODIFY"
+-PACMAN_CACHE_PATH = $(localstatedir)/lib/pacman/sync
+-PACMAN_PACKAGE_URL = "http://www.archlinux.org/packages/%s/%s/%s/"
+-PACMAN_DEFAULT_PATH = "/bin:/usr/bin:/sbin:/usr/sbin"
+-
+-DEFS = -DPACMAN_CONFIG_FILE=\"$(PACMAN_CONFIG_FILE)\" \
+- -DPACMAN_GROUP_LIST=\"$(PACMAN_GROUP_LIST)\" \
+- -DPACMAN_REPO_LIST=\"$(PACMAN_REPO_LIST)\" \
+- -DPACMAN_REPO_LIST_HEADER=\"$(PACMAN_REPO_LIST_HEADER)\" \
+- -DPACMAN_CACHE_PATH=\"$(PACMAN_CACHE_PATH)\" \
+- -DPACMAN_PACKAGE_URL=\"$(PACMAN_PACKAGE_URL)\" \
+- -DPACMAN_DEFAULT_PATH=\"$(PACMAN_DEFAULT_PATH)\"
+-
+-confdir = $(PK_CONF_DIR)/pacman.d
+-conf_DATA = groups.list \
+- pacman.conf \
+- repos.list
+-
+-plugindir = $(PK_PLUGIN_DIR)
+-plugin_LTLIBRARIES = libpk_backend_pacman.la
+-
+-libpk_backend_pacman_la_SOURCES = backend-depends.c \
+- backend-error.c \
+- backend-groups.c \
+- backend-install.c \
+- backend-packages.c \
+- backend-pacman.c \
+- backend-remove.c \
+- backend-repos.c \
+- backend-search.c \
+- backend-transaction.c \
+- backend-update.c
+-libpk_backend_pacman_la_LIBADD = $(PK_PLUGIN_LIBS) \
+- $(PACMAN_LIBS)
+-libpk_backend_pacman_la_LDFLAGS = -module -avoid-version
+-libpk_backend_pacman_la_CFLAGS = $(PK_PLUGIN_CFLAGS) \
+- $(PACMAN_CFLAGS) \
+- $(WARNINGFLAGS_C)
+-
+-repos.list:
+- echo $(PACMAN_REPO_LIST_HEADER) > $@
+-
+-BUILT_SOURCES = repos.list
+-
+-EXTRA_DIST = $(conf_DATA) $(libpk_backend_pacman_la_SOURCES:.c=.h)
+-
+-CLEANFILES = $(BUILT_SOURCES)
+diff --git a/backends/pacman/backend-depends.c b/backends/pacman/backend-depends.c
+deleted file mode 100644
+index 9bd2324..0000000
+--- a/backends/pacman/backend-depends.c
++++ /dev/null
+@@ -1,298 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pacman.h>
+-#include "backend-packages.h"
+-#include "backend-pacman.h"
+-#include "backend-repos.h"
+-#include "backend-depends.h"
+-
+-static PacmanPackage *
+-pacman_list_find_provider (const PacmanList *packages, PacmanDependency *depend)
+-{
+- const PacmanList *list;
+-
+- g_return_val_if_fail (depend != NULL, NULL);
+-
+- /* find a package that provides depend */
+- for (list = packages; list != NULL; list = pacman_list_next (list)) {
+- PacmanPackage *provider = (PacmanPackage *) pacman_list_get (list);
+-
+- if (pacman_dependency_satisfied_by (depend, provider)) {
+- return provider;
+- }
+- }
+-
+- return NULL;
+-}
+-
+-static PacmanPackage *
+-pacman_sync_databases_find_provider (PacmanDependency *depend)
+-{
+- const PacmanList *databases;
+-
+- g_return_val_if_fail (pacman != NULL, NULL);
+- g_return_val_if_fail (depend != NULL, NULL);
+-
+- /* find the default package that provides depend */
+- for (databases = pacman_manager_get_sync_databases (pacman); databases != NULL; databases = pacman_list_next (databases)) {
+- PacmanDatabase *database = (PacmanDatabase *) pacman_list_get (databases);
+- PacmanPackage *provider = pacman_database_find_package (database, pacman_dependency_get_name (depend));
+-
+- if (provider != NULL && pacman_dependency_satisfied_by (depend, provider)) {
+- return provider;
+- }
+- }
+-
+- /* find any package that provides depend */
+- for (databases = pacman_manager_get_sync_databases (pacman); databases != NULL; databases = pacman_list_next (databases)) {
+- PacmanDatabase *database = (PacmanDatabase *) pacman_list_get (databases);
+- PacmanPackage *provider = pacman_list_find_provider (pacman_database_get_packages (database), depend);
+-
+- if (provider != NULL) {
+- return provider;
+- }
+- }
+-
+- return NULL;
+-}
+-
+-static gboolean
+-backend_get_depends_thread (PkBackend *backend)
+-{
+- guint iterator;
+- PacmanList *list, *packages = NULL;
+-
+- PkBitfield filters;
+- gchar **package_ids;
+- gboolean recursive;
+-
+- gboolean search_installed;
+- gboolean search_not_installed;
+-
+- g_return_val_if_fail (local_database != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- package_ids = pk_backend_get_strv (backend, "package_ids");
+- recursive = pk_backend_get_bool (backend, "recursive");
+-
+- g_return_val_if_fail (package_ids != NULL, FALSE);
+-
+- filters = pk_backend_get_uint (backend, "filters");
+- search_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED);
+- search_not_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_NOT_INSTALLED);
+-
+- /* construct an initial package list */
+- for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+- PacmanPackage *package = backend_get_package (backend, package_ids[iterator]);
+-
+- if (backend_cancelled (backend)) {
+- break;
+- } else if (package == NULL) {
+- pacman_list_free (packages);
+- backend_finished (backend);
+- return FALSE;
+- }
+-
+- packages = pacman_list_add (packages, package);
+- }
+-
+- /* package list might be modified along the way but that is ok */
+- for (list = packages; list != NULL; list = pacman_list_next (list)) {
+- PacmanPackage *package = (PacmanPackage *) pacman_list_get (list);
+- const PacmanList *depends;
+-
+- if (backend_cancelled (backend)) {
+- break;
+- }
+-
+- for (depends = pacman_package_get_dependencies (package); depends != NULL; depends = pacman_list_next (depends)) {
+- PacmanDependency *depend = (PacmanDependency *) pacman_list_get (depends);
+- PacmanPackage *provider = pacman_list_find_provider (packages, depend);
+-
+- if (backend_cancelled (backend)) {
+- break;
+- } else if (provider != NULL) {
+- continue;
+- }
+-
+- /* look for installed dependencies */
+- provider = pacman_list_find_provider (pacman_database_get_packages (local_database), depend);
+- if (provider != NULL) {
+- /* don't emit when not needed... */
+- if (!search_not_installed) {
+- backend_package (backend, provider, PK_INFO_ENUM_INSTALLED);
+- /* ... and assume installed packages also have installed dependencies */
+- if (recursive) {
+- packages = pacman_list_add (packages, provider);
+- }
+- }
+- continue;
+- }
+-
+- /* look for non-installed dependencies */
+- provider = pacman_sync_databases_find_provider (depend);
+- if (provider != NULL) {
+- /* don't emit when not needed... */
+- if (!search_installed) {
+- backend_package (backend, provider, PK_INFO_ENUM_AVAILABLE);
+- }
+- /* ... but keep looking for installed dependencies */
+- if (recursive) {
+- packages = pacman_list_add (packages, provider);
+- }
+- } else {
+- gchar *depend_id = pacman_dependency_to_string (depend);
+- pk_backend_error_code (backend, PK_ERROR_ENUM_DEP_RESOLUTION_FAILED, "Could not resolve dependency %s", depend_id);
+- g_free (depend_id);
+-
+- pacman_list_free (packages);
+- backend_finished (backend);
+- return FALSE;
+- }
+- }
+- }
+-
+- pacman_list_free (packages);
+- backend_finished (backend);
+- return TRUE;
+-}
+-
+-/**
+- * backend_get_depends:
+- **/
+-void
+-backend_get_depends (PkBackend *backend, PkBitfield filters, gchar **package_ids, gboolean recursive)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (package_ids != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_depends_thread);
+-}
+-
+-static PacmanPackage *
+-pacman_list_find_package (const PacmanList *packages, const gchar *name)
+-{
+- const PacmanList *list;
+-
+- g_return_val_if_fail (name != NULL, NULL);
+-
+- /* find a package called name */
+- for (list = packages; list != NULL; list = pacman_list_next (list)) {
+- PacmanPackage *package = (PacmanPackage *) pacman_list_get (list);
+-
+- if (g_strcmp0 (name, pacman_package_get_name (package)) == 0) {
+- return package;
+- }
+- }
+-
+- return NULL;
+-}
+-
+-static gboolean
+-backend_get_requires_thread (PkBackend *backend)
+-{
+- guint iterator;
+- PacmanList *list, *packages = NULL;
+-
+- gchar **package_ids;
+- gboolean recursive;
+-
+- g_return_val_if_fail (local_database != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- package_ids = pk_backend_get_strv (backend, "package_ids");
+- recursive = pk_backend_get_bool (backend, "recursive");
+-
+- g_return_val_if_fail (package_ids != NULL, FALSE);
+-
+- /* construct an initial package list */
+- for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+- PacmanPackage *package = backend_get_package (backend, package_ids[iterator]);
+-
+- if (backend_cancelled (backend)) {
+- break;
+- } else if (package == NULL) {
+- pacman_list_free (packages);
+- backend_finished (backend);
+- return FALSE;
+- }
+-
+- packages = pacman_list_add (packages, package);
+- }
+-
+- /* package list might be modified along the way but that is ok */
+- for (list = packages; list != NULL; list = pacman_list_next (list)) {
+- PacmanPackage *package = (PacmanPackage *) pacman_list_get (list);
+- PacmanList *requires, *required_by = pacman_package_find_required_by (package);
+-
+- if (backend_cancelled (backend)) {
+- break;
+- }
+-
+- for (requires = required_by; requires != NULL; requires = pacman_list_next (requires)) {
+- const gchar *name = (const gchar *) pacman_list_get (requires);
+- PacmanPackage *requirer = pacman_list_find_package (packages, name);
+-
+- if (backend_cancelled (backend)) {
+- break;
+- } else if (requirer != NULL) {
+- continue;
+- }
+-
+- /* look for installed requirers */
+- requirer = pacman_database_find_package (local_database, name);
+- if (requirer == NULL) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "Could not find package %s", name);
+-
+- pacman_list_free_full (required_by, g_free);
+- pacman_list_free (packages);
+- backend_finished (backend);
+- return FALSE;
+- }
+-
+- backend_package (backend, requirer, PK_INFO_ENUM_INSTALLED);
+- if (recursive) {
+- packages = pacman_list_add (packages, requirer);
+- }
+- }
+-
+- pacman_list_free_full (required_by, g_free);
+- }
+-
+- pacman_list_free (packages);
+- backend_finished (backend);
+- return TRUE;
+-}
+-
+-/**
+- * backend_get_requires:
+- **/
+-void
+-backend_get_requires (PkBackend *backend, PkBitfield filters, gchar **package_ids, gboolean recursive)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (package_ids != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_requires_thread);
+-}
+diff --git a/backends/pacman/backend-depends.h b/backends/pacman/backend-depends.h
+deleted file mode 100644
+index c6f7b6a..0000000
+--- a/backends/pacman/backend-depends.h
++++ /dev/null
+@@ -1,33 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pk-backend.h>
+-
+-void backend_get_depends (PkBackend *backend,
+- PkBitfield filters,
+- gchar **package_ids,
+- gboolean recursive);
+-void backend_get_requires (PkBackend *backend,
+- PkBitfield filters,
+- gchar **package_ids,
+- gboolean recursive);
+diff --git a/backends/pacman/backend-error.c b/backends/pacman/backend-error.c
+deleted file mode 100644
+index 2336508..0000000
+--- a/backends/pacman/backend-error.c
++++ /dev/null
+@@ -1,185 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pacman.h>
+-#include "backend-error.h"
+-
+-void
+-backend_error (PkBackend *backend, GError *error)
+-{
+- PkErrorEnum code = PK_ERROR_ENUM_INTERNAL_ERROR;
+-
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (error != NULL);
+-
+- /* convert error codes */
+- if (error->domain == PACMAN_ERROR) {
+- switch (error->code) {
+- case PACMAN_ERROR_MEMORY:
+- code = PK_ERROR_ENUM_OOM;
+- break;
+-
+- case PACMAN_ERROR_SYSTEM:
+- case PACMAN_ERROR_INVALID_ARGS:
+- case PACMAN_ERROR_NOT_INITIALIZED:
+- case PACMAN_ERROR_DATABASE_NOT_INITIALIZED:
+- case PACMAN_ERROR_SERVER_INVALID_URL:
+- case PACMAN_ERROR_REGEX_INVALID:
+- case PACMAN_ERROR_LIBARCHIVE:
+- case PACMAN_ERROR_LIBFETCH:
+- case PACMAN_ERROR_DOWNLOAD_HANDLER:
+- code = PK_ERROR_ENUM_INTERNAL_ERROR;
+- break;
+-
+- case PACMAN_ERROR_NOT_PERMITTED:
+- code = PK_ERROR_ENUM_NOT_AUTHORIZED;
+- break;
+-
+- case PACMAN_ERROR_FILE_NOT_FOUND:
+- case PACMAN_ERROR_DIRECTORY_NOT_FOUND:
+- code = PK_ERROR_ENUM_FILE_NOT_FOUND;
+- break;
+-
+- case PACMAN_ERROR_ALREADY_INITIALIZED:
+- case PACMAN_ERROR_DATABASE_ALREADY_INITIALIZED:
+- code = PK_ERROR_ENUM_FAILED_INITIALIZATION;
+- break;
+-
+- case PACMAN_ERROR_ALREADY_RUNNING:
+- code = PK_ERROR_ENUM_CANNOT_GET_LOCK;
+- break;
+-
+- case PACMAN_ERROR_DATABASE_OPEN_FAILED:
+- code = PK_ERROR_ENUM_REPO_NOT_FOUND;
+- break;
+-
+- case PACMAN_ERROR_DATABASE_CREATE_FAILED:
+- code = PK_ERROR_ENUM_CANNOT_WRITE_REPO_CONFIG;
+- break;
+-
+- case PACMAN_ERROR_DATABASE_NOT_FOUND:
+- code = PK_ERROR_ENUM_REPO_NOT_FOUND;
+- break;
+-
+- case PACMAN_ERROR_DATABASE_UPDATE_FAILED:
+- code = PK_ERROR_ENUM_REPO_NOT_AVAILABLE;
+- break;
+-
+- case PACMAN_ERROR_DATABASE_REMOVE_FAILED:
+- code = PK_ERROR_ENUM_REPO_CONFIGURATION_ERROR;
+- break;
+-
+- case PACMAN_ERROR_SERVER_NONE_AVAILABLE:
+- code = PK_ERROR_ENUM_NO_MORE_MIRRORS_TO_TRY;
+- break;
+-
+- case PACMAN_ERROR_TRANSACTION_ALREADY_INITIALIZED:
+- case PACMAN_ERROR_TRANSACTION_NOT_INITIALIZED:
+- case PACMAN_ERROR_TRANSACTION_DUPLICATE_TARGET:
+- case PACMAN_ERROR_TRANSACTION_NOT_READY:
+- case PACMAN_ERROR_TRANSACTION_NOT_PREPARED:
+- case PACMAN_ERROR_TRANSACTION_INVALID_OPERATION:
+- case PACMAN_ERROR_TRANSACTION_NOT_LOCKED:
+- code = PK_ERROR_ENUM_TRANSACTION_ERROR;
+- break;
+-
+- case PACMAN_ERROR_TRANSACTION_ABORTED:
+- code = PK_ERROR_ENUM_TRANSACTION_CANCELLED;
+- break;
+-
+- case PACMAN_ERROR_PACKAGE_NOT_FOUND:
+- code = PK_ERROR_ENUM_PACKAGE_NOT_FOUND;
+- break;
+-
+- case PACMAN_ERROR_PACKAGE_IGNORED:
+- code = PK_ERROR_ENUM_PACKAGE_INSTALL_BLOCKED;
+- break;
+-
+- case PACMAN_ERROR_DELTA_INVALID:
+- case PACMAN_ERROR_PACKAGE_INVALID:
+- code = PK_ERROR_ENUM_INVALID_PACKAGE_FILE;
+- break;
+-
+- case PACMAN_ERROR_PACKAGE_OPEN_FAILED:
+- code = PK_ERROR_ENUM_PACKAGE_NOT_FOUND;
+- break;
+-
+- case PACMAN_ERROR_PACKAGE_REMOVE_FAILED:
+- code = PK_ERROR_ENUM_PACKAGE_FAILED_TO_REMOVE;
+- break;
+-
+- case PACMAN_ERROR_PACKAGE_UNKNOWN_FILENAME:
+- case PACMAN_ERROR_PACKAGE_DATABASE_NOT_FOUND:
+- code = PK_ERROR_ENUM_PACKAGE_FAILED_TO_CONFIGURE;
+- break;
+-
+- case PACMAN_ERROR_DELTA_PATCH_FAILED:
+- code = PK_ERROR_ENUM_PACKAGE_FAILED_TO_BUILD;
+- break;
+-
+- case PACMAN_ERROR_DEPENDENCY_UNSATISFIED:
+- code = PK_ERROR_ENUM_DEP_RESOLUTION_FAILED;
+- break;
+-
+- case PACMAN_ERROR_CONFLICT:
+- code = PK_ERROR_ENUM_PACKAGE_CONFLICTS;
+- break;
+-
+- case PACMAN_ERROR_FILE_CONFLICT:
+- code = PK_ERROR_ENUM_FILE_CONFLICTS;
+- break;
+-
+- case PACMAN_ERROR_DOWNLOAD_FAILED:
+- code = PK_ERROR_ENUM_PACKAGE_DOWNLOAD_FAILED;
+- break;
+-
+- case PACMAN_ERROR_CONFIG_INVALID:
+- code = PK_ERROR_ENUM_FAILED_CONFIG_PARSING;
+- break;
+-
+- case PACMAN_ERROR_PACKAGE_HELD:
+- code = PK_ERROR_ENUM_CANNOT_REMOVE_SYSTEM_PACKAGE;
+- break;
+- }
+- }
+-
+- pk_backend_error_code (backend, code, "%s", error->message);
+- g_error_free (error);
+-}
+-
+-void
+-backend_message (PkBackend *backend, const gchar *message)
+-{
+- guint iterator;
+- gchar **messages = g_strsplit_set (message, "\r\n", 0);
+-
+- /* display multi-line messages in a nice format */
+- for (iterator = 0; messages[iterator] != NULL; ++iterator) {
+- g_strstrip (messages[iterator]);
+- if (*messages[iterator] != '\0') {
+- pk_backend_message (backend, PK_MESSAGE_ENUM_UNKNOWN, "%s", messages[iterator]);
+- }
+- }
+-
+- g_strfreev (messages);
+-}
+diff --git a/backends/pacman/backend-error.h b/backends/pacman/backend-error.h
+deleted file mode 100644
+index 2be8021..0000000
+--- a/backends/pacman/backend-error.h
++++ /dev/null
+@@ -1,29 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pk-backend.h>
+-
+-void backend_error (PkBackend *backend,
+- GError *error);
+-void backend_message (PkBackend *backend,
+- const gchar *message);
+diff --git a/backends/pacman/backend-groups.c b/backends/pacman/backend-groups.c
+deleted file mode 100644
+index 95ebce6..0000000
+--- a/backends/pacman/backend-groups.c
++++ /dev/null
+@@ -1,150 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <string.h>
+-#include <gio/gio.h>
+-#include "backend-error.h"
+-#include "backend-groups.h"
+-
+-static GHashTable *group_map = NULL;
+-static PkBitfield groups = 0;
+-
+-static GHashTable *
+-group_map_new (GError **error)
+-{
+- GHashTable *map;
+- GFile *file;
+-
+- GFileInputStream *file_stream;
+- GDataInputStream *data_stream;
+-
+- gchar *key, *value;
+- GError *e = NULL;
+-
+- g_debug ("pacman: reading groups from %s", PACMAN_GROUP_LIST);
+- file = g_file_new_for_path (PACMAN_GROUP_LIST);
+- file_stream = g_file_read (file, NULL, &e);
+-
+- if (file_stream == NULL) {
+- g_object_unref (file);
+- g_propagate_error (error, e);
+- return NULL;
+- }
+-
+- map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+- data_stream = g_data_input_stream_new (G_INPUT_STREAM (file_stream));
+-
+- /* read groups line by line, ignoring comments */
+- while ((value = g_data_input_stream_read_line (data_stream, NULL, NULL, &e)) != NULL) {
+- PkGroupEnum group;
+-
+- g_strstrip (value);
+- if (*value == '\0' || *value == '#') {
+- g_free (value);
+- continue;
+- }
+-
+- /* line format: alpm-group (space|tab)+ packagekit-group */
+- key = strsep (&value, " ");
+- g_strchomp (key);
+-
+- if (value == NULL) {
+- /* safe to cast as it is never freed or modified */
+- value = (gchar *) "other";
+- group = PK_GROUP_ENUM_OTHER;
+- } else {
+- g_strchug (value);
+- group = pk_group_enum_from_string (value);
+- }
+-
+- if (group != PK_GROUP_ENUM_UNKNOWN) {
+- /* use replace because key and value are allocated together */
+- g_hash_table_replace (map, key, value);
+- pk_bitfield_add (groups, group);
+- }
+- }
+-
+- g_object_unref (data_stream);
+- g_object_unref (file_stream);
+- g_object_unref (file);
+-
+- if (e != NULL) {
+- g_hash_table_unref (map);
+- g_propagate_error (error, e);
+- return NULL;
+- } else {
+- return map;
+- }
+-}
+-
+-gboolean
+-backend_initialize_groups (PkBackend *backend, GError **error)
+-{
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- group_map = group_map_new (error);
+- if (group_map == NULL) {
+- return FALSE;
+- }
+-
+- return TRUE;
+-}
+-
+-void
+-backend_destroy_groups (PkBackend *backend)
+-{
+- g_return_if_fail (backend != NULL);
+-
+- if (group_map != NULL) {
+- g_hash_table_unref (group_map);
+- }
+-}
+-
+-const gchar *
+-pacman_package_get_group (PacmanPackage *package)
+-{
+- const PacmanList *list;
+-
+- g_return_val_if_fail (group_map != NULL, NULL);
+- g_return_val_if_fail (package != NULL, NULL);
+-
+- /* use the first group that we recognise */
+- for (list = pacman_package_get_groups (package); list != NULL; list = pacman_list_next (list)) {
+- gpointer value = g_hash_table_lookup (group_map, pacman_list_get (list));
+- if (value != NULL) {
+- return (const gchar *) value;
+- }
+- }
+-
+- return "other";
+-}
+-
+-/**
+- * backend_get_groups:
+- **/
+-PkBitfield backend_get_groups (PkBackend *backend)
+-{
+- g_return_val_if_fail (backend != NULL, 0);
+-
+- return groups;
+-}
+diff --git a/backends/pacman/backend-groups.h b/backends/pacman/backend-groups.h
+deleted file mode 100644
+index 9642015..0000000
+--- a/backends/pacman/backend-groups.h
++++ /dev/null
+@@ -1,32 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pacman.h>
+-#include <pk-backend.h>
+-
+-gboolean backend_initialize_groups (PkBackend *backend,
+- GError **error);
+-void backend_destroy_groups (PkBackend *backend);
+-
+-const gchar *pacman_package_get_group (PacmanPackage *package);
+-PkBitfield backend_get_groups (PkBackend *backend);
+diff --git a/backends/pacman/backend-install.c b/backends/pacman/backend-install.c
+deleted file mode 100644
+index 5c188cc..0000000
+--- a/backends/pacman/backend-install.c
++++ /dev/null
+@@ -1,348 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pacman.h>
+-#include "backend-error.h"
+-#include "backend-pacman.h"
+-#include "backend-packages.h"
+-#include "backend-repos.h"
+-#include "backend-transaction.h"
+-#include "backend-install.h"
+-
+-static PacmanList *
+-backend_transaction_list_targets (PkBackend *backend)
+-{
+- gchar **package_ids;
+- guint iterator;
+- PacmanList *list = NULL;
+-
+- g_return_val_if_fail (backend != NULL, NULL);
+-
+- package_ids = pk_backend_get_strv (backend, "package_ids");
+-
+- g_return_val_if_fail (package_ids != NULL, NULL);
+-
+- for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+- gchar **package_id_data = pk_package_id_split (package_ids[iterator]);
+- list = pacman_list_add (list, g_strdup_printf ("%s/%s", package_id_data[PK_PACKAGE_ID_DATA], package_id_data[PK_PACKAGE_ID_NAME]));
+- g_strfreev (package_id_data);
+- }
+-
+- return list;
+-}
+-
+-static gboolean
+-backend_download_packages_thread (PkBackend *backend)
+-{
+- PacmanList *list;
+- PacmanList *cache_paths;
+- const gchar *directory;
+-
+- PacmanTransaction *transaction = NULL;
+- PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_IGNORE_DEPENDENCIES |
+- PACMAN_TRANSACTION_FLAGS_IGNORE_DEPENDENCY_CONFLICTS |
+- PACMAN_TRANSACTION_FLAGS_SYNC_DOWNLOAD_ONLY;
+-
+- g_return_val_if_fail (pacman != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- directory = pk_backend_get_string (backend, "directory");
+-
+- g_return_val_if_fail (directory != NULL, FALSE);
+-
+- /* download files to a PackageKit directory */
+- cache_paths = pacman_list_strdup (pacman_manager_get_cache_paths (pacman));
+- pacman_manager_set_cache_paths (pacman, NULL);
+- pacman_manager_add_cache_path (pacman, directory);
+-
+- /* run the transaction */
+- list = backend_transaction_list_targets (backend);
+- if (list != NULL) {
+- transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_SYNC, flags, list);
+- pacman_list_free_full (list, g_free);
+- }
+-
+- pacman_manager_set_cache_paths (pacman, cache_paths);
+- pacman_list_free_full (cache_paths, g_free);
+- return backend_transaction_finished (backend, transaction);
+-}
+-
+-/**
+- * backend_download_packages:
+- **/
+-void
+-backend_download_packages (PkBackend *backend, gchar **package_ids, const gchar *directory)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (package_ids != NULL);
+- g_return_if_fail (directory != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_SETUP, backend_download_packages_thread);
+-}
+-
+-static gboolean
+-backend_install_files_thread (PkBackend *backend)
+-{
+- guint iterator;
+- PacmanList *list = NULL;
+-
+- /* FS#5331: use only_trusted */
+- gchar **full_paths;
+-
+- PacmanTransaction *transaction = NULL;
+- PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE;
+-
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- full_paths = pk_backend_get_strv (backend, "full_paths");
+-
+- g_return_val_if_fail (full_paths != NULL, FALSE);
+-
+- /* run the transaction */
+- for (iterator = 0; full_paths[iterator] != NULL; ++iterator) {
+- list = pacman_list_add (list, full_paths[iterator]);
+- }
+- if (list != NULL) {
+- transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_INSTALL, flags, list);
+- pacman_list_free (list);
+- }
+-
+- return backend_transaction_finished (backend, transaction);
+-}
+-
+-/**
+- * backend_install_files:
+- **/
+-void
+-backend_install_files (PkBackend *backend, gboolean only_trusted, gchar **full_paths)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (full_paths != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_SETUP, backend_install_files_thread);
+-}
+-
+-static gboolean
+-backend_simulate_install_files_thread (PkBackend *backend)
+-{
+- guint iterator;
+- PacmanList *list = NULL;
+-
+- gchar **full_paths;
+-
+- PacmanTransaction *transaction = NULL;
+- PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE;
+-
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- full_paths = pk_backend_get_strv (backend, "full_paths");
+-
+- g_return_val_if_fail (full_paths != NULL, FALSE);
+-
+- /* prepare the transaction */
+- for (iterator = 0; full_paths[iterator] != NULL; ++iterator) {
+- list = pacman_list_add (list, full_paths[iterator]);
+- }
+- if (list != NULL) {
+- transaction = backend_transaction_simulate (backend, PACMAN_TRANSACTION_INSTALL, flags, list);
+- pacman_list_free (list);
+-
+- if (transaction != NULL) {
+- /* emit packages that would have been installed or removed */
+- backend_transaction_packages (backend, transaction);
+- }
+- }
+-
+- return backend_transaction_finished (backend, transaction);
+-}
+-
+-/**
+- * backend_install_files:
+- **/
+-void
+-backend_simulate_install_files (PkBackend *backend, gchar **full_paths)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (full_paths != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_SETUP, backend_simulate_install_files_thread);
+-}
+-
+-static gboolean
+-backend_install_packages_thread (PkBackend *backend)
+-{
+- PacmanList *list;
+- /* FS#5331: use only_trusted */
+- PacmanTransaction *transaction = NULL;
+- PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE;
+-
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- /* run the transaction */
+- list = backend_transaction_list_targets (backend);
+- if (list != NULL) {
+- transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_SYNC, flags, list);
+- pacman_list_free_full (list, g_free);
+- }
+-
+- return backend_transaction_finished (backend, transaction);
+-}
+-
+-/**
+- * backend_install_packages:
+- **/
+-void
+-backend_install_packages (PkBackend *backend, gboolean only_trusted, gchar **package_ids)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (package_ids != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_SETUP, backend_install_packages_thread);
+-}
+-
+-static gboolean
+-backend_simulate_install_packages_thread (PkBackend *backend)
+-{
+- PacmanList *list;
+-
+- PacmanTransaction *transaction = NULL;
+- PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE;
+-
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- /* prepare the transaction */
+- list = backend_transaction_list_targets (backend);
+- if (list != NULL) {
+- transaction = backend_transaction_simulate (backend, PACMAN_TRANSACTION_SYNC, flags, list);
+- pacman_list_free_full (list, g_free);
+-
+- if (transaction != NULL) {
+- /* emit packages that would have been installed or removed */
+- backend_transaction_packages (backend, transaction);
+- }
+- }
+-
+- return backend_transaction_finished (backend, transaction);
+-}
+-
+-/**
+- * backend_simulate_install_packages:
+- **/
+-void
+-backend_simulate_install_packages (PkBackend *backend, gchar **package_ids)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (package_ids != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_SETUP, backend_simulate_install_packages_thread);
+-}
+-
+-static gboolean
+-backend_update_packages_thread (PkBackend *backend)
+-{
+- PacmanList *list, *asdeps = NULL;
+- /* FS#5331: use only_trusted */
+- PacmanTransaction *transaction = NULL;
+- PacmanTransactionFlags sflags = PACMAN_TRANSACTION_FLAGS_NONE, mflags = PACMAN_TRANSACTION_FLAGS_INSTALL_IMPLICIT;
+-
+- g_return_val_if_fail (local_database != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- /* prepare the transaction */
+- list = backend_transaction_list_targets (backend);
+- if (list != NULL) {
+- transaction = backend_transaction_simulate (backend, PACMAN_TRANSACTION_SYNC, sflags, list);
+- pacman_list_free_full (list, g_free);
+-
+- if (transaction != NULL) {
+- const PacmanList *installs, *removes;
+-
+- /* change the install reason of for packages that replace only dependencies of other packages */
+- for (installs = pacman_transaction_get_installs (transaction); installs != NULL; installs = pacman_list_next (installs)) {
+- PacmanPackage *install = (PacmanPackage *) pacman_list_get (installs);
+- const gchar *name = pacman_package_get_name (install);
+-
+- if (backend_cancelled (backend)) {
+- break;
+- } else if (pacman_database_find_package (local_database, name) == NULL) {
+- const PacmanList *replaces = pacman_package_get_replaces (install);
+-
+- for (removes = pacman_transaction_get_removes (transaction); removes != NULL; removes = pacman_list_next (removes)) {
+- PacmanPackage *remove = (PacmanPackage *) pacman_list_get (removes);
+- const gchar *replace = pacman_package_get_name (remove);
+-
+- if (backend_cancelled (backend)) {
+- break;
+- } else if (pacman_list_find_string (replaces, replace)) {
+- if (pacman_package_was_explicitly_installed (remove)) {
+- break;
+- }
+- }
+- }
+-
+- /* none of the replaced packages were installed explicitly */
+- if (removes == NULL) {
+- asdeps = pacman_list_add (asdeps, g_strdup (name));
+- }
+- }
+- }
+-
+- transaction = backend_transaction_commit (backend, transaction);
+- }
+- }
+-
+- /* mark replacements as deps if required */
+- if (asdeps != NULL) {
+- if (transaction != NULL) {
+- g_object_unref (transaction);
+- transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_MODIFY, mflags, asdeps);
+- }
+- pacman_list_free_full (asdeps, g_free);
+- }
+-
+- return backend_transaction_finished (backend, transaction);
+-}
+-
+-/**
+- * backend_update_packages:
+- **/
+-void
+-backend_update_packages (PkBackend *backend, gboolean only_trusted, gchar **package_ids)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (package_ids != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_SETUP, backend_update_packages_thread);
+-}
+-
+-/**
+- * backend_simulate_update_packages:
+- **/
+-void
+-backend_simulate_update_packages (PkBackend *backend, gchar **package_ids)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (package_ids != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_SETUP, backend_simulate_install_packages_thread);
+-}
+diff --git a/backends/pacman/backend-install.h b/backends/pacman/backend-install.h
+deleted file mode 100644
+index 0685a48..0000000
+--- a/backends/pacman/backend-install.h
++++ /dev/null
+@@ -1,45 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pk-backend.h>
+-
+-void backend_download_packages (PkBackend *backend,
+- gchar **package_ids,
+- const gchar *directory);
+-void backend_install_files (PkBackend *backend,
+- gboolean only_trusted,
+- gchar **full_paths);
+-void backend_simulate_install_files (PkBackend *backend,
+- gchar **full_paths);
+-
+-void backend_install_packages (PkBackend *backend,
+- gboolean only_trusted,
+- gchar **package_ids);
+-void backend_simulate_install_packages (PkBackend *backend,
+- gchar **package_ids);
+-
+-void backend_update_packages (PkBackend *backend,
+- gboolean only_trusted,
+- gchar **package_ids);
+-void backend_simulate_update_packages (PkBackend *backend,
+- gchar **package_ids);
+diff --git a/backends/pacman/backend-packages.c b/backends/pacman/backend-packages.c
+deleted file mode 100644
+index a00f107..0000000
+--- a/backends/pacman/backend-packages.c
++++ /dev/null
+@@ -1,345 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pacman.h>
+-#include "backend-groups.h"
+-#include "backend-pacman.h"
+-#include "backend-repos.h"
+-#include "backend-packages.h"
+-
+-gchar *
+-pacman_package_make_id (PacmanPackage *package)
+-{
+- const gchar *name, *version, *arch, *repo;
+- PacmanDatabase *database;
+-
+- g_return_val_if_fail (local_database != NULL, NULL);
+- g_return_val_if_fail (package != NULL, NULL);
+-
+- name = pacman_package_get_name (package);
+- version = pacman_package_get_version (package);
+-
+- arch = pacman_package_get_arch (package);
+- if (arch == NULL) {
+- arch = "any";
+- }
+-
+- /* PackageKit requires "local" for package files and "installed" for installed packages */
+- database = pacman_package_get_database (package);
+- if (database == NULL) {
+- repo = "local";
+- } else if (database == local_database) {
+- repo = "installed";
+- } else {
+- repo = pacman_database_get_name (database);
+- }
+-
+- return pk_package_id_build (name, version, arch, repo);
+-}
+-
+-void
+-backend_package (PkBackend *backend, PacmanPackage *package, PkInfoEnum info)
+-{
+- gchar *package_id;
+-
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (package != NULL);
+-
+- /* build and emit package id */
+- package_id = pacman_package_make_id (package);
+- pk_backend_package (backend, info, package_id, pacman_package_get_description (package));
+- g_free (package_id);
+-}
+-
+-PacmanPackage *
+-backend_get_package (PkBackend *backend, const gchar *package_id)
+-{
+- gchar **package_id_data;
+- const gchar *repo;
+- PacmanDatabase *database;
+- PacmanPackage *package;
+-
+- g_return_val_if_fail (pacman != NULL, NULL);
+- g_return_val_if_fail (local_database != NULL, NULL);
+- g_return_val_if_fail (backend != NULL, NULL);
+- g_return_val_if_fail (package_id != NULL, NULL);
+-
+- package_id_data = pk_package_id_split (package_id);
+- repo = package_id_data[PK_PACKAGE_ID_DATA];
+-
+- /* find the database to search in */
+- if (g_strcmp0 (repo, "installed") == 0) {
+- database = local_database;
+- } else {
+- database = pacman_manager_find_sync_database (pacman, repo);
+- }
+-
+- if (database == NULL) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_REPO_NOT_FOUND, "Could not find repo [%s]", repo);
+- g_strfreev (package_id_data);
+- return NULL;
+- }
+-
+- /* find the package in the database */
+- package = pacman_database_find_package (database, package_id_data[PK_PACKAGE_ID_NAME]);
+- if (package == NULL || g_strcmp0 (pacman_package_get_version (package), package_id_data[PK_PACKAGE_ID_VERSION]) != 0) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "Could not find package with ID %s", package_id);
+- g_strfreev (package_id_data);
+- return NULL;
+- }
+-
+- g_strfreev (package_id_data);
+- return package;
+-}
+-
+-static gboolean
+-backend_resolve_thread (PkBackend *backend)
+-{
+- guint iterator;
+-
+- gchar **package_ids;
+- PkBitfield filters;
+-
+- gboolean search_installed;
+- gboolean search_not_installed;
+-
+- g_return_val_if_fail (pacman != NULL, FALSE);
+- g_return_val_if_fail (local_database != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- package_ids = pk_backend_get_strv (backend, "package_ids");
+- filters = pk_backend_get_uint (backend, "filters");
+-
+- g_return_val_if_fail (package_ids != NULL, FALSE);
+-
+- search_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED);
+- search_not_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_NOT_INSTALLED);
+-
+- for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+- if (backend_cancelled (backend)) {
+- break;
+- }
+-
+- /* find a package with the given id or name */
+- if (pk_package_id_check (package_ids[iterator])) {
+- PacmanPackage *package = backend_get_package (backend, package_ids[iterator]);
+- if (package == NULL) {
+- backend_finished (backend);
+- return FALSE;
+- }
+-
+- /* don't emit when not needed */
+- if (pacman_package_get_database (package) == local_database) {
+- if (!search_not_installed) {
+- backend_package (backend, package, PK_INFO_ENUM_INSTALLED);
+- }
+- } else {
+- if (!search_installed) {
+- backend_package (backend, package, PK_INFO_ENUM_AVAILABLE);
+- }
+- }
+- } else {
+- /* find installed packages first */
+- if (!search_not_installed) {
+- PacmanPackage *package = pacman_database_find_package (local_database, package_ids[iterator]);
+-
+- if (package != NULL) {
+- backend_package (backend, package, PK_INFO_ENUM_INSTALLED);
+- continue;
+- }
+- }
+-
+- if (!search_installed) {
+- const PacmanList *databases;
+-
+- for (databases = pacman_manager_get_sync_databases (pacman); databases != NULL; databases = pacman_list_next (databases)) {
+- PacmanDatabase *database = (PacmanDatabase *) pacman_list_get (databases);
+- PacmanPackage *package = pacman_database_find_package (database, package_ids[iterator]);
+-
+- if (package != NULL) {
+- backend_package (backend, package, PK_INFO_ENUM_AVAILABLE);
+- break;
+- }
+- }
+- }
+- }
+- }
+-
+- backend_finished (backend);
+- return TRUE;
+-}
+-
+-/**
+- * backend_resolve:
+- **/
+-void
+-backend_resolve (PkBackend *backend, PkBitfield filters, gchar **package_ids)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (package_ids != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_resolve_thread);
+-}
+-
+-static gboolean
+-backend_get_details_thread (PkBackend *backend)
+-{
+- guint iterator;
+-
+- gchar **package_ids;
+-
+- g_return_val_if_fail (local_database != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- package_ids = pk_backend_get_strv (backend, "package_ids");
+-
+- g_return_val_if_fail (package_ids != NULL, FALSE);
+-
+- /* collect details about packages */
+- for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+- PacmanPackage *package;
+- const PacmanList *list;
+- GString *string;
+-
+- gchar *licenses;
+- PkGroupEnum group;
+- const gchar *description, *url;
+- gulong size;
+-
+- if (backend_cancelled (backend)) {
+- break;
+- }
+-
+- package = backend_get_package (backend, package_ids[iterator]);
+- if (package == NULL) {
+- backend_finished (backend);
+- return FALSE;
+- }
+-
+- list = pacman_package_get_licenses (package);
+- if (list == NULL) {
+- string = g_string_new ("unknown");
+- } else {
+- string = g_string_new ((const gchar *) pacman_list_get (list));
+- for (list = pacman_list_next (list); list != NULL; list = pacman_list_next (list)) {
+- /* assume OR although it may not be correct */
+- g_string_append_printf (string, " or %s", (const gchar *) pacman_list_get (list));
+- }
+- }
+-
+- group = pk_group_enum_from_string (pacman_package_get_group (package));
+- description = pacman_package_get_description (package);
+- url = pacman_package_get_url (package);
+-
+- if (pacman_package_get_database (package) == local_database) {
+- size = pacman_package_get_installed_size (package);
+- } else {
+- size = pacman_package_get_download_size (package);
+- }
+-
+- licenses = g_string_free (string, FALSE);
+- pk_backend_details (backend, package_ids[iterator], licenses, group, description, url, size);
+- g_free (licenses);
+- }
+-
+- backend_finished (backend);
+- return TRUE;
+-}
+-
+-/**
+- * backend_get_details:
+- **/
+-void
+-backend_get_details (PkBackend *backend, gchar **package_ids)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (package_ids != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_details_thread);
+-}
+-
+-static gboolean
+-backend_get_files_thread (PkBackend *backend)
+-{
+- guint iterator;
+-
+- gchar **package_ids;
+-
+- g_return_val_if_fail (pacman != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- package_ids = pk_backend_get_strv (backend, "package_ids");
+-
+- g_return_val_if_fail (package_ids != NULL, FALSE);
+-
+- /* enumerate files provided by package */
+- for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+- PacmanPackage *package;
+- const PacmanList *list;
+-
+- GString *string;
+- gchar *files;
+-
+- if (backend_cancelled (backend)) {
+- break;
+- }
+-
+- package = backend_get_package (backend, package_ids[iterator]);
+- if (package == NULL) {
+- backend_finished (backend);
+- return FALSE;
+- }
+-
+- list = pacman_package_get_files (package);
+- if (list == NULL) {
+- string = g_string_new ("");
+- } else {
+- const gchar *root_path = pacman_manager_get_root_path (pacman);
+- string = g_string_new (root_path);
+- g_string_append (string, (const gchar *) pacman_list_get (list));
+-
+- for (list = pacman_list_next (list); list != NULL; list = pacman_list_next (list)) {
+- g_string_append_printf (string, ";%s%s", root_path, (const gchar *) pacman_list_get (list));
+- }
+- }
+-
+- files = g_string_free (string, FALSE);
+- pk_backend_files (backend, package_ids[iterator], files);
+- g_free (files);
+- }
+-
+- backend_finished (backend);
+- return TRUE;
+-}
+-
+-/**
+- * backend_get_files:
+- **/
+-void
+-backend_get_files (PkBackend *backend, gchar **package_ids)
+-{
+- g_return_if_fail (pacman != NULL);
+- g_return_if_fail (backend != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_files_thread);
+-}
+diff --git a/backends/pacman/backend-packages.h b/backends/pacman/backend-packages.h
+deleted file mode 100644
+index 2064b89..0000000
+--- a/backends/pacman/backend-packages.h
++++ /dev/null
+@@ -1,41 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pacman.h>
+-#include <pk-backend.h>
+-
+-gchar *pacman_package_make_id (PacmanPackage *package);
+-void backend_package (PkBackend *backend,
+- PacmanPackage *package,
+- PkInfoEnum info);
+-
+-PacmanPackage *backend_get_package (PkBackend *backend,
+- const gchar *package_id);
+-void backend_resolve (PkBackend *backend,
+- PkBitfield filters,
+- gchar **package_ids);
+-
+-void backend_get_details (PkBackend *backend,
+- gchar **package_ids);
+-void backend_get_files (PkBackend *backend,
+- gchar **package_ids);
+diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
+deleted file mode 100644
+index 1276f15..0000000
+--- a/backends/pacman/backend-pacman.c
++++ /dev/null
+@@ -1,260 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include "backend-depends.h"
+-#include "backend-error.h"
+-#include "backend-groups.h"
+-#include "backend-install.h"
+-#include "backend-packages.h"
+-#include "backend-remove.h"
+-#include "backend-repos.h"
+-#include "backend-search.h"
+-#include "backend-transaction.h"
+-#include "backend-update.h"
+-#include "backend-pacman.h"
+-
+-PacmanManager *pacman = NULL;
+-GCancellable *cancellable = NULL;
+-
+-static void
+-pacman_message_cb (const gchar *domain, GLogLevelFlags level, const gchar *message, gpointer user_data)
+-{
+- g_return_if_fail (message != NULL);
+- g_return_if_fail (user_data != NULL);
+-
+-/* disable due to recursive logging, will fix via improving alpm backend */
+-#if 0
+- /* report important output to PackageKit */
+- switch (level) {
+- case G_LOG_LEVEL_WARNING:
+- case G_LOG_LEVEL_MESSAGE:
+- g_warning ("pacman: %s", message);
+- backend_message ((PkBackend *) user_data, message);
+- break;
+-
+- case G_LOG_LEVEL_INFO:
+- case G_LOG_LEVEL_DEBUG:
+- g_debug ("pacman: %s", message);
+- break;
+-
+- default:
+- g_warning ("pacman: %s", message);
+- break;
+- }
+-#endif
+-}
+-
+-/**
+- * backend_initialize:
+- **/
+-static void
+-backend_initialize (PkBackend *backend)
+-{
+- GError *error = NULL;
+- GLogLevelFlags flags = G_LOG_LEVEL_MASK;
+-
+- g_return_if_fail (backend != NULL);
+-
+- /* handle output from pacman */
+- g_log_set_handler ("Pacman", flags, pacman_message_cb, backend);
+-
+- /* PATH needs to be set for install scriptlets */
+- g_setenv ("PATH", PACMAN_DEFAULT_PATH, FALSE);
+-
+- g_debug ("pacman: initializing");
+-
+- /* initialize pacman-glib */
+- pacman = pacman_manager_get (&error);
+- if (pacman == NULL) {
+- g_error ("pacman: %s", error->message);
+- g_error_free (error);
+- return;
+- }
+-
+- /* configure and disable the relevant databases */
+- if (!backend_initialize_databases (backend, &error)) {
+- g_error ("pacman: %s", error->message);
+- g_error_free (error);
+- return;
+- }
+-
+- /* read the group mapping from a config file */
+- if (!backend_initialize_groups (backend, &error)) {
+- g_error ("pacman: %s", error->message);
+- g_error_free (error);
+- return;
+- }
+-
+- /* setup better download progress reporting */
+- if (!backend_initialize_downloads (backend, &error)) {
+- g_error ("pacman: %s", error->message);
+- g_error_free (error);
+- return;
+- }
+-}
+-
+-/**
+- * backend_destroy:
+- **/
+-static void
+-backend_destroy (PkBackend *backend)
+-{
+- g_return_if_fail (backend != NULL);
+-
+- g_debug ("pacman: cleaning up");
+-
+- backend_destroy_downloads (backend);
+- backend_destroy_groups (backend);
+- backend_destroy_databases (backend);
+-
+- if (pacman != NULL) {
+- g_object_unref (pacman);
+- }
+-}
+-
+-/**
+- * backend_get_filters:
+- **/
+-static PkBitfield
+-backend_get_filters (PkBackend *backend)
+-{
+- g_return_val_if_fail (backend != NULL, 0);
+-
+- return pk_bitfield_from_enums (PK_FILTER_ENUM_INSTALLED, -1);
+-}
+-
+-/**
+- * backend_get_mime_types:
+- **/
+-static gchar *
+-backend_get_mime_types (PkBackend *backend)
+-{
+- g_return_val_if_fail (backend != NULL, NULL);
+-
+- /* packages currently use .pkg.tar.gz and .pkg.tar.xz */
+- return g_strdup ("application/x-compressed-tar;application/x-xz-compressed-tar");
+-}
+-
+-void
+-backend_run (PkBackend *backend, PkStatusEnum status, PkBackendThreadFunc func)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (func != NULL);
+-
+- if (cancellable != NULL) {
+- g_warning ("pacman: cancellable was not NULL");
+- g_object_unref (cancellable);
+- }
+- cancellable = g_cancellable_new ();
+- pk_backend_set_allow_cancel (backend, TRUE);
+-
+- pk_backend_set_status (backend, status);
+- pk_backend_thread_create (backend, func);
+-}
+-
+-/**
+- * backend_cancel:
+- **/
+-static void
+-backend_cancel (PkBackend *backend)
+-{
+- g_return_if_fail (backend != NULL);
+-
+- if (cancellable != NULL) {
+- g_cancellable_cancel (cancellable);
+- }
+-}
+-
+-gboolean
+-backend_cancelled (PkBackend *backend)
+-{
+- g_return_val_if_fail (cancellable != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- if (g_cancellable_is_cancelled (cancellable)) {
+- pk_backend_set_status (backend, PK_STATUS_ENUM_CANCEL);
+- return TRUE;
+- } else {
+- return FALSE;
+- }
+-}
+-
+-void
+-backend_finished (PkBackend *backend)
+-{
+- g_return_if_fail (backend != NULL);
+-
+- pk_backend_set_allow_cancel (backend, FALSE);
+- if (cancellable != NULL) {
+- g_object_unref (cancellable);
+- cancellable = NULL;
+- }
+-
+- pk_backend_thread_finished (backend);
+-}
+-
+-PK_BACKEND_OPTIONS (
+- "pacman", /* description */
+- "Jonathan Conder <j@skurvy.no-ip.org>", /* author */
+- backend_initialize, /* initialize */
+- backend_destroy, /* destroy */
+- backend_get_groups, /* get_groups */
+- backend_get_filters, /* get_filters */
+- NULL, /* get_roles */
+- backend_get_mime_types, /* get_mime_types */
+- backend_cancel, /* cancel */
+- backend_download_packages, /* download_packages */
+- NULL, /* get_categories */
+- backend_get_depends, /* get_depends */
+- backend_get_details, /* get_details */
+- NULL, /* get_distro_upgrades */
+- backend_get_files, /* get_files */
+- backend_get_packages, /* get_packages */
+- backend_get_repo_list, /* get_repo_list */
+- backend_get_requires, /* get_requires */
+- backend_get_update_detail, /* get_update_detail */
+- backend_get_updates, /* get_updates */
+- backend_install_files, /* install_files */
+- backend_install_packages, /* install_packages */
+- NULL, /* install_signature */
+- backend_refresh_cache, /* refresh_cache */
+- backend_remove_packages, /* remove_packages */
+- backend_repo_enable, /* repo_enable */
+- NULL, /* repo_set_data */
+- backend_resolve, /* resolve */
+- NULL, /* rollback */
+- backend_search_details, /* search_details */
+- backend_search_files, /* search_files */
+- backend_search_groups, /* search_groups */
+- backend_search_names, /* search_names */
+- backend_update_packages, /* update_packages */
+- NULL, /* update_system */
+- backend_what_provides, /* what_provides */
+- backend_simulate_install_files, /* simulate_install_files */
+- backend_simulate_install_packages, /* simulate_install_packages */
+- backend_simulate_remove_packages, /* simulate_remove_packages */
+- backend_simulate_update_packages, /* simulate_update_packages */
+- NULL, /* upgrade_packages */
+- NULL, /* transaction_start */
+- NULL /* transaction_stop */
+-);
+diff --git a/backends/pacman/backend-pacman.h b/backends/pacman/backend-pacman.h
+deleted file mode 100644
+index 0d7b89b..0000000
+--- a/backends/pacman/backend-pacman.h
++++ /dev/null
+@@ -1,35 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <gio/gio.h>
+-#include <pacman.h>
+-#include <pk-backend.h>
+-
+-extern PacmanManager *pacman;
+-extern GCancellable *cancellable;
+-
+-void backend_run (PkBackend *backend,
+- PkStatusEnum status,
+- PkBackendThreadFunc func);
+-gboolean backend_cancelled (PkBackend *backend);
+-void backend_finished (PkBackend *backend);
+diff --git a/backends/pacman/backend-remove.c b/backends/pacman/backend-remove.c
+deleted file mode 100644
+index b31218b..0000000
+--- a/backends/pacman/backend-remove.c
++++ /dev/null
+@@ -1,142 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pacman.h>
+-#include "backend-error.h"
+-#include "backend-packages.h"
+-#include "backend-pacman.h"
+-#include "backend-transaction.h"
+-#include "backend-remove.h"
+-
+-static PacmanList *
+-backend_remove_list_targets (PkBackend *backend)
+-{
+- gchar **package_ids;
+- guint iterator;
+- PacmanList *list = NULL;
+-
+- g_return_val_if_fail (backend != NULL, NULL);
+-
+- package_ids = pk_backend_get_strv (backend, "package_ids");
+-
+- g_return_val_if_fail (package_ids != NULL, NULL);
+-
+- for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+- gchar **package_id_data = pk_package_id_split (package_ids[iterator]);
+- list = pacman_list_add (list, g_strdup (package_id_data[PK_PACKAGE_ID_NAME]));
+- g_strfreev (package_id_data);
+- }
+-
+- return list;
+-}
+-
+-static gboolean
+-backend_remove_packages_thread (PkBackend *backend)
+-{
+- PacmanList *list;
+- gboolean allow_deps;
+- gboolean autoremove;
+-
+- PacmanTransaction *transaction = NULL;
+- PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE;
+-
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- allow_deps = pk_backend_get_bool (backend, "allow_deps");
+- autoremove = pk_backend_get_bool (backend, "autoremove");
+-
+- /* remove packages that depend on those to be removed */
+- if (allow_deps) {
+- flags |= PACMAN_TRANSACTION_FLAGS_REMOVE_CASCADE;
+- }
+- /* remove unneeded packages that were required by those to be removed */
+- if (autoremove) {
+- flags |= PACMAN_TRANSACTION_FLAGS_REMOVE_RECURSIVE;
+- }
+-
+- /* run the transaction */
+- list = backend_remove_list_targets (backend);
+- if (list != NULL) {
+- transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_REMOVE, flags, list);
+- pacman_list_free_full (list, g_free);
+- }
+-
+- return backend_transaction_finished (backend, transaction);
+-}
+-
+-/**
+- * backend_remove_packages:
+- **/
+-void
+-backend_remove_packages (PkBackend *backend, gchar **package_ids, gboolean allow_deps, gboolean autoremove)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (package_ids != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_SETUP, backend_remove_packages_thread);
+-}
+-
+-static gboolean
+-backend_simulate_remove_packages_thread (PkBackend *backend)
+-{
+- PacmanList *list;
+- gboolean autoremove;
+-
+- PacmanTransaction *transaction = NULL;
+- PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_REMOVE_CASCADE;
+-
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- autoremove = pk_backend_get_bool (backend, "autoremove");
+-
+- /* remove unneeded packages that were required by those to be removed */
+- if (autoremove) {
+- flags |= PACMAN_TRANSACTION_FLAGS_REMOVE_RECURSIVE;
+- }
+-
+- /* prepare the transaction */
+- list = backend_remove_list_targets (backend);
+- if (list != NULL) {
+- transaction = backend_transaction_simulate (backend, PACMAN_TRANSACTION_REMOVE, flags, list);
+- pacman_list_free_full (list, g_free);
+-
+- if (transaction != NULL) {
+- /* emit packages that would have been installed or removed */
+- backend_transaction_packages (backend, transaction);
+- }
+- }
+-
+- return backend_transaction_finished (backend, transaction);
+-}
+-
+-/**
+- * backend_simulate_remove_packages:
+- **/
+-void
+-backend_simulate_remove_packages (PkBackend *backend, gchar **package_ids, gboolean autoremove)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (package_ids != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_SETUP, backend_simulate_remove_packages_thread);
+-}
+diff --git a/backends/pacman/backend-remove.h b/backends/pacman/backend-remove.h
+deleted file mode 100644
+index 90f0374..0000000
+--- a/backends/pacman/backend-remove.h
++++ /dev/null
+@@ -1,32 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pk-backend.h>
+-
+-void backend_remove_packages (PkBackend *backend,
+- gchar **package_ids,
+- gboolean allow_deps,
+- gboolean autoremove);
+-void backend_simulate_remove_packages (PkBackend *backend,
+- gchar **package_ids,
+- gboolean autoremove);
+diff --git a/backends/pacman/backend-repos.c b/backends/pacman/backend-repos.c
+deleted file mode 100644
+index 8ef23d9..0000000
+--- a/backends/pacman/backend-repos.c
++++ /dev/null
+@@ -1,298 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include "backend-error.h"
+-#include "backend-pacman.h"
+-#include "backend-repos.h"
+-
+-PacmanDatabase *local_database = NULL;
+-static GHashTable *disabled_repos = NULL;
+-
+-static GHashTable *
+-disabled_repos_new (GError **error)
+-{
+- GHashTable *disabled;
+- GFile *file;
+-
+- GFileInputStream *file_stream;
+- GDataInputStream *data_stream;
+-
+- gchar *line;
+- GError *e = NULL;
+-
+- g_debug ("pacman: reading disabled repos from %s", PACMAN_REPO_LIST);
+- file = g_file_new_for_path (PACMAN_REPO_LIST);
+- file_stream = g_file_read (file, NULL, &e);
+-
+- if (file_stream == NULL) {
+- g_object_unref (file);
+- g_propagate_error (error, e);
+- return NULL;
+- }
+-
+- disabled = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+- data_stream = g_data_input_stream_new (G_INPUT_STREAM (file_stream));
+-
+- /* read disabled repos line by line, ignoring comments */
+- while ((line = g_data_input_stream_read_line (data_stream, NULL, NULL, &e)) != NULL) {
+- g_strstrip (line);
+-
+- if (*line == '\0' || *line == '#') {
+- g_free (line);
+- continue;
+- }
+-
+- g_hash_table_insert (disabled, line, GINT_TO_POINTER (1));
+- }
+-
+- g_object_unref (data_stream);
+- g_object_unref (file_stream);
+- g_object_unref (file);
+-
+- if (e != NULL) {
+- g_hash_table_unref (disabled);
+- g_propagate_error (error, e);
+- return NULL;
+- } else {
+- return disabled;
+- }
+-}
+-
+-static gboolean
+-disabled_repos_configure (GHashTable *disabled, GError **error)
+-{
+- const PacmanList *databases;
+-
+- g_return_val_if_fail (pacman != NULL, FALSE);
+-
+- g_debug ("pacman: reading config from %s", PACMAN_CONFIG_FILE);
+-
+- /* read configuration from pacman config file */
+- if (!pacman_manager_configure (pacman, PACMAN_CONFIG_FILE, error)) {
+- return FALSE;
+- }
+-
+- local_database = pacman_manager_get_local_database (pacman);
+-
+- /* disable disabled repos */
+- for (databases = pacman_manager_get_sync_databases (pacman); databases != NULL; databases = pacman_list_next (databases)) {
+- PacmanDatabase *database = (PacmanDatabase *) pacman_list_get (databases);
+- const gchar *repo = pacman_database_get_name (database);
+-
+- if (g_hash_table_lookup (disabled, repo) != NULL) {
+- if (!pacman_manager_unregister_database (pacman, database, error)) {
+- return FALSE;
+- }
+-
+- /* start again as the list gets invalidated */
+- databases = pacman_manager_get_sync_databases (pacman);
+- }
+- }
+-
+- return TRUE;
+-}
+-
+-static void
+-disabled_repos_free (GHashTable *disabled)
+-{
+- GHashTableIter iter;
+- GFile *file;
+-
+- GFileOutputStream *file_stream;
+- GDataOutputStream *data_stream;
+-
+- const gchar *line = PACMAN_REPO_LIST_HEADER "\n";
+-
+- g_return_if_fail (disabled != NULL);
+-
+- g_debug ("pacman: storing disabled repos in %s", PACMAN_REPO_LIST);
+- file = g_file_new_for_path (PACMAN_REPO_LIST);
+- file_stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL);
+-
+- if (file_stream == NULL) {
+- g_object_unref (file);
+- g_hash_table_unref (disabled);
+- return;
+- }
+-
+- g_hash_table_iter_init (&iter, disabled);
+- data_stream = g_data_output_stream_new (G_OUTPUT_STREAM (file_stream));
+-
+- /* write header, then all disabled repos line by line */
+- if (g_data_output_stream_put_string (data_stream, line, NULL, NULL)) {
+- while (g_hash_table_iter_next (&iter, (gpointer *) &line, NULL) &&
+- g_data_output_stream_put_string (data_stream, line, NULL, NULL) &&
+- g_data_output_stream_put_string (data_stream, "\n", NULL, NULL));
+- }
+-
+- g_object_unref (data_stream);
+- g_object_unref (file_stream);
+- g_object_unref (file);
+- g_hash_table_unref (disabled);
+-}
+-
+-gboolean
+-backend_initialize_databases (PkBackend *backend, GError **error)
+-{
+- g_return_val_if_fail (pacman != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- disabled_repos = disabled_repos_new (error);
+- if (disabled_repos == NULL) {
+- return FALSE;
+- }
+-
+- if (!disabled_repos_configure (disabled_repos, error)) {
+- return FALSE;
+- }
+-
+- return TRUE;
+-}
+-
+-void
+-backend_destroy_databases (PkBackend *backend)
+-{
+- g_return_if_fail (backend != NULL);
+-
+- if (disabled_repos != NULL) {
+- disabled_repos_free (disabled_repos);
+- }
+-}
+-
+-static gboolean
+-backend_get_repo_list_thread (PkBackend *backend)
+-{
+- const PacmanList *databases;
+- GHashTableIter iter;
+- gpointer key, value;
+-
+- g_return_val_if_fail (pacman != NULL, FALSE);
+- g_return_val_if_fail (disabled_repos != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- /* emit enabled repos */
+- for (databases = pacman_manager_get_sync_databases (pacman); databases != NULL; databases = pacman_list_next (databases)) {
+- PacmanDatabase *database = (PacmanDatabase *) pacman_list_get (databases);
+- const gchar *repo = pacman_database_get_name (database);
+-
+- if (backend_cancelled (backend)) {
+- break;
+- } else {
+- pk_backend_repo_detail (backend, repo, repo, TRUE);
+- }
+- }
+-
+- /* emit disabled repos */
+- g_hash_table_iter_init (&iter, disabled_repos);
+- while (g_hash_table_iter_next (&iter, &key, &value)) {
+- const gchar *repo = (const gchar *) key;
+-
+- if (backend_cancelled (backend)) {
+- break;
+- } else {
+- pk_backend_repo_detail (backend, repo, repo, FALSE);
+- }
+- }
+-
+- backend_finished (backend);
+- return TRUE;
+-}
+-
+-/**
+- * backend_get_repo_list:
+- **/
+-void
+-backend_get_repo_list (PkBackend *backend, PkBitfield filters)
+-{
+- g_return_if_fail (backend != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_repo_list_thread);
+-}
+-
+-static gboolean
+-backend_repo_enable_thread (PkBackend *backend)
+-{
+- GError *error = NULL;
+-
+- const gchar *repo;
+- gboolean enabled;
+-
+- g_return_val_if_fail (pacman != NULL, FALSE);
+- g_return_val_if_fail (disabled_repos != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- repo = pk_backend_get_string (backend, "repo_id");
+- enabled = pk_backend_get_bool (backend, "enabled");
+-
+- g_return_val_if_fail (repo != NULL, FALSE);
+-
+- if (enabled) {
+- /* check that repo is indeed disabled */
+- if (g_hash_table_remove (disabled_repos, repo)) {
+- /* reload configuration to preserve the correct order */
+- if (disabled_repos_configure (disabled_repos, &error)) {
+- pk_backend_repo_list_changed (backend);
+- } else {
+- backend_error (backend, error);
+- pk_backend_thread_finished (backend);
+- return FALSE;
+- }
+- } else {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_REPO_NOT_FOUND, "Could not find repo [%s]", repo);
+- pk_backend_thread_finished (backend);
+- return FALSE;
+- }
+- } else {
+- PacmanDatabase *database = pacman_manager_find_sync_database (pacman, repo);
+-
+- if (database != NULL) {
+- if (pacman_manager_unregister_database (pacman, database, &error)) {
+- g_hash_table_insert (disabled_repos, g_strdup (repo), GINT_TO_POINTER (1));
+- } else {
+- backend_error (backend, error);
+- pk_backend_thread_finished (backend);
+- return FALSE;
+- }
+- } else {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_REPO_NOT_FOUND, "Could not find repo [%s]", repo);
+- pk_backend_thread_finished (backend);
+- return FALSE;
+- }
+- }
+-
+- pk_backend_thread_finished (backend);
+- return TRUE;
+-}
+-
+-/**
+- * backend_repo_enable:
+- **/
+-void
+-backend_repo_enable (PkBackend *backend, const gchar *repo, gboolean enabled)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (repo != NULL);
+-
+- pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_thread_create (backend, backend_repo_enable_thread);
+-}
+diff --git a/backends/pacman/backend-repos.h b/backends/pacman/backend-repos.h
+deleted file mode 100644
+index 7faba0c..0000000
+--- a/backends/pacman/backend-repos.h
++++ /dev/null
+@@ -1,37 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pacman.h>
+-#include <pk-backend.h>
+-
+-extern PacmanDatabase *local_database;
+-
+-gboolean backend_initialize_databases (PkBackend *backend,
+- GError **error);
+-void backend_destroy_databases (PkBackend *backend);
+-
+-void backend_get_repo_list (PkBackend *backend,
+- PkBitfield filters);
+-void backend_repo_enable (PkBackend *backend,
+- const gchar *repo,
+- gboolean enabled);
+diff --git a/backends/pacman/backend-search.c b/backends/pacman/backend-search.c
+deleted file mode 100644
+index 32b4df8..0000000
+--- a/backends/pacman/backend-search.c
++++ /dev/null
+@@ -1,479 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <string.h>
+-#include <pacman.h>
+-#include "backend-error.h"
+-#include "backend-groups.h"
+-#include "backend-packages.h"
+-#include "backend-pacman.h"
+-#include "backend-repos.h"
+-#include "backend-search.h"
+-
+-static gpointer
+-backend_pattern_needle (const gchar *needle, GError **error)
+-{
+- return (gpointer) needle;
+-}
+-
+-static gpointer
+-backend_pattern_regex (const gchar *needle, GError **error)
+-{
+- gchar *pattern;
+- GRegex *regex;
+-
+- g_return_val_if_fail (needle != NULL, NULL);
+-
+- pattern = g_regex_escape_string (needle, -1);
+- regex = g_regex_new (pattern, G_REGEX_CASELESS, 0, error);
+- g_free (pattern);
+-
+- return regex;
+-}
+-
+-static gpointer
+-backend_pattern_chroot (const gchar *needle, GError **error)
+-{
+- g_return_val_if_fail (pacman != NULL, FALSE);
+- g_return_val_if_fail (needle != NULL, NULL);
+-
+- if (G_IS_DIR_SEPARATOR (*needle)) {
+- const gchar *file = needle, *path = pacman_manager_get_root_path (pacman);
+-
+- /* adjust needle to the correct prefix */
+- while (*file++ == *path++) {
+- if (*path == '\0') {
+- needle = file - 1;
+- break;
+- } else if (*file == '\0') {
+- break;
+- }
+- }
+- }
+-
+- return (gpointer) needle;
+-}
+-
+-static gboolean
+-backend_match_all (PacmanPackage *package, gpointer pattern)
+-{
+- g_return_val_if_fail (package != NULL, FALSE);
+- g_return_val_if_fail (pattern != NULL, FALSE);
+-
+- /* match all packages */
+- return TRUE;
+-}
+-
+-static gboolean
+-backend_match_details (PacmanPackage *package, gpointer pattern)
+-{
+- const gchar *description;
+- PacmanDatabase *database;
+- const PacmanList *licenses;
+-
+- GRegex *regex = (GRegex *) pattern;
+-
+- g_return_val_if_fail (package != NULL, FALSE);
+- g_return_val_if_fail (regex != NULL, FALSE);
+-
+- /* match the name first... */
+- if (g_regex_match (regex, pacman_package_get_name (package), 0, NULL)) {
+- return TRUE;
+- }
+-
+- /* ... then the description... */
+- description = pacman_package_get_description (package);
+- if (description != NULL && g_regex_match (regex, description, 0, NULL)) {
+- return TRUE;
+- }
+-
+- /* ... then the database... */
+- database = pacman_package_get_database (package);
+- if (database != NULL && g_regex_match (regex, pacman_database_get_name (database), G_REGEX_MATCH_ANCHORED, NULL)) {
+- return TRUE;
+- }
+-
+- /* ... then the licenses */
+- for (licenses = pacman_package_get_licenses (package); licenses != NULL; licenses = pacman_list_next (licenses)) {
+- const gchar *license = (const gchar *) pacman_list_get (licenses);
+- if (g_regex_match (regex, license, G_REGEX_MATCH_ANCHORED, NULL)) {
+- return TRUE;
+- }
+- }
+-
+- return FALSE;
+-}
+-
+-static gboolean
+-backend_match_file (PacmanPackage *package, gpointer pattern)
+-{
+- const PacmanList *files;
+- const gchar *needle = (const gchar *) pattern;
+-
+- g_return_val_if_fail (package != NULL, FALSE);
+- g_return_val_if_fail (needle != NULL, FALSE);
+-
+- /* match any file the package contains */
+- if (G_IS_DIR_SEPARATOR (*needle)) {
+- for (files = pacman_package_get_files (package); files != NULL; files = pacman_list_next (files)) {
+- const gchar *file = (const gchar *) pacman_list_get (files);
+-
+- /* match the full path of file */
+- if (g_strcmp0 (file, needle + 1) == 0) {
+- return TRUE;
+- }
+- }
+- } else {
+- for (files = pacman_package_get_files (package); files != NULL; files = pacman_list_next (files)) {
+- const gchar *file = (const gchar *) pacman_list_get (files);
+- file = strrchr (file, G_DIR_SEPARATOR);
+-
+- /* match the basename of file */
+- if (file != NULL && g_strcmp0 (file + 1, needle) == 0) {
+- return TRUE;
+- }
+- }
+- }
+-
+- return FALSE;
+-}
+-
+-static gboolean
+-backend_match_group (PacmanPackage *package, gpointer pattern)
+-{
+- const gchar *needle = (const gchar *) pattern;
+-
+- g_return_val_if_fail (package != NULL, FALSE);
+- g_return_val_if_fail (needle != NULL, FALSE);
+-
+- /* match the group the package is in */
+- return g_strcmp0 (needle, pacman_package_get_group (package)) == 0;
+-}
+-
+-static gboolean
+-backend_match_name (PacmanPackage *package, gpointer pattern)
+-{
+- GRegex *regex = (GRegex *) pattern;
+-
+- g_return_val_if_fail (package != NULL, FALSE);
+- g_return_val_if_fail (regex != NULL, FALSE);
+-
+- /* match the name of the package */
+- return g_regex_match (regex, pacman_package_get_name (package), 0, NULL);
+-}
+-
+-static gboolean
+-backend_match_provides (PacmanPackage *package, gpointer pattern)
+-{
+- /* TODO: implement GStreamer codecs, Pango fonts, etc. */
+- const PacmanList *provides;
+-
+- g_return_val_if_fail (package != NULL, FALSE);
+- g_return_val_if_fail (pattern != NULL, FALSE);
+-
+- /* match features provided by package */
+- for (provides = pacman_package_get_provides (package); provides != NULL; provides = pacman_list_next (provides)) {
+- const gchar *needle = (const gchar *) pattern, *name = (const gchar *) pacman_list_get (provides);
+-
+- while (*needle == *name && *needle != '\0') {
+- ++needle;
+- ++name;
+- }
+-
+- if (*needle == '\0' && (*name == '\0' || *name == '=')) {
+- return TRUE;
+- }
+- }
+-
+- return FALSE;
+-}
+-
+-typedef enum {
+- SEARCH_TYPE_ALL,
+- SEARCH_TYPE_DETAILS,
+- SEARCH_TYPE_FILES,
+- SEARCH_TYPE_GROUP,
+- SEARCH_TYPE_NAME,
+- SEARCH_TYPE_PROVIDES,
+- SEARCH_TYPE_LAST
+-} SearchType;
+-
+-typedef gpointer (*PatternFunc) (const gchar *needle, GError **error);
+-typedef gboolean (*MatchFunc) (PacmanPackage *package, gpointer pattern);
+-
+-static PatternFunc pattern_funcs[] = {
+- backend_pattern_needle,
+- backend_pattern_regex,
+- backend_pattern_chroot,
+- backend_pattern_needle,
+- backend_pattern_regex,
+- backend_pattern_needle
+-};
+-
+-static GDestroyNotify pattern_frees[] = {
+- NULL,
+- (GDestroyNotify) g_regex_unref,
+- NULL,
+- NULL,
+- (GDestroyNotify) g_regex_unref,
+- NULL
+-};
+-
+-static MatchFunc match_funcs[] = {
+- backend_match_all,
+- backend_match_details,
+- backend_match_file,
+- backend_match_group,
+- backend_match_name,
+- backend_match_provides
+-};
+-
+-static gboolean
+-pacman_package_is_installed (PacmanPackage *package)
+-{
+- PacmanPackage *installed;
+-
+- g_return_val_if_fail (local_database != NULL, FALSE);
+- g_return_val_if_fail (package != NULL, FALSE);
+-
+- /* find an installed package with the same name */
+- installed = pacman_database_find_package (local_database, pacman_package_get_name (package));
+- if (installed == NULL) {
+- return FALSE;
+- }
+-
+- /* make sure the installed version is the same */
+- if (pacman_package_compare_version (pacman_package_get_version (installed), pacman_package_get_version (package)) != 0) {
+- return FALSE;
+- }
+-
+- /* make sure the installed arch is the same */
+- if (g_strcmp0 (pacman_package_get_arch (installed), pacman_package_get_arch (package)) != 0) {
+- return FALSE;
+- }
+-
+- return TRUE;
+-}
+-
+-static void
+-backend_search_database (PkBackend *backend, PacmanDatabase *database, MatchFunc match, const PacmanList *patterns)
+-{
+- const PacmanList *packages, *list;
+-
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (database != NULL);
+- g_return_if_fail (match != NULL);
+-
+- /* emit packages that match all search terms */
+- for (packages = pacman_database_get_packages (database); packages != NULL; packages = pacman_list_next (packages)) {
+- PacmanPackage *package = (PacmanPackage *) pacman_list_get (packages);
+-
+- if (backend_cancelled (backend)) {
+- break;
+- }
+-
+- for (list = patterns; list != NULL; list = pacman_list_next (list)) {
+- if (!match (package, pacman_list_get (list))) {
+- break;
+- }
+- }
+-
+- /* all search terms matched */
+- if (list == NULL) {
+- if (database == local_database) {
+- backend_package (backend, package, PK_INFO_ENUM_INSTALLED);
+- } else if (!pacman_package_is_installed (package)) {
+- backend_package (backend, package, PK_INFO_ENUM_AVAILABLE);
+- }
+- }
+- }
+-}
+-
+-static gboolean
+-backend_search_thread (PkBackend *backend)
+-{
+- gchar **search;
+- SearchType search_type;
+-
+- PatternFunc pattern_func;
+- GDestroyNotify pattern_free;
+- MatchFunc match_func;
+-
+- PkBitfield filters;
+- gboolean search_installed;
+- gboolean search_not_installed;
+-
+- guint iterator;
+- PacmanList *patterns = NULL;
+- GError *error = NULL;
+-
+- g_return_val_if_fail (pacman != NULL, FALSE);
+- g_return_val_if_fail (local_database != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- search = pk_backend_get_strv (backend, "search");
+- search_type = (SearchType) pk_backend_get_uint (backend, "search-type");
+-
+- g_return_val_if_fail (search != NULL, FALSE);
+- g_return_val_if_fail (search_type < SEARCH_TYPE_LAST, FALSE);
+-
+- pattern_func = pattern_funcs[search_type];
+- pattern_free = pattern_frees[search_type];
+- match_func = match_funcs[search_type];
+-
+- g_return_val_if_fail (pattern_func != NULL, FALSE);
+- g_return_val_if_fail (match_func != NULL, FALSE);
+-
+- filters = pk_backend_get_uint (backend, "filters");
+- search_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED);
+- search_not_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_NOT_INSTALLED);
+-
+- /* convert search terms to the pattern requested */
+- for (iterator = 0; search[iterator] != NULL; ++iterator) {
+- gpointer pattern = pattern_func (search[iterator], &error);
+-
+- if (pattern != NULL) {
+- patterns = pacman_list_add (patterns, pattern);
+- } else {
+- backend_error (backend, error);
+- if (pattern_free != NULL) {
+- pacman_list_free_full (patterns, pattern_free);
+- } else {
+- pacman_list_free (patterns);
+- }
+- backend_finished (backend);
+- return FALSE;
+- }
+- }
+-
+- /* find installed packages first */
+- if (!search_not_installed) {
+- backend_search_database (backend, local_database, match_func, patterns);
+- }
+-
+- if (!search_installed) {
+- const PacmanList *databases;
+-
+- for (databases = pacman_manager_get_sync_databases (pacman); databases != NULL; databases = pacman_list_next (databases)) {
+- PacmanDatabase *database = (PacmanDatabase *) pacman_list_get (databases);
+-
+- if (backend_cancelled (backend)) {
+- break;
+- }
+-
+- backend_search_database (backend, database, match_func, patterns);
+- }
+- }
+-
+- if (pattern_free != NULL) {
+- pacman_list_free_full (patterns, pattern_free);
+- } else {
+- pacman_list_free (patterns);
+- }
+- backend_finished (backend);
+- return TRUE;
+-}
+-
+-/**
+- * backend_get_packages:
+- **/
+-void
+-backend_get_packages (PkBackend *backend, PkBitfield filters)
+-{
+- g_return_if_fail (backend != NULL);
+-
+- /* provide a dummy needle */
+- pk_backend_set_strv (backend, "search", g_strsplit ("", ";", 0));
+-
+- pk_backend_set_uint (backend, "search-type", SEARCH_TYPE_ALL);
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_search_thread);
+-}
+-
+-/**
+- * backend_search_details:
+- **/
+-void
+-backend_search_details (PkBackend *backend, PkBitfield filters, gchar **values)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (values != NULL);
+-
+- pk_backend_set_uint (backend, "search-type", SEARCH_TYPE_DETAILS);
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_search_thread);
+-}
+-
+-/**
+- * backend_search_files:
+- **/
+-void
+-backend_search_files (PkBackend *backend, PkBitfield filters, gchar **values)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (values != NULL);
+-
+- /* speed up search by restricting it to local database */
+- pk_bitfield_add (filters, PK_FILTER_ENUM_INSTALLED);
+- pk_backend_set_uint (backend, "filters", filters);
+-
+- pk_backend_set_uint (backend, "search-type", SEARCH_TYPE_FILES);
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_search_thread);
+-}
+-
+-/**
+- * backend_search_groups:
+- **/
+-void
+-backend_search_groups (PkBackend *backend, PkBitfield filters, gchar **values)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (values != NULL);
+-
+- pk_backend_set_uint (backend, "search-type", SEARCH_TYPE_GROUP);
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_search_thread);
+-}
+-
+-/**
+- * backend_search_names:
+- **/
+-void
+-backend_search_names (PkBackend *backend, PkBitfield filters, gchar **values)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (values != NULL);
+-
+- pk_backend_set_uint (backend, "search-type", SEARCH_TYPE_NAME);
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_search_thread);
+-}
+-
+-/**
+- * backend_what_provides:
+- **/
+-void
+-backend_what_provides (PkBackend *backend, PkBitfield filters, PkProvidesEnum provides, gchar **values)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (values != NULL);
+-
+- pk_backend_set_uint (backend, "search-type", SEARCH_TYPE_PROVIDES);
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_search_thread);
+-}
+diff --git a/backends/pacman/backend-search.h b/backends/pacman/backend-search.h
+deleted file mode 100644
+index c2ce6a0..0000000
+--- a/backends/pacman/backend-search.h
++++ /dev/null
+@@ -1,43 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pk-backend.h>
+-
+-void backend_get_packages (PkBackend *backend,
+- PkBitfield filters);
+-void backend_search_details (PkBackend *backend,
+- PkBitfield filters,
+- gchar **values);
+-void backend_search_files (PkBackend *backend,
+- PkBitfield filters,
+- gchar **values);
+-void backend_search_groups (PkBackend *backend,
+- PkBitfield filters,
+- gchar **values);
+-void backend_search_names (PkBackend *backend,
+- PkBitfield filters,
+- gchar **values);
+-void backend_what_provides (PkBackend *backend,
+- PkBitfield filters,
+- PkProvidesEnum provides,
+- gchar **values);
+diff --git a/backends/pacman/backend-transaction.c b/backends/pacman/backend-transaction.c
+deleted file mode 100644
+index 748760b..0000000
+--- a/backends/pacman/backend-transaction.c
++++ /dev/null
+@@ -1,532 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <string.h>
+-#include "backend-error.h"
+-#include "backend-packages.h"
+-#include "backend-pacman.h"
+-#include "backend-repos.h"
+-#include "backend-transaction.h"
+-
+-typedef struct {
+- guint complete;
+- guint total;
+-
+- PacmanPackage *package;
+- GString *files;
+-} BackendDownloadData;
+-
+-static GHashTable *downloads = NULL;
+-
+-gboolean
+-backend_initialize_downloads (PkBackend *backend, GError **error)
+-{
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- downloads = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+- return TRUE;
+-}
+-
+-void
+-backend_destroy_downloads (PkBackend *backend)
+-{
+- g_return_if_fail (backend != NULL);
+-
+- if (downloads != NULL) {
+- g_hash_table_unref (downloads);
+- }
+-}
+-
+-static void
+-transaction_download_end (PacmanTransaction *transaction, BackendDownloadData *download, PkBackend *backend) {
+- g_return_if_fail (transaction != NULL);
+- g_return_if_fail (download != NULL);
+- g_return_if_fail (backend != NULL);
+-
+- /* emit the finished signal for the old package */
+- backend_package (backend, download->package, PK_INFO_ENUM_FINISHED);
+-
+- /* emit the list of files downloaded for DownloadPackages */
+- if (download->files != NULL) {
+- gchar *package_id, *files;
+-
+- package_id = pacman_package_make_id (download->package);
+- files = g_string_free (download->files, FALSE);
+-
+- pk_backend_files (backend, package_id, files);
+-
+- g_free (package_id);
+- g_free (files);
+- }
+-
+- download->package = NULL;
+- download->files = NULL;
+-}
+-
+-static gchar *
+-backend_filename_make_path (PkBackend *backend, const gchar *filename)
+-{
+- const gchar *directory;
+-
+- g_return_val_if_fail (backend != NULL, NULL);
+- g_return_val_if_fail (filename != NULL, NULL);
+-
+- directory = pk_backend_get_string (backend, "directory");
+-
+- g_return_val_if_fail (directory != NULL, NULL);
+-
+- return g_build_filename (directory, filename, NULL);
+-}
+-
+-static void
+-transaction_download_start (PacmanTransaction *transaction, BackendDownloadData *download, const gchar *filename, PkBackend *backend)
+-{
+- const PacmanList *packages;
+-
+- g_return_if_fail (transaction != NULL);
+- g_return_if_fail (download != NULL);
+- g_return_if_fail (filename != NULL);
+- g_return_if_fail (backend != NULL);
+-
+- /* continue or finish downloading the old package */
+- if (download->package != NULL) {
+- if (pacman_package_has_filename (download->package, filename)) {
+- if (download->files != NULL) {
+- gchar *path = backend_filename_make_path (backend, filename);
+- g_string_append_printf (download->files, ";%s", path);
+- g_free (path);
+- }
+- return;
+- } else {
+- transaction_download_end (transaction, download, backend);
+- }
+- }
+-
+- /* find a new package for the current file */
+- for (packages = pacman_transaction_get_installs (transaction); packages != NULL; packages = pacman_list_next (packages)) {
+- PacmanPackage *package = (PacmanPackage *) pacman_list_get (packages);
+- if (pacman_package_has_filename (package, filename)) {
+- download->package = package;
+- break;
+- }
+- }
+-
+- /* emit the downloading signal and start collecting files for the new package */
+- if (download->package != NULL) {
+- backend_package (backend, download->package, PK_INFO_ENUM_DOWNLOADING);
+-
+- /* only emit files downloaded for DownloadPackages */
+- if (pk_backend_get_role (backend) == PK_ROLE_ENUM_DOWNLOAD_PACKAGES) {
+- gchar *path = backend_filename_make_path (backend, filename);
+- download->files = g_string_new (path);
+- g_free (path);
+- }
+- }
+-}
+-
+-static void
+-transaction_download_cb (PacmanTransaction *transaction, const gchar *filename, guint complete, guint total, gpointer user_data)
+-{
+- BackendDownloadData *download;
+-
+- g_return_if_fail (pacman != NULL);
+- g_return_if_fail (transaction != NULL);
+- g_return_if_fail (user_data != NULL);
+-
+- download = (BackendDownloadData *) g_hash_table_lookup (downloads, transaction);
+-
+- if (filename == NULL) {
+- if (download == NULL) {
+- /* start a new download */
+- download = g_new0 (BackendDownloadData, 1);
+- download->complete = complete;
+- download->total = total;
+- g_hash_table_insert (downloads, transaction, download);
+- } else {
+- /* finish the current download */
+- if (download->package != NULL) {
+- transaction_download_end (transaction, download, (PkBackend *) user_data);
+- }
+- g_hash_table_remove (downloads, transaction);
+- }
+- } else {
+- guint percentage = 100, sub_percentage = 100;
+-
+- g_return_if_fail (download != NULL);
+-
+- if (total > 0) {
+- sub_percentage = complete * 100 / total;
+- }
+-
+- if (strstr (filename, ".db.tar.") != NULL) {
+- const PacmanList *databases = pacman_manager_get_sync_databases (pacman);
+- guint database_total = pacman_list_length (databases);
+-
+- /* report download progress for databases */
+- if (database_total > 0) {
+- percentage = (sub_percentage + download->complete * 100) / database_total;
+- }
+-
+- if (complete == 0) {
+- g_debug ("pacman: downloading database %s", filename);
+- pk_backend_set_status ((PkBackend *) user_data, PK_STATUS_ENUM_REFRESH_CACHE);
+- }
+-
+- if (complete == total) {
+- download->complete += 1;
+- }
+- } else {
+- /* report download progress for package or delta files */
+- if (download->total > 0) {
+- percentage = (download->complete + complete) * 100 / download->total;
+- }
+-
+- if (complete == 0) {
+- g_debug ("pacman: downloading package %s", filename);
+- pk_backend_set_status ((PkBackend *) user_data, PK_STATUS_ENUM_DOWNLOAD);
+- transaction_download_start (transaction, download, filename, (PkBackend *) user_data);
+- }
+-
+- if (complete == total) {
+- download->complete += complete;
+- }
+- }
+-
+- pk_backend_set_sub_percentage ((PkBackend *) user_data, sub_percentage);
+- pk_backend_set_percentage ((PkBackend *) user_data, percentage);
+- }
+-}
+-
+-static void
+-transaction_progress_cb (PacmanTransaction *transaction, PacmanTransactionProgress type, const gchar *target, guint percent, guint current, guint targets, gpointer user_data)
+-{
+- g_return_if_fail (transaction != NULL);
+- g_return_if_fail (user_data != NULL);
+-
+- g_return_if_fail (percent >= 0);
+- g_return_if_fail (percent <= 100);
+- g_return_if_fail (current >= 1);
+- g_return_if_fail (current <= targets);
+-
+- /* update transaction progress */
+- switch (type) {
+- case PACMAN_TRANSACTION_PROGRESS_INSTALL:
+- case PACMAN_TRANSACTION_PROGRESS_UPGRADE:
+- case PACMAN_TRANSACTION_PROGRESS_REMOVE:
+- case PACMAN_TRANSACTION_PROGRESS_FILE_CONFLICT_CHECK:
+- {
+- g_debug ("pacman: progress for %s (%u of %u) is %u%%", target, current, targets, percent);
+- pk_backend_set_sub_percentage ((PkBackend *) user_data, percent);
+- pk_backend_set_percentage ((PkBackend *) user_data, (percent + (current - 1) * 100) / targets);
+- break;
+- }
+- default:
+- g_debug ("pacman: progress of type %d (%u of %u) is %u%%", type, current, targets, percent);
+- break;
+- }
+-}
+-
+-static gboolean
+-transaction_question_cb (PacmanTransaction *transaction, PacmanTransactionQuestion question, const gchar *message, gpointer user_data)
+-{
+- g_return_val_if_fail (transaction != NULL, FALSE);
+- g_return_val_if_fail (user_data != NULL, FALSE);
+-
+- switch (question) {
+- case PACMAN_TRANSACTION_QUESTION_INSTALL_IGNORE_PACKAGE:
+- {
+- PkRoleEnum role = pk_backend_get_role ((PkBackend *) user_data);
+- if (role == PK_ROLE_ENUM_INSTALL_PACKAGES) {
+- gchar *packages = pacman_package_make_list (pacman_transaction_get_marked_packages (transaction));
+- gchar *warning = g_strdup_printf ("The following packages were marked as ignored:\n%s\n", packages);
+-
+- /* ignored packages are blocked in updates, can be explicitly installed */
+- g_warning ("pacman: %s", warning);
+- backend_message ((PkBackend *) user_data, warning);
+-
+- g_free (warning);
+- g_free (packages);
+- return TRUE;
+- } else if (role == PK_ROLE_ENUM_DOWNLOAD_PACKAGES || role == PK_ROLE_ENUM_SIMULATE_INSTALL_PACKAGES) {
+- return TRUE;
+- } else {
+- return FALSE;
+- }
+- }
+- case PACMAN_TRANSACTION_QUESTION_SKIP_UNRESOLVABLE_PACKAGES:
+- case PACMAN_TRANSACTION_QUESTION_REMOVE_HOLD_PACKAGES:
+- case PACMAN_TRANSACTION_QUESTION_SYNC_FIRST:
+- /* none of these actions are safe */
+- g_warning ("pacman: ignoring question '%s'", message);
+- return FALSE;
+-
+- case PACMAN_TRANSACTION_QUESTION_REPLACE_PACKAGE:
+- case PACMAN_TRANSACTION_QUESTION_REMOVE_CONFLICTING_PACKAGE:
+- case PACMAN_TRANSACTION_QUESTION_INSTALL_OLDER_PACKAGE:
+- case PACMAN_TRANSACTION_QUESTION_DELETE_CORRUPTED_PACKAGE:
+- /* these actions are mostly harmless */
+- g_warning ("pacman: confirming question '%s'", message);
+- return TRUE;
+-
+- default:
+- g_warning ("pacman: unrecognised question '%s'", message);
+- return FALSE;
+- }
+-}
+-
+-static void
+-transaction_status_cb (PacmanTransaction *transaction, PacmanTransactionStatus status, const gchar *message, gpointer user_data)
+-{
+- PkStatusEnum state;
+- PkInfoEnum info;
+-
+- g_return_if_fail (transaction != NULL);
+- g_return_if_fail (user_data != NULL);
+-
+- /* figure out the backend status and package info */
+- switch (status) {
+- case PACMAN_TRANSACTION_STATUS_INSTALL_START:
+- state = PK_STATUS_ENUM_INSTALL;
+- info = PK_INFO_ENUM_INSTALLING;
+- break;
+-
+- case PACMAN_TRANSACTION_STATUS_UPGRADE_START:
+- if (pk_backend_get_role ((PkBackend *) user_data) == PK_ROLE_ENUM_INSTALL_FILES) {
+- state = PK_STATUS_ENUM_INSTALL;
+- info = PK_INFO_ENUM_INSTALLING;
+- } else {
+- state = PK_STATUS_ENUM_UPDATE;
+- info = PK_INFO_ENUM_UPDATING;
+- }
+- break;
+-
+- case PACMAN_TRANSACTION_STATUS_REMOVE_START:
+- state = PK_STATUS_ENUM_REMOVE;
+- info = PK_INFO_ENUM_REMOVING;
+- break;
+-
+- case PACMAN_TRANSACTION_STATUS_INSTALL_END:
+- case PACMAN_TRANSACTION_STATUS_UPGRADE_END:
+- case PACMAN_TRANSACTION_STATUS_REMOVE_END:
+- state = PK_STATUS_ENUM_UNKNOWN;
+- info = PK_INFO_ENUM_FINISHED;
+- break;
+-
+- case PACMAN_TRANSACTION_STATUS_DEPENDENCY_CHECK_START:
+- case PACMAN_TRANSACTION_STATUS_DEPENDENCY_RESOLVE_START:
+- state = PK_STATUS_ENUM_DEP_RESOLVE;
+- info = PK_INFO_ENUM_UNKNOWN;
+- break;
+-
+- case PACMAN_TRANSACTION_STATUS_FILE_CONFLICT_CHECK_START:
+- case PACMAN_TRANSACTION_STATUS_CONFLICT_CHECK_START:
+- case PACMAN_TRANSACTION_STATUS_PACKAGE_INTEGRITY_CHECK_START:
+- case PACMAN_TRANSACTION_STATUS_DELTA_INTEGRITY_CHECK_START:
+- state = PK_STATUS_ENUM_TEST_COMMIT;
+- info = PK_INFO_ENUM_UNKNOWN;
+- break;
+-
+- default:
+- state = PK_STATUS_ENUM_UNKNOWN;
+- info = PK_INFO_ENUM_UNKNOWN;
+- g_debug ("pacman: %s", message);
+- break;
+- }
+-
+- /* update the backend status */
+- if (state != PK_STATUS_ENUM_UNKNOWN) {
+- pk_backend_set_status ((PkBackend *) user_data, state);
+- }
+-
+- /* update the package info */
+- if (info != PK_INFO_ENUM_UNKNOWN) {
+- const PacmanList *packages;
+-
+- for (packages = pacman_transaction_get_marked_packages (transaction); packages != NULL; packages = pacman_list_next (packages)) {
+- PacmanPackage *package;
+-
+- /* only report the old versions */
+- if (status == PACMAN_TRANSACTION_STATUS_UPGRADE_START || status == PACMAN_TRANSACTION_STATUS_UPGRADE_END) {
+- packages = pacman_list_next (packages);
+- if (packages == NULL) {
+- break;
+- }
+- }
+-
+- package = (PacmanPackage *) pacman_list_get (packages);
+- backend_package ((PkBackend *) user_data, package, info);
+- }
+- }
+-}
+-
+-static void
+-transaction_cancelled_cb (GCancellable *object, gpointer user_data)
+-{
+- g_return_if_fail (user_data != NULL);
+-
+- pacman_transaction_cancel ((PacmanTransaction *) user_data, NULL);
+-}
+-
+-PacmanTransaction *
+-backend_transaction_simulate (PkBackend *backend, PacmanTransactionType type, guint32 flags, const PacmanList *targets)
+-{
+- PacmanTransaction *transaction;
+- GError *error = NULL;
+-
+- g_return_val_if_fail (pacman != NULL, NULL);
+- g_return_val_if_fail (cancellable != NULL, NULL);
+- g_return_val_if_fail (backend != NULL, NULL);
+- g_return_val_if_fail (type < PACMAN_TRANSACTION_LAST, NULL);
+-
+- switch (type) {
+- case PACMAN_TRANSACTION_INSTALL:
+- transaction = pacman_manager_install (pacman, flags, &error);
+- break;
+- case PACMAN_TRANSACTION_MODIFY:
+- transaction = pacman_manager_modify (pacman, flags, &error);
+- break;
+- case PACMAN_TRANSACTION_REMOVE:
+- transaction = pacman_manager_remove (pacman, flags, &error);
+- break;
+- case PACMAN_TRANSACTION_SYNC:
+- transaction = pacman_manager_sync (pacman, flags, &error);
+- break;
+- case PACMAN_TRANSACTION_UPDATE:
+- transaction = pacman_manager_update (pacman, flags, &error);
+- break;
+- default:
+- g_return_val_if_reached (NULL);
+- }
+-
+- if (transaction == NULL) {
+- backend_error (backend, error);
+- return NULL;
+- }
+-
+- g_signal_connect (transaction, "download", G_CALLBACK (transaction_download_cb), backend);
+- g_signal_connect (transaction, "progress", G_CALLBACK (transaction_progress_cb), backend);
+- g_signal_connect (transaction, "question", G_CALLBACK (transaction_question_cb), backend);
+- g_signal_connect (transaction, "status", G_CALLBACK (transaction_status_cb), backend);
+-
+- if (g_cancellable_connect (cancellable, G_CALLBACK (transaction_cancelled_cb), transaction, NULL) == 0 && backend_cancelled (backend)) {
+- return transaction;
+- }
+-
+- if (!pacman_transaction_prepare (transaction, targets, &error)) {
+- backend_error (backend, error);
+- g_object_unref (transaction);
+- return NULL;
+- }
+-
+- return transaction;
+-}
+-
+-PacmanTransaction *
+-backend_transaction_run (PkBackend *backend, PacmanTransactionType type, guint32 flags, const PacmanList *targets)
+-{
+- PacmanTransaction *transaction;
+-
+- g_return_val_if_fail (backend != NULL, NULL);
+-
+- transaction = backend_transaction_simulate (backend, type, flags, targets);
+-
+- return backend_transaction_commit (backend, transaction);
+-}
+-
+-void
+-backend_transaction_packages (PkBackend *backend, PacmanTransaction *transaction)
+-{
+- const PacmanList *installs, *removes;
+- PkInfoEnum info;
+-
+- g_return_if_fail (local_database != NULL);
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (transaction != NULL);
+-
+- /* emit packages that would have been installed */
+- for (installs = pacman_transaction_get_installs (transaction); installs != NULL; installs = pacman_list_next (installs)) {
+- PacmanPackage *install = (PacmanPackage *) pacman_list_get (installs);
+-
+- if (backend_cancelled (backend)) {
+- break;
+- } else {
+- const gchar *name = pacman_package_get_name (install);
+- if (pacman_database_find_package (local_database, name) != NULL) {
+- backend_package (backend, install, PK_INFO_ENUM_UPDATING);
+- } else {
+- backend_package (backend, install, PK_INFO_ENUM_INSTALLING);
+- }
+- }
+- }
+-
+- if (pk_backend_get_role (backend) == PK_ROLE_ENUM_SIMULATE_UPDATE_PACKAGES) {
+- info = PK_INFO_ENUM_OBSOLETING;
+- } else {
+- info = PK_INFO_ENUM_REMOVING;
+- }
+-
+- /* emit packages that would have been removed */
+- for (removes = pacman_transaction_get_removes (transaction); removes != NULL; removes = pacman_list_next (removes)) {
+- PacmanPackage *remove = (PacmanPackage *) pacman_list_get (removes);
+-
+- if (backend_cancelled (backend)) {
+- break;
+- } else {
+- backend_package (backend, remove, info);
+- }
+- }
+-}
+-
+-PacmanTransaction *
+-backend_transaction_commit (PkBackend *backend, PacmanTransaction *transaction)
+-{
+- GError *error = NULL;
+-
+- if (transaction != NULL && !backend_cancelled (backend)) {
+- pk_backend_set_status (backend, PK_STATUS_ENUM_RUNNING);
+-
+- if (!pacman_transaction_commit (transaction, &error)) {
+- backend_error (backend, error);
+- g_hash_table_remove (downloads, transaction);
+- g_object_unref (transaction);
+- return NULL;
+- }
+- }
+-
+- return transaction;
+-}
+-
+-gboolean
+-backend_transaction_finished (PkBackend *backend, PacmanTransaction *transaction)
+-{
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- if (transaction != NULL) {
+- g_object_unref (transaction);
+- backend_finished (backend);
+- return TRUE;
+- } else {
+- backend_finished (backend);
+- return FALSE;
+- }
+-}
+diff --git a/backends/pacman/backend-transaction.h b/backends/pacman/backend-transaction.h
+deleted file mode 100644
+index a7db49a..0000000
+--- a/backends/pacman/backend-transaction.h
++++ /dev/null
+@@ -1,54 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pacman.h>
+-#include <pk-backend.h>
+-
+-typedef enum {
+- PACMAN_TRANSACTION_INSTALL,
+- PACMAN_TRANSACTION_MODIFY,
+- PACMAN_TRANSACTION_REMOVE,
+- PACMAN_TRANSACTION_SYNC,
+- PACMAN_TRANSACTION_UPDATE,
+- PACMAN_TRANSACTION_LAST
+-} PacmanTransactionType;
+-
+-gboolean backend_initialize_downloads (PkBackend *backend,
+- GError **error);
+-void backend_destroy_downloads (PkBackend *backend);
+-
+-PacmanTransaction *backend_transaction_simulate (PkBackend *backend,
+- PacmanTransactionType type,
+- guint32 flags,
+- const PacmanList *targets);
+-PacmanTransaction *backend_transaction_run (PkBackend *backend,
+- PacmanTransactionType type,
+- guint32 flags,
+- const PacmanList *targets);
+-
+-void backend_transaction_packages (PkBackend *backend,
+- PacmanTransaction *transaction);
+-PacmanTransaction *backend_transaction_commit (PkBackend *backend,
+- PacmanTransaction *transaction);
+-gboolean backend_transaction_finished (PkBackend *backend,
+- PacmanTransaction *transaction);
+diff --git a/backends/pacman/backend-update.c b/backends/pacman/backend-update.c
+deleted file mode 100644
+index a34eb05..0000000
+--- a/backends/pacman/backend-update.c
++++ /dev/null
+@@ -1,394 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <string.h>
+-#include <pacman.h>
+-#include <glib/gstdio.h>
+-#include "backend-error.h"
+-#include "backend-pacman.h"
+-#include "backend-packages.h"
+-#include "backend-repos.h"
+-#include "backend-transaction.h"
+-#include "backend-update.h"
+-
+-static gchar *
+-pacman_package_make_replaces_ids (PacmanPackage *package)
+-{
+- const PacmanList *list;
+- GString *string = NULL;
+-
+- g_return_val_if_fail (local_database != NULL, NULL);
+- g_return_val_if_fail (package != NULL, NULL);
+-
+- /* make a list of the packages that package replaces */
+- for (list = pacman_package_get_replaces (package); list != NULL; list = pacman_list_next (list)) {
+- const gchar *name = pacman_list_get (list);
+- PacmanPackage *replaces = pacman_database_find_package (local_database, name);
+-
+- if (replaces != NULL) {
+- gchar *package_id = pacman_package_make_id (replaces);
+- if (string == NULL) {
+- string = g_string_new (package_id);
+- } else {
+- g_string_append_printf (string, "&%s", package_id);
+- }
+- g_free (package_id);
+- }
+- }
+-
+- if (string != NULL) {
+- return g_string_free (string, FALSE);
+- } else {
+- return NULL;
+- }
+-}
+-
+-static gchar *
+-pacman_package_make_vendor_url (PacmanPackage *package)
+-{
+- GString *string = g_string_new ("");
+-#ifdef PACMAN_PACKAGE_URL
+- const gchar *name, *arch, *repo, *url;
+-#else
+- const gchar *url;
+-#endif
+-
+- g_return_val_if_fail (package != NULL, NULL);
+-
+- /* grab the URL of the package... */
+- url = pacman_package_get_url (package);
+- if (url != NULL) {
+- g_string_append_printf (string, "%s;Package website;", url);
+- }
+-
+-#ifdef PACMAN_PACKAGE_URL
+- /* ... and construct the distro URL if possible */
+- name = pacman_package_get_name (package);
+- arch = pacman_package_get_arch (package);
+- repo = pacman_database_get_name (pacman_package_get_database (package));
+-
+- g_string_append_printf (string, PACMAN_PACKAGE_URL ";Distribution website;", repo, arch, name);
+-#endif
+-
+- g_string_truncate (string, string->len - 1);
+- return g_string_free (string, FALSE);
+-}
+-
+-static gint
+-pacman_package_compare_pkgver (PacmanPackage *a, PacmanPackage *b)
+-{
+- gint result;
+- const gchar *version_a, *version_b, *last_a, *last_b;
+- gchar *pkgver_a, *pkgver_b;
+-
+- g_return_val_if_fail (a != NULL, (b == NULL) ? 0 : -1);
+- g_return_val_if_fail (b != NULL, 1);
+-
+- version_a = pacman_package_get_version (a);
+- version_b = pacman_package_get_version (b);
+-
+- last_a = strrchr (version_a, '-');
+- last_b = strrchr (version_b, '-');
+-
+- if (last_a != NULL) {
+- pkgver_a = g_strndup (version_a, last_a - version_a);
+- } else {
+- pkgver_a = g_strdup (version_a);
+- }
+-
+- if (last_b != NULL) {
+- pkgver_b = g_strndup (version_b, last_b - version_b);
+- } else {
+- pkgver_b = g_strdup (version_b);
+- }
+-
+- result = pacman_package_compare_version (pkgver_a, pkgver_b);
+-
+- g_free (pkgver_a);
+- g_free (pkgver_b);
+-
+- return result;
+-}
+-
+-static gboolean
+-backend_get_update_detail_thread (PkBackend *backend)
+-{
+- guint iterator;
+-
+- gchar **package_ids;
+-
+- g_return_val_if_fail (local_database != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- package_ids = pk_backend_get_strv (backend, "package_ids");
+-
+- g_return_val_if_fail (package_ids != NULL, FALSE);
+-
+- /* collect details about updates */
+- for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+- PacmanPackage *package, *upgrades;
+- PacmanDatabase *database;
+-
+- gchar *upgrades_id, *replaces_ids, *vendor_url;
+- const gchar *message;
+-
+- PkRestartEnum restart;
+- PkUpdateStateEnum state;
+-
+- GTimeVal built = { 0 }, installed = { 0 };
+- gchar *issued, *updated;
+-
+- if (backend_cancelled (backend)) {
+- break;
+- }
+-
+- package = backend_get_package (backend, package_ids[iterator]);
+- if (package == NULL) {
+- backend_finished (backend);
+- return FALSE;
+- }
+-
+- upgrades = pacman_database_find_package (local_database, pacman_package_get_name (package));
+- if (upgrades != NULL) {
+- upgrades_id = pacman_package_make_id (upgrades);
+- if (pacman_package_compare_pkgver (package, upgrades) != 0) {
+- message = "Update to newest upstream version";
+- } else {
+- message = "Update to newest release";
+- }
+- } else {
+- upgrades_id = NULL;
+- message = "Install as a replacement for an older package";
+- }
+-
+- database = pacman_package_get_database (package);
+- replaces_ids = pacman_package_make_replaces_ids (package);
+- vendor_url = pacman_package_make_vendor_url (package);
+-
+- if (g_str_has_prefix (pacman_package_get_name (package), "kernel")) {
+- restart = PK_RESTART_ENUM_SYSTEM;
+- } else {
+- restart = PK_RESTART_ENUM_NONE;
+- }
+-
+- if (g_str_has_suffix (pacman_database_get_name (database), "testing")) {
+- state = PK_UPDATE_STATE_ENUM_TESTING;
+- } else {
+- state = PK_UPDATE_STATE_ENUM_STABLE;
+- }
+-
+- built.tv_sec = pacman_package_get_build_date (package);
+- if (built.tv_sec > 0) {
+- issued = g_time_val_to_iso8601 (&built);
+- } else {
+- issued = NULL;
+- }
+-
+- if (upgrades != NULL) {
+- installed.tv_sec = pacman_package_get_install_date (upgrades);
+- if (installed.tv_sec > 0) {
+- updated = g_time_val_to_iso8601 (&installed);
+- } else {
+- updated = NULL;
+- }
+- } else {
+- updated = NULL;
+- }
+-
+- pk_backend_update_detail (backend, package_ids[iterator], upgrades_id, replaces_ids, vendor_url, NULL, NULL, restart, message, NULL, state, issued, updated);
+-
+- g_free (issued);
+- g_free (updated);
+-
+- g_free (vendor_url);
+- g_free (replaces_ids);
+- g_free (upgrades_id);
+- }
+-
+- backend_finished (backend);
+- return TRUE;
+-}
+-
+-/**
+- * backend_get_update_detail:
+- **/
+-void
+-backend_get_update_detail (PkBackend *backend, gchar **package_ids)
+-{
+- g_return_if_fail (backend != NULL);
+- g_return_if_fail (package_ids != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_update_detail_thread);
+-}
+-
+-static gboolean
+-pacman_package_should_ignore (PacmanPackage *package)
+-{
+- const PacmanList *groups;
+- const PacmanList *ignore_packages;
+- const PacmanList *ignore_groups;
+-
+- g_return_val_if_fail (pacman != NULL, TRUE);
+- g_return_val_if_fail (package != NULL, TRUE);
+-
+- ignore_packages = pacman_manager_get_ignore_packages (pacman);
+-
+- /* check if package is an IgnorePkg */
+- if (pacman_list_find_string (ignore_packages, pacman_package_get_name (package)) != NULL) {
+- return TRUE;
+- }
+-
+- ignore_groups = pacman_manager_get_ignore_groups (pacman);
+-
+- /* check if package is in an IgnoreGroup */
+- for (groups = pacman_package_get_groups (package); groups != NULL; groups = pacman_list_next (groups)) {
+- if (pacman_list_find_string (ignore_groups, (const gchar *) pacman_list_get (groups)) != NULL) {
+- return TRUE;
+- }
+- }
+-
+- return FALSE;
+-}
+-
+-static gboolean
+-pacman_package_should_sync_first (PacmanPackage *package)
+-{
+- const PacmanList *sync_firsts;
+-
+- g_return_val_if_fail (pacman != NULL, FALSE);
+- g_return_val_if_fail (package != NULL, FALSE);
+-
+- sync_firsts = pacman_manager_get_sync_firsts (pacman);
+-
+- /* check if package is in SyncFirst */
+- if (pacman_list_find_string (sync_firsts, pacman_package_get_name (package)) != NULL) {
+- return TRUE;
+- }
+-
+- return FALSE;
+-}
+-
+-static gboolean
+-backend_get_updates_thread (PkBackend *backend)
+-{
+- struct stat cache;
+- time_t one_hour_ago;
+-
+- PacmanTransaction *transaction = NULL;
+- PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE;
+-
+- const PacmanList *packages;
+-
+- g_return_val_if_fail (local_database != NULL, FALSE);
+- g_return_val_if_fail (pacman != NULL, FALSE);
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- time (&one_hour_ago);
+- one_hour_ago -= 60 * 60;
+-
+- /* refresh databases if they are older than an hour */
+- if (g_stat (PACMAN_CACHE_PATH, &cache) < 0 || cache.st_mtime < one_hour_ago) {
+- transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_UPDATE, flags, NULL);
+-
+- if (transaction != NULL) {
+- g_object_unref (transaction);
+- } else {
+- backend_finished (backend);
+- return FALSE;
+- }
+- } else {
+- g_debug ("pacman: databases have been refreshed recently");
+- }
+-
+- /* find outdated and replacement packages */
+- for (packages = pacman_database_get_packages (local_database); packages != NULL; packages = pacman_list_next (packages)) {
+- PacmanPackage *package = (PacmanPackage *) pacman_list_get (packages);
+- PacmanPackage *upgrade = pacman_package_find_upgrade (package, pacman_manager_get_sync_databases (pacman));
+-
+- if (backend_cancelled (backend)) {
+- break;
+- }
+-
+- if (upgrade != NULL) {
+- PkInfoEnum info;
+-
+- if (pacman_package_should_ignore (upgrade)) {
+- info = PK_INFO_ENUM_BLOCKED;
+- } else if (pacman_package_should_sync_first (upgrade)) {
+- info = PK_INFO_ENUM_IMPORTANT;
+- } else {
+- info = PK_INFO_ENUM_NORMAL;
+- }
+-
+- backend_package (backend, upgrade, info);
+- }
+- }
+-
+- backend_finished (backend);
+- return TRUE;
+-}
+-
+-/**
+- * backend_get_updates:
+- **/
+-void
+-backend_get_updates (PkBackend *backend, PkBitfield filters)
+-{
+- g_return_if_fail (backend != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_updates_thread);
+-}
+-
+-static gboolean
+-backend_refresh_cache_thread (PkBackend *backend)
+-{
+- gboolean force;
+-
+- PacmanTransaction *transaction = NULL;
+- PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE;
+-
+- g_return_val_if_fail (backend != NULL, FALSE);
+-
+- force = pk_backend_get_bool (backend, "force");
+-
+- /* download databases even if they are older than current */
+- if (force) {
+- flags |= PACMAN_TRANSACTION_FLAGS_UPDATE_ALLOW_DOWNGRADE;
+- }
+-
+- /* run the transaction */
+- transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_UPDATE, flags, NULL);
+-
+- return backend_transaction_finished (backend, transaction);
+-}
+-
+-/**
+- * backend_refresh_cache:
+- **/
+-void
+-backend_refresh_cache (PkBackend *backend, gboolean force)
+-{
+- g_return_if_fail (backend != NULL);
+-
+- backend_run (backend, PK_STATUS_ENUM_SETUP, backend_refresh_cache_thread);
+-}
+diff --git a/backends/pacman/backend-update.h b/backends/pacman/backend-update.h
+deleted file mode 100644
+index 2a8bf02..0000000
+--- a/backends/pacman/backend-update.h
++++ /dev/null
+@@ -1,31 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Andreas Obergrusberger <tradiaz@yahoo.de>
+- * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep@ukr.net>
+- * Copyright (C) 2010 Jonathan Conder <j@skurvy.no-ip.org>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * 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 2 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 copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <pk-backend.h>
+-
+-void backend_get_update_detail (PkBackend *backend,
+- gchar **package_ids);
+-void backend_get_updates (PkBackend *backend,
+- PkBitfield filters);
+-void backend_refresh_cache (PkBackend *backend,
+- gboolean force);
+diff --git a/backends/pacman/groups.list b/backends/pacman/groups.list
+deleted file mode 100644
+index b2c02ae..0000000
+--- a/backends/pacman/groups.list
++++ /dev/null
+@@ -1,65 +0,0 @@
+-adesklet-desklets desktop-other
+-base system
+-base-devel programming
+-bmp-io-plugins multimedia
+-bmp-plugins multimedia
+-cegcc programming
+-compiz desktop-other
+-compiz-fusion desktop-other
+-compiz-fusion-gtk desktop-gnome
+-compiz-fusion-kde desktop-kde
+-compiz-gnome desktop-gnome
+-compiz-gtk desktop-gnome
+-compiz-kde desktop-kde
+-e17-extra-svn desktop-other
+-e17-libs-svn desktop-other
+-e17-svn desktop-other
+-fprint other
+-gimp-help other
+-gimp-plugins other
+-gnome desktop-gnome
+-gnome-extra desktop-gnome
+-gnustep-core desktop-other
+-google-gadgets desktop-other
+-gstreamer0.10-plugins multimedia
+-kde desktop-kde
+-kdeaccessibility desktop-kde
+-kdeadmin desktop-kde
+-kdeartwork desktop-kde
+-kdebase desktop-kde
+-kdeedu desktop-kde
+-kde-extragear desktop-kde
+-kdegames desktop-kde
+-kdegraphics desktop-kde
+-kde-l10n desktop-kde
+-kde-meta desktop-kde
+-kdemultimedia desktop-kde
+-kdenetwork desktop-kde
+-kdepim desktop-kde
+-kdeplasma-addons desktop-kde
+-kdesdk desktop-kde
+-kdetoys desktop-kde
+-kdeutils desktop-kde
+-kdewebdev desktop-kde
+-koffice desktop-kde
+-ladspa-plugins multimedia
+-lib32 other
+-lxde other
+-qtcurve desktop-kde
+-rox-desktop desktop-other
+-telepathy other
+-texlive-lang other
+-texlive-lang-doc other
+-texlive-most other
+-texlive-most-doc other
+-thunderbird-i18n other
+-thunderbird-spell-i18n other
+-vim-plugins other
+-xfce4 desktop-xfce
+-xfce4-goodies desktop-xfce
+-xmms-effect-plugins multimedia
+-xmms-io-plugins multimedia
+-xmms-plugins multimedia
+-xorg desktop-other
+-xorg-input-drivers desktop-other
+-xorg-video-drivers desktop-other
+diff --git a/backends/pacman/pacman.conf b/backends/pacman/pacman.conf
+deleted file mode 100644
+index 40b8e4a..0000000
+--- a/backends/pacman/pacman.conf
++++ /dev/null
+@@ -1,12 +0,0 @@
+-# PackageKit configuration for the pacman backend
+-# See the pacman.conf(5) manpage for option and repository directives.
+-
+-[options]
+-
+-# Use default pacman configuration initially
+-#
+-Include = /etc/pacman.conf
+-
+-# Prevent PackageKit from removing itself
+-#
+-HoldPkg = packagekit
+diff --git a/configure.ac b/configure.ac
+index ad86e3b..6604ac5 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -487,7 +487,6 @@ AC_ARG_ENABLE(conary, AS_HELP_STRING([--enable-conary],[use the CONARY backend])
+ AC_ARG_ENABLE(dummy, AS_HELP_STRING([--enable-dummy],[use the dummy backend]),enable_dummy=$enableval,enable_dummy=yes)
+ AC_ARG_ENABLE(entropy, AS_HELP_STRING([--enable-entropy],[use the entropy backend]),enable_entropy=$enableval,enable_entropy=no)
+ AC_ARG_ENABLE(opkg, AS_HELP_STRING([--enable-opkg],[use the OPKG backend]),enable_opkg=$enableval,enable_opkg=no)
+-AC_ARG_ENABLE(pacman, AS_HELP_STRING([--enable-pacman],[use the Pacman backend]),enable_pacman=$enableval,enable_pacman=no)
+ AC_ARG_ENABLE(pisi, AS_HELP_STRING([--enable-pisi],[use the PiSi backend]),enable_pisi=$enableval,enable_pisi=no)
+ AC_ARG_ENABLE(poldek, AS_HELP_STRING([--enable-poldek],[use the poldek backend]),enable_poldek=$enableval,enable_poldek=no)
+ AC_ARG_ENABLE(portage, AS_HELP_STRING([--enable-portage],[use the portage backend]),enable_portage=$enableval,enable_portage=no)
+@@ -509,7 +508,6 @@ AM_CONDITIONAL(BACKEND_TYPE_CONARY, [test x$enable_conary = xyes])
+ AM_CONDITIONAL(BACKEND_TYPE_DUMMY, [test x$enable_dummy = xyes])
+ AM_CONDITIONAL(BACKEND_TYPE_ENTROPY, [test x$enable_entropy = xyes])
+ AM_CONDITIONAL(BACKEND_TYPE_OPKG, [test x$enable_opkg = xyes])
+-AM_CONDITIONAL(BACKEND_TYPE_PACMAN, [test x$enable_pacman = xyes])
+ AM_CONDITIONAL(BACKEND_TYPE_PISI, [test x$enable_pisi = xyes])
+ AM_CONDITIONAL(BACKEND_TYPE_POLDEK, [test x$enable_poldek = xyes])
+ AM_CONDITIONAL(BACKEND_TYPE_PORTAGE, [test x$enable_portage = xyes])
+@@ -610,8 +608,6 @@ if test x$with_default_backend = x; then
+ with_default_backend=slapt
+ elif test -f /usr/bin/smart ; then
+ with_default_backend=smart
+- elif test -f /usr/lib/libpacman-glib.so ; then
+- with_default_backend=pacman
+ elif test -f /usr/bin/pisi ; then
+ with_default_backend=pisi
+ elif test -f /usr/bin/razor ; then
+@@ -710,12 +706,6 @@ if test x$enable_alpm = xyes; then
+ [AC_MSG_ERROR([No ALPM headers found])])
+ fi
+
+-if test x$enable_pacman = xyes; then
+- PKG_CHECK_MODULES(PACMAN, pacman-glib >= 3.3.0)
+- AC_SUBST(PACMAN_CFLAGS)
+- AC_SUBST(PACMAN_LIBS)
+-fi
+-
+ if test x$enable_poldek = xyes; then
+ POLDEK_CFLAGS="-I/usr/include/poldek"
+ POLDEK_LIBS="-lpoclidek -lpoldek"
+@@ -794,7 +784,6 @@ backends/conary/Makefile
+ backends/dummy/Makefile
+ backends/entropy/Makefile
+ backends/opkg/Makefile
+-backends/pacman/Makefile
+ backends/slapt/Makefile
+ backends/smart/Makefile
+ backends/test/Makefile
+@@ -870,7 +859,6 @@ echo "
+ Entropy backend: ${enable_entropy}
+ OPKG backend: ${enable_opkg}
+ Razor backend: ${enable_razor}
+- Pacman backend: ${enable_pacman}
+ PiSi backend: ${enable_pisi}
+ poldek backend: ${enable_poldek}
+ Portage backend: ${enable_portage}
+diff --git a/docs/html/pk-matrix.html b/docs/html/pk-matrix.html
+index 33f2efb..91dc2d4 100644
+--- a/docs/html/pk-matrix.html
++++ b/docs/html/pk-matrix.html
+@@ -28,7 +28,6 @@
+ <td><center>conary</center></td>
+ <td><center>entropy</center></td>
+ <td><center>opkg</center></td>
+-<td><center>pacman</center></td>
+ <td><center>pisi</center></td>
+ <td><center>poldek</center></td>
+ <td><center>portage</center></td>
+@@ -43,12 +42,11 @@
+ <td><b>Cancel</b></td>
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- aptcc -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -68,7 +66,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -88,7 +85,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -108,7 +104,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -128,7 +123,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -148,7 +142,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -168,7 +161,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -188,7 +180,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -203,12 +194,11 @@
+ <td><b>GetRequires</b></td>
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- aptcc -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -228,7 +218,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -248,7 +237,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -268,7 +256,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -288,7 +275,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -308,7 +294,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -328,7 +313,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -348,7 +332,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -363,12 +346,11 @@
+ <td><b>RepoEnable</b></td>
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- aptcc -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -388,7 +370,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -408,7 +389,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -428,7 +408,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[no]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -448,7 +427,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -463,12 +441,11 @@
+ <td><b>SearchFile</b></td>
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- aptcc -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -488,7 +465,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -508,7 +484,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -523,12 +498,11 @@
+ <td><b>SimulateInstallFiles</b></td>
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- aptcc -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -543,12 +517,11 @@
+ <td><b>SimulateInstallPackages</b></td>
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- aptcc -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -563,12 +536,11 @@
+ <td><b>SimulateRemovePackages</b></td>
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- aptcc -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -583,12 +555,11 @@
+ <td><b>SimulateUpdatePackages</b></td>
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- aptcc -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -608,7 +579,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -628,7 +598,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -648,7 +617,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -672,7 +640,6 @@
+ <td><center>conary</center></td>
+ <td><center>entropy</center></td>
+ <td><center>opkg</center></td>
+-<td><center>pacman</center></td>
+ <td><center>pisi</center></td>
+ <td><center>poldek</center></td>
+ <td><center>portage</center></td>
+@@ -692,7 +659,6 @@
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -712,7 +678,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -732,7 +697,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -752,7 +716,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -772,7 +735,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -792,7 +754,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -812,7 +773,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
+@@ -832,7 +792,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
+@@ -852,7 +811,6 @@
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- entropy -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
diff --git a/community/packagekit/packagekit.install b/community/packagekit/packagekit.install
new file mode 100644
index 000000000..7c8a8bd2b
--- /dev/null
+++ b/community/packagekit/packagekit.install
@@ -0,0 +1,11 @@
+post_install() {
+ update-mime-database usr/share/mime &> /dev/null
+}
+
+post_upgrade() {
+ post_install
+}
+
+post_remove() {
+ post_install
+}