[packagekit] packagekit: Branch 'master' - 6 commits

Richard Hughes hughsient at kemper.freedesktop.org
Thu Oct 25 13:58:25 PDT 2007


 backends/BACKENDS                           |   25 --
 backends/apt.old/.gitignore                 |   10 
 backends/apt.old/Makefile.am                |   17 +
 backends/apt.old/helpers/.gitignore         |    2 
 backends/apt.old/helpers/Makefile.am        |   16 +
 backends/apt.old/helpers/aptBackend.py      |   55 ++++
 backends/apt.old/helpers/refresh-cache.py   |   22 +
 backends/apt.old/pk-apt-build-db.cpp        |  283 +++++++++++++++++++++++
 backends/apt.old/pk-backend-apt.cpp         |  162 +++++++++++++
 backends/apt.old/pk-backend-apt.h           |   30 ++
 backends/apt.old/pk-python-backend-common.c |   39 +++
 backends/apt.old/pk-python-backend-common.h |   28 ++
 backends/apt.old/pk-sqlite-pkg-cache.c      |  228 +++++++++++++++++++
 backends/apt.old/pk-sqlite-pkg-cache.h      |   39 +++
 backends/apt/Makefile.am                    |   15 -
 backends/apt/helpers/.gitignore             |    2 
 backends/apt/helpers/Makefile.am            |    5 
 backends/apt/helpers/aptBackend.py          |  336 ++++++++++++++++++++++++----
 backends/apt/helpers/get-description.py     |   18 +
 backends/apt/helpers/packagekit             |    1 
 backends/apt/helpers/refresh-cache.py       |    7 
 backends/apt/helpers/search-details.py      |   21 +
 backends/apt/helpers/search-file.py         |   21 +
 backends/apt/helpers/search-group.py        |   21 +
 backends/apt/helpers/search-name.py         |   21 +
 backends/apt/pk-apt-build-db.cpp            |  283 -----------------------
 backends/apt/pk-backend-apt.c               |  225 ++++++++++++++++++
 backends/apt/pk-backend-apt.cpp             |  162 -------------
 backends/apt/pk-backend-apt.h               |   30 --
 backends/apt/pk-python-backend-common.c     |   39 ---
 backends/apt/pk-python-backend-common.h     |   28 --
 backends/apt/pk-sqlite-pkg-cache.c          |  228 -------------------
 backends/apt/pk-sqlite-pkg-cache.h          |   39 ---
 backends/dummy/pk-backend-dummy.c           |    2 
 docs/pk-introduction.xml                    |  100 ++------
 html/pk-faq.html                            |    2 
 libpackagekit/pk-common.c                   |   59 ++++
 libpackagekit/pk-common.h                   |    1 
 src/pk-backend.c                            |   31 ++
 src/pk-transaction-db.c                     |    1 
 40 files changed, 1684 insertions(+), 970 deletions(-)

New commits:
commit c58f267f13be44dcae9b8a872e34edb05bee2c4b
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Oct 25 21:54:02 2007 +0100

    sanitise more text from the backends

diff --git a/src/pk-backend.c b/src/pk-backend.c
index e719b49..209ab6e 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -37,6 +37,7 @@
 
 #include <glib/gi18n.h>
 #include <gmodule.h>
+#include <pk-common.h>
 #include <pk-package-id.h>
 #include <pk-enum.h>
 #include <pk-network.h>
@@ -737,6 +738,8 @@ pk_backend_change_status (PkBackend *backend, PkStatusEnum status)
 gboolean
 pk_backend_package (PkBackend *backend, PkInfoEnum info, const gchar *package, const gchar *summary)
 {
+	gchar *summary_safe;
+
 	g_return_val_if_fail (backend != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
 
@@ -744,9 +747,12 @@ pk_backend_package (PkBackend *backend, PkInfoEnum info, const gchar *package, c
 	g_free (backend->priv->last_package);
 	backend->priv->last_package = g_strdup (package);
 
-	pk_debug ("emit package %i, %s, %s", info, package, summary);
-	g_signal_emit (backend, signals [PK_BACKEND_PACKAGE], 0, info, package, summary);
+	/* replace unsafe chars */
+	summary_safe = pk_string_replace_unsafe (summary);
 
+	pk_debug ("emit package %i, %s, %s", info, package, summary_safe);
+	g_signal_emit (backend, signals [PK_BACKEND_PACKAGE], 0, info, package, summary_safe);
+	g_free (summary_safe);
 	return TRUE;
 }
 
@@ -759,13 +765,18 @@ pk_backend_update_detail (PkBackend *backend, const gchar *package_id,
 			  const gchar *url, const gchar *restart,
 			  const gchar *update_text)
 {
+	gchar *update_text_safe;
 	g_return_val_if_fail (backend != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
 
+	/* replace unsafe chars */
+	update_text_safe = pk_string_replace_unsafe (update_text);
+
 	pk_debug ("emit update-detail %s, %s, %s, %s, %s, %s",
-		  package_id, updates, obsoletes, url, restart, update_text);
+		  package_id, updates, obsoletes, url, restart, update_text_safe);
 	g_signal_emit (backend, signals [PK_BACKEND_UPDATE_DETAIL], 0,
-		       package_id, updates, obsoletes, url, restart, update_text);
+		       package_id, updates, obsoletes, url, restart, update_text_safe);
+	g_free (update_text_safe);
 	return TRUE;
 }
 
@@ -841,14 +852,20 @@ pk_backend_description (PkBackend *backend, const gchar *package_id,
 			const gchar *description, const gchar *url,
 			gulong size, const gchar *filelist)
 {
+	gchar *description_safe;
 	g_return_val_if_fail (backend != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
 
-	pk_debug ("emit description %s, %s, %i, %s, %s, %ld, %s", package_id, licence, group, description, url,
+	/* replace unsafe chars */
+	description_safe = pk_string_replace_unsafe (description);
+
+	pk_debug ("emit description %s, %s, %i, %s, %s, %ld, %s",
+		  package_id, licence, group, description_safe, url,
 		  size, filelist);
-	g_signal_emit (backend, signals [PK_BACKEND_DESCRIPTION], 0, package_id, licence, group, description, url,
+	g_signal_emit (backend, signals [PK_BACKEND_DESCRIPTION], 0,
+		       package_id, licence, group, description_safe, url,
 		       size, filelist);
-
+	g_free (description_safe);
 	return TRUE;
 }
 
commit 9bd7940265bd25233a222609f7edc0c4a476c037
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Oct 25 21:47:41 2007 +0100

    add pk_string_replace_unsafe as a common function, and unit test

diff --git a/libpackagekit/pk-common.c b/libpackagekit/pk-common.c
index e5c5d4d..0898986 100644
--- a/libpackagekit/pk-common.c
+++ b/libpackagekit/pk-common.c
@@ -143,6 +143,22 @@ pk_validate_input_char (gchar item)
 }
 
 /**
+ * pk_string_replace_unsafe:
+ **/
+gchar *
+pk_string_replace_unsafe (const gchar *text)
+{
+	gchar *text_safe;
+	const gchar *delimiters;
+
+	/* rip out any insane characters */
+	delimiters = "\\\f\n\r\t\"'";
+	text_safe = g_strdup (text);
+	g_strdelimit (text_safe, delimiters, ' ');
+	return text_safe;
+}
+
+/**
  * pk_validate_input:
  **/
 gboolean
@@ -283,6 +299,7 @@ libst_common (LibSelfTest *test)
 {
 	gboolean ret;
 	gchar **array;
+	gchar *text_safe;
 	const gchar *temp;
 
 	if (libst_start (test, "PkCommon", CLASS_AUTO) == FALSE) {
@@ -571,6 +588,48 @@ libst_common (LibSelfTest *test)
 		libst_failed (test, "failed the filter '%s'", temp);
 	}
 
+	/************************************************************
+	 ****************       REPLACE CHARS      ******************
+	 ************************************************************/
+	libst_title (test, "test replace unsafe (okay)");
+	text_safe = pk_string_replace_unsafe ("Richard Hughes");
+	if (text_safe != NULL && strcmp (text_safe, "Richard Hughes") == 0) {
+		libst_success (test, NULL);
+	} else {
+		libst_failed (test, "failed the replace unsafe '%s'", text_safe);
+	}
+	g_free (text_safe);
+
+	/************************************************************/
+	libst_title (test, "test replace unsafe (one invalid)");
+	text_safe = pk_string_replace_unsafe ("Richard\tHughes");
+	if (text_safe != NULL && strcmp (text_safe, "Richard Hughes") == 0) {
+		libst_success (test, NULL);
+	} else {
+		libst_failed (test, "failed the replace unsafe '%s'", text_safe);
+	}
+	g_free (text_safe);
+
+	/************************************************************/
+	libst_title (test, "test replace unsafe (one invalid 2)");
+	text_safe = pk_string_replace_unsafe ("Richard\"Hughes\"");
+	if (text_safe != NULL && strcmp (text_safe, "Richard Hughes ") == 0) {
+		libst_success (test, NULL);
+	} else {
+		libst_failed (test, "failed the replace unsafe '%s'", text_safe);
+	}
+	g_free (text_safe);
+
+	/************************************************************/
+	libst_title (test, "test replace unsafe (multiple invalid)");
+	text_safe = pk_string_replace_unsafe ("'Richard\"Hughes\"");
+	if (text_safe != NULL && strcmp (text_safe, " Richard Hughes ") == 0) {
+		libst_success (test, NULL);
+	} else {
+		libst_failed (test, "failed the replace unsafe '%s'", text_safe);
+	}
+	g_free (text_safe);
+
 	libst_end (test);
 }
 #endif
diff --git a/libpackagekit/pk-common.h b/libpackagekit/pk-common.h
index e39658f..192c17d 100644
--- a/libpackagekit/pk-common.h
+++ b/libpackagekit/pk-common.h
@@ -32,6 +32,7 @@ G_BEGIN_DECLS
 
 gboolean	 pk_validate_input			(const gchar	*text);
 gboolean	 pk_filter_check			(const gchar	*filter);
+gchar		*pk_string_replace_unsafe		(const gchar	*text);
 gchar		**pk_string_id_split			(const gchar	*id,
 							 guint		 parts);
 gboolean	 pk_string_id_strcmp			(const gchar	*id1,
commit 6ddc030b301f131f9038d6ecee0bbace903b8127
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Oct 25 21:10:33 2007 +0100

    make a comment about SQL injection - it's only from the backends but we need to be careful

diff --git a/backends/dummy/pk-backend-dummy.c b/backends/dummy/pk-backend-dummy.c
index b85f650..fe71ca8 100644
--- a/backends/dummy/pk-backend-dummy.c
+++ b/backends/dummy/pk-backend-dummy.c
@@ -308,7 +308,7 @@ backend_search_details (PkBackend *backend, const gchar *filter, const gchar *se
 	g_return_if_fail (backend != NULL);
 	pk_backend_package (backend, PK_INFO_ENUM_AVAILABLE,
 			    "vips-doc;7.12.4-2.fc8;noarch;linva",
-			    "The vips documentation package.");
+			    "The vips \"documentation\" package.");
 	pk_backend_finished (backend);
 }
 
diff --git a/src/pk-transaction-db.c b/src/pk-transaction-db.c
index d033c0a..1a2420e 100644
--- a/src/pk-transaction-db.c
+++ b/src/pk-transaction-db.c
@@ -275,6 +275,7 @@ pk_transaction_db_set_data (PkTransactionDb *tdb, const gchar *tid, const gchar
 	g_return_val_if_fail (tdb != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), FALSE);
 
+	/* TODO: we have to be careful of SQL injection attacks */
 	statement = g_strdup_printf ("UPDATE transactions SET data = \"%s\" WHERE transaction_id = '%s'",
 				     data, tid);
 	pk_transaction_db_sql_statement (tdb, statement);
commit 4035fe0c6240215a5ac35c61b78af4983379da98
Author: Ali Sabil <ali.sabil at gmail.com>
Date:   Thu Oct 25 22:09:05 2007 +0200

    apt: Added a missing symlink in the helpers folder

diff --git a/backends/apt/helpers/packagekit b/backends/apt/helpers/packagekit
new file mode 120000
index 0000000..8d22531
--- /dev/null
+++ b/backends/apt/helpers/packagekit
@@ -0,0 +1 @@
+../../../python/packagekit
\ No newline at end of file
commit ebb108fb6ed7a851f50a8f68b435bbf43cf67889
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Oct 25 19:50:04 2007 +0100

    add an apt backend by Ali Sabil - I've renamed the old apt backend to apt.old

diff --git a/backends/apt.old/.gitignore b/backends/apt.old/.gitignore
new file mode 100644
index 0000000..c851833
--- /dev/null
+++ b/backends/apt.old/.gitignore
@@ -0,0 +1,10 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.la
+*.lo
+*.loT
+*.o
+*~
+
diff --git a/backends/apt.old/Makefile.am b/backends/apt.old/Makefile.am
new file mode 100644
index 0000000..a4126a0
--- /dev/null
+++ b/backends/apt.old/Makefile.am
@@ -0,0 +1,17 @@
+SUBDIRS = helpers
+plugindir = @PK_PLUGIN_DIR@
+plugin_LTLIBRARIES = libpk_backend_apt.la
+libpk_backend_apt_la_INCLUDES = $(APT_CFLAGS) $(SQLITE_CFLAGS)
+libpk_backend_apt_la_SOURCES =		\
+	pk-backend-apt.h		\
+	pk-backend-apt.cpp		\
+	pk-sqlite-pkg-cache.h		\
+	pk-sqlite-pkg-cache.c		\
+	pk-apt-build-db.cpp		\
+	pk-python-backend-common.h		\
+	pk-python-backend-common.c
+libpk_backend_apt_la_LIBADD = @PK_PLUGIN_LIBS@ $(APT_LIBS) $(SQLITE_LIBS)
+libpk_backend_apt_la_LDFLAGS = -module -avoid-version
+libpk_backend_apt_la_CFLAGS = @PK_PLUGIN_CFLAGS@ -DDATABASEDIR=\""$(PK_DB_DIR)"\"
+libpk_backend_apt_la_CXXFLAGS = @PK_PLUGIN_CFLAGS@ -DDATABASEDIR=\""$(PK_DB_DIR)"\"
+
diff --git a/backends/apt.old/helpers/.gitignore b/backends/apt.old/helpers/.gitignore
new file mode 100644
index 0000000..d18402d
--- /dev/null
+++ b/backends/apt.old/helpers/.gitignore
@@ -0,0 +1,2 @@
+*.pyc
+.*.swp
diff --git a/backends/apt.old/helpers/Makefile.am b/backends/apt.old/helpers/Makefile.am
new file mode 100644
index 0000000..c14397e
--- /dev/null
+++ b/backends/apt.old/helpers/Makefile.am
@@ -0,0 +1,16 @@
+
+helperdir = $(datadir)/PackageKit/helpers/apt
+
+NULL =
+
+dist_helper_DATA = 			\
+	refresh-cache.py		\
+	aptBackend.py			\
+	$(NULL)
+
+install-data-hook:
+	chmod a+rx $(DESTDIR)$(helperdir)/*.py
+
+clean-local :
+	rm -f *~
+
diff --git a/backends/apt.old/helpers/aptBackend.py b/backends/apt.old/helpers/aptBackend.py
new file mode 100644
index 0000000..d0f370a
--- /dev/null
+++ b/backends/apt.old/helpers/aptBackend.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+
+# 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+
+from packagekit.backend import *
+import apt
+
+class PackageKitProgress(apt.progress.OpProgress, apt.progress.FetchProgress):
+	def __init__(self, backend):
+		self.backend = backend
+
+	# OpProgress callbacks
+	def update(self, percent):
+		self.backend.percentage(percent)
+
+	def done(self):
+		self.backend.percentage(50.0)
+
+	# FetchProgress callbacks
+	def pulse(self):
+		apt.progress.FetchProgress.pulse(self)
+		self.backend.percentage(self.percent)
+
+	def stop(self):
+		print "self.inc (stop)"
+		self.backend.percentage(100)
+
+	def mediaChange(self, medium, drive):
+		self.backend.error(ERROR_INTERNAL_ERROR, "Needed to do a medium change!")
+
+class PackageKitAptBackend(PackageKitBaseBackend):
+	def refresh_cache(self):
+		'''
+		Implement the {backend}-refresh_cache functionality
+		'''
+		self.percentage(0)
+		pkp = PackageKitProgress(self)
+		cache = apt.Cache(pkp)
+		if cache.update(pkp) == False:
+			self.error(ERROR_INTERNAL_ERROR,"Fetch failure")
+
diff --git a/backends/apt.old/helpers/refresh-cache.py b/backends/apt.old/helpers/refresh-cache.py
new file mode 100755
index 0000000..5feb6e5
--- /dev/null
+++ b/backends/apt.old/helpers/refresh-cache.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+#
+# Apt refresh-cache handler. Modified from the yum handler
+#
+# Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
+# Copyright (C) 2007 Red Hat Inc, Seth Vidal <skvidal at fedoraproject.org>
+# Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+#
+# 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.
+
+import sys
+
+from aptBackend import PackageKitAptBackend
+
+backend = PackageKitAptBackend(sys.argv[1:])
+backend.refresh_cache()
+sys.exit(0)
diff --git a/backends/apt.old/pk-apt-build-db.cpp b/backends/apt.old/pk-apt-build-db.cpp
new file mode 100644
index 0000000..894b70b
--- /dev/null
+++ b/backends/apt.old/pk-apt-build-db.cpp
@@ -0,0 +1,283 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "pk-backend-apt.h"
+#include <apt-pkg/configuration.h>
+#include <sqlite3.h>
+
+typedef enum {FIELD_PKG=1,FIELD_VER,FIELD_DEPS,FIELD_ARCH,FIELD_SHORT,FIELD_LONG,FIELD_REPO} Fields;
+
+void apt_build_db(PkBackend * backend, sqlite3 *db)
+{
+	GMatchInfo *match_info;
+	GError *error = NULL;
+	gchar *contents = NULL;
+	gchar *sdir;
+	const gchar *fname;
+	GRegex *origin, *suite;
+	GDir *dir;
+	GHashTable *releases;
+	int res;
+	sqlite3_stmt *package = NULL;
+
+	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
+	pk_backend_no_percentage_updates(backend);
+
+	sdir = g_build_filename(_config->Find("Dir").c_str(),_config->Find("Dir::State").c_str(),_config->Find("Dir::State::lists").c_str(), NULL);
+	dir = g_dir_open(sdir,0,&error);
+	if (error!=NULL)
+	{
+		pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "can't open %s",dir);
+		g_error_free(error);
+		goto search_task_cleanup;
+	}
+
+	origin = g_regex_new("^Origin: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
+	suite = g_regex_new("^Suite: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
+
+	releases = g_hash_table_new_full(g_str_hash,g_str_equal,g_free,g_free);
+	while ((fname = g_dir_read_name(dir))!=NULL)
+	{
+		gchar *temp, *parsed_name;
+		gchar** items = g_strsplit(fname,"_",-1);
+		guint len = g_strv_length(items);
+		if(len<=3) // minimum is <source>_<type>_<group>
+		{
+			g_strfreev(items);
+			continue;
+		}
+
+		/* warning: nasty hack with g_strjoinv */
+		temp = items[len-2];
+		items[len-2] = NULL;
+		parsed_name = g_strjoinv("_",items);
+		items[len-2] = temp;
+
+		if (g_ascii_strcasecmp(items[len-1],"Release")==0 && g_ascii_strcasecmp(items[len-2],"source")!=0)
+		{
+			gchar * repo = NULL, *fullname;
+			fullname = g_build_filename(sdir,fname,NULL);
+			if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
+			{
+				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
+				goto search_task_cleanup;
+			}
+			g_free(fullname);
+
+			g_regex_match (origin, contents, (GRegexMatchFlags)0, &match_info);
+			if (!g_match_info_matches(match_info))
+			{
+				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "origin regex failure in %s",fname);
+				goto search_task_cleanup;
+			}
+			repo = g_match_info_fetch (match_info, 1);
+
+			g_regex_match (suite, contents, (GRegexMatchFlags)0, &match_info);
+			if (g_match_info_matches(match_info))
+			{
+				temp = g_strconcat(repo,"/",g_match_info_fetch (match_info, 1),NULL);
+				g_free(repo);
+				repo = temp;
+			}
+
+			temp = parsed_name;
+			parsed_name = g_strconcat(temp,"_",items[len-2],NULL);
+			g_free(temp);
+
+			pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
+
+			g_hash_table_insert(releases, parsed_name, repo);
+			g_free(contents);
+			contents = NULL;
+		}
+		else
+			g_free(parsed_name);
+		g_strfreev(items);
+	}
+	g_dir_close(dir);
+
+	/* and then we need to do this again, but this time we're looking for the packages */
+	dir = g_dir_open(sdir,0,&error);
+	res = sqlite3_prepare_v2(db, "insert or replace into packages values (?,?,?,?,?,?,?)", -1, &package, NULL);
+	if (res!=SQLITE_OK)
+		pk_error("sqlite error during insert prepare: %s", sqlite3_errmsg(db));
+	else
+		pk_debug("insert prepare ok for %p",package);
+	while ((fname = g_dir_read_name(dir))!=NULL)
+	{
+		gchar** items = g_strsplit(fname,"_",-1);
+		guint len = g_strv_length(items);
+		if(len<=3) // minimum is <source>_<type>_<group>
+		{
+			g_strfreev(items);
+			continue;
+		}
+
+		if (g_ascii_strcasecmp(items[len-1],"Packages")==0)
+		{
+			const gchar *repo;
+			gchar *temp=NULL, *parsed_name=NULL;
+			gchar *fullname= NULL;
+			gchar *begin=NULL, *next=NULL, *description = NULL;
+			glong count = 0;
+			gboolean haspk = FALSE;
+
+			/* warning: nasty hack with g_strjoinv */
+			if (g_str_has_prefix(items[len-2],"binary-"))
+			{
+				temp = items[len-3];
+				items[len-3] = NULL;
+				parsed_name = g_strjoinv("_",items);
+				items[len-3] = temp;
+			}
+			else
+			{
+				temp = items[len-1];
+				items[len-1] = NULL;
+				parsed_name = g_strjoinv("_",items);
+				items[len-1] = temp;
+			}
+
+			pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
+
+			repo = (const gchar *)g_hash_table_lookup(releases,parsed_name);
+			if (repo == NULL)
+			{
+				pk_debug("Can't find repo for %s, marking as \"unknown\"",parsed_name);
+				repo = g_strdup("unknown");
+				//g_assert(0);
+			}
+			else
+				pk_debug("repo for %s is %s",parsed_name,repo);
+			g_free(parsed_name);
+
+			fullname = g_build_filename(sdir,fname,NULL);
+			pk_debug("loading %s",fullname);
+			if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
+			{
+				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
+				goto search_task_cleanup;
+			}
+			/*else
+				pk_debug("loaded");*/
+
+			res = sqlite3_bind_text(package,FIELD_REPO,repo,-1,SQLITE_TRANSIENT);
+			if (res!=SQLITE_OK)
+				pk_error("sqlite error during repo bind: %s", sqlite3_errmsg(db));
+			/*else
+				pk_debug("repo bind ok");*/
+
+			res = sqlite3_exec(db,"begin",NULL,NULL,NULL);
+			g_assert(res == SQLITE_OK);
+
+			begin = contents;
+
+			while (true)
+			{
+				next = strstr(begin,"\n");
+				if (next!=NULL)
+				{
+					next[0] = '\0';
+					next++;
+				}
+
+				if (begin[0]=='\0')
+				{
+					if (haspk)
+					{
+						if (description!=NULL)
+						{
+							res=sqlite3_bind_text(package,FIELD_LONG,description,-1,SQLITE_TRANSIENT);
+							if (res!=SQLITE_OK)
+								pk_error("sqlite error during description bind: %s", sqlite3_errmsg(db));
+							g_free(description);
+							description = NULL;
+						}
+						res = sqlite3_step(package);
+						if (res!=SQLITE_DONE)
+							pk_error("sqlite error during step: %s", sqlite3_errmsg(db));
+						sqlite3_reset(package);
+						//pk_debug("added package");
+						haspk = FALSE;
+					}
+					//g_assert(0);
+				}
+				else if (begin[0]==' ')
+				{
+					if (description == NULL)
+						description = g_strdup(&begin[1]);
+					else
+					{
+						gchar *oldval = description;
+						description = g_strconcat(oldval, "\n",&begin[1],NULL);
+						g_free(oldval);
+					}
+				}
+				else
+				{
+					gchar *colon = strchr(begin,':');
+					g_assert(colon!=NULL);
+					colon[0] = '\0';
+					colon+=2;
+					/*if (strlen(colon)>3000)
+						pk_error("strlen(colon) = %d\ncolon = %s",strlen(colon),colon);*/
+					//pk_debug("entry = '%s','%s'",begin,colon);
+					if (begin[0] == 'P' && g_strcasecmp("Package",begin)==0)
+					{
+						res=sqlite3_bind_text(package,FIELD_PKG,colon,-1,SQLITE_STATIC);
+						haspk = TRUE;
+						count++;
+						if (count%1000==0)
+							pk_debug("Package %ld (%s)",count,colon);
+					}
+					else if (begin[0] == 'V' && g_strcasecmp("Version",begin)==0)
+						res=sqlite3_bind_text(package,FIELD_VER,colon,-1,SQLITE_STATIC);
+					else if (begin[0] == 'D' && g_strcasecmp("Depends",begin)==0)
+						res=sqlite3_bind_text(package,FIELD_DEPS,colon,-1,SQLITE_STATIC);
+					else if (begin[0] == 'A' && g_strcasecmp("Architecture",begin)==0)
+						res=sqlite3_bind_text(package,FIELD_ARCH,colon,-1,SQLITE_STATIC);
+					else if (begin[0] == 'D' && g_strcasecmp("Description",begin)==0)
+						res=sqlite3_bind_text(package,FIELD_SHORT,colon,-1,SQLITE_STATIC);
+					if (res!=SQLITE_OK)
+						pk_error("sqlite error during %s bind: %s", begin, sqlite3_errmsg(db));
+				}
+				if (next == NULL)
+					break;
+				begin = next;
+			}
+			res = sqlite3_exec(db,"commit",NULL,NULL,NULL);
+			if (res!=SQLITE_OK)
+				pk_error("sqlite error during commit: %s", sqlite3_errmsg(db));
+			res = sqlite3_clear_bindings(package);
+			if (res!=SQLITE_OK)
+				pk_error("sqlite error during clear: %s", sqlite3_errmsg(db));
+			g_free(contents);
+			contents = NULL;
+		}
+	}
+	sqlite3_finalize(package);
+
+search_task_cleanup:
+	g_dir_close(dir);
+	g_free(sdir);
+	g_free(contents);
+}
+
diff --git a/backends/apt.old/pk-backend-apt.cpp b/backends/apt.old/pk-backend-apt.cpp
new file mode 100644
index 0000000..2c5e159
--- /dev/null
+++ b/backends/apt.old/pk-backend-apt.cpp
@@ -0,0 +1,162 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <gmodule.h>
+#include <glib.h>
+#include <glib/gprintf.h>
+
+#include <math.h>
+#include <string.h>
+
+#include <pk-backend.h>
+#include <pk-debug.h>
+#include <pk-package-id.h>
+#include "config.h"
+
+#include <apt-pkg/configuration.h>
+#include <apt-pkg/init.h>
+
+#include "pk-backend-apt.h"
+extern "C" {
+#include "sqlite-pkg-cache.h"
+#include "python-backend-common.h"
+}
+
+static gboolean inited = FALSE;
+
+#define APT_DB DATABASEDIR "/apt.db"
+
+static void backend_initialize(PkBackend *backend)
+{
+	if (!inited)
+	{
+		gchar *apt_fname = NULL;
+		if (pkgInitConfig(*_config) == false)
+			pk_debug("pkginitconfig was false");
+		if (pkgInitSystem(*_config, _system) == false)
+			pk_debug("pkginitsystem was false");
+
+		apt_fname = g_strconcat(
+				_config->Find("Dir").c_str(),
+				_config->Find("Dir::Cache").c_str(),
+				_config->Find("Dir::Cache::pkgcache").c_str(),
+				NULL);
+
+		sqlite_init_cache(backend, APT_DB, apt_fname, apt_build_db);
+		g_free(apt_fname);
+		inited = TRUE;
+	}
+}
+
+/**
+ * backend_get_groups:
+ */
+static void
+backend_get_groups (PkBackend *backend, PkEnumList *elist)
+{
+	g_return_if_fail (backend != NULL);
+	pk_enum_list_append_multiple (elist,
+				      PK_GROUP_ENUM_ACCESSIBILITY,
+				      PK_GROUP_ENUM_GAMES,
+				      PK_GROUP_ENUM_SYSTEM,
+				      -1);
+}
+
+/**
+ * backend_get_filters:
+ */
+static void
+backend_get_filters (PkBackend *backend, PkEnumList *elist)
+{
+	g_return_if_fail (backend != NULL);
+	pk_enum_list_append_multiple (elist,
+				      PK_FILTER_ENUM_GUI,
+				      PK_FILTER_ENUM_INSTALLED,
+				      PK_FILTER_ENUM_DEVELOPMENT,
+				      -1);
+}
+
+static gboolean backend_search_file_thread (PkBackend *backend, gpointer data)
+{
+	//search_task *st = (search_task*)data;
+	gchar *sdir = g_path_get_dirname(_config->Find("Dir::State::status").c_str());
+	gchar *ldir = g_build_filename(sdir,"info",NULL);
+	g_free(sdir);
+	GError *error = NULL;
+	GDir *list = g_dir_open(ldir,0,&error);
+	if (error!=NULL)
+	{
+		pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "can't open %s",ldir);
+		g_free(ldir);
+		g_error_free(error);
+		return FALSE;
+	}
+	const gchar * fname = NULL;
+	while ((fname = g_dir_read_name(list))!=NULL)
+	{
+		//pk_backend_package(backend, J->installed, pid, P.ShortDesc().c_str());
+	}
+	pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "search file is incomplete");
+	g_dir_close(list);
+	g_free(ldir);
+	return TRUE;
+}
+
+/**
+ * backend_search_file:
+ **/
+static void backend_search_file(PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	backend_search_common(backend, filter, search, SEARCH_FILE, backend_search_file_thread);
+}
+
+extern "C" PK_BACKEND_OPTIONS (
+	"APT",					/* description */
+	"0.0.1",				/* version */
+	"Tom Parker <palfrey at tevp.net>",	/* author */
+	backend_initialize,			/* initalize */
+	NULL,					/* destroy */
+	backend_get_groups,			/* get_groups */
+	backend_get_filters,			/* get_filters */
+	NULL,					/* cancel */
+	NULL,					/* get_depends */
+	sqlite_get_description,		/* get_description */
+	NULL,					/* get_requires */
+	NULL,					/* get_update_detail */
+	NULL,					/* get_updates */
+	NULL,					/* install_package */
+	NULL,					/* install_name */
+	python_refresh_cache,			/* refresh_cache */
+	NULL,					/* remove_package */
+	NULL,					/* resolve */
+	NULL,					/* rollback */
+	sqlite_search_details,			/* search_details */
+	backend_search_file,			/* search_file */
+	NULL,					/* search_group */
+	sqlite_search_name,			/* search_name */
+	NULL,					/* update_package */
+	NULL,					/* update_system */
+	NULL,					/* get_repo_list */
+	NULL,					/* repo_enable */
+	NULL					/* repo_set_data */
+);
+
diff --git a/backends/apt.old/pk-backend-apt.h b/backends/apt.old/pk-backend-apt.h
new file mode 100644
index 0000000..ff67654
--- /dev/null
+++ b/backends/apt.old/pk-backend-apt.h
@@ -0,0 +1,30 @@
+#ifndef PK_BACKEND_APT
+#define PK_BACKEND_APT
+
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <sqlite3.h>
+#include <pk-backend.h>
+
+void apt_build_db(PkBackend * backend, sqlite3 *db);
+
+#endif
diff --git a/backends/apt.old/pk-python-backend-common.c b/backends/apt.old/pk-python-backend-common.c
new file mode 100644
index 0000000..41b3788
--- /dev/null
+++ b/backends/apt.old/pk-python-backend-common.c
@@ -0,0 +1,39 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <pk-backend.h>
+
+/**
+ * python_refresh_cache:
+ **/
+void python_refresh_cache(PkBackend * backend, gboolean force)
+{
+	/* check network state */
+	if (pk_backend_network_is_online(backend) == FALSE)
+	{
+		pk_backend_error_code(backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot refresh cache whilst offline");
+		pk_backend_finished(backend);
+		return;
+	}
+
+	pk_backend_spawn_helper (backend, "refresh-cache.py", NULL);
+}
+
diff --git a/backends/apt.old/pk-python-backend-common.h b/backends/apt.old/pk-python-backend-common.h
new file mode 100644
index 0000000..a0b56bd
--- /dev/null
+++ b/backends/apt.old/pk-python-backend-common.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef PYTHON_BACKEND_COMMON_H
+#define PYTHON_BACKEND_COMMON_H
+
+void python_refresh_cache(PkBackend * backend, gboolean force);
+
+#endif
+
diff --git a/backends/apt.old/pk-sqlite-pkg-cache.c b/backends/apt.old/pk-sqlite-pkg-cache.c
new file mode 100644
index 0000000..29647a5
--- /dev/null
+++ b/backends/apt.old/pk-sqlite-pkg-cache.c
@@ -0,0 +1,228 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <sqlite3.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include "sqlite-pkg-cache.h"
+
+static sqlite3 *db = NULL;
+
+typedef struct {
+	PkPackageId *pi;
+} desc_task;
+
+typedef struct {
+	gchar *search;
+	gchar *filter;
+	SearchDepth depth;
+} search_task;
+
+void
+sqlite_init_cache(PkBackend *backend, const char* dbname, const char *compare_fname, void (*build_db)(PkBackend *, sqlite3 *))
+{
+	int ret;
+	struct stat st;
+	time_t db_age;
+
+	ret = sqlite3_open (dbname, &db);
+	ret = sqlite3_exec(db,"PRAGMA synchronous = OFF",NULL,NULL,NULL);
+	g_assert(ret == SQLITE_OK);
+
+	g_stat(dbname, &st);
+	db_age = st.st_mtime;
+	g_stat(compare_fname, &st);
+	if (db_age>=st.st_mtime)
+	{
+		ret = sqlite3_exec(db, "select value from params where name = 'build_complete'", NULL, NULL, NULL);
+		if (ret != SQLITE_ERROR)
+			return;
+	}
+	ret = sqlite3_exec(db,"drop table packages",NULL,NULL,NULL); // wipe it!
+	//g_assert(ret == SQLITE_OK);
+	pk_debug("wiped db");
+	ret = sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string, primary key(name,version,arch,repo))",NULL,NULL,NULL);
+	g_assert(ret == SQLITE_OK);
+
+	build_db(backend,db);
+
+	sqlite3_exec(db,"create table params (name text primary key, value integer)", NULL, NULL, NULL);
+	sqlite3_exec(db,"insert into params values ('build_complete',1)", NULL, NULL, NULL);
+}
+
+// sqlite_search_packages_thread
+static gboolean
+sqlite_search_packages_thread (PkBackend *backend, gpointer data)
+{
+	search_task *st = (search_task *) data;
+	int res;
+	gchar *sel;
+
+	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
+	pk_backend_no_percentage_updates(backend);
+
+	pk_debug("finding %s", st->search);
+
+	sqlite3_stmt *package = NULL;
+	g_strdelimit(st->search," ",'%');
+
+	if (st->depth == SEARCH_NAME)
+		sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%'",st->search);
+	else if (st->depth == SEARCH_DETAILS)
+		sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%' or short_desc like '%%%s%%' or long_desc like '%%%s%%'",st->search, st->search, st->search);
+	else
+	{
+		pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "Unknown search task type");
+		goto end_search_packages;
+	}
+
+	pk_debug("statement is '%s'",sel);
+	res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
+	g_free(sel);
+	if (res!=SQLITE_OK)
+		pk_error("sqlite error during select prepare: %s", sqlite3_errmsg(db));
+	res = sqlite3_step(package);
+	while (res == SQLITE_ROW)
+	{
+		gchar *pid = pk_package_id_build((const gchar*)sqlite3_column_text(package,0),
+				(const gchar*)sqlite3_column_text(package,1),
+				(const gchar*)sqlite3_column_text(package,2),
+				(const gchar*)sqlite3_column_text(package,3));
+		pk_backend_package(backend, PK_INFO_ENUM_UNKNOWN, pid, (const gchar*)sqlite3_column_text(package,4));
+		g_free(pid);
+		if (res==SQLITE_ROW)
+			res = sqlite3_step(package);
+	}
+	if (res!=SQLITE_DONE)
+	{
+		pk_debug("sqlite error during step (%d): %s", res, sqlite3_errmsg(db));
+		g_assert(0);
+	}
+
+	end_search_packages:
+	g_free(st->search);
+	g_free(st);
+
+	return TRUE;
+}
+
+/**
+ * backend_search_common
+ **/
+void
+backend_search_common(PkBackend * backend, const gchar * filter, const gchar * search, SearchDepth which, PkBackendThreadFunc func)
+{
+	g_return_if_fail (backend != NULL);
+	search_task *data = g_new(search_task, 1);
+	if (data == NULL)
+	{
+		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory for search task");
+		pk_backend_finished(backend);
+	}
+	else
+	{
+		data->search = g_strdup(search);
+		data->filter = g_strdup(filter);
+		data->depth = which;
+		pk_backend_thread_helper (backend, func, data);
+	}
+}
+
+/**
+ * sqlite_search_details:
+ */
+void
+sqlite_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	backend_search_common(backend, filter, search, SEARCH_DETAILS, sqlite_search_packages_thread);
+}
+
+/**
+ * sqlite_search_name:
+ */
+void
+sqlite_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	backend_search_common(backend, filter, search, SEARCH_NAME, sqlite_search_packages_thread);
+}
+
+// sqlite_get_description_thread
+static gboolean sqlite_get_description_thread (PkBackend *backend, gpointer data)
+{
+	desc_task *dt = (desc_task *) data;
+	int res;
+
+	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
+	pk_backend_no_percentage_updates(backend);
+
+	pk_debug("finding %s", dt->pi->name);
+
+	sqlite3_stmt *package = NULL;
+	gchar *sel = g_strdup_printf("select long_desc from packages where name = '%s' and version = '%s' and repo = '%s'",dt->pi->name,dt->pi->version,dt->pi->data);
+	pk_debug("statement is '%s'",sel);
+	res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
+	g_free(sel);
+	if (res!=SQLITE_OK)
+		pk_error("sqlite error during select prepare: %s", sqlite3_errmsg(db));
+	res = sqlite3_step(package);
+	pk_backend_description(backend,dt->pi->name, "unknown", PK_GROUP_ENUM_OTHER,(const gchar*)sqlite3_column_text(package,0),"",0,"");
+	res = sqlite3_step(package);
+	if (res==SQLITE_ROW)
+		pk_error("multiple matches for that package!");
+	if (res!=SQLITE_DONE)
+	{
+		pk_debug("sqlite error during step (%d): %s", res, sqlite3_errmsg(db));
+		g_assert(0);
+	}
+
+	g_free(dt);
+
+	return TRUE;
+}
+
+/**
+ * sqlite_get_description:
+ */
+void
+sqlite_get_description (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	desc_task *data = g_new(desc_task, 1);
+	if (data == NULL)
+	{
+		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory for search task");
+		pk_backend_finished(backend);
+		return;
+	}
+
+	data->pi = pk_package_id_new_from_string(package_id);
+	if (data->pi == NULL)
+	{
+		pk_backend_error_code(backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "invalid package id");
+		pk_backend_finished(backend);
+		return;
+	}
+
+	pk_backend_thread_helper (backend, sqlite_get_description_thread, data);
+	return;
+}
+
+
diff --git a/backends/apt.old/pk-sqlite-pkg-cache.h b/backends/apt.old/pk-sqlite-pkg-cache.h
new file mode 100644
index 0000000..68f5287
--- /dev/null
+++ b/backends/apt.old/pk-sqlite-pkg-cache.h
@@ -0,0 +1,39 @@
+#ifndef SQLITE_PKT_CACHE
+#define SQLITE_PKT_CACHE
+
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+typedef enum {
+	SEARCH_NAME = 1,
+	SEARCH_DETAILS,
+	SEARCH_FILE
+} SearchDepth;
+
+#include <pk-backend.h>
+
+void sqlite_init_cache(PkBackend *backend, const char* dbname, const char* compare_fname, void (*build_db)(PkBackend *, sqlite3 *db));
+void sqlite_search_details (PkBackend *backend, const gchar *filter, const gchar *search);
+void sqlite_search_name (PkBackend *backend, const gchar *filter, const gchar *search);
+void backend_search_common(PkBackend * backend, const gchar * filter, const gchar * search, SearchDepth which, PkBackendThreadFunc func);
+void sqlite_get_description (PkBackend *backend, const gchar *package_id);
+
+#endif
diff --git a/backends/apt/Makefile.am b/backends/apt/Makefile.am
index a4126a0..473eb96 100644
--- a/backends/apt/Makefile.am
+++ b/backends/apt/Makefile.am
@@ -1,17 +1,8 @@
 SUBDIRS = helpers
 plugindir = @PK_PLUGIN_DIR@
 plugin_LTLIBRARIES = libpk_backend_apt.la
-libpk_backend_apt_la_INCLUDES = $(APT_CFLAGS) $(SQLITE_CFLAGS)
-libpk_backend_apt_la_SOURCES =		\
-	pk-backend-apt.h		\
-	pk-backend-apt.cpp		\
-	pk-sqlite-pkg-cache.h		\
-	pk-sqlite-pkg-cache.c		\
-	pk-apt-build-db.cpp		\
-	pk-python-backend-common.h		\
-	pk-python-backend-common.c
-libpk_backend_apt_la_LIBADD = @PK_PLUGIN_LIBS@ $(APT_LIBS) $(SQLITE_LIBS)
+libpk_backend_apt_la_SOURCES = pk-backend-apt.c
+libpk_backend_apt_la_LIBADD = @PK_PLUGIN_LIBS@
 libpk_backend_apt_la_LDFLAGS = -module -avoid-version
-libpk_backend_apt_la_CFLAGS = @PK_PLUGIN_CFLAGS@ -DDATABASEDIR=\""$(PK_DB_DIR)"\"
-libpk_backend_apt_la_CXXFLAGS = @PK_PLUGIN_CFLAGS@ -DDATABASEDIR=\""$(PK_DB_DIR)"\"
+libpk_backend_apt_la_CFLAGS = @PK_PLUGIN_CFLAGS@
 
diff --git a/backends/apt/helpers/.gitignore b/backends/apt/helpers/.gitignore
deleted file mode 100644
index d18402d..0000000
--- a/backends/apt/helpers/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*.pyc
-.*.swp
diff --git a/backends/apt/helpers/Makefile.am b/backends/apt/helpers/Makefile.am
index c14397e..f33344c 100644
--- a/backends/apt/helpers/Makefile.am
+++ b/backends/apt/helpers/Makefile.am
@@ -4,6 +4,11 @@ helperdir = $(datadir)/PackageKit/helpers/apt
 NULL =
 
 dist_helper_DATA = 			\
+	search-name.py			\
+	search-details.py		\
+	search-group.py			\
+	search-file.py			\
+	get-description.py		\
 	refresh-cache.py		\
 	aptBackend.py			\
 	$(NULL)
diff --git a/backends/apt/helpers/aptBackend.py b/backends/apt/helpers/aptBackend.py
index d0f370a..3fbfc62 100644
--- a/backends/apt/helpers/aptBackend.py
+++ b/backends/apt/helpers/aptBackend.py
@@ -1,55 +1,313 @@
-#!/usr/bin/python
-
-# 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 Library General Public License for more details.
+# Copyright (C) 2007 Ali Sabil <ali.sabil at gmail.com>
 #
-# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Licensed under the GNU General Public License Version 2
 #
-# Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+# 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.
+
+import sys
+import os
+import re
 
 from packagekit.backend import *
+import apt_pkg
+
+import warnings
+warnings.filterwarnings(action='ignore', category=FutureWarning)
 import apt
 
+_HYPHEN_PATTERN = re.compile(r'(\s|_)+')
+
+class Package(object):
+    def __init__(self, pkg, backend):
+        self._pkg = pkg
+        self._cache = backend._apt_cache
+        self._depcache = backend._apt_dep_cache
+        self._records = backend._apt_records
+
+    @property
+    def id(self):
+        return self._pkg.ID
+
+    @property
+    def name(self):
+        return self._pkg.Name
+
+    @property
+    def summary(self):
+        if not self._seek_records():
+            return ""
+        ver = self._depcache.GetCandidateVer(self._pkg)
+        desc_iter = ver.TranslatedDescription
+        self._records.Lookup(desc_iter.FileList.pop(0))
+        return self._records.ShortDesc
+
+    @property
+    def description(self):
+        if not self._seek_records():
+            return ""
+        # get the translated description
+        ver = self._depcache.GetCandidateVer(self._pkg)
+        desc_iter = ver.TranslatedDescription
+        self._records.Lookup(desc_iter.FileList.pop(0))
+        desc = ""
+        try:
+            s = unicode(self._records.LongDesc,"utf-8")
+        except UnicodeDecodeError,e:
+            s = _("Invalid unicode in description for '%s' (%s). "
+                  "Please report.") % (self.name, e)
+        for line in s.splitlines():
+                tmp = line.strip()
+                if tmp == ".":
+                    desc += "\n"
+                else:
+                    desc += tmp + "\n"
+        return desc
+
+    @property
+    def architecture(self):
+        if not self._seek_records():
+            return None
+        sec = apt_pkg.ParseSection(self._records.Record)
+        if sec.has_key("Architecture"):
+            return sec["Architecture"]
+        return None
+
+    @property
+    def section(self):
+        return self._pkg.Section
+
+    @property
+    def installed_version(self):
+        version = self._pkg.CurrentVer
+        if version != None:
+            return version.VerStr
+        else:
+            return None
+
+    @property
+    def candidate_version(self):
+        version = self._depcache.GetCandidateVer(self._pkg)
+        if version != None:
+            return version.VerStr
+        else:
+            return None
+
+    @property
+    def is_installed(self):
+        return (self._pkg.CurrentVer != None)
+
+    @property
+    def is_upgradable(self):
+        return self.is_installed and self._depcache.IsUpgradable(self._pkg)
+
+    @property
+    def is_development(self):
+        name = self.name.lower()
+        section = self.section.split('/')[-1].lower()
+        return name.endswith('-dev') or name.endswith('-dbg') or \
+                section in ('devel', )
+
+    @property
+    def is_gui(self):
+        section = self.section.split('/')[-1].lower()
+        return section in ('x11', 'gnome', 'kde')
+
+    def match_name(self, name):
+        needle = name.strip().lower()
+        haystack = self.name.lower()
+        needle = _HYPHEN_PATTERN.sub('-', needle)
+        haystack = _HYPHEN_PATTERN.sub('-', haystack)
+        if haystack.find(needle) >= 0:
+            return True
+        return False
+
+    def match_details(self, details):
+        if self.match_name(details):
+            return True
+        needle = details.strip().lower()
+        haystack = self.description.lower()
+        if haystack.find(needle) >= 0:
+            return True
+        return False
+
+    ### Helpers ###
+    def _seek_records(self, use_candidate=True):
+        if use_candidate:
+            version = self._depcache.GetCandidateVer(self._pkg)
+        else:
+            version = self._pkg.CurrentVer
+
+        # check if we found a version
+        if version == None or version.FileList == None:
+            return False
+        self._records.Lookup(version.FileList.pop(0))
+        return True
+
+
 class PackageKitProgress(apt.progress.OpProgress, apt.progress.FetchProgress):
-	def __init__(self, backend):
-		self.backend = backend
+    def __init__(self, backend):
+        self._backend = backend
+        apt.progress.OpProgress.__init__(self)
+        apt.progress.FetchProgress.__init__(self)
+
+    # OpProgress callbacks
+    def update(self, percent):
+        pass
 
-	# OpProgress callbacks
-	def update(self, percent):
-		self.backend.percentage(percent)
+    def done(self):
+        pass
 
-	def done(self):
-		self.backend.percentage(50.0)
+    # FetchProgress callbacks
+    def pulse(self):
+        apt.progress.FetchProgress.pulse(self)
+        self._backend.percentage(self.percent)
+        return True
 
-	# FetchProgress callbacks
-	def pulse(self):
-		apt.progress.FetchProgress.pulse(self)
-		self.backend.percentage(self.percent)
+    def stop(self):
+        self._backend.percentage(100)
 
-	def stop(self):
-		print "self.inc (stop)"
-		self.backend.percentage(100)
+    def mediaChange(self, medium, drive):
+        self._backend.error(ERROR_INTERNAL_ERROR,
+                "Medium change needed")
 
-	def mediaChange(self, medium, drive):
-		self.backend.error(ERROR_INTERNAL_ERROR, "Needed to do a medium change!")
 
 class PackageKitAptBackend(PackageKitBaseBackend):
-	def refresh_cache(self):
-		'''
-		Implement the {backend}-refresh_cache functionality
-		'''
-		self.percentage(0)
-		pkp = PackageKitProgress(self)
-		cache = apt.Cache(pkp)
-		if cache.update(pkp) == False:
-			self.error(ERROR_INTERNAL_ERROR,"Fetch failure")
+    def __init__(self, args):
+        PackageKitBaseBackend.__init__(self, args)
+        self._apt_cache = apt_pkg.GetCache(PackageKitProgress(self))
+        self._apt_dep_cache = apt_pkg.GetDepCache(self._apt_cache)
+        self._apt_records = apt_pkg.GetPkgRecords(self._apt_cache)
+        self._apt_list = apt_pkg.GetPkgSourceList()
+        self._apt_list.ReadMainList()
+
+    def search_name(self, filters, key):
+        '''
+        Implement the {backend}-search-name functionality
+        '''
+        self.allow_interrupt(True)
+        for package in self._do_search(filters,
+                lambda pkg: pkg.match_name(key)):
+            self._emit_package(package)
+
+    def search_details(self, filters, key):
+        '''
+        Implement the {backend}-search-details functionality
+        '''
+        self.allow_interrupt(True)
+        for package in self._do_search(filters,
+                lambda pkg: pkg.match_details(key)):
+            self._emit_package(package)
+
+    def search_group(self, filters, key):
+        '''
+        Implement the {backend}-search-group functionality
+        '''
+        self.allow_interrupt(True)
+        self.percentage(None)
+
+        self.error(ERROR_NOT_SUPPORTED,
+                "This function is not implemented in this backend")
+
+    def search_file(self, filters, key):
+        '''
+        Implement the {backend}-search-file functionality
+        '''
+        self.allow_interrupt(True)
+        self.percentage(None)
+
+        self.error(ERROR_NOT_SUPPORTED,
+                "This function is not implemented in this backend")
+
+    def refresh_cache(self):
+        '''
+        Implement the {backend}-refresh_cache functionality
+        '''
+        lockfile = apt_pkg.Config.FindDir("Dir::State::Lists") + "lock"
+        lock = apt_pkg.GetLock(lockfile)
+        if lock < 0:
+            self.error(ERROR_INTERNAL_ERROR,
+                    "Failed to acquire the lock")
+
+        try:
+            fetcher = apt_pkg.GetAcquire(PackageKitProgress(self))
+            # this can throw a exception
+            self._apt_list.GetIndexes(fetcher)
+            self._do_fetch(fetcher)
+        finally:
+            os.close(lock)
+
+    ### Helpers ###
+    def _emit_package(self, package):
+        id = self.get_package_id(package.name,
+                package.installed_version or package.candidate_version,
+                package.architecture,
+                "")
+        if package.is_installed:
+            status = INFO_INSTALLED
+        else:
+            status = INFO_AVAILABLE
+        summary = package.summary
+        self.package(id, status, summary)
+
+    def _do_search(self, filters, condition):
+        filters = filters.split(';')
+        size = len(self._apt_cache.Packages)
+        percentage = 0
+        for i, pkg in enumerate(self._apt_cache.Packages):
+            new_percentage = i / float(size) * 100
+            if new_percentage - percentage >= 5:
+                percentage = new_percentage
+                self.percentage(percentage)
+            package = Package(pkg, self)
+            if package.installed_version is None and \
+                    package.candidate_version is None:
+                continue
+            if not condition(package):
+                continue
+            if not self._do_filtering(package, filters):
+                continue
+            yield package
+        self.percentage(100)
+
+    def _do_fetch(self, fetcher):
+        result = fetcher.Run()
+        failed = False
+        transient = False
+        error_message = ""
+        for item in fetcher.Items:
+            if item.Status == item.StatDone:
+                continue
+            if item.StatIdle:
+                transient = True
+                continue
+            error_message += "%s %s\n" % \
+                    (item.DescURI, item.ErrorText)
+            failed = True
+
+        # we raise a exception if the download failed or it was cancelt
+        if failed:
+            self.error(ERROR_INTERNAL_ERROR,
+                    "Failed to fetch the following items:\n%s" % error_message)
+        return (result == fetcher.ResultContinue)
+
+    def _do_filtering(self, package, filters):
+        if len(filters) == 0 or filters == ['none']:
+            return True
+        if (FILTER_INSTALLED in filters) and (not package.is_installed):
+            return False
+        if (FILTER_NON_INSTALLED in filters) and package.is_installed:
+            return False
+        if (FILTER_GUI in filters) and (not package.is_gui):
+            return False
+        if (FILTER_NON_GUI in filters) and package.is_gui:
+            return False
+        if (FILTER_DEVEL in filters) and (not package.is_development):
+            return False
+        if (FILTER_NON_DEVEL in filters) and package.is_development:
+            return False
+        return TRUE
 
diff --git a/backends/apt/helpers/get-description.py b/backends/apt/helpers/get-description.py
new file mode 100755
index 0000000..5f6287d
--- /dev/null
+++ b/backends/apt/helpers/get-description.py
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2007 Ali Sabil <ali.sabil at 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.
+
+import sys
+from aptBackend import PackageKitAptBackend
+
+package = sys.argv[1]
+backend = PackageKitAptBackend(sys.argv[1:])
+backend.get_description(package)
+sys.exit(0)
diff --git a/backends/apt/helpers/refresh-cache.py b/backends/apt/helpers/refresh-cache.py
index 5feb6e5..881479d 100755
--- a/backends/apt/helpers/refresh-cache.py
+++ b/backends/apt/helpers/refresh-cache.py
@@ -1,10 +1,6 @@
 #!/usr/bin/python
 #
-# Apt refresh-cache handler. Modified from the yum handler
-#
-# Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
-# Copyright (C) 2007 Red Hat Inc, Seth Vidal <skvidal at fedoraproject.org>
-# Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+# Copyright (C) 2007 Ali Sabil <ali.sabil at gmail.com>
 #
 # Licensed under the GNU General Public License Version 2
 #
@@ -14,7 +10,6 @@
 # (at your option) any later version.
 
 import sys
-
 from aptBackend import PackageKitAptBackend
 
 backend = PackageKitAptBackend(sys.argv[1:])
diff --git a/backends/apt/helpers/search-details.py b/backends/apt/helpers/search-details.py
new file mode 100755
index 0000000..d02f1b0
--- /dev/null
+++ b/backends/apt/helpers/search-details.py
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2007 Ali Sabil <ali.sabil at 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.
+
+import sys
+
+options = sys.argv[1]
+searchlist = sys.argv[2]
+
+from aptBackend import PackageKitAptBackend
+
+backend = PackageKitAptBackend(sys.argv[1:])
+backend.search_details(options,searchlist)
+sys.exit(0)
diff --git a/backends/apt/helpers/search-file.py b/backends/apt/helpers/search-file.py
new file mode 100755
index 0000000..ec60319
--- /dev/null
+++ b/backends/apt/helpers/search-file.py
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2007 Ali Sabil <ali.sabil at 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.
+
+import sys
+
+options = sys.argv[1]
+searchlist = sys.argv[2]
+
+from aptBackend import PackageKitAptBackend
+
+backend = PackageKitAptBackend(sys.argv[1:])
+backend.search_file(options,searchlist)
+sys.exit(0)
diff --git a/backends/apt/helpers/search-group.py b/backends/apt/helpers/search-group.py
new file mode 100755
index 0000000..f63ee80
--- /dev/null
+++ b/backends/apt/helpers/search-group.py
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2007 Ali Sabil <ali.sabil at 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.
+
+import sys
+
+options = sys.argv[1]
+searchlist = sys.argv[2]
+
+from aptBackend import PackageKitAptBackend
+
+backend = PackageKitAptBackend(sys.argv[1:])
+backend.search_group(options,searchlist)
+sys.exit(0)
diff --git a/backends/apt/helpers/search-name.py b/backends/apt/helpers/search-name.py
new file mode 100755
index 0000000..9f73c89
--- /dev/null
+++ b/backends/apt/helpers/search-name.py
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2007 Ali Sabil <ali.sabil at 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.
+
+import sys
+
+options = sys.argv[1]
+searchlist = sys.argv[2]
+
+from aptBackend import PackageKitAptBackend
+
+backend = PackageKitAptBackend(sys.argv[1:])
+backend.search_name(options,searchlist)
+sys.exit(0)
diff --git a/backends/apt/pk-apt-build-db.cpp b/backends/apt/pk-apt-build-db.cpp
deleted file mode 100644
index 894b70b..0000000
--- a/backends/apt/pk-apt-build-db.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include "pk-backend-apt.h"
-#include <apt-pkg/configuration.h>
-#include <sqlite3.h>
-
-typedef enum {FIELD_PKG=1,FIELD_VER,FIELD_DEPS,FIELD_ARCH,FIELD_SHORT,FIELD_LONG,FIELD_REPO} Fields;
-
-void apt_build_db(PkBackend * backend, sqlite3 *db)
-{
-	GMatchInfo *match_info;
-	GError *error = NULL;
-	gchar *contents = NULL;
-	gchar *sdir;
-	const gchar *fname;
-	GRegex *origin, *suite;
-	GDir *dir;
-	GHashTable *releases;
-	int res;
-	sqlite3_stmt *package = NULL;
-
-	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
-	pk_backend_no_percentage_updates(backend);
-
-	sdir = g_build_filename(_config->Find("Dir").c_str(),_config->Find("Dir::State").c_str(),_config->Find("Dir::State::lists").c_str(), NULL);
-	dir = g_dir_open(sdir,0,&error);
-	if (error!=NULL)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "can't open %s",dir);
-		g_error_free(error);
-		goto search_task_cleanup;
-	}
-
-	origin = g_regex_new("^Origin: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
-	suite = g_regex_new("^Suite: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
-
-	releases = g_hash_table_new_full(g_str_hash,g_str_equal,g_free,g_free);
-	while ((fname = g_dir_read_name(dir))!=NULL)
-	{
-		gchar *temp, *parsed_name;
-		gchar** items = g_strsplit(fname,"_",-1);
-		guint len = g_strv_length(items);
-		if(len<=3) // minimum is <source>_<type>_<group>
-		{
-			g_strfreev(items);
-			continue;
-		}
-
-		/* warning: nasty hack with g_strjoinv */
-		temp = items[len-2];
-		items[len-2] = NULL;
-		parsed_name = g_strjoinv("_",items);
-		items[len-2] = temp;
-
-		if (g_ascii_strcasecmp(items[len-1],"Release")==0 && g_ascii_strcasecmp(items[len-2],"source")!=0)
-		{
-			gchar * repo = NULL, *fullname;
-			fullname = g_build_filename(sdir,fname,NULL);
-			if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
-			{
-				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
-				goto search_task_cleanup;
-			}
-			g_free(fullname);
-
-			g_regex_match (origin, contents, (GRegexMatchFlags)0, &match_info);
-			if (!g_match_info_matches(match_info))
-			{
-				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "origin regex failure in %s",fname);
-				goto search_task_cleanup;
-			}
-			repo = g_match_info_fetch (match_info, 1);
-
-			g_regex_match (suite, contents, (GRegexMatchFlags)0, &match_info);
-			if (g_match_info_matches(match_info))
-			{
-				temp = g_strconcat(repo,"/",g_match_info_fetch (match_info, 1),NULL);
-				g_free(repo);
-				repo = temp;
-			}
-
-			temp = parsed_name;
-			parsed_name = g_strconcat(temp,"_",items[len-2],NULL);
-			g_free(temp);
-
-			pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
-
-			g_hash_table_insert(releases, parsed_name, repo);
-			g_free(contents);
-			contents = NULL;
-		}
-		else
-			g_free(parsed_name);
-		g_strfreev(items);
-	}
-	g_dir_close(dir);
-
-	/* and then we need to do this again, but this time we're looking for the packages */
-	dir = g_dir_open(sdir,0,&error);
-	res = sqlite3_prepare_v2(db, "insert or replace into packages values (?,?,?,?,?,?,?)", -1, &package, NULL);
-	if (res!=SQLITE_OK)
-		pk_error("sqlite error during insert prepare: %s", sqlite3_errmsg(db));
-	else
-		pk_debug("insert prepare ok for %p",package);
-	while ((fname = g_dir_read_name(dir))!=NULL)
-	{
-		gchar** items = g_strsplit(fname,"_",-1);
-		guint len = g_strv_length(items);
-		if(len<=3) // minimum is <source>_<type>_<group>
-		{
-			g_strfreev(items);
-			continue;
-		}
-
-		if (g_ascii_strcasecmp(items[len-1],"Packages")==0)
-		{
-			const gchar *repo;
-			gchar *temp=NULL, *parsed_name=NULL;
-			gchar *fullname= NULL;
-			gchar *begin=NULL, *next=NULL, *description = NULL;
-			glong count = 0;
-			gboolean haspk = FALSE;
-
-			/* warning: nasty hack with g_strjoinv */
-			if (g_str_has_prefix(items[len-2],"binary-"))
-			{
-				temp = items[len-3];
-				items[len-3] = NULL;
-				parsed_name = g_strjoinv("_",items);
-				items[len-3] = temp;
-			}
-			else
-			{
-				temp = items[len-1];
-				items[len-1] = NULL;
-				parsed_name = g_strjoinv("_",items);
-				items[len-1] = temp;
-			}
-
-			pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
-
-			repo = (const gchar *)g_hash_table_lookup(releases,parsed_name);
-			if (repo == NULL)
-			{
-				pk_debug("Can't find repo for %s, marking as \"unknown\"",parsed_name);
-				repo = g_strdup("unknown");
-				//g_assert(0);
-			}
-			else
-				pk_debug("repo for %s is %s",parsed_name,repo);
-			g_free(parsed_name);
-
-			fullname = g_build_filename(sdir,fname,NULL);
-			pk_debug("loading %s",fullname);
-			if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
-			{
-				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
-				goto search_task_cleanup;
-			}
-			/*else
-				pk_debug("loaded");*/
-
-			res = sqlite3_bind_text(package,FIELD_REPO,repo,-1,SQLITE_TRANSIENT);
-			if (res!=SQLITE_OK)
-				pk_error("sqlite error during repo bind: %s", sqlite3_errmsg(db));
-			/*else
-				pk_debug("repo bind ok");*/
-
-			res = sqlite3_exec(db,"begin",NULL,NULL,NULL);
-			g_assert(res == SQLITE_OK);
-
-			begin = contents;
-
-			while (true)
-			{
-				next = strstr(begin,"\n");
-				if (next!=NULL)
-				{
-					next[0] = '\0';
-					next++;
-				}
-
-				if (begin[0]=='\0')
-				{
-					if (haspk)
-					{
-						if (description!=NULL)
-						{
-							res=sqlite3_bind_text(package,FIELD_LONG,description,-1,SQLITE_TRANSIENT);
-							if (res!=SQLITE_OK)
-								pk_error("sqlite error during description bind: %s", sqlite3_errmsg(db));
-							g_free(description);
-							description = NULL;
-						}
-						res = sqlite3_step(package);
-						if (res!=SQLITE_DONE)
-							pk_error("sqlite error during step: %s", sqlite3_errmsg(db));
-						sqlite3_reset(package);
-						//pk_debug("added package");
-						haspk = FALSE;
-					}
-					//g_assert(0);
-				}
-				else if (begin[0]==' ')
-				{
-					if (description == NULL)
-						description = g_strdup(&begin[1]);
-					else
-					{
-						gchar *oldval = description;
-						description = g_strconcat(oldval, "\n",&begin[1],NULL);
-						g_free(oldval);
-					}
-				}
-				else
-				{
-					gchar *colon = strchr(begin,':');
-					g_assert(colon!=NULL);
-					colon[0] = '\0';
-					colon+=2;
-					/*if (strlen(colon)>3000)
-						pk_error("strlen(colon) = %d\ncolon = %s",strlen(colon),colon);*/
-					//pk_debug("entry = '%s','%s'",begin,colon);
-					if (begin[0] == 'P' && g_strcasecmp("Package",begin)==0)
-					{
-						res=sqlite3_bind_text(package,FIELD_PKG,colon,-1,SQLITE_STATIC);
-						haspk = TRUE;
-						count++;
-						if (count%1000==0)
-							pk_debug("Package %ld (%s)",count,colon);
-					}
-					else if (begin[0] == 'V' && g_strcasecmp("Version",begin)==0)
-						res=sqlite3_bind_text(package,FIELD_VER,colon,-1,SQLITE_STATIC);
-					else if (begin[0] == 'D' && g_strcasecmp("Depends",begin)==0)
-						res=sqlite3_bind_text(package,FIELD_DEPS,colon,-1,SQLITE_STATIC);
-					else if (begin[0] == 'A' && g_strcasecmp("Architecture",begin)==0)
-						res=sqlite3_bind_text(package,FIELD_ARCH,colon,-1,SQLITE_STATIC);
-					else if (begin[0] == 'D' && g_strcasecmp("Description",begin)==0)
-						res=sqlite3_bind_text(package,FIELD_SHORT,colon,-1,SQLITE_STATIC);
-					if (res!=SQLITE_OK)
-						pk_error("sqlite error during %s bind: %s", begin, sqlite3_errmsg(db));
-				}
-				if (next == NULL)
-					break;
-				begin = next;
-			}
-			res = sqlite3_exec(db,"commit",NULL,NULL,NULL);
-			if (res!=SQLITE_OK)
-				pk_error("sqlite error during commit: %s", sqlite3_errmsg(db));
-			res = sqlite3_clear_bindings(package);
-			if (res!=SQLITE_OK)
-				pk_error("sqlite error during clear: %s", sqlite3_errmsg(db));
-			g_free(contents);
-			contents = NULL;
-		}
-	}
-	sqlite3_finalize(package);
-
-search_task_cleanup:
-	g_dir_close(dir);
-	g_free(sdir);
-	g_free(contents);
-}
-
diff --git a/backends/apt/pk-backend-apt.c b/backends/apt/pk-backend-apt.c
new file mode 100644
index 0000000..a0b6c5c
--- /dev/null
+++ b/backends/apt/pk-backend-apt.c
@@ -0,0 +1,225 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Ali Sabil <ali.sabil at 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <gmodule.h>
+#include <glib.h>
+#include <string.h>
+#include <pk-backend.h>
+
+/**
+ * backend_get_groups:
+ */
+static void
+backend_get_groups (PkBackend *backend, PkEnumList *elist)
+{
+	g_return_if_fail (backend != NULL);
+	pk_enum_list_append_multiple (elist,
+				      PK_GROUP_ENUM_ACCESSIBILITY,
+				      PK_GROUP_ENUM_ACCESSORIES,
+				      PK_GROUP_ENUM_EDUCATION,
+				      PK_GROUP_ENUM_GAMES,
+				      PK_GROUP_ENUM_GRAPHICS,
+				      PK_GROUP_ENUM_INTERNET,
+				      PK_GROUP_ENUM_OFFICE,
+				      PK_GROUP_ENUM_OTHER,
+				      PK_GROUP_ENUM_PROGRAMMING,
+				      PK_GROUP_ENUM_MULTIMEDIA,
+				      PK_GROUP_ENUM_SYSTEM,
+				      -1);
+}
+
+/**
+ * backend_get_filters:
+ */
+static void
+backend_get_filters (PkBackend *backend, PkEnumList *elist)
+{
+	g_return_if_fail (backend != NULL);
+	pk_enum_list_append_multiple (elist,
+				      PK_FILTER_ENUM_GUI,
+				      PK_FILTER_ENUM_INSTALLED,
+				      PK_FILTER_ENUM_DEVELOPMENT,
+				      -1);
+}
+
+/**
+ * backend_get_description:
+ */
+
+static void
+backend_get_description (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_allow_interrupt (backend, TRUE);
+	pk_backend_spawn_helper (backend, "get-description.py", package_id, NULL);
+}
+
+/**
+ * backend_get_updates:
+ */
+static void
+backend_get_updates (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_allow_interrupt (backend, TRUE);
+	pk_backend_spawn_helper (backend, "get-updates.py", NULL);
+}
+
+/**
+ * backend_install_package:
+ */
+static void
+backend_install_package (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	/* check network state */
+	if (pk_backend_network_is_online (backend) == FALSE) {
+		pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot install when offline");
+		pk_backend_finished (backend);
+		return;
+	}
+	pk_backend_spawn_helper (backend, "install.py", package_id, NULL);
+}
+
+/**
+ * backend_refresh_cache:
+ */
+static void
+backend_refresh_cache (PkBackend *backend, gboolean force)
+{
+	g_return_if_fail (backend != NULL);
+	/* check network state */
+	if (pk_backend_network_is_online (backend) == FALSE) {
+		pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot refresh cache when offline");
+		pk_backend_finished (backend);
+		return;
+	}
+	pk_backend_spawn_helper (backend, "refresh-cache.py", NULL);
+}
+
+/**
+ * backend_remove_package:
+ */
+static void
+backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
+{
+	g_return_if_fail (backend != NULL);
+	const gchar *deps;
+	if (allow_deps == TRUE) {
+		deps = "yes";
+	} else {
+		deps = "no";
+	}
+	pk_backend_spawn_helper (backend, "remove.py", deps, package_id, NULL);
+}
+
+/**
+ * backend_search_details:
+ */
+
+static void
+backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_allow_interrupt (backend, TRUE);
+	pk_backend_spawn_helper (backend, "search-details.py", filter, search, NULL);
+}
+
+/**
+ * backend_search_name:
+ */
+static void
+backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_allow_interrupt (backend, TRUE);
+	pk_backend_spawn_helper (backend, "search-name.py", filter, search, NULL);
+}
+
+/**
+  * backend_update_package:
+ */
+static void
+backend_update_package (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	/* check network state */
+	if (pk_backend_network_is_online (backend) == FALSE) {
+		pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot update when offline");
+		pk_backend_finished (backend);
+		return;
+	}
+	pk_backend_spawn_helper (backend, "update.py", package_id, NULL);
+}
+
+/**
+ * backend_update_system:
+ */
+static void
+backend_update_system (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_spawn_helper (backend, "update-system.py", NULL);
+}
+
+/**
+ * backend_get_depends:
+ */
+/**
+static void
+backend_get_depends (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_allow_interrupt (backend, TRUE);
+	pk_backend_spawn_helper (backend, "get-depends.py", package_id, NULL);
+}
+ */
+
+PK_BACKEND_OPTIONS (
+	"Apt",				/* description */
+	"0.0.1",				/* version */
+	"Ali Sabil <ali.sabil at gmail.com>",	/* author */
+	NULL,					/* initalize */
+	NULL,					/* destroy */
+	backend_get_groups,			/* get_groups */
+	backend_get_filters,			/* get_filters */
+	NULL,					/* cancel */
+	NULL,					/* get_depends */
+	backend_get_description,		/* get_description */
+	NULL,					/* get_requires */
+	NULL,					/* get_update_detail */
+	backend_get_updates,			/* get_updates */
+	backend_install_package,		/* install_package */
+	NULL,					/* install_file */
+	backend_refresh_cache,			/* refresh_cache */
+	backend_remove_package,			/* remove_package */
+	NULL,					/* resolve */
+	NULL,					/* rollback */
+	backend_search_details,			/* search_details */
+	NULL,					/* search_file */
+	NULL,					/* search_group */
+	backend_search_name,			/* search_name */
+	backend_update_package,			/* update_package */
+	backend_update_system,			/* update_system */
+	NULL,					/* get_repo_list */
+	NULL,					/* repo_enable */
+	NULL					/* repo_set_data */
+);
diff --git a/backends/apt/pk-backend-apt.cpp b/backends/apt/pk-backend-apt.cpp
deleted file mode 100644
index 2c5e159..0000000
--- a/backends/apt/pk-backend-apt.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
- * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <gmodule.h>
-#include <glib.h>
-#include <glib/gprintf.h>
-
-#include <math.h>
-#include <string.h>
-
-#include <pk-backend.h>
-#include <pk-debug.h>
-#include <pk-package-id.h>
-#include "config.h"
-
-#include <apt-pkg/configuration.h>
-#include <apt-pkg/init.h>
-
-#include "pk-backend-apt.h"
-extern "C" {
-#include "sqlite-pkg-cache.h"
-#include "python-backend-common.h"
-}
-
-static gboolean inited = FALSE;
-
-#define APT_DB DATABASEDIR "/apt.db"
-
-static void backend_initialize(PkBackend *backend)
-{
-	if (!inited)
-	{
-		gchar *apt_fname = NULL;
-		if (pkgInitConfig(*_config) == false)
-			pk_debug("pkginitconfig was false");
-		if (pkgInitSystem(*_config, _system) == false)
-			pk_debug("pkginitsystem was false");
-
-		apt_fname = g_strconcat(
-				_config->Find("Dir").c_str(),
-				_config->Find("Dir::Cache").c_str(),
-				_config->Find("Dir::Cache::pkgcache").c_str(),
-				NULL);
-
-		sqlite_init_cache(backend, APT_DB, apt_fname, apt_build_db);
-		g_free(apt_fname);
-		inited = TRUE;
-	}
-}
-
-/**
- * backend_get_groups:
- */
-static void
-backend_get_groups (PkBackend *backend, PkEnumList *elist)
-{
-	g_return_if_fail (backend != NULL);
-	pk_enum_list_append_multiple (elist,
-				      PK_GROUP_ENUM_ACCESSIBILITY,
-				      PK_GROUP_ENUM_GAMES,
-				      PK_GROUP_ENUM_SYSTEM,
-				      -1);
-}
-
-/**
- * backend_get_filters:
- */
-static void
-backend_get_filters (PkBackend *backend, PkEnumList *elist)
-{
-	g_return_if_fail (backend != NULL);
-	pk_enum_list_append_multiple (elist,
-				      PK_FILTER_ENUM_GUI,
-				      PK_FILTER_ENUM_INSTALLED,
-				      PK_FILTER_ENUM_DEVELOPMENT,
-				      -1);
-}
-
-static gboolean backend_search_file_thread (PkBackend *backend, gpointer data)
-{
-	//search_task *st = (search_task*)data;
-	gchar *sdir = g_path_get_dirname(_config->Find("Dir::State::status").c_str());
-	gchar *ldir = g_build_filename(sdir,"info",NULL);
-	g_free(sdir);
-	GError *error = NULL;
-	GDir *list = g_dir_open(ldir,0,&error);
-	if (error!=NULL)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "can't open %s",ldir);
-		g_free(ldir);
-		g_error_free(error);
-		return FALSE;
-	}
-	const gchar * fname = NULL;
-	while ((fname = g_dir_read_name(list))!=NULL)
-	{
-		//pk_backend_package(backend, J->installed, pid, P.ShortDesc().c_str());
-	}
-	pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "search file is incomplete");
-	g_dir_close(list);
-	g_free(ldir);
-	return TRUE;
-}
-
-/**
- * backend_search_file:
- **/
-static void backend_search_file(PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	backend_search_common(backend, filter, search, SEARCH_FILE, backend_search_file_thread);
-}
-
-extern "C" PK_BACKEND_OPTIONS (
-	"APT",					/* description */
-	"0.0.1",				/* version */
-	"Tom Parker <palfrey at tevp.net>",	/* author */
-	backend_initialize,			/* initalize */
-	NULL,					/* destroy */
-	backend_get_groups,			/* get_groups */
-	backend_get_filters,			/* get_filters */
-	NULL,					/* cancel */
-	NULL,					/* get_depends */
-	sqlite_get_description,		/* get_description */
-	NULL,					/* get_requires */
-	NULL,					/* get_update_detail */
-	NULL,					/* get_updates */
-	NULL,					/* install_package */
-	NULL,					/* install_name */
-	python_refresh_cache,			/* refresh_cache */
-	NULL,					/* remove_package */
-	NULL,					/* resolve */
-	NULL,					/* rollback */
-	sqlite_search_details,			/* search_details */
-	backend_search_file,			/* search_file */
-	NULL,					/* search_group */
-	sqlite_search_name,			/* search_name */
-	NULL,					/* update_package */
-	NULL,					/* update_system */
-	NULL,					/* get_repo_list */
-	NULL,					/* repo_enable */
-	NULL					/* repo_set_data */
-);
-
diff --git a/backends/apt/pk-backend-apt.h b/backends/apt/pk-backend-apt.h
deleted file mode 100644
index ff67654..0000000
--- a/backends/apt/pk-backend-apt.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef PK_BACKEND_APT
-#define PK_BACKEND_APT
-
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <sqlite3.h>
-#include <pk-backend.h>
-
-void apt_build_db(PkBackend * backend, sqlite3 *db);
-
-#endif
diff --git a/backends/apt/pk-python-backend-common.c b/backends/apt/pk-python-backend-common.c
deleted file mode 100644
index 41b3788..0000000
--- a/backends/apt/pk-python-backend-common.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <pk-backend.h>
-
-/**
- * python_refresh_cache:
- **/
-void python_refresh_cache(PkBackend * backend, gboolean force)
-{
-	/* check network state */
-	if (pk_backend_network_is_online(backend) == FALSE)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot refresh cache whilst offline");
-		pk_backend_finished(backend);
-		return;
-	}
-
-	pk_backend_spawn_helper (backend, "refresh-cache.py", NULL);
-}
-
diff --git a/backends/apt/pk-python-backend-common.h b/backends/apt/pk-python-backend-common.h
deleted file mode 100644
index a0b56bd..0000000
--- a/backends/apt/pk-python-backend-common.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef PYTHON_BACKEND_COMMON_H
-#define PYTHON_BACKEND_COMMON_H
-
-void python_refresh_cache(PkBackend * backend, gboolean force);
-
-#endif
-
diff --git a/backends/apt/pk-sqlite-pkg-cache.c b/backends/apt/pk-sqlite-pkg-cache.c
deleted file mode 100644
index 29647a5..0000000
--- a/backends/apt/pk-sqlite-pkg-cache.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <sqlite3.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-#include "sqlite-pkg-cache.h"
-
-static sqlite3 *db = NULL;
-
-typedef struct {
-	PkPackageId *pi;
-} desc_task;
-
-typedef struct {
-	gchar *search;
-	gchar *filter;
-	SearchDepth depth;
-} search_task;
-
-void
-sqlite_init_cache(PkBackend *backend, const char* dbname, const char *compare_fname, void (*build_db)(PkBackend *, sqlite3 *))
-{
-	int ret;
-	struct stat st;
-	time_t db_age;
-
-	ret = sqlite3_open (dbname, &db);
-	ret = sqlite3_exec(db,"PRAGMA synchronous = OFF",NULL,NULL,NULL);
-	g_assert(ret == SQLITE_OK);
-
-	g_stat(dbname, &st);
-	db_age = st.st_mtime;
-	g_stat(compare_fname, &st);
-	if (db_age>=st.st_mtime)
-	{
-		ret = sqlite3_exec(db, "select value from params where name = 'build_complete'", NULL, NULL, NULL);
-		if (ret != SQLITE_ERROR)
-			return;
-	}
-	ret = sqlite3_exec(db,"drop table packages",NULL,NULL,NULL); // wipe it!
-	//g_assert(ret == SQLITE_OK);
-	pk_debug("wiped db");
-	ret = sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string, primary key(name,version,arch,repo))",NULL,NULL,NULL);
-	g_assert(ret == SQLITE_OK);
-
-	build_db(backend,db);
-
-	sqlite3_exec(db,"create table params (name text primary key, value integer)", NULL, NULL, NULL);
-	sqlite3_exec(db,"insert into params values ('build_complete',1)", NULL, NULL, NULL);
-}
-
-// sqlite_search_packages_thread
-static gboolean
-sqlite_search_packages_thread (PkBackend *backend, gpointer data)
-{
-	search_task *st = (search_task *) data;
-	int res;
-	gchar *sel;
-
-	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
-	pk_backend_no_percentage_updates(backend);
-
-	pk_debug("finding %s", st->search);
-
-	sqlite3_stmt *package = NULL;
-	g_strdelimit(st->search," ",'%');
-
-	if (st->depth == SEARCH_NAME)
-		sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%'",st->search);
-	else if (st->depth == SEARCH_DETAILS)
-		sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%' or short_desc like '%%%s%%' or long_desc like '%%%s%%'",st->search, st->search, st->search);
-	else
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "Unknown search task type");
-		goto end_search_packages;
-	}
-
-	pk_debug("statement is '%s'",sel);
-	res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
-	g_free(sel);
-	if (res!=SQLITE_OK)
-		pk_error("sqlite error during select prepare: %s", sqlite3_errmsg(db));
-	res = sqlite3_step(package);
-	while (res == SQLITE_ROW)
-	{
-		gchar *pid = pk_package_id_build((const gchar*)sqlite3_column_text(package,0),
-				(const gchar*)sqlite3_column_text(package,1),
-				(const gchar*)sqlite3_column_text(package,2),
-				(const gchar*)sqlite3_column_text(package,3));
-		pk_backend_package(backend, PK_INFO_ENUM_UNKNOWN, pid, (const gchar*)sqlite3_column_text(package,4));
-		g_free(pid);
-		if (res==SQLITE_ROW)
-			res = sqlite3_step(package);
-	}
-	if (res!=SQLITE_DONE)
-	{
-		pk_debug("sqlite error during step (%d): %s", res, sqlite3_errmsg(db));
-		g_assert(0);
-	}
-
-	end_search_packages:
-	g_free(st->search);
-	g_free(st);
-
-	return TRUE;
-}
-
-/**
- * backend_search_common
- **/
-void
-backend_search_common(PkBackend * backend, const gchar * filter, const gchar * search, SearchDepth which, PkBackendThreadFunc func)
-{
-	g_return_if_fail (backend != NULL);
-	search_task *data = g_new(search_task, 1);
-	if (data == NULL)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory for search task");
-		pk_backend_finished(backend);
-	}
-	else
-	{
-		data->search = g_strdup(search);
-		data->filter = g_strdup(filter);
-		data->depth = which;
-		pk_backend_thread_helper (backend, func, data);
-	}
-}
-
-/**
- * sqlite_search_details:
- */
-void
-sqlite_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	backend_search_common(backend, filter, search, SEARCH_DETAILS, sqlite_search_packages_thread);
-}
-
-/**
- * sqlite_search_name:
- */
-void
-sqlite_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	backend_search_common(backend, filter, search, SEARCH_NAME, sqlite_search_packages_thread);
-}
-
-// sqlite_get_description_thread
-static gboolean sqlite_get_description_thread (PkBackend *backend, gpointer data)
-{
-	desc_task *dt = (desc_task *) data;
-	int res;
-
-	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
-	pk_backend_no_percentage_updates(backend);
-
-	pk_debug("finding %s", dt->pi->name);
-
-	sqlite3_stmt *package = NULL;
-	gchar *sel = g_strdup_printf("select long_desc from packages where name = '%s' and version = '%s' and repo = '%s'",dt->pi->name,dt->pi->version,dt->pi->data);
-	pk_debug("statement is '%s'",sel);
-	res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
-	g_free(sel);
-	if (res!=SQLITE_OK)
-		pk_error("sqlite error during select prepare: %s", sqlite3_errmsg(db));
-	res = sqlite3_step(package);
-	pk_backend_description(backend,dt->pi->name, "unknown", PK_GROUP_ENUM_OTHER,(const gchar*)sqlite3_column_text(package,0),"",0,"");
-	res = sqlite3_step(package);
-	if (res==SQLITE_ROW)
-		pk_error("multiple matches for that package!");
-	if (res!=SQLITE_DONE)
-	{
-		pk_debug("sqlite error during step (%d): %s", res, sqlite3_errmsg(db));
-		g_assert(0);
-	}
-
-	g_free(dt);
-
-	return TRUE;
-}
-
-/**
- * sqlite_get_description:
- */
-void
-sqlite_get_description (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	desc_task *data = g_new(desc_task, 1);
-	if (data == NULL)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory for search task");
-		pk_backend_finished(backend);
-		return;
-	}
-
-	data->pi = pk_package_id_new_from_string(package_id);
-	if (data->pi == NULL)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "invalid package id");
-		pk_backend_finished(backend);
-		return;
-	}
-
-	pk_backend_thread_helper (backend, sqlite_get_description_thread, data);
-	return;
-}
-
-
diff --git a/backends/apt/pk-sqlite-pkg-cache.h b/backends/apt/pk-sqlite-pkg-cache.h
deleted file mode 100644
index 68f5287..0000000
--- a/backends/apt/pk-sqlite-pkg-cache.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef SQLITE_PKT_CACHE
-#define SQLITE_PKT_CACHE
-
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-typedef enum {
-	SEARCH_NAME = 1,
-	SEARCH_DETAILS,
-	SEARCH_FILE
-} SearchDepth;
-
-#include <pk-backend.h>
-
-void sqlite_init_cache(PkBackend *backend, const char* dbname, const char* compare_fname, void (*build_db)(PkBackend *, sqlite3 *db));
-void sqlite_search_details (PkBackend *backend, const gchar *filter, const gchar *search);
-void sqlite_search_name (PkBackend *backend, const gchar *filter, const gchar *search);
-void backend_search_common(PkBackend * backend, const gchar * filter, const gchar * search, SearchDepth which, PkBackendThreadFunc func);
-void sqlite_get_description (PkBackend *backend, const gchar *package_id);
-
-#endif
diff --git a/docs/pk-introduction.xml b/docs/pk-introduction.xml
index d339757..fc3364e 100644
--- a/docs/pk-introduction.xml
+++ b/docs/pk-introduction.xml
@@ -594,8 +594,7 @@
       </para>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Error</literal> and
         <literal>Package</literal>.
       </para>
@@ -638,8 +637,7 @@
       </para>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Error</literal> and
         <literal>Package</literal>.
       </para>
@@ -685,8 +683,7 @@
       </para>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Error</literal> and
         <literal>Package</literal>.
       </para>
@@ -731,8 +728,7 @@
       </para>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Error</literal> and
         <literal>Package</literal>.
       </para>
@@ -775,9 +771,7 @@
       </para>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>Subpercentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Status</literal> and
         <literal>Error</literal> and
         <literal>Package</literal>.
@@ -819,9 +813,7 @@
       </informaltable>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>Subpercentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Status</literal> and
         <literal>Error</literal> and
         <literal>Package</literal>.
@@ -866,9 +858,7 @@
       </informaltable>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>Subpercentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Status</literal> and
         <literal>Error</literal> and
         <literal>Package</literal>.
@@ -908,9 +898,7 @@
       </informaltable>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>Subpercentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Status</literal> and
         <literal>Error</literal> and
         <literal>Package</literal>.
@@ -1023,9 +1011,7 @@
       </informaltable>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>Subpercentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Status</literal> and
         <literal>Error</literal> and
         <literal>Package</literal>.
@@ -1063,9 +1049,7 @@
       </informaltable>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>Subpercentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Status</literal> and
         <literal>Error</literal> and
         <literal>Description</literal>.
@@ -1103,9 +1087,7 @@
       </para>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>Subpercentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Status</literal> and
         <literal>Error</literal> and
         <literal>Package</literal>.
@@ -1119,9 +1101,7 @@
       </para>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>Subpercentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Error</literal> and
         <literal>RequireRestart</literal> and
         <literal>Package</literal>.
@@ -1142,8 +1122,7 @@
       </para>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Error</literal> and
         <literal>Package</literal>.
       </para>
@@ -1168,9 +1147,7 @@
       </para>
       <para>
         This method typically emits
-        <literal>Percentage</literal>,
-        <literal>Subpercentage</literal>,
-        <literal>NoPercentageUpdates</literal>,
+        <literal>Progress</literal>,
         <literal>Error</literal> and
         <literal>Package</literal>.
       </para>
@@ -1277,11 +1254,11 @@
       Signals used by the backends are as follows:
     </para>
     <sect2 id="api-percentage">
-      <title>Percentage</title>
+      <title>Progress</title>
       <para>
         This is optional.
-        Backends should send the DBUS signal NoPercentageUpdates or use
-        no-percentage-updates if the remaining position cannot be calculated.
+        Backends should send the percentage fields to 101 if the amount complete
+        cannot be calculated.
       </para>
       <informaltable>
         <tgroup cols="2">
@@ -1293,45 +1270,32 @@
           </thead>
           <tbody>
             <row>
-              <entry><literal>value</literal></entry>
+              <entry><literal>percentage</literal></entry>
               <entry>The percentage complete of the entire transaction</entry>
             </row>
-          </tbody>
-        </tgroup>
-      </informaltable>
-    </sect2>
-
-    <sect2 id="api-subpercentage">
-      <title>Subpercentage</title>
-      <para>
-        This is optional.
-      </para>
-      <informaltable>
-        <tgroup cols="2">
-          <thead>
             <row>
-              <entry>Option</entry>
-              <entry>Description</entry>
+              <entry><literal>subpercentage</literal></entry>
+              <entry>The subpercentage complete of the sub-transaction</entry>
             </row>
-          </thead>
-          <tbody>
             <row>
-              <entry><literal>value</literal></entry>
-              <entry>Percentage complete of the sub-transaction.</entry>
+              <entry><literal>elapsed</literal></entry>
+              <entry>
+                The amount of time in seconds this transaction has been in the
+                running state
+              </entry>
+            </row>
+            <row>
+              <entry><literal>remaining</literal></entry>
+              <entry>
+                The amount of time in seconds this transaction will tyake to
+                complete. Zero is sent for unknown.
+              </entry>
             </row>
           </tbody>
         </tgroup>
       </informaltable>
     </sect2>
 
-    <sect2 id="api-no-percentage-updates">
-      <title>NoPercentageUpdates</title>
-      <para>
-        This is optional and signifies that the helper is no longer able to
-        send percentage updates.
-      </para>
-    </sect2>
-
     <sect2 id="api-error">
       <title>Error</title>
       <para>
commit eb3c751175266a24650be470ab41efcb51965e8c
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Oct 25 19:16:49 2007 +0100

    remove the BACKENDS by popular vote

diff --git a/backends/BACKENDS b/backends/BACKENDS
deleted file mode 100644
index a9bd437..0000000
--- a/backends/BACKENDS
+++ /dev/null
@@ -1,25 +0,0 @@
-Current status of the backends
-
-                  | conary | yum | apt | box | alpm | smart | pisi |
---------------------------------------------------------------------
-resolve           |        |  X  |     |  X  |      |   X   |   X  |
-refresh-cache     |   X    |  X  |  X  |  X  |      |   X   |   X  |
-get-updates       |   X    |  X  |     |  X  |      |   X   |   X  |
-update-system     |   X    |  X  |     |  X  |      |   X   |   X  |
-search-name       |   X    |  X  |  X  |  X  |  X   |   X   |      |
-search-details    |        |  X  |  X  |  X  |      |       |      |
-search-file       |        |  X  |     |  X  |      |       |      |
-search-group      |        |     |     |     |      |       |      |
-install-package   |   X    |  X  |     |  X  |  X   |   X   |   X  |
-install-file      |        |  X  |     |  X  |      |       |      |
-remove-package    |   X    |  X  |     |  X  |  X   |   X   |   X  |
-update-package    |        |  X  |     |  X  |      |   X   |   X  |
-get-depends       |        |  X  |     |  X  |      |       |   X  |
-get-requires      |   X    |     |     |  X  |      |       |   X  |
-get-description   |   X    |  X  |  X  |  X  |      |       |   X  |
-get-update-detail |        |     |     |     |      |       |      |
-get-repo-list     |        |  X  |     |  X  |  X   |       |   X  |
-repo-enable       |        |  X  |     |     |      |       |      |
-repo-set-data     |        |     |     |     |      |       |      |
-cancel-transaction|        |     |     |     |      |       |   X  |
-
diff --git a/html/pk-faq.html b/html/pk-faq.html
index 8845218..83b48f9 100644
--- a/html/pk-faq.html
+++ b/html/pk-faq.html
@@ -41,7 +41,7 @@ get-depends       |        |  X  |     |  X  |      |       |   X  |
 get-requires      |   X    |     |     |  X  |      |       |   X  |
 get-description   |   X    |  X  |  X  |  X  |      |       |   X  |
 get-update-detail |        |     |     |     |      |       |      |
-get-repo-list     |        |  X  |     |     |  X   |       |   X  |
+get-repo-list     |        |  X  |     |  X  |  X   |       |   X  |
 repo-enable       |        |  X  |     |     |      |       |      |
 repo-set-data     |        |     |     |     |      |       |      |
 cancel-transaction|        |     |     |     |      |       |   X  |



More information about the PackageKit mailing list