[PackageKit-commit] packagekit: Branch 'master' - 25 commits

Richard Hughes hughsient at kemper.freedesktop.org
Thu May 6 13:48:37 PDT 2010


 RELEASE                                  |   12 
 backends/Makefile.am                     |    4 
 backends/pacman/Makefile.am              |   50 ++
 backends/pacman/backend-depends.c        |  298 ++++++++++++++++
 backends/pacman/backend-depends.h        |   33 +
 backends/pacman/backend-error.c          |  185 ++++++++++
 backends/pacman/backend-error.h          |   29 +
 backends/pacman/backend-groups.c         |  150 ++++++++
 backends/pacman/backend-groups.h         |   32 +
 backends/pacman/backend-install.c        |  342 +++++++++++++++++++
 backends/pacman/backend-install.h        |   43 ++
 backends/pacman/backend-packages.c       |  346 +++++++++++++++++++
 backends/pacman/backend-packages.h       |   41 ++
 backends/pacman/backend-pacman.c         |  253 ++++++++++++++
 backends/pacman/backend-pacman.h         |   35 +
 backends/pacman/backend-remove.c         |  151 ++++++++
 backends/pacman/backend-remove.h         |   32 +
 backends/pacman/backend-repos.c          |  298 ++++++++++++++++
 backends/pacman/backend-repos.h          |   37 ++
 backends/pacman/backend-search.c         |  474 ++++++++++++++++++++++++++
 backends/pacman/backend-search.h         |   43 ++
 backends/pacman/backend-transaction.c    |  487 +++++++++++++++++++++++++++
 backends/pacman/backend-transaction.h    |   51 ++
 backends/pacman/backend-update.c         |  389 +++++++++++++++++++++
 backends/pacman/backend-update.h         |   31 +
 backends/pacman/groups.list              |   65 +++
 backends/pacman/pacman.conf              |   12 
 backends/zypp/TODO                       |   26 +
 backends/zypp/pk-backend-zypp.cpp        |  146 +++-----
 backends/zypp/zypp-events.h              |    2 
 backends/zypp/zypp-utils.cpp             |  117 +++++-
 backends/zypp/zypp-utils.h               |   16 
 configure.ac                             |   14 
 contrib/PackageKit.spec.in               |   13 
 docs/html/pk-matrix.html                 |   42 ++
 lib/packagekit-glib2/pk-console-shared.c |   12 
 po/zh_TW.po                              |  555 ++++++++++++++++---------------
 src/pk-transaction.c                     |   12 
 38 files changed, 4479 insertions(+), 399 deletions(-)

New commits:
commit bd817872214107f3aab5fb3a8ac76b263dcc73d1
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu May 6 20:31:32 2010 +0100

    trivial: sync the rpm spec file with fedora

diff --git a/contrib/PackageKit.spec.in b/contrib/PackageKit.spec.in
index a6c1356..fe39b91 100644
--- a/contrib/PackageKit.spec.in
+++ b/contrib/PackageKit.spec.in
@@ -1,7 +1,4 @@
-%define glib2_version                   2.16.1
 %define dbus_version                    1.1.1
-%define dbus_glib_version               0.74
-%define polkit_version                  0.92
 %define alphatag                        #ALPHATAG#
 
 %{!?python_sitelib: %define python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
@@ -23,17 +20,16 @@ Requires: comps-extras
 %if 0%{?rhel} == 0
 Requires: preupgrade
 %endif
-BuildRequires: polkit >= %{polkit_version}
 
-BuildRequires: glib2-devel >= %{glib2_version}
+BuildRequires: glib2-devel >= 2.16.1
 BuildRequires: dbus-devel  >= %{dbus_version}
-BuildRequires: dbus-glib-devel >= %{dbus_glib_version}
+BuildRequires: dbus-glib-devel >= 0.74
 BuildRequires: pam-devel
 BuildRequires: libX11-devel
 BuildRequires: xmlto
 BuildRequires: sqlite-devel
-BuildRequires: NetworkManager-devel >= %{libnm_glib_version}
-BuildRequires: polkit-devel >= %{polkit_version}
+BuildRequires: NetworkManager-devel
+BuildRequires: polkit-devel >= 0.92
 BuildRequires: libtool
 BuildRequires: docbook-utils
 BuildRequires: gnome-doc-utils
@@ -125,6 +121,7 @@ GLib libraries for accessing PackageKit.
 Summary: QT libraries for accessing PackageKit
 Group: Development/Libraries
 Requires: %{name} = %{version}-%{release}
+%{?_qt4_version:Requires: qt4%{?_isa} >= %{_qt4_version}}
 
 %description qt
 QT libraries for accessing PackageKit.
commit 990e9094abe713599d64e8c6010b057c1a34a8a1
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu May 6 10:12:21 2010 +0100

    trivial: post release version bump

diff --git a/RELEASE b/RELEASE
index a7ba2e0..5b5ca6c 100644
--- a/RELEASE
+++ b/RELEASE
@@ -2,10 +2,10 @@ PackageKit Release Notes
 
 1. Write NEWS entries for PackageKit in the same format as usual.
 
-git shortlog PACKAGEKIT_0_6_3.. | grep -i -v trivial | grep -v Merge > NEWS.new
+git shortlog PACKAGEKIT_0_6_4.. | grep -i -v trivial | grep -v Merge > NEWS.new
 
 --------------------------------------------------------------------------------
-Version 0.6.x
+Version 0.6.5
 ~~~~~~~~~~~~~
 Released: 2010-xx-xx
 
@@ -28,8 +28,8 @@ Bugfixes:
 
 4. Commit changes in PackageKit git:
 
-git commit -a -m "Release version 0.6.4"
-git tag -s -f -m "Release 0.6.4" PACKAGEKIT_0_6_4
+git commit -a -m "Release version 0.6.5"
+git tag -s -f -m "Release 0.6.5" PACKAGEKIT_0_6_5
 <gpg password>
 git push --tags
 git push
@@ -54,9 +54,9 @@ git push
 10. Send an email to packagekit at lists.freedesktop.org
 
 =================================================
-Subject: PackageKit 0.6.3 released!
+Subject: PackageKit 0.6.5 released!
 
-Today I released PackageKit 0.6.3.
+Today I released PackageKit 0.6.5.
 
 PackageKit release notes: http://cgit.freedesktop.org/packagekit/tree/NEWS
 
diff --git a/configure.ac b/configure.ac
index 8a10036..653c320 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@ AC_PREREQ(2.63)
 
 m4_define([pk_major_version], [0])
 m4_define([pk_minor_version], [6])
-m4_define([pk_micro_version], [4])
+m4_define([pk_micro_version], [5])
 m4_define([pk_version],
           [pk_major_version.pk_minor_version.pk_micro_version])
 
commit bfe0f6760e90e414c20c1f3cbb0460da1930250f
Author: Michael Meeks <michael.meeks at novell.com>
Date:   Thu May 6 17:35:28 2010 +0100

    update

diff --git a/backends/zypp/TODO b/backends/zypp/TODO
index 320855d..ea7db50 100644
--- a/backends/zypp/TODO
+++ b/backends/zypp/TODO
@@ -1,3 +1,10 @@
+progress reporting
+	+ seems not to work - I get 0%'s for most things (why?)
+	+ particularly (eg.) updating a lot of packages; most odd.
+		+ we get signals starting / finishing packages etc.
+			+ but nothing more (?)
+		+ do we only notify on a 'sub' progress %age ?
+
 package updating
 	+ re-test patch updating carefully
 	+ ensure no packages overlap with patches etc.
commit 3c01fb78ecbdf7bd1bd5dfa3717ac0547ea48285
Author: Michael Meeks <michael.meeks at novell.com>
Date:   Thu May 6 17:29:17 2010 +0100

    add TODO
    Updating:
      + unify code used to generate the list of updates
      + merge in packages, not contained in any patch
        ( also allows us to update from pure patch repos )

diff --git a/backends/zypp/TODO b/backends/zypp/TODO
new file mode 100644
index 0000000..320855d
--- /dev/null
+++ b/backends/zypp/TODO
@@ -0,0 +1,19 @@
+package updating
+	+ re-test patch updating carefully
+	+ ensure no packages overlap with patches etc.
+
+pkcon remove glibc
+	+ morphs the remove into an install (somehow)
+	+ doesn't complain that we might destroy the system
+	+ OTOH: doesn't destroy the system 
+
+implement backend_download ...
+	+ essentially an install with --download-only set to true.
+
+NEWEST handling
+	+ should move from backend_resolve_thread to
+	+ zypp_emit_filtered_packages_in_list
+		+ where it can be shared & more generic
+		+ will require calculating 'newest' per package
+		+ which would make that method more efficient anyway
+
diff --git a/backends/zypp/pk-backend-zypp.cpp b/backends/zypp/pk-backend-zypp.cpp
index ec01090..fec6fb1 100644
--- a/backends/zypp/pk-backend-zypp.cpp
+++ b/backends/zypp/pk-backend-zypp.cpp
@@ -620,6 +620,8 @@ backend_get_updates_thread (PkBackend *backend)
 {
 	PkBitfield _filters = (PkBitfield) pk_backend_get_uint (backend, "filters");
 
+	typedef std::set<zypp::PoolItem>::iterator pi_it_t;
+
 	pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
 	pk_backend_set_percentage (backend, 0);
 
@@ -633,27 +635,13 @@ backend_get_updates_thread (PkBackend *backend)
 	pk_backend_set_percentage (backend, 40);
 
 	// check if the repositories may be dead (feature #301904)
-	 warn_outdated_repos(backend, pool);
-
-	// get all Packages and Patches for Update
-	std::set<zypp::PoolItem> *candidates = zypp_get_patches ();
-	//std::set<zypp::PoolItem> *candidates2 = new std::set<zypp::PoolItem> ();
-
-	if (!_updating_self) {
-		// exclude the patch-repository
-		std::string patchRepo;
-		if (!candidates->empty ()) {
-			patchRepo = candidates->begin ()->resolvable ()->repoInfo ().alias ();
-		}
+	warn_outdated_repos (backend, pool);
 
-		//candidates2 = zypp_get_updates (patchRepo);
-
-		//candidates->insert (candidates2->begin (), candidates2->end ());
-	}
+	std::set<zypp::PoolItem> *candidates = zypp_get_updates ();
 
 	pk_backend_set_percentage (backend, 80);
 
-	std::set<zypp::PoolItem>::iterator cb = candidates->begin (), ce = candidates->end (), ci;
+	pi_it_t cb = candidates->begin (), ce = candidates->end (), ci;
 	for (ci = cb; ci != ce; ++ci) {
 		zypp::ResObject::constPtr res = ci->resolvable();
 
@@ -683,9 +671,7 @@ backend_get_updates_thread (PkBackend *backend)
 					      res->summary ().c_str ());
 		}
 	}
-
 	delete (candidates);
-	//delete (candidates2);
 
 	pk_backend_set_percentage (backend, 100);
 	pk_backend_finished (backend);
@@ -931,27 +917,11 @@ backend_update_system_thread (PkBackend *backend)
 	pk_backend_set_percentage (backend, 40);
 	PkRestartEnum restart = PK_RESTART_ENUM_NONE;
 
-	//get all Patches for Update
-	std::set<zypp::PoolItem> *candidates = zypp_get_patches ();
-	//std::set<zypp::PoolItem> *candidates2 = new std::set<zypp::PoolItem> ();
+	std::set<zypp::PoolItem> *candidates = zypp_get_updates ();
 
 	if (_updating_self) {
 		_updating_self = FALSE;
 	}
-	else {
-		//disabling patchrepo
-		std::string patchRepo;
-		if (!candidates->empty ()) {
-			patchRepo = candidates->begin ()->resolvable ()->repoInfo ().alias ();
-		}
-
-		//get all Updates
-		//candidates2 = zypp_get_updates (patchRepo);
-
-		//concatenate these sets
-
-		//candidates->insert (candidates2->begin (), candidates2->end ());
-	}
 
 	pk_backend_set_percentage (backend, 80);
 	std::set<zypp::PoolItem>::iterator cb = candidates->begin (), ce = candidates->end (), ci;
@@ -959,7 +929,9 @@ backend_update_system_thread (PkBackend *backend)
 		// set the status of the update to ToBeInstalled
 		zypp::ResStatus &status = ci->status ();
 		status.setToBeInstalled (zypp::ResStatus::USER);
-		zypp_get_restart (restart, zypp::asKind<zypp::Patch>(ci->resolvable ()));
+		if (zypp::isKind<zypp::Patch>(ci->resolvable ())) {
+			zypp_get_restart (restart, zypp::asKind<zypp::Patch>(ci->resolvable ()));
+		}
 	}
 
 	if (!zypp_perform_execution (backend, UPDATE, FALSE)) {
@@ -971,7 +943,6 @@ backend_update_system_thread (PkBackend *backend)
 	if (restart != PK_RESTART_ENUM_NONE)
 		pk_backend_require_restart (backend, restart, "A restart is needed");
 
-	//delete (candidates2);
 	delete (candidates);
 	pk_backend_set_percentage (backend, 100);
 	pk_backend_finished (backend);
@@ -1621,7 +1592,7 @@ backend_update_packages_thread (PkBackend *backend)
 	package_ids = pk_backend_get_strv (backend, "package_ids");
 	PkRestartEnum restart = PK_RESTART_ENUM_NONE;
 
-	delete zypp_get_patches (); // make sure _updating_self is set
+	delete zypp_get_updates (); // make sure _updating_self is set
 
 	if (_updating_self) {
 		egg_debug ("updating self and setting restart");
diff --git a/backends/zypp/zypp-utils.cpp b/backends/zypp/zypp-utils.cpp
index f81c370..ba81c7b 100644
--- a/backends/zypp/zypp-utils.cpp
+++ b/backends/zypp/zypp-utils.cpp
@@ -573,9 +573,6 @@ zypp_emit_filtered_packages_in_list (PkBackend *backend, const std::vector<zypp:
 {
 	typedef std::vector<zypp::sat::Solvable>::const_iterator sat_it_t;
 
-	// FIXME: we should move the 'NEWEST' handling here from _resolve_thread
-	//        that will require calculating 'newest' per package name.
-
 	std::vector<zypp::sat::Solvable> installed;
 	PkBitfield filters = (PkBitfield) pk_backend_get_uint (backend, "filters");
 
@@ -649,8 +646,12 @@ zypp_find_arch_update_item (const zypp::ResPool & pool, zypp::PoolItem item)
 	return info.best;
 }
 
-std::set<zypp::PoolItem> *
-zypp_get_updates (std::string repo)
+/**
+ * Returns a set of all packages the could be updated
+ * (you're able to exclude a single (normally the 'patch' repo)
+ */
+static std::set<zypp::PoolItem> *
+zypp_get_package_updates (std::string repo)
 {
         std::set<zypp::PoolItem> *pks = new std::set<zypp::PoolItem> ();
         zypp::ResPool pool = zypp::ResPool::instance ();
@@ -676,7 +677,10 @@ zypp_get_updates (std::string repo)
         return pks;
 }
 
-std::set<zypp::PoolItem> *
+/**
+ * Returns a set of all patches the could be installed
+ */
+static std::set<zypp::PoolItem> *
 zypp_get_patches ()
 {
         std::set<zypp::PoolItem> *patches = new std::set<zypp::PoolItem> ();
@@ -713,6 +717,55 @@ zypp_get_patches ()
 
 }
 
+std::set<zypp::PoolItem> *
+zypp_get_updates ()
+{
+	typedef std::set<zypp::PoolItem>::iterator pi_it_t;
+
+	std::set<zypp::PoolItem> *candidates = zypp_get_patches ();
+
+	if (!_updating_self) {
+		// exclude the patch-repository
+		std::string patchRepo;
+		if (!candidates->empty ()) {
+			patchRepo = candidates->begin ()->resolvable ()->repoInfo ().alias ();
+		}
+
+		std::set<zypp::PoolItem> *packages;
+
+		packages = zypp_get_package_updates (patchRepo);
+		pi_it_t cb = candidates->begin (), ce = candidates->end (), ci;
+		for (ci = cb; ci != ce; ++ci) {
+			if (!zypp::isKind<zypp::Patch>(ci->resolvable()))
+				continue;
+
+			zypp::Patch::constPtr patch = zypp::asKind<zypp::Patch>(ci->resolvable());
+
+			// Remove contained packages from list of packages to add
+			zypp::sat::SolvableSet::const_iterator pki;
+			for (pki = patch->contents().begin(); pki != patch->contents().end(); pki++) {
+
+				pi_it_t pb = packages->begin (), pe = packages->end (), pi;
+				for (pi = pb; pi != pe; ++pi) {
+					if (pi->satSolvable() == zypp::sat::Solvable::noSolvable)
+						continue;
+					
+					if (pi->satSolvable().identical (*pki)) {
+						packages->erase (pi);
+						break;
+					}
+				}
+			}
+		}
+
+		// merge into the list
+		candidates->insert (packages->begin (), packages->end ());
+		delete (packages);
+	}
+
+	return candidates;
+}
+
 gboolean
 zypp_get_restart (PkRestartEnum &restart, zypp::Patch::constPtr patch)
 {
@@ -720,9 +773,9 @@ zypp_get_restart (PkRestartEnum &restart, zypp::Patch::constPtr patch)
 	if (restart != PK_RESTART_ENUM_SYSTEM && (patch->reloginSuggested () ||
 						  patch->restartSuggested () ||
 						  patch->rebootSuggested ())) {
-			if(patch->reloginSuggested () || patch->restartSuggested ())
+			if (patch->reloginSuggested () || patch->restartSuggested ())
 				restart = PK_RESTART_ENUM_SESSION;
-			if(patch->rebootSuggested ())
+			if (patch->rebootSuggested ())
 				restart = PK_RESTART_ENUM_SYSTEM;
 	}
 	return true;
diff --git a/backends/zypp/zypp-utils.h b/backends/zypp/zypp-utils.h
index 707f517..de6ea70 100644
--- a/backends/zypp/zypp-utils.h
+++ b/backends/zypp/zypp-utils.h
@@ -164,14 +164,11 @@ gboolean zypp_signature_required (PkBackend *backend, const std::string &file, c
 zypp::PoolItem zypp_find_arch_update_item (const zypp::ResPool & pool, zypp::PoolItem item);
 
 /**
-  * Returns a set of all packages the could be updated (you're able to exclude a repo)
+  * Return the best, most friendly selection of update patches and packages that
+  * we can find. Also manages _updating_self to prioritise critical infrastructure
+  * updates.
   */
-std::set<zypp::PoolItem> * zypp_get_updates (std::string repo);
-
-/**
-  * Returns a set of all patches the could be installed
-  */
-std::set<zypp::PoolItem> * zypp_get_patches ();
+std::set<zypp::PoolItem> * zypp_get_updates ();
 
 /**
   * Sets the restart flag of a patch
commit d5f2f324e52fce355b41c7a1bfde6393ca9cc900
Author: Michael Meeks <michael.meeks at novell.com>
Date:   Thu May 6 11:51:07 2010 +0100

    Remove if (a == TRUE) type sillies; the processor has no boolean type,
    and this sort of thing is dangerous; if (2) is true, if (2 == TRUE) is not.

diff --git a/backends/zypp/pk-backend-zypp.cpp b/backends/zypp/pk-backend-zypp.cpp
index dc850ae..ec01090 100644
--- a/backends/zypp/pk-backend-zypp.cpp
+++ b/backends/zypp/pk-backend-zypp.cpp
@@ -149,7 +149,7 @@ backend_get_requires_thread (PkBackend *backend)
 			}
 			g_strfreev (id_parts);
 
-			if (found == FALSE) {
+			if (!found) {
 				return zypp_backend_finished_error (
 					backend, PK_ERROR_ENUM_PACKAGE_NOT_INSTALLED,
 					"Package is not installed");
@@ -176,7 +176,7 @@ backend_get_requires_thread (PkBackend *backend)
 
 		solver.setForceResolve (true);
 
-		if (solver.resolvePool () == FALSE) {
+		if (!solver.resolvePool ()) {
 			std::list<zypp::ResolverProblem_Ptr> problems = solver.problems ();
 			for (std::list<zypp::ResolverProblem_Ptr>::iterator it = problems.begin (); it != problems.end (); it++){
 				egg_warning("Solver problem (This should never happen): '%s'", (*it)->description ().c_str ());
@@ -321,7 +321,7 @@ backend_get_depends_thread (PkBackend *backend)
 
 		pk_backend_set_percentage (backend, 40);
 
-		if (pool_item_found == FALSE) {
+		if (!pool_item_found) {
 			return zypp_backend_finished_error (
 				backend, PK_ERROR_ENUM_DEP_RESOLUTION_FAILED,
 				"Did not find the specified package.");
@@ -1814,7 +1814,7 @@ backend_what_provides_thread (PkBackend *backend)
 		zypp::Resolver solver(pool);
 		solver.setIgnoreAlreadyRecommended (TRUE);
 
-		if (solver.resolvePool () == FALSE) {
+		if (!solver.resolvePool ()) {
 			std::list<zypp::ResolverProblem_Ptr> problems = solver.problems ();
 			for (std::list<zypp::ResolverProblem_Ptr>::iterator it = problems.begin (); it != problems.end (); it++){
 				egg_warning("Solver problem (This should never happen): '%s'", (*it)->description ().c_str ());
diff --git a/backends/zypp/zypp-events.h b/backends/zypp/zypp-events.h
index 2dca996..bccc31f 100644
--- a/backends/zypp/zypp-events.h
+++ b/backends/zypp/zypp-events.h
@@ -114,7 +114,7 @@ struct ZyppBackendReceiver
 		first_dash_found = FALSE;
 		for (tmp--; tmp != basename; tmp--) {
 			if (tmp [0] == '-') {
-				if (first_dash_found == FALSE) {
+				if (!first_dash_found) {
 					first_dash_found = TRUE;
 					continue;
 				} else {
diff --git a/backends/zypp/zypp-utils.cpp b/backends/zypp/zypp-utils.cpp
index 46c17b2..f81c370 100644
--- a/backends/zypp/zypp-utils.cpp
+++ b/backends/zypp/zypp-utils.cpp
@@ -71,7 +71,7 @@ class LookForArchUpdate : public zypp::resfilter::PoolItemFilterFunctor
 
 	bool operator() (zypp::PoolItem provider)
 	{
-		if ((provider.status ().isLocked () == FALSE) && (!best || best->edition ().compare (provider->edition ()) < 0)) {
+		if (!provider.status ().isLocked () && (!best || best->edition ().compare (provider->edition ()) < 0)) {
 			best = provider;
 		}
 
@@ -92,7 +92,7 @@ get_zypp ()
 	        zypp = zypp::ZYppFactory::instance ().getZYpp ();
 
 	        // TODO: Make this threadsafe
-	        if (initialized == FALSE) {
+	        if (!initialized) {
 		        zypp::filesystem::Pathname pathname("/");
 		        zypp->initializeTarget (pathname);
 
@@ -154,7 +154,7 @@ zypp_build_pool (gboolean include_local)
 {
 	zypp::ZYpp::Ptr zypp = get_zypp ();
 
-	if (include_local == TRUE) {
+	if (include_local) {
 		//FIXME have to wait for fix in zypp (repeated loading of target)
 		if (zypp::sat::Pool::instance().reposFind( zypp::sat::Pool::systemRepoAlias() ).solvablesEmpty ())
 		{
@@ -746,7 +746,7 @@ zypp_perform_execution (PkBackend *backend, PerformType type, gboolean force)
 
                 // Gather up any dependencies
 		pk_backend_set_status (backend, PK_STATUS_ENUM_DEP_RESOLVE);
-		if (zypp->resolver ()->resolvePool () == FALSE) {
+		if (!zypp->resolver ()->resolvePool ()) {
                        // Manual intervention required to resolve dependencies
                        // TODO: Figure out what we need to do with PackageKit
                        // to pull off interactive problem solving.
@@ -754,7 +754,7 @@ zypp_perform_execution (PkBackend *backend, PerformType type, gboolean force)
 			zypp::ResolverProblemList problems = zypp->resolver ()->problems ();
 			gchar * emsg = NULL, * tempmsg = NULL;
 
-			for (zypp::ResolverProblemList::iterator it = problems.begin (); it != problems.end (); it++){
+			for (zypp::ResolverProblemList::iterator it = problems.begin (); it != problems.end (); it++) {
 				if (emsg == NULL) {
 					emsg = g_strdup ((*it)->description ().c_str ());
 				}
@@ -984,10 +984,10 @@ zypp_refresh_cache (PkBackend *backend, gboolean force)
 		try {
 			// Refreshing metadata
 			_repoName = g_strdup (repo.alias ().c_str ());
-			manager.refreshMetadata (repo, force == TRUE ?
+			manager.refreshMetadata (repo, force ?
 				zypp::RepoManager::RefreshForced :
 				zypp::RepoManager::RefreshIfNeeded);
-			manager.buildCache (repo, force == TRUE ?
+			manager.buildCache (repo, force ?
 				zypp::RepoManager::BuildForced :
 				zypp::RepoManager::BuildIfNeeded);
 		} catch (const zypp::Exception &ex) {
@@ -1050,8 +1050,8 @@ zypp_backend_pool_item_notify (PkBackend  *backend,
 		status = PK_INFO_ENUM_REMOVING;
 
 		const std::string &name = item.satSolvable().name();
-		egg_debug ("should we remove '%s'", name.c_str());
-		if (name == "glibc" || name == "gedit") {
+		if (name == "glibc" || name == "PackageKit" ||
+		    name == "rpm" || name == "libzypp") {
 			pk_backend_error_code (backend, PK_ERROR_ENUM_CANNOT_REMOVE_SYSTEM_PACKAGE,
 					       "The package %s is essential to correct operation and cannot be removed using this tool.",
 					       name.c_str());
commit d0f8413287587c37c9d8efc945cd6e0237c9c58b
Author: zerng07 <zerng07 at fedoraproject.org>
Date:   Thu May 6 15:06:14 2010 +0000

    l10n: Updates to Chinese (Taiwan) (zh_TW) translation
    
    Transmitted-via: Transifex (translate.fedoraproject.org)

diff --git a/po/zh_TW.po b/po/zh_TW.po
index 1002103..b7d3a2c 100644
--- a/po/zh_TW.po
+++ b/po/zh_TW.po
@@ -8,8 +8,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: packagekit.master\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-03-09 09:20+0000\n"
-"PO-Revision-Date: 2010-03-09 23:06+0800\n"
+"POT-Creation-Date: 2010-05-04 11:16+0000\n"
+"PO-Revision-Date: 2010-05-05 18:03+0800\n"
 "Last-Translator: Cheng-Chia Tseng <pswo10680 at gmail.com>\n"
 "Language-Team: chinese-l10n at googlegroups.com\n"
 "MIME-Version: 1.0\n"
@@ -20,119 +20,119 @@ msgstr ""
 
 #. TRANSLATORS: this is an atomic transaction
 #. TRANSLATORS: the role is the point of the transaction, e.g. update-system
-#: ../client/pk-console.c:175
-#: ../client/pk-console.c:597
+#: ../client/pk-console.c:176
+#: ../client/pk-console.c:598
 msgid "Transaction"
 msgstr "處理事項"
 
 #. TRANSLATORS: this is the time the transaction was started in system timezone
-#: ../client/pk-console.c:177
+#: ../client/pk-console.c:178
 msgid "System time"
 msgstr "系統時間"
 
 #. TRANSLATORS: this is if the transaction succeeded or not
-#: ../client/pk-console.c:179
+#: ../client/pk-console.c:180
 msgid "Succeeded"
 msgstr "已成功"
 
-#: ../client/pk-console.c:179
+#: ../client/pk-console.c:180
 msgid "True"
 msgstr "True"
 
-#: ../client/pk-console.c:179
+#: ../client/pk-console.c:180
 msgid "False"
 msgstr "False"
 
 #. TRANSLATORS: this is the transactions role, e.g. "update-system"
 #. TRANSLATORS: the trasaction role, e.g. update-system
-#: ../client/pk-console.c:181
+#: ../client/pk-console.c:182
 #: ../src/pk-polkit-action-lookup.c:332
 msgid "Role"
 msgstr "任務"
 
 #. TRANSLATORS: this is The duration of the transaction
-#: ../client/pk-console.c:186
+#: ../client/pk-console.c:187
 msgid "Duration"
 msgstr "持續時間"
 
-#: ../client/pk-console.c:186
+#: ../client/pk-console.c:187
 msgid "(seconds)"
 msgstr "(秒)"
 
 #. TRANSLATORS: this is The command line used to do the action
 #. TRANSLATORS: the command line of the thing that wants the authentication
-#: ../client/pk-console.c:190
+#: ../client/pk-console.c:191
 #: ../src/pk-polkit-action-lookup.c:346
 msgid "Command line"
 msgstr "指令列"
 
 #. TRANSLATORS: this is the user ID of the user that started the action
-#: ../client/pk-console.c:192
+#: ../client/pk-console.c:193
 msgid "User ID"
 msgstr "使用者 ID"
 
 #. TRANSLATORS: this is the username, e.g. hughsie
-#: ../client/pk-console.c:199
+#: ../client/pk-console.c:200
 msgid "Username"
 msgstr "使用者名稱"
 
 #. TRANSLATORS: this is the users real name, e.g. "Richard Hughes"
-#: ../client/pk-console.c:203
+#: ../client/pk-console.c:204
 msgid "Real name"
 msgstr "真實名稱"
 
-#: ../client/pk-console.c:211
+#: ../client/pk-console.c:212
 msgid "Affected packages:"
 msgstr "受影響的套件:"
 
-#: ../client/pk-console.c:213
+#: ../client/pk-console.c:214
 msgid "Affected packages: None"
 msgstr "受影響的套件:無"
 
 #. TRANSLATORS: this is the distro, e.g. Fedora 10
-#: ../client/pk-console.c:248
+#: ../client/pk-console.c:249
 msgid "Distribution"
 msgstr "發行版"
 
 #. TRANSLATORS: this is type of update, stable or testing
-#: ../client/pk-console.c:250
+#: ../client/pk-console.c:251
 msgid "Type"
 msgstr "é¡žåž‹"
 
 #. TRANSLATORS: this is any summary text describing the upgrade
 #. TRANSLATORS: this is the summary of the group
-#: ../client/pk-console.c:252
-#: ../client/pk-console.c:291
+#: ../client/pk-console.c:253
+#: ../client/pk-console.c:292
 msgid "Summary"
 msgstr "摘要"
 
 #. TRANSLATORS: this is the group category name
-#: ../client/pk-console.c:280
+#: ../client/pk-console.c:281
 msgid "Category"
 msgstr "分類"
 
 #. TRANSLATORS: this is group identifier
-#: ../client/pk-console.c:282
+#: ../client/pk-console.c:283
 msgid "ID"
 msgstr "ID"
 
 #. TRANSLATORS: this is the parent group
-#: ../client/pk-console.c:285
+#: ../client/pk-console.c:286
 msgid "Parent"
 msgstr "親代"
 
 #. TRANSLATORS: this is the name of the parent group
-#: ../client/pk-console.c:288
+#: ../client/pk-console.c:289
 msgid "Name"
 msgstr "名稱"
 
 #. TRANSLATORS: this is preferred icon for the group
-#: ../client/pk-console.c:294
+#: ../client/pk-console.c:295
 msgid "Icon"
 msgstr "圖示"
 
 #. TRANSLATORS: this is a header for the package that can be updated
-#: ../client/pk-console.c:340
+#: ../client/pk-console.c:341
 msgid "Details about the update:"
 msgstr "關於更新的詳細資料:"
 
@@ -141,8 +141,8 @@ msgstr "關於更新的詳細資料:"
 #. TRANSLATORS: the package that is not signed by a known key
 #. TRANSLATORS: the package name that was trying to be installed
 #. TRANSLATORS: title, the names of the packages that the method is processing
-#: ../client/pk-console.c:346
-#: ../client/pk-console.c:616
+#: ../client/pk-console.c:347
+#: ../client/pk-console.c:617
 #: ../lib/packagekit-glib2/pk-task-text.c:126
 #: ../lib/packagekit-glib2/pk-task-text.c:208
 #: ../src/pk-polkit-action-lookup.c:357
@@ -152,196 +152,196 @@ msgstr[0] "套件"
 msgstr[1] "套件"
 
 #. TRANSLATORS: details about the update, any packages that this update updates
-#: ../client/pk-console.c:349
+#: ../client/pk-console.c:350
 msgid "Updates"
 msgstr "æ›´æ–°"
 
 #. TRANSLATORS: details about the update, any packages that this update obsoletes
-#: ../client/pk-console.c:353
+#: ../client/pk-console.c:354
 msgid "Obsoletes"
 msgstr "廢棄"
 
 #. TRANSLATORS: details about the update, the vendor URLs
 #. TRANSLATORS: the vendor (e.g. vmware) that is providing the EULA
-#: ../client/pk-console.c:357
+#: ../client/pk-console.c:358
 #: ../lib/packagekit-glib2/pk-task-text.c:211
 msgid "Vendor"
 msgstr "廠商"
 
 #. TRANSLATORS: details about the update, the bugzilla URLs
-#: ../client/pk-console.c:361
+#: ../client/pk-console.c:362
 msgid "Bugzilla"
 msgstr "Bugzilla"
 
 #. TRANSLATORS: details about the update, the CVE URLs
-#: ../client/pk-console.c:365
+#: ../client/pk-console.c:366
 msgid "CVE"
 msgstr "CVE"
 
 #. TRANSLATORS: details about the update, if the package requires a restart
-#: ../client/pk-console.c:369
+#: ../client/pk-console.c:370
 msgid "Restart"
 msgstr "重新啟動"
 
 #. TRANSLATORS: details about the update, any description of the update
-#: ../client/pk-console.c:373
+#: ../client/pk-console.c:374
 msgid "Update text"
 msgstr "更新文字"
 
 #. TRANSLATORS: details about the update, the changelog for the package
-#: ../client/pk-console.c:377
+#: ../client/pk-console.c:378
 msgid "Changes"
 msgstr "變更"
 
 #. TRANSLATORS: details about the update, the ongoing state of the update
-#: ../client/pk-console.c:381
+#: ../client/pk-console.c:382
 msgid "State"
 msgstr "狀態"
 
 #. TRANSLATORS: details about the update, date the update was issued
-#: ../client/pk-console.c:385
+#: ../client/pk-console.c:386
 msgid "Issued"
 msgstr "已發佈的"
 
 #. TRANSLATORS: details about the update, date the update was updated
 #. TRANSLATORS: The action of the package, in past tense
-#: ../client/pk-console.c:389
-#: ../lib/packagekit-glib2/pk-console-shared.c:510
+#: ../client/pk-console.c:390
+#: ../lib/packagekit-glib2/pk-console-shared.c:511
 msgid "Updated"
 msgstr "已更新"
 
 #. TRANSLATORS: if the repo is enabled
-#: ../client/pk-console.c:425
+#: ../client/pk-console.c:426
 msgid "Enabled"
 msgstr "已啟用"
 
 #. TRANSLATORS: if the repo is disabled
-#: ../client/pk-console.c:428
+#: ../client/pk-console.c:429
 msgid "Disabled"
 msgstr "已停用"
 
 #. TRANSLATORS: a package requires the system to be restarted
-#: ../client/pk-console.c:460
+#: ../client/pk-console.c:461
 msgid "System restart required by:"
 msgstr "系統重新啟動被此需求:"
 
 #. TRANSLATORS: a package requires the session to be restarted
-#: ../client/pk-console.c:463
+#: ../client/pk-console.c:464
 msgid "Session restart required:"
 msgstr "需要重新啟動作業階段:"
 
 #. TRANSLATORS: a package requires the system to be restarted due to a security update
-#: ../client/pk-console.c:466
+#: ../client/pk-console.c:467
 msgid "System restart (security) required by:"
 msgstr "系統重新啟動(安全性)被此需求:"
 
 #. TRANSLATORS: a package requires the session to be restarted due to a security update
-#: ../client/pk-console.c:469
+#: ../client/pk-console.c:470
 msgid "Session restart (security) required:"
 msgstr "需要重新啟動(安全性)作業階段:"
 
 #. TRANSLATORS: a package requires the application to be restarted
-#: ../client/pk-console.c:472
+#: ../client/pk-console.c:473
 msgid "Application restart required by:"
 msgstr "應用程式重新啟動被此需求:"
 
 #. TRANSLATORS: This a list of details about the package
-#: ../client/pk-console.c:507
+#: ../client/pk-console.c:508
 msgid "Package description"
 msgstr "套件描述"
 
 #. TRANSLATORS: This a message (like a little note that may be of interest) from the transaction
-#: ../client/pk-console.c:538
+#: ../client/pk-console.c:539
 msgid "Message:"
 msgstr "訊息:"
 
 #. TRANSLATORS: This where the package has no files
-#: ../client/pk-console.c:559
+#: ../client/pk-console.c:560
 msgid "No files"
 msgstr "無檔案"
 
 #. TRANSLATORS: This a list files contained in the package
-#: ../client/pk-console.c:564
+#: ../client/pk-console.c:565
 msgid "Package files"
 msgstr "套件檔案"
 
 #. TRANSLATORS: the percentage complete of the transaction
-#: ../client/pk-console.c:632
+#: ../client/pk-console.c:633
 msgid "Percentage"
 msgstr "百分比"
 
 #. TRANSLATORS: the status of the transaction (e.g. downloading)
-#: ../client/pk-console.c:650
+#: ../client/pk-console.c:651
 msgid "Status"
 msgstr "狀態"
 
 #. TRANSLATORS: the results from the transaction
-#: ../client/pk-console.c:679
+#: ../client/pk-console.c:680
 msgid "Results:"
 msgstr "結果:"
 
 #. TRANSLATORS: we failed to get any results, which is pretty fatal in my book
-#: ../client/pk-console.c:686
+#: ../client/pk-console.c:687
 msgid "Fatal error"
 msgstr "嚴重錯誤"
 
 #. TRANSLATORS: the transaction failed in a way we could not expect
-#: ../client/pk-console.c:695
-#: ../contrib/command-not-found/pk-command-not-found.c:432
-#: ../contrib/command-not-found/pk-command-not-found.c:603
+#: ../client/pk-console.c:696
+#: ../contrib/command-not-found/pk-command-not-found.c:433
+#: ../contrib/command-not-found/pk-command-not-found.c:606
 msgid "The transaction failed"
 msgstr "處理事項失敗"
 
 #. TRANSLATORS: print a message when there are no updates
-#: ../client/pk-console.c:726
+#: ../client/pk-console.c:727
 msgid "There are no updates available at this time."
 msgstr "此刻尚無更新可用。"
 
-#: ../client/pk-console.c:749
+#: ../client/pk-console.c:750
 msgid "There are no upgrades available at this time."
 msgstr "此刻尚無升級可用。"
 
 #. TRANSLATORS: a package needs to restart their system
-#: ../client/pk-console.c:816
+#: ../client/pk-console.c:817
 msgid "Please restart the computer to complete the update."
 msgstr "請重新啟動電腦來完成更新。"
 
 #. TRANSLATORS: a package needs to restart the session
-#: ../client/pk-console.c:819
+#: ../client/pk-console.c:820
 msgid "Please logout and login to complete the update."
 msgstr "請登出並再次登入來完成更新。"
 
 #. TRANSLATORS: a package needs to restart their system (due to security)
-#: ../client/pk-console.c:822
+#: ../client/pk-console.c:823
 msgid "Please restart the computer to complete the update as important security updates have been installed."
 msgstr "因為重大安全性更新已安裝,請重新啟動電腦來完成更新動作。"
 
 #. TRANSLATORS: a package needs to restart the session (due to security)
-#: ../client/pk-console.c:825
+#: ../client/pk-console.c:826
 msgid "Please logout and login to complete the update as important security updates have been installed."
 msgstr "因為重大安全性更新已安裝,請登出並再次登入來完成更新動作。"
 
 #. TRANSLATORS: The user used 'pkcon install dave.rpm' rather than 'pkcon install-local dave.rpm'
-#: ../client/pk-console.c:851
+#: ../client/pk-console.c:852
 #, c-format
-msgid "Extected package name, actually got file. Try using 'pkcon install-local %s' instead."
+msgid "Expected package name, actually got file. Try using 'pkcon install-local %s' instead."
 msgstr "預期的套件名稱,已實際取得檔案。嘗試使用 'pkcon install-local %s' 來替代。"
 
 #. TRANSLATORS: There was an error getting the list of files for the package. The detailed error follows
-#: ../client/pk-console.c:859
+#: ../client/pk-console.c:860
 #, c-format
 msgid "This tool could not find any available package: %s"
 msgstr "此工具無法找到任何可用的套件:%s"
 
 #. TRANSLATORS: There was an error getting the list of files for the package. The detailed error follows
-#: ../client/pk-console.c:887
+#: ../client/pk-console.c:888
 #, c-format
 msgid "This tool could not find the installed package: %s"
 msgstr "此工具無法找到已安裝的套件:%s"
 
 #. TRANSLATORS: There was an error getting the list of files for the package. The detailed error follows
-#: ../client/pk-console.c:915
-#: ../client/pk-console.c:943
+#: ../client/pk-console.c:916
+#: ../client/pk-console.c:944
 #, c-format
 msgid "This tool could not find the package: %s"
 msgstr "此工具無法找到這個套件:%s"
@@ -350,185 +350,200 @@ msgstr "此工具無法找到這個套件:%s"
 #. TRANSLATORS: There was an error getting the dependencies for the package. The detailed error follows
 #. TRANSLATORS: There was an error getting the details about the package. The detailed error follows
 #. TRANSLATORS: The package name was not found in any software sources. The detailed error follows
-#: ../client/pk-console.c:971
-#: ../client/pk-console.c:999
-#: ../client/pk-console.c:1027
-#: ../client/pk-console.c:1055
-#: ../client/pk-console.c:1083
+#: ../client/pk-console.c:972
+#: ../client/pk-console.c:1000
+#: ../client/pk-console.c:1028
+#: ../client/pk-console.c:1056
+#: ../client/pk-console.c:1084
 #, c-format
 msgid "This tool could not find all the packages: %s"
 msgstr "此工具無法找到所有套件:%s"
 
 #. TRANSLATORS: This is when the daemon crashed, and we are up shit creek without a paddle
-#: ../client/pk-console.c:1112
+#: ../client/pk-console.c:1113
 msgid "The daemon crashed mid-transaction!"
 msgstr "幕後程式損壞了 mid-transaction!"
 
 #. TRANSLATORS: This is the header to the --help menu
-#: ../client/pk-console.c:1146
+#: ../client/pk-console.c:1147
 msgid "PackageKit Console Interface"
 msgstr "PackageKit 主控台介面"
 
 #. these are commands we can use with pkcon
-#: ../client/pk-console.c:1148
+#: ../client/pk-console.c:1149
 msgid "Subcommands:"
 msgstr "次指令:"
 
 #. TRANSLATORS: we keep a database updated with the time that an action was last executed
-#: ../client/pk-console.c:1227
+#: ../client/pk-console.c:1228
 msgid "Failed to get the time since this action was last completed"
 msgstr "無法取得此動作最後完成後的時間"
 
 #. TRANSLATORS: command line argument, just show the version string
-#: ../client/pk-console.c:1263
-#: ../client/pk-monitor.c:306
+#: ../client/pk-console.c:1268
+#: ../client/pk-monitor.c:326
 msgid "Show the program version and exit"
 msgstr "顯示程式版本然後離開"
 
 #. TRANSLATORS: command line argument, use a filter to narrow down results
-#: ../client/pk-console.c:1266
+#: ../client/pk-console.c:1271
 msgid "Set the filter, e.g. installed"
 msgstr "設定過濾條件,例如:installed"
 
+#. TRANSLATORS: command line argument, use a non-standard install prefix
+#: ../client/pk-console.c:1274
+msgid "Set the install root, e.g. '/' or '/mnt/ltsp'"
+msgstr "設定安裝的根目錄,例:'/' 或 '/mnt/ltsp'"
+
 #. TRANSLATORS: command line argument, work asynchronously
-#: ../client/pk-console.c:1269
+#: ../client/pk-console.c:1277
 msgid "Exit without waiting for actions to complete"
 msgstr "不等待動作完成便離開"
 
 #. command line argument, do we ask questions
-#: ../client/pk-console.c:1272
+#: ../client/pk-console.c:1280
 #: ../contrib/debuginfo-install/pk-debuginfo-install.c:527
 msgid "Install the packages without asking for confirmation"
 msgstr "安裝套件而不要詢問是否確認"
 
 #. TRANSLATORS: command line argument, this command is not a priority
-#: ../client/pk-console.c:1275
+#: ../client/pk-console.c:1283
 msgid "Run the command using idle network bandwidth and also using less power"
 msgstr "使用閒置的網路頻寬與較少的能源來執行指令"
 
 #. TRANSLATORS: command line argument, just output without fancy formatting
-#: ../client/pk-console.c:1278
+#: ../client/pk-console.c:1286
 msgid "Print to screen a machine readable output, rather than using animated widgets"
 msgstr "將機器可讀的輸出列印到畫面,而不是使用動畫的小工具"
 
 #. TRANSLATORS: we failed to contact the daemon
-#: ../client/pk-console.c:1300
+#: ../client/pk-console.c:1308
 msgid "Failed to contact PackageKit"
 msgstr "聯絡 PackageKit 失敗"
 
 #. TRANSLATORS: The user specified an incorrect filter
-#: ../client/pk-console.c:1358
+#: ../client/pk-console.c:1369
+msgid "The proxy could not be set"
+msgstr "無法設定 proxy"
+
+#. TRANSLATORS: The user specified an incorrect filter
+#: ../client/pk-console.c:1381
+msgid "The install root could not be set"
+msgstr "無法設定安裝的根目錄"
+
+#. TRANSLATORS: The user specified an incorrect filter
+#: ../client/pk-console.c:1393
 msgid "The filter specified was invalid"
 msgstr "指定的過濾條件無效"
 
 #. TRANSLATORS: a search type can be name, details, file, etc
-#: ../client/pk-console.c:1377
+#: ../client/pk-console.c:1412
 msgid "A search type is required, e.g. name"
 msgstr "需要選取搜尋類型,例如:名稱"
 
 #. TRANSLATORS: the user needs to provide a search term
-#: ../client/pk-console.c:1384
-#: ../client/pk-console.c:1396
-#: ../client/pk-console.c:1408
-#: ../client/pk-console.c:1420
+#: ../client/pk-console.c:1419
+#: ../client/pk-console.c:1431
+#: ../client/pk-console.c:1443
+#: ../client/pk-console.c:1455
 msgid "A search term is required"
 msgstr "需要輸入搜尋用的關鍵詞"
 
 #. TRANSLATORS: the search type was provided, but invalid
-#: ../client/pk-console.c:1430
+#: ../client/pk-console.c:1465
 msgid "Invalid search type"
 msgstr "無效的搜尋類型"
 
 #. TRANSLATORS: the user did not specify what they wanted to install
-#: ../client/pk-console.c:1436
+#: ../client/pk-console.c:1471
 msgid "A package name to install is required"
 msgstr "需要有要安裝的套件名稱"
 
 #. TRANSLATORS: the user did not specify what they wanted to install
-#: ../client/pk-console.c:1445
+#: ../client/pk-console.c:1480
 msgid "A filename to install is required"
 msgstr "需要有要安裝的檔案名稱"
 
 #. TRANSLATORS: geeky error, 99.9999% of users won't see this
-#: ../client/pk-console.c:1457
+#: ../client/pk-console.c:1492
 msgid "A type, key_id and package_id are required"
 msgstr "需要指定一個類型、key_id 以及 package_id"
 
 #. TRANSLATORS: the user did not specify what they wanted to remove
-#: ../client/pk-console.c:1468
+#: ../client/pk-console.c:1503
 msgid "A package name to remove is required"
 msgstr "需要想移除的套件名稱"
 
 #. TRANSLATORS: the user did not specify anything about what to download or where
-#: ../client/pk-console.c:1477
+#: ../client/pk-console.c:1512
 msgid "A destination directory and the package names to download are required"
 msgstr "需要有目標資料夾與要下載的套件名稱"
 
 #. TRANSLATORS: the directory does not exist, so we can't continue
-#: ../client/pk-console.c:1484
+#: ../client/pk-console.c:1519
 msgid "Directory not found"
 msgstr "找不到目錄"
 
 #. TRANSLATORS: geeky error, 99.9999% of users won't see this
-#: ../client/pk-console.c:1493
+#: ../client/pk-console.c:1528
 msgid "A licence identifier (eula-id) is required"
 msgstr "需要指定一個授權合約的標示符號(eula-id)"
 
 #. TRANSLATORS: geeky error, 99.9999% of users won't see this
-#: ../client/pk-console.c:1504
+#: ../client/pk-console.c:1539
 msgid "A transaction identifier (tid) is required"
 msgstr "需要處理事項識別符 (tid)"
 
 #. TRANSLATORS: The user did not specify a package name
-#: ../client/pk-console.c:1525
+#: ../client/pk-console.c:1560
 msgid "A package name to resolve is required"
 msgstr "需要欲解析的套件之名稱"
 
 #. TRANSLATORS: The user did not specify a repository (software source) name
-#: ../client/pk-console.c:1536
-#: ../client/pk-console.c:1547
+#: ../client/pk-console.c:1571
+#: ../client/pk-console.c:1582
 msgid "A repository name is required"
 msgstr "需要套件庫的名稱"
 
 #. TRANSLATORS: The user didn't provide any data
-#: ../client/pk-console.c:1558
+#: ../client/pk-console.c:1593
 msgid "A repo name, parameter and value are required"
 msgstr "需要指定一個套件庫名稱、參數和值"
 
 #. TRANSLATORS: The user didn't specify what action to use
-#: ../client/pk-console.c:1575
+#: ../client/pk-console.c:1610
 msgid "An action, e.g. 'update-system' is required"
 msgstr "需要指定一項動作,例如:「update-system」"
 
 #. TRANSLATORS: The user specified an invalid action
-#: ../client/pk-console.c:1582
+#: ../client/pk-console.c:1617
 msgid "A correct role is required"
 msgstr "需要正確的任務"
 
 #. TRANSLATORS: The user did not provide a package name
 #. TRANSLATORS: This is when the user fails to supply the package name
-#: ../client/pk-console.c:1592
-#: ../client/pk-console.c:1607
-#: ../client/pk-console.c:1616
-#: ../client/pk-console.c:1636
-#: ../client/pk-console.c:1645
+#: ../client/pk-console.c:1627
+#: ../client/pk-console.c:1642
+#: ../client/pk-console.c:1651
+#: ../client/pk-console.c:1671
+#: ../client/pk-console.c:1680
 #: ../client/pk-generate-pack.c:316
 msgid "A package name is required"
 msgstr "需要套件名稱"
 
 #. TRANSLATORS: each package "provides" certain things, e.g. mime(gstreamer-decoder-mp3), the user didn't specify it
-#: ../client/pk-console.c:1625
+#: ../client/pk-console.c:1660
 msgid "A package provide string is required"
 msgstr "需要套件的提供字串"
 
 #. TRANSLATORS: The user tried to use an unsupported option on the command line
-#: ../client/pk-console.c:1705
+#: ../client/pk-console.c:1740
 #, c-format
 msgid "Option '%s' is not supported"
 msgstr "「%s」選項不被支援"
 
 #. TRANSLATORS: Generic failure of what they asked to do
-#: ../client/pk-console.c:1715
+#: ../client/pk-console.c:1750
 msgid "Command failed"
 msgstr "指令失敗"
 
@@ -539,8 +554,8 @@ msgstr "設定要排除的相依檔名"
 
 #. TRANSLATORS: the output location
 #: ../client/pk-generate-pack.c:258
-msgid "The output file or directory (the current directory is used if ommitted)"
-msgstr "輸出檔案或目錄(若省略的話,目前的目錄便會被使用)"
+msgid "The output file or directory (the current directory is used if omitted)"
+msgstr "輸出檔或目錄(若省略的話會使用目前的目錄)"
 
 #. TRANSLATORS: put a list of packages in the pack
 #: ../client/pk-generate-pack.c:261
@@ -567,10 +582,10 @@ msgstr "兩個選項皆被選取。"
 msgid "A output directory or file name is required"
 msgstr "需要輸出目錄或檔案名稱"
 
-#. TRANSLATORS: This is when the dameon is not-installed/broken and fails to startup
+#. TRANSLATORS: This is when the daemon is not-installed/broken and fails to startup
 #: ../client/pk-generate-pack.c:342
-msgid "The dameon failed to startup"
-msgstr "幕後程式未能啟動"
+msgid "The daemon failed to startup"
+msgstr "幕後程式啟動失敗"
 
 #. TRANSLATORS: This is when the backend doesn't have the capability to get-depends
 #. TRANSLATORS: This is when the backend doesn't have the capability to download
@@ -637,12 +652,12 @@ msgstr "服務包建立了「%s」"
 msgid "Failed to create '%s': %s"
 msgstr "無法建立「%s」:%s"
 
-#: ../client/pk-monitor.c:236
+#: ../client/pk-monitor.c:256
 msgid "Failed to get daemon state"
 msgstr "未能取得幕後程式狀態"
 
 #. TRANSLATORS: this is a program that monitors PackageKit
-#: ../client/pk-monitor.c:322
+#: ../client/pk-monitor.c:342
 msgid "PackageKit Monitor"
 msgstr "PackageKit 監控程式"
 
@@ -701,42 +716,42 @@ msgid "Installing..."
 msgstr "正在安裝..."
 
 #. TRANSLATORS: downloading repo data so we can search
-#: ../contrib/command-not-found/pk-command-not-found.c:365
+#: ../contrib/command-not-found/pk-command-not-found.c:366
 msgid "Downloading details about the software sources."
 msgstr "正在下載關於軟體來源的詳細資料。"
 
 #. TRANSLATORS: downloading file lists so we can search
-#: ../contrib/command-not-found/pk-command-not-found.c:369
+#: ../contrib/command-not-found/pk-command-not-found.c:370
 msgid "Downloading filelists (this may take some time to complete)."
 msgstr "正在下載檔案清單(這會花上一段時間才能完成)。"
 
 #. TRANSLATORS: waiting for native lock
-#: ../contrib/command-not-found/pk-command-not-found.c:373
+#: ../contrib/command-not-found/pk-command-not-found.c:374
 msgid "Waiting for package manager lock."
 msgstr "正在等待套件管理程式解鎖。"
 
 #. TRANSLATORS: loading package cache so we can search
-#: ../contrib/command-not-found/pk-command-not-found.c:377
+#: ../contrib/command-not-found/pk-command-not-found.c:378
 msgid "Loading list of packages."
 msgstr "正在載入套件清單。"
 
 #. TRANSLATORS: we failed to find the package, this shouldn't happen
-#: ../contrib/command-not-found/pk-command-not-found.c:423
+#: ../contrib/command-not-found/pk-command-not-found.c:424
 msgid "Failed to search for file"
 msgstr "搜尋檔案失敗"
 
 #. TRANSLATORS: we failed to launch the executable, the error follows
-#: ../contrib/command-not-found/pk-command-not-found.c:566
+#: ../contrib/command-not-found/pk-command-not-found.c:569
 msgid "Failed to launch:"
 msgstr "啟動失敗:"
 
 #. TRANSLATORS: we failed to install the package
-#: ../contrib/command-not-found/pk-command-not-found.c:594
+#: ../contrib/command-not-found/pk-command-not-found.c:597
 msgid "Failed to install packages"
 msgstr "安裝套件失敗"
 
 #. TRANSLATORS: tool that gets called when the command is not found
-#: ../contrib/command-not-found/pk-command-not-found.c:670
+#: ../contrib/command-not-found/pk-command-not-found.c:673
 msgid "PackageKit Command Not Found"
 msgstr "找不到 PackageKit 指令"
 
@@ -746,51 +761,51 @@ msgid "Command not found."
 msgstr "找不到指令。"
 
 #. TRANSLATORS: tell the user what we think the command is
-#: ../contrib/command-not-found/pk-command-not-found.c:706
+#: ../contrib/command-not-found/pk-command-not-found.c:717
 msgid "Similar command is:"
 msgstr "相似指令為:"
 
 #. TRANSLATORS: Ask the user if we should run the similar command
-#: ../contrib/command-not-found/pk-command-not-found.c:716
+#: ../contrib/command-not-found/pk-command-not-found.c:727
 msgid "Run similar command:"
 msgstr "執行相似指令:"
 
 #. TRANSLATORS: show the user a list of commands that they could have meant
 #. TRANSLATORS: show the user a list of commands we could run
-#: ../contrib/command-not-found/pk-command-not-found.c:730
-#: ../contrib/command-not-found/pk-command-not-found.c:739
+#: ../contrib/command-not-found/pk-command-not-found.c:741
+#: ../contrib/command-not-found/pk-command-not-found.c:750
 msgid "Similar commands are:"
 msgstr "相似指令有:"
 
 #. TRANSLATORS: ask the user to choose a file to run
-#: ../contrib/command-not-found/pk-command-not-found.c:746
+#: ../contrib/command-not-found/pk-command-not-found.c:757
 msgid "Please choose a command to run"
 msgstr "請選擇一項指令來執行"
 
 #. TRANSLATORS: tell the user what package provides the command
-#: ../contrib/command-not-found/pk-command-not-found.c:764
+#: ../contrib/command-not-found/pk-command-not-found.c:775
 msgid "The package providing this file is:"
 msgstr "提供此檔案的套件為:"
 
 #. TRANSLATORS: as the user if we want to install a package to provide the command
-#: ../contrib/command-not-found/pk-command-not-found.c:769
+#: ../contrib/command-not-found/pk-command-not-found.c:780
 #, c-format
 msgid "Install package '%s' to provide command '%s'?"
 msgstr "是否要安裝「%s」套件以提供「%s」指令?"
 
 #. TRANSLATORS: Show the user a list of packages that provide this command
-#: ../contrib/command-not-found/pk-command-not-found.c:793
+#: ../contrib/command-not-found/pk-command-not-found.c:804
 msgid "Packages providing this file are:"
 msgstr "提供此檔案的套件有:"
 
 #. TRANSLATORS: Show the user a list of packages that they can install to provide this command
-#: ../contrib/command-not-found/pk-command-not-found.c:803
+#: ../contrib/command-not-found/pk-command-not-found.c:814
 msgid "Suitable packages are:"
 msgstr "合適的套件有:"
 
 #. get selection
 #. TRANSLATORS: ask the user to choose a file to install
-#: ../contrib/command-not-found/pk-command-not-found.c:812
+#: ../contrib/command-not-found/pk-command-not-found.c:823
 msgid "Please choose a package to install"
 msgstr "請選擇欲安裝的套件"
 
@@ -958,7 +973,7 @@ msgstr "在模擬模式內不會安裝套件"
 #. TRANSLATORS: we are now installing the debuginfo packages we found earlier
 #. TRANSLATORS: transaction state, installing packages
 #: ../contrib/debuginfo-install/pk-debuginfo-install.c:862
-#: ../lib/packagekit-glib2/pk-console-shared.c:282
+#: ../lib/packagekit-glib2/pk-console-shared.c:283
 #, c-format
 msgid "Installing packages"
 msgstr "正在安裝套件"
@@ -1095,7 +1110,7 @@ msgid "Please enter a number from 1 to %i: "
 msgstr "請輸入一個 1 到 %i 之間的數字:"
 
 #. TRANSLATORS: more than one package could be found that matched, to follow is a list of possible packages
-#: ../lib/packagekit-glib2/pk-console-shared.c:183
+#: ../lib/packagekit-glib2/pk-console-shared.c:185
 msgid "More than one package matches:"
 msgstr "超過一個符合的套件:"
 
@@ -1105,448 +1120,448 @@ msgid "Please choose the correct package: "
 msgstr "請選擇正確的套件:"
 
 #. TRANSLATORS: This is when the transaction status is not known
-#: ../lib/packagekit-glib2/pk-console-shared.c:250
+#: ../lib/packagekit-glib2/pk-console-shared.c:251
 msgid "Unknown state"
 msgstr "不明的狀態"
 
 #. TRANSLATORS: transaction state, the daemon is in the process of starting
-#: ../lib/packagekit-glib2/pk-console-shared.c:254
+#: ../lib/packagekit-glib2/pk-console-shared.c:255
 msgid "Starting"
 msgstr "正在開始"
 
 #. TRANSLATORS: transaction state, the transaction is waiting for another to complete
-#: ../lib/packagekit-glib2/pk-console-shared.c:258
+#: ../lib/packagekit-glib2/pk-console-shared.c:259
 msgid "Waiting in queue"
 msgstr "正在依佇列等待"
 
 #. TRANSLATORS: transaction state, just started
-#: ../lib/packagekit-glib2/pk-console-shared.c:262
+#: ../lib/packagekit-glib2/pk-console-shared.c:263
 msgid "Running"
 msgstr "正在執行"
 
 #. TRANSLATORS: transaction state, is querying data
-#: ../lib/packagekit-glib2/pk-console-shared.c:266
+#: ../lib/packagekit-glib2/pk-console-shared.c:267
 msgid "Querying"
 msgstr "正在查詢"
 
 #. TRANSLATORS: transaction state, getting data from a server
-#: ../lib/packagekit-glib2/pk-console-shared.c:270
+#: ../lib/packagekit-glib2/pk-console-shared.c:271
 msgid "Getting information"
 msgstr "正在取得資訊"
 
 #. TRANSLATORS: transaction state, removing packages
-#: ../lib/packagekit-glib2/pk-console-shared.c:274
+#: ../lib/packagekit-glib2/pk-console-shared.c:275
 msgid "Removing packages"
 msgstr "正在移除套件"
 
 #. TRANSLATORS: transaction state, downloading package files
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:278
-#: ../lib/packagekit-glib2/pk-console-shared.c:656
+#: ../lib/packagekit-glib2/pk-console-shared.c:279
+#: ../lib/packagekit-glib2/pk-console-shared.c:657
 msgid "Downloading packages"
 msgstr "正在下載套件"
 
 #. TRANSLATORS: transaction state, refreshing internal lists
-#: ../lib/packagekit-glib2/pk-console-shared.c:286
+#: ../lib/packagekit-glib2/pk-console-shared.c:287
 msgid "Refreshing software list"
 msgstr "正在重新整理軟體清單"
 
 #. TRANSLATORS: transaction state, installing updates
-#: ../lib/packagekit-glib2/pk-console-shared.c:290
+#: ../lib/packagekit-glib2/pk-console-shared.c:291
 msgid "Installing updates"
 msgstr "正在安裝更新"
 
 #. TRANSLATORS: transaction state, removing old packages, and cleaning config files
-#: ../lib/packagekit-glib2/pk-console-shared.c:294
+#: ../lib/packagekit-glib2/pk-console-shared.c:295
 msgid "Cleaning up packages"
 msgstr "正在清理套件"
 
 #. TRANSLATORS: transaction state, obsoleting old packages
-#: ../lib/packagekit-glib2/pk-console-shared.c:298
+#: ../lib/packagekit-glib2/pk-console-shared.c:299
 msgid "Obsoleting packages"
 msgstr "正在廢棄套件"
 
 #. TRANSLATORS: transaction state, checking the transaction before we do it
-#: ../lib/packagekit-glib2/pk-console-shared.c:302
+#: ../lib/packagekit-glib2/pk-console-shared.c:303
 msgid "Resolving dependencies"
 msgstr "正在解析相依性"
 
 #. TRANSLATORS: transaction state, checking if we have all the security keys for the operation
-#: ../lib/packagekit-glib2/pk-console-shared.c:306
+#: ../lib/packagekit-glib2/pk-console-shared.c:307
 msgid "Checking signatures"
 msgstr "正在檢查簽章"
 
 #. TRANSLATORS: transaction state, when we return to a previous system state
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:310
-#: ../lib/packagekit-glib2/pk-console-shared.c:616
+#: ../lib/packagekit-glib2/pk-console-shared.c:311
+#: ../lib/packagekit-glib2/pk-console-shared.c:617
 msgid "Rolling back"
 msgstr "正在回復"
 
 #. TRANSLATORS: transaction state, when we're doing a test transaction
-#: ../lib/packagekit-glib2/pk-console-shared.c:314
+#: ../lib/packagekit-glib2/pk-console-shared.c:315
 msgid "Testing changes"
 msgstr "正在測試變更"
 
 #. TRANSLATORS: transaction state, when we're writing to the system package database
-#: ../lib/packagekit-glib2/pk-console-shared.c:318
+#: ../lib/packagekit-glib2/pk-console-shared.c:319
 msgid "Committing changes"
 msgstr "正在遞交變更"
 
 #. TRANSLATORS: transaction state, requesting data from a server
-#: ../lib/packagekit-glib2/pk-console-shared.c:322
+#: ../lib/packagekit-glib2/pk-console-shared.c:323
 msgid "Requesting data"
 msgstr "正在請求資料"
 
 #. TRANSLATORS: transaction state, all done!
-#: ../lib/packagekit-glib2/pk-console-shared.c:326
+#: ../lib/packagekit-glib2/pk-console-shared.c:327
 msgid "Finished"
 msgstr "已完成"
 
 #. TRANSLATORS: transaction state, in the process of cancelling
-#: ../lib/packagekit-glib2/pk-console-shared.c:330
+#: ../lib/packagekit-glib2/pk-console-shared.c:331
 msgid "Cancelling"
 msgstr "正在取消"
 
 #. TRANSLATORS: transaction state, downloading metadata
-#: ../lib/packagekit-glib2/pk-console-shared.c:334
+#: ../lib/packagekit-glib2/pk-console-shared.c:335
 msgid "Downloading repository information"
 msgstr "正在下載套件庫資訊"
 
 #. TRANSLATORS: transaction state, downloading metadata
-#: ../lib/packagekit-glib2/pk-console-shared.c:338
+#: ../lib/packagekit-glib2/pk-console-shared.c:339
 msgid "Downloading list of packages"
 msgstr "正在下載套件清單"
 
 #. TRANSLATORS: transaction state, downloading metadata
-#: ../lib/packagekit-glib2/pk-console-shared.c:342
+#: ../lib/packagekit-glib2/pk-console-shared.c:343
 msgid "Downloading file lists"
 msgstr "正在下載檔案清單"
 
 #. TRANSLATORS: transaction state, downloading metadata
-#: ../lib/packagekit-glib2/pk-console-shared.c:346
+#: ../lib/packagekit-glib2/pk-console-shared.c:347
 msgid "Downloading lists of changes"
 msgstr "正在下載變更的清單"
 
 #. TRANSLATORS: transaction state, downloading metadata
-#: ../lib/packagekit-glib2/pk-console-shared.c:350
+#: ../lib/packagekit-glib2/pk-console-shared.c:351
 msgid "Downloading groups"
 msgstr "正在下載群組"
 
 #. TRANSLATORS: transaction state, downloading metadata
-#: ../lib/packagekit-glib2/pk-console-shared.c:354
+#: ../lib/packagekit-glib2/pk-console-shared.c:355
 msgid "Downloading update information"
 msgstr "正在下載更新資訊"
 
 #. TRANSLATORS: transaction state, repackaging delta files
-#: ../lib/packagekit-glib2/pk-console-shared.c:358
+#: ../lib/packagekit-glib2/pk-console-shared.c:359
 msgid "Repackaging files"
 msgstr "正在重新包裝檔案"
 
 #. TRANSLATORS: transaction state, loading databases
-#: ../lib/packagekit-glib2/pk-console-shared.c:362
+#: ../lib/packagekit-glib2/pk-console-shared.c:363
 msgid "Loading cache"
 msgstr "正在載入快取"
 
 #. TRANSLATORS: transaction state, scanning for running processes
-#: ../lib/packagekit-glib2/pk-console-shared.c:366
+#: ../lib/packagekit-glib2/pk-console-shared.c:367
 msgid "Scanning applications"
 msgstr "正在掃描應用程式"
 
 #. TRANSLATORS: transaction state, generating a list of packages installed on the system
-#: ../lib/packagekit-glib2/pk-console-shared.c:370
+#: ../lib/packagekit-glib2/pk-console-shared.c:371
 msgid "Generating package lists"
 msgstr "正在產生套件清單"
 
 #. TRANSLATORS: transaction state, when we're waiting for the native tools to exit
-#: ../lib/packagekit-glib2/pk-console-shared.c:374
+#: ../lib/packagekit-glib2/pk-console-shared.c:375
 msgid "Waiting for package manager lock"
 msgstr "正在等候套件管程式解鎖"
 
 #. TRANSLATORS: transaction state, waiting for user to type in a password
-#: ../lib/packagekit-glib2/pk-console-shared.c:378
+#: ../lib/packagekit-glib2/pk-console-shared.c:379
 msgid "Waiting for authentication"
 msgstr "正在等候認證"
 
 #. TRANSLATORS: transaction state, we are updating the list of processes
-#: ../lib/packagekit-glib2/pk-console-shared.c:382
+#: ../lib/packagekit-glib2/pk-console-shared.c:383
 msgid "Updating running applications"
 msgstr "正在更新正在執行中的應用程式"
 
 #. TRANSLATORS: transaction state, we are checking executable files currently in use
-#: ../lib/packagekit-glib2/pk-console-shared.c:386
+#: ../lib/packagekit-glib2/pk-console-shared.c:387
 msgid "Checking applications in use"
 msgstr "正在檢查使用中的應用程式"
 
 #. TRANSLATORS: transaction state, we are checking for libraries currently in use
-#: ../lib/packagekit-glib2/pk-console-shared.c:390
+#: ../lib/packagekit-glib2/pk-console-shared.c:391
 msgid "Checking libraries in use"
 msgstr "正在檢查使用中的函式庫"
 
 #. TRANSLATORS: transaction state, we are copying package files before or after the transaction
-#: ../lib/packagekit-glib2/pk-console-shared.c:394
+#: ../lib/packagekit-glib2/pk-console-shared.c:395
 msgid "Copying files"
 msgstr "正在複製檔案"
 
 #. TRANSLATORS: The type of update
-#: ../lib/packagekit-glib2/pk-console-shared.c:412
+#: ../lib/packagekit-glib2/pk-console-shared.c:413
 msgid "Trivial"
 msgstr "小"
 
 #. TRANSLATORS: The type of update
-#: ../lib/packagekit-glib2/pk-console-shared.c:416
+#: ../lib/packagekit-glib2/pk-console-shared.c:417
 msgid "Normal"
 msgstr "一般"
 
 #. TRANSLATORS: The type of update
-#: ../lib/packagekit-glib2/pk-console-shared.c:420
+#: ../lib/packagekit-glib2/pk-console-shared.c:421
 msgid "Important"
 msgstr "重大"
 
 #. TRANSLATORS: The type of update
-#: ../lib/packagekit-glib2/pk-console-shared.c:424
+#: ../lib/packagekit-glib2/pk-console-shared.c:425
 msgid "Security"
 msgstr "安全性"
 
 #. TRANSLATORS: The type of update
-#: ../lib/packagekit-glib2/pk-console-shared.c:428
+#: ../lib/packagekit-glib2/pk-console-shared.c:429
 msgid "Bug fix "
 msgstr "錯誤修正"
 
 #. TRANSLATORS: The type of update
-#: ../lib/packagekit-glib2/pk-console-shared.c:432
+#: ../lib/packagekit-glib2/pk-console-shared.c:433
 msgid "Enhancement"
 msgstr "增強"
 
 #. TRANSLATORS: The type of update
-#: ../lib/packagekit-glib2/pk-console-shared.c:436
+#: ../lib/packagekit-glib2/pk-console-shared.c:437
 msgid "Blocked"
 msgstr "已阻擋"
 
 #. TRANSLATORS: The state of a package
 #. TRANSLATORS: The action of the package, in past tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:441
-#: ../lib/packagekit-glib2/pk-console-shared.c:514
+#: ../lib/packagekit-glib2/pk-console-shared.c:442
+#: ../lib/packagekit-glib2/pk-console-shared.c:515
 msgid "Installed"
 msgstr "已安裝的"
 
 #. TRANSLATORS: The state of a package, i.e. not installed
-#: ../lib/packagekit-glib2/pk-console-shared.c:446
+#: ../lib/packagekit-glib2/pk-console-shared.c:447
 msgid "Available"
 msgstr "可用"
 
 #. TRANSLATORS: The action of the package, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:464
+#: ../lib/packagekit-glib2/pk-console-shared.c:465
 msgid "Downloading"
 msgstr "正在下載"
 
 #. TRANSLATORS: The action of the package, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:468
+#: ../lib/packagekit-glib2/pk-console-shared.c:469
 msgid "Updating"
 msgstr "正在更新"
 
 #. TRANSLATORS: The action of the package, in present tense
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:472
-#: ../lib/packagekit-glib2/pk-console-shared.c:592
+#: ../lib/packagekit-glib2/pk-console-shared.c:473
+#: ../lib/packagekit-glib2/pk-console-shared.c:593
 msgid "Installing"
 msgstr "正在安裝"
 
 #. TRANSLATORS: The action of the package, in present tense
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:476
-#: ../lib/packagekit-glib2/pk-console-shared.c:588
+#: ../lib/packagekit-glib2/pk-console-shared.c:477
+#: ../lib/packagekit-glib2/pk-console-shared.c:589
 msgid "Removing"
 msgstr "正在移除"
 
 #. TRANSLATORS: The action of the package, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:480
+#: ../lib/packagekit-glib2/pk-console-shared.c:481
 msgid "Cleaning up"
 msgstr "正在清除"
 
 #. TRANSLATORS: The action of the package, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:484
+#: ../lib/packagekit-glib2/pk-console-shared.c:485
 msgid "Obsoleting"
 msgstr "正在廢棄"
 
 #. TRANSLATORS: The action of the package, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:488
+#: ../lib/packagekit-glib2/pk-console-shared.c:489
 msgid "Reinstalling"
 msgstr "正在重新安裝"
 
 #. TRANSLATORS: The action of the package, in past tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:506
+#: ../lib/packagekit-glib2/pk-console-shared.c:507
 msgid "Downloaded"
 msgstr "已下載"
 
 #. TRANSLATORS: The action of the package, in past tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:518
+#: ../lib/packagekit-glib2/pk-console-shared.c:519
 msgid "Removed"
 msgstr "已移除"
 
 #. TRANSLATORS: The action of the package, in past tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:522
+#: ../lib/packagekit-glib2/pk-console-shared.c:523
 msgid "Cleaned up"
 msgstr "已清除"
 
 #. TRANSLATORS: The action of the package, in past tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:526
+#: ../lib/packagekit-glib2/pk-console-shared.c:527
 msgid "Obsoleted"
 msgstr "已廢棄"
 
 #. TRANSLATORS: The action of the package, in past tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:530
+#: ../lib/packagekit-glib2/pk-console-shared.c:531
 msgid "Reinstalled"
 msgstr "已重新安裝"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:548
+#: ../lib/packagekit-glib2/pk-console-shared.c:549
 msgid "Unknown role type"
 msgstr "未知的任務類型"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:552
+#: ../lib/packagekit-glib2/pk-console-shared.c:553
 msgid "Getting dependencies"
 msgstr "正在取得相容性"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:556
+#: ../lib/packagekit-glib2/pk-console-shared.c:557
 msgid "Getting update details"
 msgstr "正在取得更新詳細資料"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:560
+#: ../lib/packagekit-glib2/pk-console-shared.c:561
 msgid "Getting details"
 msgstr "正在取得詳細資料"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:564
+#: ../lib/packagekit-glib2/pk-console-shared.c:565
 msgid "Getting requires"
 msgstr "正在取得需求"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:568
+#: ../lib/packagekit-glib2/pk-console-shared.c:569
 msgid "Getting updates"
 msgstr "正在取得更新"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:572
+#: ../lib/packagekit-glib2/pk-console-shared.c:573
 msgid "Searching by details"
 msgstr "正在依詳細資料搜尋"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:576
+#: ../lib/packagekit-glib2/pk-console-shared.c:577
 msgid "Searching by file"
 msgstr "正在依檔案搜尋"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:580
+#: ../lib/packagekit-glib2/pk-console-shared.c:581
 msgid "Searching groups"
 msgstr "正在搜尋群組"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:584
+#: ../lib/packagekit-glib2/pk-console-shared.c:585
 msgid "Searching by name"
 msgstr "正在依名稱搜尋"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:596
+#: ../lib/packagekit-glib2/pk-console-shared.c:597
 msgid "Installing files"
 msgstr "正在安裝檔案"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:600
+#: ../lib/packagekit-glib2/pk-console-shared.c:601
 msgid "Refreshing cache"
 msgstr "正在重新整理快取"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:604
+#: ../lib/packagekit-glib2/pk-console-shared.c:605
 msgid "Updating packages"
 msgstr "正在更新套件"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:608
+#: ../lib/packagekit-glib2/pk-console-shared.c:609
 msgid "Updating system"
 msgstr "正在更新系統"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:612
+#: ../lib/packagekit-glib2/pk-console-shared.c:613
 msgid "Canceling"
 msgstr "正在取消"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:620
+#: ../lib/packagekit-glib2/pk-console-shared.c:621
 msgid "Getting repositories"
 msgstr "正在取得套件庫"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:624
+#: ../lib/packagekit-glib2/pk-console-shared.c:625
 msgid "Enabling repository"
 msgstr "正在啟用套件庫"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:628
+#: ../lib/packagekit-glib2/pk-console-shared.c:629
 msgid "Setting data"
 msgstr "正在設定資料"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:632
+#: ../lib/packagekit-glib2/pk-console-shared.c:633
 msgid "Resolving"
 msgstr "正在解析"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:636
+#: ../lib/packagekit-glib2/pk-console-shared.c:637
 msgid "Getting file list"
 msgstr "正在取得檔案清單"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:640
+#: ../lib/packagekit-glib2/pk-console-shared.c:641
 msgid "Getting provides"
 msgstr "正在取得提供什麼"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:644
+#: ../lib/packagekit-glib2/pk-console-shared.c:645
 msgid "Installing signature"
 msgstr "正在安裝簽章"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:648
+#: ../lib/packagekit-glib2/pk-console-shared.c:649
 msgid "Getting packages"
 msgstr "正在取得套件"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:652
+#: ../lib/packagekit-glib2/pk-console-shared.c:653
 msgid "Accepting EULA"
 msgstr "正在接受終端使用者授權同意書"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:660
+#: ../lib/packagekit-glib2/pk-console-shared.c:661
 msgid "Getting upgrades"
 msgstr "正在取得升級"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:664
+#: ../lib/packagekit-glib2/pk-console-shared.c:665
 msgid "Getting categories"
 msgstr "正在取得分類"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:668
+#: ../lib/packagekit-glib2/pk-console-shared.c:669
 msgid "Getting transactions"
 msgstr "正在取得處理事項"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:672
-#: ../lib/packagekit-glib2/pk-console-shared.c:676
+#: ../lib/packagekit-glib2/pk-console-shared.c:673
+#: ../lib/packagekit-glib2/pk-console-shared.c:677
 msgid "Simulating install"
 msgstr "正在模擬安裝"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:680
+#: ../lib/packagekit-glib2/pk-console-shared.c:681
 msgid "Simulating remove"
 msgstr "正在模擬移除"
 
 #. TRANSLATORS: The role of the transaction, in present tense
-#: ../lib/packagekit-glib2/pk-console-shared.c:684
+#: ../lib/packagekit-glib2/pk-console-shared.c:685
 msgid "Simulating update"
 msgstr "正在模擬更新"
 
@@ -1713,38 +1728,42 @@ msgid "Authentication is required to change software source parameters"
 msgstr "要更改軟體來源參數需先經過身份認證"
 
 #: ../policy/org.freedesktop.packagekit.policy.in.h:11
+msgid "Authentication is required to change the location used to decompress packages"
+msgstr "要變更用來解壓縮套件的位置需先通過身份認證"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:12
 msgid "Authentication is required to consider a key used for signing packages as trusted"
 msgstr "要將一個用來簽署套件的金鑰列為已信任的金鑰需先經過身份認證"
 
-#: ../policy/org.freedesktop.packagekit.policy.in.h:12
+#: ../policy/org.freedesktop.packagekit.policy.in.h:13
 msgid "Authentication is required to install a signed package"
 msgstr "要安裝一個已簽署的套件需先經過身份認證"
 
-#: ../policy/org.freedesktop.packagekit.policy.in.h:13
+#: ../policy/org.freedesktop.packagekit.policy.in.h:14
 msgid "Authentication is required to install an untrusted package"
 msgstr "要安裝未信任的套件需先經過身份認證"
 
-#: ../policy/org.freedesktop.packagekit.policy.in.h:14
+#: ../policy/org.freedesktop.packagekit.policy.in.h:15
 msgid "Authentication is required to refresh the system sources"
 msgstr "要重新整理系統來源需先經過身份認證"
 
-#: ../policy/org.freedesktop.packagekit.policy.in.h:15
+#: ../policy/org.freedesktop.packagekit.policy.in.h:16
 msgid "Authentication is required to reload the device with a new driver"
 msgstr "要以新驅動程式重新載入裝置的話需要通過認證"
 
-#: ../policy/org.freedesktop.packagekit.policy.in.h:16
+#: ../policy/org.freedesktop.packagekit.policy.in.h:17
 msgid "Authentication is required to remove packages"
 msgstr "要移除套件需先經過身份認證"
 
-#: ../policy/org.freedesktop.packagekit.policy.in.h:17
+#: ../policy/org.freedesktop.packagekit.policy.in.h:18
 msgid "Authentication is required to rollback a transaction"
 msgstr "要回復處理事項需要先經過身份認證"
 
-#: ../policy/org.freedesktop.packagekit.policy.in.h:18
+#: ../policy/org.freedesktop.packagekit.policy.in.h:19
 msgid "Authentication is required to set the network proxy used for downloading packages"
 msgstr "要設定用來下載套件的網路代理伺服器 需先經過身份認證"
 
-#: ../policy/org.freedesktop.packagekit.policy.in.h:19
+#: ../policy/org.freedesktop.packagekit.policy.in.h:20
 msgid "Authentication is required to update packages"
 msgstr "要更新套件需先經過身份認證"
 
@@ -1753,16 +1772,26 @@ msgstr "要更新套件需先經過身份認證"
 #. authentication, but a different user id needs the admin password
 #. to cancel another users task.
 #.
-#: ../policy/org.freedesktop.packagekit.policy.in.h:25
+#: ../policy/org.freedesktop.packagekit.policy.in.h:26
 msgid "Cancel foreign task"
 msgstr "取消外來的工作"
 
 #. SECURITY:
+#. - This is used when users want to install to a different prefix, for
+#. instance to a LTSP image or a virtual machine.
+#. - This could be used to overwrite files not owned by the user using
+#. a carefully created package file.
+#.
+#: ../policy/org.freedesktop.packagekit.policy.in.h:33
+msgid "Change location that packages are installed"
+msgstr "變更套件要安裝的位置"
+
+#. SECURITY:
 #. - Normal users require admin authentication to enable or disable
 #. software sources as this can be used to enable new updates or
 #. install different versions of software.
 #.
-#: ../policy/org.freedesktop.packagekit.policy.in.h:31
+#: ../policy/org.freedesktop.packagekit.policy.in.h:39
 msgid "Change software source parameters"
 msgstr "更改軟體來源參數"
 
@@ -1772,7 +1801,7 @@ msgstr "更改軟體來源參數"
 #. - Paranoid users (or parents!) can change this to 'auth_admin' or
 #. 'auth_admin_keep'.
 #.
-#: ../policy/org.freedesktop.packagekit.policy.in.h:38
+#: ../policy/org.freedesktop.packagekit.policy.in.h:46
 msgid "Install signed package"
 msgstr "安裝已簽署的套件"
 
@@ -1782,7 +1811,7 @@ msgstr "安裝已簽署的套件"
 #. password would be a massive security hole.
 #. - This is not retained as each package should be authenticated.
 #.
-#: ../policy/org.freedesktop.packagekit.policy.in.h:45
+#: ../policy/org.freedesktop.packagekit.policy.in.h:53
 msgid "Install untrusted local file"
 msgstr "安裝未信任的本地檔案"
 
@@ -1790,7 +1819,7 @@ msgstr "安裝未信任的本地檔案"
 #. - Normal users do not require admin authentication to refresh the
 #. cache, as this doesn't actually install or remove software.
 #.
-#: ../policy/org.freedesktop.packagekit.policy.in.h:50
+#: ../policy/org.freedesktop.packagekit.policy.in.h:58
 msgid "Refresh system sources"
 msgstr "重新整理系統來源"
 
@@ -1801,7 +1830,7 @@ msgstr "重新整理系統來源"
 #. try to rebind drivers in use, for instance security authentication
 #. devices.
 #.
-#: ../policy/org.freedesktop.packagekit.policy.in.h:58
+#: ../policy/org.freedesktop.packagekit.policy.in.h:66
 msgid "Reload a device"
 msgstr "重新載入裝置"
 
@@ -1814,7 +1843,7 @@ msgstr "重新載入裝置"
 #. be removed. If this is not possible, change this authentication to
 #. 'auth_admin'.
 #.
-#: ../policy/org.freedesktop.packagekit.policy.in.h:68
+#: ../policy/org.freedesktop.packagekit.policy.in.h:76
 msgid "Remove package"
 msgstr "移除套件"
 
@@ -1823,7 +1852,7 @@ msgstr "移除套件"
 #. as this will change a large number of packages, and could expose the
 #. system to previously patched security vulnerabilities.
 #.
-#: ../policy/org.freedesktop.packagekit.policy.in.h:74
+#: ../policy/org.freedesktop.packagekit.policy.in.h:82
 msgid "Rollback to a previous transaction"
 msgstr "回復至上一個處理事項"
 
@@ -1831,7 +1860,7 @@ msgstr "回復至上一個處理事項"
 #. - Normal users do not require admin authentication to set the proxy
 #. used for downloading packages.
 #.
-#: ../policy/org.freedesktop.packagekit.policy.in.h:79
+#: ../policy/org.freedesktop.packagekit.policy.in.h:87
 msgid "Set network proxy"
 msgstr "設定網路代理伺服器"
 
@@ -1841,7 +1870,7 @@ msgstr "設定網路代理伺服器"
 #. without a secure authentication.
 #. - This is not kept as each package should be authenticated.
 #.
-#: ../policy/org.freedesktop.packagekit.policy.in.h:86
+#: ../policy/org.freedesktop.packagekit.policy.in.h:94
 msgid "Trust a key used for signing packages"
 msgstr "信任一個用來簽署套件的金鑰"
 
@@ -1852,7 +1881,7 @@ msgstr "信任一個用來簽署套件的金鑰"
 #. - Changing this to anything other than 'yes' will break unattended
 #. updates.
 #.
-#: ../policy/org.freedesktop.packagekit.policy.in.h:94
+#: ../policy/org.freedesktop.packagekit.policy.in.h:102
 msgid "Update packages"
 msgstr "更新套件"
 
@@ -1869,7 +1898,7 @@ msgstr "這可能有兩種原因:"
 #. TRANSLATORS: only allowed to be owned by root
 #: ../src/pk-main.c:91
 msgid "The correct user is not launching the executable (usually root)"
-msgstr "正確的用戶(一般為 root)沒有執行可執行檔"
+msgstr "正確的使用者(一般為 root)沒有啟動可執行檔"
 
 #. TRANSLATORS: or we are installed in a prefix
 #: ../src/pk-main.c:93
@@ -1963,25 +1992,25 @@ msgid "Show debugging information for all files"
 msgstr "顯示供所有檔案用的額外除錯資訊"
 
 #. TRANSLATORS: a list of modules to debug
-#: ../src/egg-debug.c:459
+#: ../src/egg-debug.c:458
 msgid "Debug these specific modules"
 msgstr "針對這些指定的模組除錯"
 
 #. TRANSLATORS: a list of functions to debug
-#: ../src/egg-debug.c:462
+#: ../src/egg-debug.c:461
 msgid "Debug these specific functions"
 msgstr "針對這些指定的功能除錯"
 
 #. TRANSLATORS: save to a log
-#: ../src/egg-debug.c:465
+#: ../src/egg-debug.c:464
 msgid "Log debugging data to a file"
 msgstr "將除錯資料紀錄到檔案"
 
-#: ../src/egg-debug.c:469
+#: ../src/egg-debug.c:468
 msgid "Debugging Options"
 msgstr "除錯選項"
 
-#: ../src/egg-debug.c:469
+#: ../src/egg-debug.c:468
 msgid "Show debugging options"
 msgstr "顯示除錯選項"
 
@@ -1993,8 +2022,6 @@ msgstr "顯示除錯選項"
 #~ msgstr "請重新啟動應用程式因為該應用程式正被使用中。"
 #~ msgid "This tool could not install the files: %s"
 #~ msgstr "此工具無法安裝檔案:%s"
-#~ msgid "This tool could not remove %s: %s"
-#~ msgstr "此工具無法移除 %s:%s"
 #~ msgid "This tool could not remove the packages: %s"
 #~ msgstr "此工具無法移除套件:%s"
 #~ msgid "Proceed removing additional packages?"
commit 37c3a8fdd351b9141e1cadf876c743d10c14821a
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Fri May 7 02:18:17 2010 +1200

    pacman: fixed potential memory leak

diff --git a/backends/pacman/backend-install.c b/backends/pacman/backend-install.c
index 84f5086..53dfe8d 100644
--- a/backends/pacman/backend-install.c
+++ b/backends/pacman/backend-install.c
@@ -310,6 +310,8 @@ backend_update_packages_thread (PkBackend *backend)
 		g_object_unref (transaction);
 		transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_SYNC, dflags, asdeps);
 		pacman_list_free_full (asdeps, g_free);
+	} else if (asdeps != NULL) {
+		pacman_list_free_full (asdeps, g_free);
 	}
 
 	return backend_transaction_finished (backend, transaction);
commit 95a156fbc4176e77065f20206e618ba440c79275
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Fri May 7 01:52:45 2010 +1200

    pacman: Update status in pk-matrix.html

diff --git a/docs/html/pk-matrix.html b/docs/html/pk-matrix.html
index 7a97758..b923dab 100644
--- a/docs/html/pk-matrix.html
+++ b/docs/html/pk-matrix.html
@@ -27,6 +27,7 @@
 <td><center>box</center></td>
 <td><center>conary</center></td>
 <td><center>opkg</center></td>
+<td><center>pacman</center></td>
 <td><center>pisi</center></td>
 <td><center>poldek</center></td>
 <td><center>portage</center></td>
@@ -45,6 +46,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -63,6 +65,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -81,6 +84,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -99,6 +103,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -117,6 +122,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -135,6 +141,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -153,6 +160,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -171,6 +179,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -189,6 +198,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -207,6 +217,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -225,6 +236,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -243,6 +255,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -261,6 +274,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -279,6 +293,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -297,6 +312,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -315,6 +331,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -333,6 +350,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -351,6 +369,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -369,6 +388,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -387,6 +407,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -405,6 +426,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -423,6 +445,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -441,6 +464,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -459,6 +483,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -477,6 +502,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -495,6 +521,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -513,6 +540,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -531,6 +559,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -549,6 +578,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -567,6 +597,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -585,6 +616,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -607,6 +639,7 @@
 <td><center>box</center></td>
 <td><center>conary</center></td>
 <td><center>opkg</center></td>
+<td><center>pacman</center></td>
 <td><center>pisi</center></td>
 <td><center>poldek</center></td>
 <td><center>portage</center></td>
@@ -625,6 +658,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-good.png" alt="[yes]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -643,6 +677,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -661,6 +696,7 @@
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -679,6 +715,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -697,6 +734,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -715,6 +753,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -733,6 +772,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- poldek -->
 <td><img src="img/status-good.png" alt="[yes]"/></td><!-- portage -->
@@ -751,6 +791,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
@@ -769,6 +810,7 @@
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+<td><img src="img/status-bad.png" alt="[no]"/></td><!-- pacman -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- pisi -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- poldek -->
 <td><img src="img/status-bad.png" alt="[no]"/></td><!-- portage -->
commit bc4456e647667d72a90fec998f402bba16bb38a4
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Tue May 4 19:58:22 2010 +1200

    pacman: add support for updating packages

diff --git a/backends/pacman/Makefile.am b/backends/pacman/Makefile.am
index 7832008..e78a26d 100644
--- a/backends/pacman/Makefile.am
+++ b/backends/pacman/Makefile.am
@@ -2,12 +2,16 @@ PACMAN_CONFIG_FILE = $(confdir)/pacman.conf
 PACMAN_GROUP_LIST = $(confdir)/groups.list
 PACMAN_REPO_LIST = $(confdir)/repos.list
 PACMAN_REPO_LIST_HEADER = "\# Generated by $(PACKAGE_NAME) - DO NOT MODIFY"
+PACMAN_CACHE_PATH = $(localstatedir)/lib/pacman/sync
+PACMAN_PACKAGE_URL = "http://www.archlinux.org/packages/%s/%s/%s/"
 PACMAN_DEFAULT_PATH = "/bin:/usr/bin:/sbin:/usr/sbin"
 
 DEFS = -DPACMAN_CONFIG_FILE=\"$(PACMAN_CONFIG_FILE)\" \
        -DPACMAN_GROUP_LIST=\"$(PACMAN_GROUP_LIST)\" \
        -DPACMAN_REPO_LIST=\"$(PACMAN_REPO_LIST)\" \
        -DPACMAN_REPO_LIST_HEADER=\"$(PACMAN_REPO_LIST_HEADER)\" \
+       -DPACMAN_CACHE_PATH=\"$(PACMAN_CACHE_PATH)\" \
+       -DPACMAN_PACKAGE_URL=\"$(PACMAN_PACKAGE_URL)\" \
        -DPACMAN_DEFAULT_PATH=\"$(PACMAN_DEFAULT_PATH)\"
 
 confdir = $(PK_CONF_DIR)/pacman.d
@@ -27,7 +31,8 @@ libpk_backend_pacman_la_SOURCES = backend-depends.c \
                                   backend-remove.c \
                                   backend-repos.c \
                                   backend-search.c \
-                                  backend-transaction.c
+                                  backend-transaction.c \
+                                  backend-update.c
 libpk_backend_pacman_la_LIBADD = $(PK_PLUGIN_LIBS) \
                                  $(PACMAN_LIBS)
 libpk_backend_pacman_la_LDFLAGS = -module -avoid-version
diff --git a/backends/pacman/backend-install.c b/backends/pacman/backend-install.c
index a720922..84f5086 100644
--- a/backends/pacman/backend-install.c
+++ b/backends/pacman/backend-install.c
@@ -25,6 +25,7 @@
 #include "backend-error.h"
 #include "backend-pacman.h"
 #include "backend-packages.h"
+#include "backend-repos.h"
 #include "backend-transaction.h"
 #include "backend-install.h"
 
@@ -55,6 +56,9 @@ backend_transaction_packages (PkBackend *backend, PacmanTransaction *transaction
 {
 	const PacmanList *removes, *packages;
 
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (transaction != NULL);
+
 	/* emit packages that would have been installed */
 	for (packages = pacman_transaction_get_packages (transaction); packages != NULL; packages = pacman_list_next (packages)) {
 		PacmanPackage *package = (PacmanPackage *) pacman_list_get (packages);
@@ -65,14 +69,24 @@ backend_transaction_packages (PkBackend *backend, PacmanTransaction *transaction
 			if (backend_cancelled (backend)) {
 				break;
 			} else {
-				backend_package (backend, remove, PK_INFO_ENUM_REMOVING);
+				PkRoleEnum role = pk_backend_get_role (backend);
+				if (role == PK_ROLE_ENUM_SIMULATE_UPDATE_PACKAGES) {
+					backend_package (backend, remove, PK_INFO_ENUM_OBSOLETING);
+				} else {
+					backend_package (backend, remove, PK_INFO_ENUM_REMOVING);
+				}
 			}
 		}
 
 		if (backend_cancelled (backend)) {
 			break;
 		} else {
-			backend_package (backend, package, PK_INFO_ENUM_INSTALLING);
+			const gchar *name = pacman_package_get_name (package);
+			if (pacman_database_find_package (local_database, name) != NULL) {
+				backend_package (backend, package, PK_INFO_ENUM_UPDATING);
+			} else {
+				backend_package (backend, package, PK_INFO_ENUM_INSTALLING);
+			}
 		}
 	}
 }
@@ -217,6 +231,7 @@ backend_simulate_install_packages_thread (PkBackend *backend)
 		pacman_list_free_full (list, g_free);
 
 		if (transaction != NULL) {
+			/* emit packages that would have been installed or removed */
 			backend_transaction_packages (backend, transaction);
 		}
 	}
@@ -235,3 +250,91 @@ backend_simulate_install_packages (PkBackend *backend, gchar **package_ids)
 
 	backend_run (backend, PK_STATUS_ENUM_SETUP, backend_simulate_install_packages_thread);
 }
+
+static gboolean
+backend_update_packages_thread (PkBackend *backend)
+{
+	PacmanList *list, *asdeps = NULL;
+	/* FS#5331: use only_trusted */
+	PacmanTransaction *transaction = NULL;
+	PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE, dflags = PACMAN_TRANSACTION_FLAGS_INSTALL_IMPLICIT;
+
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	/* prepare the transaction */
+	list = backend_transaction_list_targets (backend);
+	if (list != NULL) {
+		transaction = backend_transaction_simulate (backend, PACMAN_TRANSACTION_SYNC, flags, list);
+		pacman_list_free_full (list, g_free);
+
+		if (transaction != NULL) {
+			const PacmanList *packages;
+
+			/* check for packages that should be installed as deps */
+			for (packages = pacman_transaction_get_packages (transaction); packages != NULL; packages = pacman_list_next (packages)) {
+				PacmanPackage *package = (PacmanPackage *) pacman_list_get (packages);
+				const PacmanList *removes = pacman_package_get_removes (package);
+
+				if (backend_cancelled (backend)) {
+					break;
+				} else if (removes != NULL) {
+					for (; removes != NULL; removes = pacman_list_next (removes)) {
+						PacmanPackage *remove = (PacmanPackage *) pacman_list_get (removes);
+
+						if (backend_cancelled (backend)) {
+							break;
+						} else if (pacman_package_was_explicitly_installed (remove)) {
+							break;
+						}
+					}
+
+					/* if all removes were installed as dependencies, do the same for this package */
+					if (removes == NULL) {
+						const gchar *name, *repo;
+						PacmanDatabase *database = pacman_package_get_database (package);
+
+						name = pacman_package_get_name (package);
+						repo = pacman_database_get_name (database);
+
+						asdeps = pacman_list_add (asdeps, g_strdup_printf ("%s/%s", repo, name));
+					}
+				}
+			}
+
+			transaction = backend_transaction_commit (backend, transaction);
+		}
+	}
+
+	/* mark replacements as deps if required */
+	if (transaction != NULL && asdeps != NULL) {
+		g_object_unref (transaction);
+		transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_SYNC, dflags, asdeps);
+		pacman_list_free_full (asdeps, g_free);
+	}
+
+	return backend_transaction_finished (backend, transaction);
+}
+
+/**
+ * backend_update_packages:
+ **/
+void
+backend_update_packages (PkBackend *backend, gboolean only_trusted, gchar **package_ids)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (package_ids != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_SETUP, backend_update_packages_thread);
+}
+
+/**
+ * backend_simulate_update_packages:
+ **/
+void
+backend_simulate_update_packages (PkBackend *backend, gchar **package_ids)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (package_ids != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_SETUP, backend_simulate_install_packages_thread);
+}
diff --git a/backends/pacman/backend-install.h b/backends/pacman/backend-install.h
index 287e65c..5b45b20 100644
--- a/backends/pacman/backend-install.h
+++ b/backends/pacman/backend-install.h
@@ -29,8 +29,15 @@ void	 backend_download_packages		(PkBackend	*backend,
 void	 backend_install_files			(PkBackend	*backend,
 						 gboolean	 only_trusted,
 						 gchar		**full_paths);
+
 void	 backend_install_packages		(PkBackend	*backend,
 						 gboolean	 only_trusted,
 						 gchar		**package_ids);
 void	 backend_simulate_install_packages	(PkBackend	*backend,
 						 gchar		**package_ids);
+
+void	 backend_update_packages		(PkBackend	*backend,
+						 gboolean	 only_trusted,
+						 gchar		**package_ids);
+void	 backend_simulate_update_packages	(PkBackend	*backend,
+						 gchar		**package_ids);
diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
index 8ac3ea1..a032403 100644
--- a/backends/pacman/backend-pacman.c
+++ b/backends/pacman/backend-pacman.c
@@ -30,6 +30,7 @@
 #include "backend-repos.h"
 #include "backend-search.h"
 #include "backend-transaction.h"
+#include "backend-update.h"
 #include "backend-pacman.h"
 
 PacmanManager *pacman = NULL;
@@ -227,12 +228,12 @@ PK_BACKEND_OPTIONS (
 	backend_get_packages,			/* get_packages */
 	backend_get_repo_list,			/* get_repo_list */
 	backend_get_requires,			/* get_requires */
-	NULL,					/* get_update_detail */
-	NULL,					/* get_updates */
+	backend_get_update_detail,		/* get_update_detail */
+	backend_get_updates,			/* get_updates */
 	backend_install_files,			/* install_files */
 	backend_install_packages,		/* install_packages */
 	NULL,					/* install_signature */
-	NULL,					/* refresh_cache */
+	backend_refresh_cache,			/* refresh_cache */
 	backend_remove_packages,		/* remove_packages */
 	backend_repo_enable,			/* repo_enable */
 	NULL,					/* repo_set_data */
@@ -242,11 +243,11 @@ PK_BACKEND_OPTIONS (
 	backend_search_files,			/* search_files */
 	backend_search_groups,			/* search_groups */
 	backend_search_names,			/* search_names */
-	NULL,					/* update_packages */
+	backend_update_packages,		/* update_packages */
 	NULL,					/* update_system */
 	backend_what_provides,			/* what_provides */
 	NULL,					/* simulate_install_files */
 	backend_simulate_install_packages,	/* simulate_install_packages */
 	backend_simulate_remove_packages,	/* simulate_remove_packages */
-	NULL					/* simulate_update_packages */
+	backend_simulate_update_packages	/* simulate_update_packages */
 );
diff --git a/backends/pacman/backend-transaction.c b/backends/pacman/backend-transaction.c
index f20070b..99e629a 100644
--- a/backends/pacman/backend-transaction.c
+++ b/backends/pacman/backend-transaction.c
@@ -442,12 +442,19 @@ PacmanTransaction *
 backend_transaction_run (PkBackend *backend, PacmanTransactionType type, guint32 flags, const PacmanList *targets)
 {
 	PacmanTransaction *transaction;
-	GError *error = NULL;
 
 	g_return_val_if_fail (backend != NULL, NULL);
 
 	transaction = backend_transaction_simulate (backend, type, flags, targets);
 
+	return backend_transaction_commit (backend, transaction);
+}
+
+PacmanTransaction *
+backend_transaction_commit (PkBackend *backend, PacmanTransaction *transaction)
+{
+	GError *error = NULL;
+
 	if (backend_cancelled (backend)) {
 		return transaction;
 	} else if (transaction != NULL) {
diff --git a/backends/pacman/backend-transaction.h b/backends/pacman/backend-transaction.h
index dd5c317..29dde88 100644
--- a/backends/pacman/backend-transaction.h
+++ b/backends/pacman/backend-transaction.h
@@ -45,5 +45,7 @@ PacmanTransaction	*backend_transaction_run	(PkBackend		*backend,
 							 guint32		 flags,
 							 const PacmanList	*targets);
 
+PacmanTransaction	*backend_transaction_commit	(PkBackend		*backend,
+							 PacmanTransaction	*transaction);
 gboolean		 backend_transaction_finished	(PkBackend		*backend,
 							 PacmanTransaction	*transaction);
diff --git a/backends/pacman/backend-update.c b/backends/pacman/backend-update.c
new file mode 100644
index 0000000..7ead935
--- /dev/null
+++ b/backends/pacman/backend-update.c
@@ -0,0 +1,389 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include <pacman.h>
+#include <glib/gstdio.h>
+#include "backend-error.h"
+#include "backend-pacman.h"
+#include "backend-packages.h"
+#include "backend-repos.h"
+#include "backend-transaction.h"
+#include "backend-update.h"
+
+static gchar *
+pacman_package_make_replaces_ids (PacmanPackage *package)
+{
+	const PacmanList *list;
+	GString *string = NULL;
+
+	g_return_val_if_fail (local_database != NULL, NULL);
+	g_return_val_if_fail (package != NULL, NULL);
+
+	/* make a list of the packages that package replaces */
+	for (list = pacman_package_get_replaces (package); list != NULL; list = pacman_list_next (list)) {
+		const gchar *name = pacman_list_get (list);
+		PacmanPackage *replaces = pacman_database_find_package (local_database, name);
+
+		if (replaces != NULL) {
+			gchar *package_id = pacman_package_make_id (replaces);
+			if (string == NULL) {
+				string = g_string_new (package_id);
+			} else {
+				g_string_append_printf (string, "&%s", package_id);
+			}
+			g_free (package_id);
+		}
+	}
+
+	if (string != NULL) {
+		return g_string_free (string, FALSE);
+	} else {
+		return NULL;
+	}
+}
+
+static gchar *
+pacman_package_make_vendor_url (PacmanPackage *package)
+{
+#ifdef PACMAN_PACKAGE_URL
+	const gchar *name, *arch, *repo, *url;
+#else
+	const gchar *url;
+#endif
+
+	g_return_val_if_fail (package != NULL, NULL);
+
+	/* grab the URL of the package... */
+	url = pacman_package_get_url (package);
+
+#ifdef PACMAN_PACKAGE_URL
+	/* ... and construct the distro URL if possible */
+	name = pacman_package_get_name (package);
+	arch = pacman_package_get_arch (package);
+	repo = pacman_database_get_name (pacman_package_get_database (package));
+
+	return g_strdup_printf ("%s;Package website;" PACMAN_PACKAGE_URL ";Distribution website", url, repo, arch, name);
+#else
+	return g_strdup_printf ("%s;Package website", url);
+#endif
+}
+
+static gint
+pacman_package_compare_pkgver (PacmanPackage *a, PacmanPackage *b)
+{
+	gint result;
+	const gchar *version_a, *version_b, *last_a, *last_b;
+	gchar *pkgver_a, *pkgver_b;
+
+	g_return_val_if_fail (a != NULL, (b == NULL) ? 0 : -1);
+	g_return_val_if_fail (b != NULL, 1);
+
+	version_a = pacman_package_get_version (a);
+	version_b = pacman_package_get_version (b);
+
+	last_a = strrchr (version_a, '-');
+	last_b = strrchr (version_b, '-');
+
+	if (last_a != NULL) {
+		pkgver_a = g_strndup (version_a, last_a - version_a);
+	} else {
+		pkgver_a = g_strdup (version_a);
+	}
+
+	if (last_b != NULL) {
+		pkgver_b = g_strndup (version_b, last_b - version_b);
+	} else {
+		pkgver_b = g_strdup (version_b);
+	}
+
+	result = pacman_package_compare_version (pkgver_a, pkgver_b);
+
+	g_free (pkgver_a);
+	g_free (pkgver_b);
+
+	return result;
+}
+
+static gboolean
+backend_get_update_detail_thread (PkBackend *backend)
+{
+	guint iterator;
+
+	gchar **package_ids;
+
+	g_return_val_if_fail (local_database != NULL, FALSE);
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	package_ids = pk_backend_get_strv (backend, "package_ids");
+
+	g_return_val_if_fail (package_ids != NULL, FALSE);
+
+	/* collect details about updates */
+	for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+		PacmanPackage *package, *upgrades;
+		PacmanDatabase *database;
+
+		gchar *upgrades_id, *replaces_ids, *vendor_url;
+		const gchar *message;
+
+		PkRestartEnum restart;
+		PkUpdateStateEnum state;
+
+		GTimeVal built = { 0 }, installed = { 0 };
+		gchar *issued, *updated;
+
+		if (backend_cancelled (backend)) {
+			break;
+		}
+
+		package = backend_get_package (backend, package_ids[iterator]);
+		if (package == NULL) {
+			backend_finished (backend);
+			return FALSE;
+		}
+
+		upgrades = pacman_database_find_package (local_database, pacman_package_get_name (package));
+		if (upgrades != NULL) {
+			upgrades_id = pacman_package_make_id (upgrades);
+			if (pacman_package_compare_pkgver (package, upgrades) != 0) {
+				message = "Update to newest upstream version";
+			} else {
+				message = "Update to newest release";
+			}
+		} else {
+			upgrades_id = NULL;
+			message = "Install as a replacement for an older package";
+		}
+
+		database = pacman_package_get_database (package);
+		replaces_ids = pacman_package_make_replaces_ids (package);
+		vendor_url = pacman_package_make_vendor_url (package);
+
+		if (g_str_has_prefix (pacman_package_get_name (package), "kernel")) {
+			restart = PK_RESTART_ENUM_SYSTEM;
+		} else {
+			restart = PK_RESTART_ENUM_NONE;
+		}
+
+		if (g_str_has_suffix (pacman_database_get_name (database), "testing")) {
+			state = PK_UPDATE_STATE_ENUM_TESTING;
+		} else {
+			state = PK_UPDATE_STATE_ENUM_STABLE;
+		}
+
+		built.tv_sec = pacman_package_get_build_date (package);
+		if (built.tv_sec > 0) {
+			issued = g_time_val_to_iso8601 (&built);
+		} else {
+			issued = NULL;
+		}
+
+		if (upgrades != NULL) {
+			installed.tv_sec = pacman_package_get_install_date (upgrades);
+			if (installed.tv_sec > 0) {
+				updated = g_time_val_to_iso8601 (&installed);
+			} else {
+				updated = NULL;
+			}
+		} else {
+			updated = NULL;
+		}
+
+		pk_backend_update_detail (backend, package_ids[iterator], upgrades_id, replaces_ids, vendor_url, NULL, NULL, restart, message, NULL, state, issued, updated);
+
+		g_free (issued);
+		g_free (updated);
+
+		g_free (vendor_url);
+		g_free (replaces_ids);
+		g_free (upgrades_id);
+	}
+
+	backend_finished (backend);
+	return TRUE;
+}
+
+/**
+ * backend_get_update_detail:
+ **/
+void
+backend_get_update_detail (PkBackend *backend, gchar **package_ids)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (package_ids != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_update_detail_thread);
+}
+
+static gboolean
+pacman_package_should_ignore (PacmanPackage *package)
+{
+	const PacmanList *groups;
+	const PacmanList *ignore_packages;
+	const PacmanList *ignore_groups;
+
+	g_return_val_if_fail (pacman != NULL, TRUE);
+	g_return_val_if_fail (package != NULL, TRUE);
+
+	ignore_packages = pacman_manager_get_ignore_packages (pacman);
+
+	/* check if package is an IgnorePkg */
+	if (pacman_list_find_string (ignore_packages, pacman_package_get_name (package)) != NULL) {
+		return TRUE;
+	}
+
+	ignore_groups = pacman_manager_get_ignore_groups (pacman);
+
+	/* check if package is in an IgnoreGroup */
+	for (groups = pacman_package_get_groups (package); groups != NULL; groups = pacman_list_next (groups)) {
+		if (pacman_list_find_string (ignore_groups, (const gchar *) pacman_list_get (groups)) != NULL) {
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+static gboolean
+pacman_package_should_sync_first (PacmanPackage *package)
+{
+	const PacmanList *sync_firsts;
+
+	g_return_val_if_fail (pacman != NULL, FALSE);
+	g_return_val_if_fail (package != NULL, FALSE);
+
+	sync_firsts = pacman_manager_get_sync_firsts (pacman);
+
+	/* check if package is in SyncFirst */
+	if (pacman_list_find_string (sync_firsts, pacman_package_get_name (package)) != NULL) {
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static gboolean
+backend_get_updates_thread (PkBackend *backend)
+{
+	struct stat cache;
+	time_t one_hour_ago;
+
+	PacmanTransaction *transaction = NULL;
+	PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE;
+
+	const PacmanList *packages;
+
+	g_return_val_if_fail (local_database != NULL, FALSE);
+	g_return_val_if_fail (pacman != NULL, FALSE);
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	time (&one_hour_ago);
+	one_hour_ago -= 60 * 60;
+
+	/* refresh databases if they are older than an hour */
+	if (g_stat (PACMAN_CACHE_PATH, &cache) < 0 || cache.st_mtime < one_hour_ago) {
+		transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_UPDATE, flags, NULL);
+
+		if (transaction != NULL) {
+			g_object_unref (transaction);
+		} else {
+			backend_finished (backend);
+			return FALSE;
+		}
+	} else {
+		egg_debug ("pacman: databases have been refreshed recently");
+	}
+
+	/* find outdated and replacement packages */
+	for (packages = pacman_database_get_packages (local_database); packages != NULL; packages = pacman_list_next (packages)) {
+		PacmanPackage *package = (PacmanPackage *) pacman_list_get (packages);
+		PacmanPackage *upgrade = pacman_package_find_upgrade (package, pacman_manager_get_sync_databases (pacman));
+
+		if (backend_cancelled (backend)) {
+			break;
+		}
+
+		if (upgrade != NULL) {
+			PkInfoEnum info;
+
+			if (pacman_package_should_ignore (upgrade)) {
+				info = PK_INFO_ENUM_BLOCKED;
+			} else if (pacman_package_should_sync_first (upgrade)) {
+				info = PK_INFO_ENUM_IMPORTANT;
+			} else {
+				info = PK_INFO_ENUM_NORMAL;
+			}
+
+			backend_package (backend, upgrade, info);
+		}
+	}
+
+	backend_finished (backend);
+	return TRUE;
+}
+
+/**
+ * backend_get_updates:
+ **/
+void
+backend_get_updates (PkBackend *backend, PkBitfield filters)
+{
+	g_return_if_fail (backend != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_updates_thread);
+}
+
+static gboolean
+backend_refresh_cache_thread (PkBackend *backend)
+{
+	gboolean force;
+
+	PacmanTransaction *transaction = NULL;
+	PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE;
+
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	force = pk_backend_get_bool (backend, "force");
+
+	/* download databases even if they are older than current */
+	if (force) {
+		flags |= PACMAN_TRANSACTION_FLAGS_UPDATE_ALLOW_DOWNGRADE;
+	}
+
+	/* run the transaction */
+	transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_UPDATE, flags, NULL);
+
+	return backend_transaction_finished (backend, transaction);
+}
+
+/**
+ * backend_refresh_cache:
+ **/
+void
+backend_refresh_cache (PkBackend *backend, gboolean force)
+{
+	g_return_if_fail (backend != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_SETUP, backend_refresh_cache_thread);
+}
diff --git a/backends/pacman/backend-update.h b/backends/pacman/backend-update.h
new file mode 100644
index 0000000..2a8bf02
--- /dev/null
+++ b/backends/pacman/backend-update.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pk-backend.h>
+
+void	 backend_get_update_detail		(PkBackend	*backend,
+						 gchar		**package_ids);
+void	 backend_get_updates			(PkBackend	*backend,
+						 PkBitfield	 filters);
+void	 backend_refresh_cache			(PkBackend	*backend,
+						 gboolean	 force);
commit 7c323b55f520a1c26b14720b2629191f5d6fbd85
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Sun May 2 19:36:02 2010 +1200

    pacman: add support for removing packages

diff --git a/backends/pacman/Makefile.am b/backends/pacman/Makefile.am
index 275e05c..7832008 100644
--- a/backends/pacman/Makefile.am
+++ b/backends/pacman/Makefile.am
@@ -24,6 +24,7 @@ libpk_backend_pacman_la_SOURCES = backend-depends.c \
                                   backend-install.c \
                                   backend-packages.c \
                                   backend-pacman.c \
+                                  backend-remove.c \
                                   backend-repos.c \
                                   backend-search.c \
                                   backend-transaction.c
diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
index fc29a6a..8ac3ea1 100644
--- a/backends/pacman/backend-pacman.c
+++ b/backends/pacman/backend-pacman.c
@@ -26,6 +26,7 @@
 #include "backend-groups.h"
 #include "backend-install.h"
 #include "backend-packages.h"
+#include "backend-remove.h"
 #include "backend-repos.h"
 #include "backend-search.h"
 #include "backend-transaction.h"
@@ -232,7 +233,7 @@ PK_BACKEND_OPTIONS (
 	backend_install_packages,		/* install_packages */
 	NULL,					/* install_signature */
 	NULL,					/* refresh_cache */
-	NULL,					/* remove_packages */
+	backend_remove_packages,		/* remove_packages */
 	backend_repo_enable,			/* repo_enable */
 	NULL,					/* repo_set_data */
 	backend_resolve,			/* resolve */
@@ -246,6 +247,6 @@ PK_BACKEND_OPTIONS (
 	backend_what_provides,			/* what_provides */
 	NULL,					/* simulate_install_files */
 	backend_simulate_install_packages,	/* simulate_install_packages */
-	NULL,					/* simulate_remove_packages */
+	backend_simulate_remove_packages,	/* simulate_remove_packages */
 	NULL					/* simulate_update_packages */
 );
diff --git a/backends/pacman/backend-remove.c b/backends/pacman/backend-remove.c
new file mode 100644
index 0000000..3ff47e1
--- /dev/null
+++ b/backends/pacman/backend-remove.c
@@ -0,0 +1,151 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pacman.h>
+#include "backend-error.h"
+#include "backend-packages.h"
+#include "backend-pacman.h"
+#include "backend-transaction.h"
+#include "backend-remove.h"
+
+static PacmanList *
+backend_remove_list_targets (PkBackend *backend)
+{
+	gchar **package_ids;
+	guint iterator;
+	PacmanList *list = NULL;
+
+	g_return_val_if_fail (backend != NULL, NULL);
+
+	package_ids = pk_backend_get_strv (backend, "package_ids");
+
+	g_return_val_if_fail (package_ids != NULL, NULL);
+
+	for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+		gchar **package_id_data = pk_package_id_split (package_ids[iterator]);
+		list = pacman_list_add (list, g_strdup (package_id_data[PK_PACKAGE_ID_NAME]));
+		g_strfreev (package_id_data);
+	}
+
+	return list;
+}
+
+static gboolean
+backend_remove_packages_thread (PkBackend *backend)
+{
+	PacmanList *list;
+	gboolean allow_deps;
+	gboolean autoremove;
+
+	PacmanTransaction *transaction = NULL;
+	PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE;
+
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	allow_deps = pk_backend_get_bool (backend, "allow_deps");
+	autoremove = pk_backend_get_bool (backend, "autoremove");
+
+	/* remove packages that depend on those to be removed */
+	if (allow_deps) {
+		flags |= PACMAN_TRANSACTION_FLAGS_REMOVE_CASCADE;
+	}
+	/* remove unneeded packages that were required by those to be removed */
+	if (autoremove) {
+		flags |= PACMAN_TRANSACTION_FLAGS_REMOVE_RECURSIVE;
+	}
+
+	/* run the transaction */
+	list = backend_remove_list_targets (backend);
+	if (list != NULL) {
+		transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_REMOVE, flags, list);
+		pacman_list_free_full (list, g_free);
+	}
+
+	return backend_transaction_finished (backend, transaction);
+}
+
+/**
+ * backend_remove_packages:
+ **/
+void
+backend_remove_packages (PkBackend *backend, gchar **package_ids, gboolean allow_deps, gboolean autoremove)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (package_ids != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_SETUP, backend_remove_packages_thread);
+}
+
+static gboolean
+backend_simulate_remove_packages_thread (PkBackend *backend)
+{
+	PacmanList *list;
+	gboolean autoremove;
+
+	PacmanTransaction *transaction = NULL;
+	PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_REMOVE_CASCADE;
+
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	autoremove = pk_backend_get_bool (backend, "autoremove");
+
+	/* remove unneeded packages that were required by those to be removed */
+	if (autoremove) {
+		flags |= PACMAN_TRANSACTION_FLAGS_REMOVE_RECURSIVE;
+	}
+
+	/* prepare the transaction */
+	list = backend_remove_list_targets (backend);
+	if (list != NULL) {
+		transaction = backend_transaction_simulate (backend, PACMAN_TRANSACTION_REMOVE, flags, list);
+		pacman_list_free_full (list, g_free);
+
+		if (transaction != NULL) {
+			const PacmanList *packages;
+
+			/* emit packages that would have been removed */
+			for (packages = pacman_transaction_get_packages (transaction); packages != NULL; packages = pacman_list_next (packages)) {
+				PacmanPackage *package = (PacmanPackage *) pacman_list_get (packages);
+				if (backend_cancelled (backend)) {
+					break;
+				} else {
+					backend_package (backend, package, PK_INFO_ENUM_REMOVING);
+				}
+			}
+		}
+	}
+
+	return backend_transaction_finished (backend, transaction);
+}
+
+/**
+ * backend_simulate_remove_packages:
+ **/
+void
+backend_simulate_remove_packages (PkBackend *backend, gchar **package_ids, gboolean autoremove)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (package_ids != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_SETUP, backend_simulate_remove_packages_thread);
+}
diff --git a/backends/pacman/backend-remove.h b/backends/pacman/backend-remove.h
new file mode 100644
index 0000000..90f0374
--- /dev/null
+++ b/backends/pacman/backend-remove.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pk-backend.h>
+
+void	 backend_remove_packages		(PkBackend	*backend,
+						 gchar		**package_ids,
+						 gboolean	 allow_deps,
+						 gboolean	 autoremove);
+void	 backend_simulate_remove_packages	(PkBackend	*backend,
+						 gchar		**package_ids,
+						 gboolean	 autoremove);
commit c637c5910157a556ba3165b94d1e5708040dc7cf
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Sun May 2 19:25:07 2010 +1200

    pacman: add support for installing packages

diff --git a/backends/pacman/Makefile.am b/backends/pacman/Makefile.am
index 7c93e57..275e05c 100644
--- a/backends/pacman/Makefile.am
+++ b/backends/pacman/Makefile.am
@@ -21,6 +21,7 @@ plugin_LTLIBRARIES = libpk_backend_pacman.la
 libpk_backend_pacman_la_SOURCES = backend-depends.c \
                                   backend-error.c \
                                   backend-groups.c \
+                                  backend-install.c \
                                   backend-packages.c \
                                   backend-pacman.c \
                                   backend-repos.c \
diff --git a/backends/pacman/backend-install.c b/backends/pacman/backend-install.c
new file mode 100644
index 0000000..a720922
--- /dev/null
+++ b/backends/pacman/backend-install.c
@@ -0,0 +1,237 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pacman.h>
+#include "backend-error.h"
+#include "backend-pacman.h"
+#include "backend-packages.h"
+#include "backend-transaction.h"
+#include "backend-install.h"
+
+static PacmanList *
+backend_transaction_list_targets (PkBackend *backend)
+{
+	gchar **package_ids;
+	guint iterator;
+	PacmanList *list = NULL;
+
+	g_return_val_if_fail (backend != NULL, NULL);
+
+	package_ids = pk_backend_get_strv (backend, "package_ids");
+
+	g_return_val_if_fail (package_ids != NULL, NULL);
+
+	for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+		gchar **package_id_data = pk_package_id_split (package_ids[iterator]);
+		list = pacman_list_add (list, g_strdup_printf ("%s/%s", package_id_data[PK_PACKAGE_ID_DATA], package_id_data[PK_PACKAGE_ID_NAME]));
+		g_strfreev (package_id_data);
+	}
+
+	return list;
+}
+
+static void
+backend_transaction_packages (PkBackend *backend, PacmanTransaction *transaction)
+{
+	const PacmanList *removes, *packages;
+
+	/* emit packages that would have been installed */
+	for (packages = pacman_transaction_get_packages (transaction); packages != NULL; packages = pacman_list_next (packages)) {
+		PacmanPackage *package = (PacmanPackage *) pacman_list_get (packages);
+
+		for (removes = pacman_package_get_removes (package); removes != NULL; removes = pacman_list_next (removes)) {
+			PacmanPackage *remove = (PacmanPackage *) pacman_list_get (removes);
+
+			if (backend_cancelled (backend)) {
+				break;
+			} else {
+				backend_package (backend, remove, PK_INFO_ENUM_REMOVING);
+			}
+		}
+
+		if (backend_cancelled (backend)) {
+			break;
+		} else {
+			backend_package (backend, package, PK_INFO_ENUM_INSTALLING);
+		}
+	}
+}
+
+static gboolean
+backend_download_packages_thread (PkBackend *backend)
+{
+	PacmanList *list;
+	PacmanList *cache_paths;
+	const gchar *directory;
+
+	PacmanTransaction *transaction = NULL;
+	PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_IGNORE_DEPENDENCIES |
+				       PACMAN_TRANSACTION_FLAGS_IGNORE_DEPENDENCY_CONFLICTS |
+				       PACMAN_TRANSACTION_FLAGS_SYNC_DOWNLOAD_ONLY;
+
+	g_return_val_if_fail (pacman != NULL, FALSE);
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	directory = pk_backend_get_string (backend, "directory");
+
+	g_return_val_if_fail (directory != NULL, FALSE);
+
+	/* download files to a PackageKit directory */
+	cache_paths = pacman_list_strdup (pacman_manager_get_cache_paths (pacman));
+	pacman_manager_set_cache_paths (pacman, NULL);
+	pacman_manager_add_cache_path (pacman, directory);
+
+	/* run the transaction */
+	list = backend_transaction_list_targets (backend);
+	if (list != NULL) {
+		transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_SYNC, flags, list);
+		pacman_list_free_full (list, g_free);
+	}
+
+	pacman_manager_set_cache_paths (pacman, cache_paths);
+	pacman_list_free_full (cache_paths, g_free);
+	return backend_transaction_finished (backend, transaction);
+}
+
+/**
+ * backend_download_packages:
+ **/
+void
+backend_download_packages (PkBackend *backend, gchar **package_ids, const gchar *directory)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (package_ids != NULL);
+	g_return_if_fail (directory != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_SETUP, backend_download_packages_thread);
+}
+
+static gboolean
+backend_install_files_thread (PkBackend *backend)
+{
+	guint iterator;
+	PacmanList *list = NULL;
+
+	/* FS#5331: use only_trusted */
+	gchar **full_paths;
+
+	PacmanTransaction *transaction = NULL;
+	PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE;
+
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	full_paths = pk_backend_get_strv (backend, "full_paths");
+
+	g_return_val_if_fail (full_paths != NULL, FALSE);
+
+	/* run the transaction */
+	for (iterator = 0; full_paths[iterator] != NULL; ++iterator) {
+		list = pacman_list_add (list, full_paths[iterator]);
+	}
+	if (list != NULL) {
+		transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_INSTALL, flags, list);
+		pacman_list_free (list);
+	}
+
+	return backend_transaction_finished (backend, transaction);
+}
+
+/**
+ * backend_install_files:
+ **/
+void
+backend_install_files (PkBackend *backend, gboolean only_trusted, gchar	**full_paths)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (full_paths != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_SETUP, backend_install_files_thread);
+}
+
+static gboolean
+backend_install_packages_thread (PkBackend *backend)
+{
+	PacmanList *list;
+	/* FS#5331: use only_trusted */
+	PacmanTransaction *transaction = NULL;
+	PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE;
+
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	/* run the transaction */
+	list = backend_transaction_list_targets (backend);
+	if (list != NULL) {
+		transaction = backend_transaction_run (backend, PACMAN_TRANSACTION_SYNC, flags, list);
+		pacman_list_free_full (list, g_free);
+	}
+
+	return backend_transaction_finished (backend, transaction);
+}
+
+/**
+ * backend_install_packages:
+ **/
+void
+backend_install_packages (PkBackend *backend, gboolean only_trusted, gchar **package_ids)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (package_ids != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_SETUP, backend_install_packages_thread);
+}
+
+static gboolean
+backend_simulate_install_packages_thread (PkBackend *backend)
+{
+	PacmanList *list;
+
+	PacmanTransaction *transaction = NULL;
+	PacmanTransactionFlags flags = PACMAN_TRANSACTION_FLAGS_NONE;
+
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	/* prepare the transaction */
+	list = backend_transaction_list_targets (backend);
+	if (list != NULL) {
+		transaction = backend_transaction_simulate (backend, PACMAN_TRANSACTION_SYNC, flags, list);
+		pacman_list_free_full (list, g_free);
+
+		if (transaction != NULL) {
+			backend_transaction_packages (backend, transaction);
+		}
+	}
+
+	return backend_transaction_finished (backend, transaction);
+}
+
+/**
+ * backend_simulate_install_packages:
+ **/
+void
+backend_simulate_install_packages (PkBackend *backend, gchar **package_ids)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (package_ids != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_SETUP, backend_simulate_install_packages_thread);
+}
diff --git a/backends/pacman/backend-install.h b/backends/pacman/backend-install.h
new file mode 100644
index 0000000..287e65c
--- /dev/null
+++ b/backends/pacman/backend-install.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pk-backend.h>
+
+void	 backend_download_packages		(PkBackend	*backend,
+						 gchar		**package_ids,
+						 const gchar	*directory);
+void	 backend_install_files			(PkBackend	*backend,
+						 gboolean	 only_trusted,
+						 gchar		**full_paths);
+void	 backend_install_packages		(PkBackend	*backend,
+						 gboolean	 only_trusted,
+						 gchar		**package_ids);
+void	 backend_simulate_install_packages	(PkBackend	*backend,
+						 gchar		**package_ids);
diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
index 71b3de4..fc29a6a 100644
--- a/backends/pacman/backend-pacman.c
+++ b/backends/pacman/backend-pacman.c
@@ -24,6 +24,7 @@
 #include "backend-depends.h"
 #include "backend-error.h"
 #include "backend-groups.h"
+#include "backend-install.h"
 #include "backend-packages.h"
 #include "backend-repos.h"
 #include "backend-search.h"
@@ -216,7 +217,7 @@ PK_BACKEND_OPTIONS (
 	NULL,					/* get_roles */
 	backend_get_mime_types,			/* get_mime_types */
 	backend_cancel,				/* cancel */
-	NULL,					/* download_packages */
+	backend_download_packages,		/* download_packages */
 	NULL,					/* get_categories */
 	backend_get_depends,			/* get_depends */
 	backend_get_details,			/* get_details */
@@ -227,8 +228,8 @@ PK_BACKEND_OPTIONS (
 	backend_get_requires,			/* get_requires */
 	NULL,					/* get_update_detail */
 	NULL,					/* get_updates */
-	NULL,					/* install_files */
-	NULL,					/* install_packages */
+	backend_install_files,			/* install_files */
+	backend_install_packages,		/* install_packages */
 	NULL,					/* install_signature */
 	NULL,					/* refresh_cache */
 	NULL,					/* remove_packages */
@@ -244,7 +245,7 @@ PK_BACKEND_OPTIONS (
 	NULL,					/* update_system */
 	backend_what_provides,			/* what_provides */
 	NULL,					/* simulate_install_files */
-	NULL,					/* simulate_install_packages */
+	backend_simulate_install_packages,	/* simulate_install_packages */
 	NULL,					/* simulate_remove_packages */
 	NULL					/* simulate_update_packages */
 );
commit fc611ca97bd2e80a940b681536e06c7c795fd4d8
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Sun May 2 18:23:48 2010 +1200

    pacman: add basic transaction infrastructure

diff --git a/backends/pacman/Makefile.am b/backends/pacman/Makefile.am
index e5a8ded..7c93e57 100644
--- a/backends/pacman/Makefile.am
+++ b/backends/pacman/Makefile.am
@@ -24,7 +24,8 @@ libpk_backend_pacman_la_SOURCES = backend-depends.c \
                                   backend-packages.c \
                                   backend-pacman.c \
                                   backend-repos.c \
-                                  backend-search.c
+                                  backend-search.c \
+                                  backend-transaction.c
 libpk_backend_pacman_la_LIBADD = $(PK_PLUGIN_LIBS) \
                                  $(PACMAN_LIBS)
 libpk_backend_pacman_la_LDFLAGS = -module -avoid-version
diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
index ff28575..71b3de4 100644
--- a/backends/pacman/backend-pacman.c
+++ b/backends/pacman/backend-pacman.c
@@ -27,6 +27,7 @@
 #include "backend-packages.h"
 #include "backend-repos.h"
 #include "backend-search.h"
+#include "backend-transaction.h"
 #include "backend-pacman.h"
 
 PacmanManager *pacman = NULL;
@@ -96,6 +97,13 @@ backend_initialize (PkBackend *backend)
 		g_error_free (error);
 		return;
 	}
+
+	/* setup better download progress reporting */
+	if (!backend_initialize_downloads (backend, &error)) {
+		egg_error ("pacman: %s", error->message);
+		g_error_free (error);
+		return;
+	}
 }
 
 /**
@@ -108,6 +116,7 @@ backend_destroy (PkBackend *backend)
 
 	egg_debug ("pacman: cleaning up");
 
+	backend_destroy_downloads (backend);
 	backend_destroy_groups (backend);
 	backend_destroy_databases (backend);
 
diff --git a/backends/pacman/backend-transaction.c b/backends/pacman/backend-transaction.c
new file mode 100644
index 0000000..f20070b
--- /dev/null
+++ b/backends/pacman/backend-transaction.c
@@ -0,0 +1,480 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include "backend-error.h"
+#include "backend-packages.h"
+#include "backend-pacman.h"
+#include "backend-repos.h"
+#include "backend-transaction.h"
+
+typedef struct {
+	guint complete;
+	guint total;
+
+	PacmanPackage *package;
+	GString *files;
+} BackendDownloadData;
+
+static GHashTable *downloads = NULL;
+
+gboolean
+backend_initialize_downloads (PkBackend *backend, GError **error)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	downloads = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+	return TRUE;
+}
+
+void
+backend_destroy_downloads (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+
+	if (downloads != NULL) {
+		g_hash_table_unref (downloads);
+	}
+}
+
+static void
+transaction_download_end (PacmanTransaction *transaction, BackendDownloadData *download, PkBackend *backend) {
+	g_return_if_fail (transaction != NULL);
+	g_return_if_fail (download != NULL);
+	g_return_if_fail (backend != NULL);
+
+	/* emit the finished signal for the old package */
+	backend_package (backend, download->package, PK_INFO_ENUM_FINISHED);
+
+	/* emit the list of files downloaded for DownloadPackages */
+	if (download->files != NULL) {
+		gchar *package_id, *files;
+
+		package_id = pacman_package_make_id (download->package);
+		files = g_string_free (download->files, FALSE);
+
+		pk_backend_files (backend, package_id, files);
+
+		g_free (package_id);
+		g_free (files);
+	}
+
+	download->package = NULL;
+	download->files = NULL;
+}
+
+static gchar *
+backend_filename_make_path (PkBackend *backend, const gchar *filename)
+{
+	const gchar *directory;
+
+	g_return_val_if_fail (backend != NULL, NULL);
+	g_return_val_if_fail (filename != NULL, NULL);
+
+	directory = pk_backend_get_string (backend, "directory");
+
+	g_return_val_if_fail (directory != NULL, NULL);
+
+	return g_build_filename (directory, filename, NULL);
+}
+
+static void
+transaction_download_start (PacmanTransaction *transaction, BackendDownloadData *download, const gchar *filename, PkBackend *backend)
+{
+	const PacmanList *packages;
+
+	g_return_if_fail (transaction != NULL);
+	g_return_if_fail (download != NULL);
+	g_return_if_fail (filename != NULL);
+	g_return_if_fail (backend != NULL);
+
+	/* continue or finish downloading the old package */
+	if (download->package != NULL) {
+		if (pacman_package_has_filename (download->package, filename)) {
+			if (download->files != NULL) {
+				gchar *path = backend_filename_make_path (backend, filename);
+				g_string_append_printf (download->files, ";%s", path);
+				g_free (path);
+			}
+			return;
+		} else {
+			transaction_download_end (transaction, download, backend);
+		}
+	}
+
+	/* find a new package for the current file */
+	for (packages = pacman_transaction_get_packages (transaction); packages != NULL; packages = pacman_list_next (packages)) {
+		PacmanPackage *package = (PacmanPackage *) pacman_list_get (packages);
+		if (pacman_package_has_filename (package, filename)) {
+			download->package = package;
+			break;
+		}
+	}
+
+	/* emit the downloading signal and start collecting files for the new package */
+	if (download->package != NULL) {
+		backend_package (backend, download->package, PK_INFO_ENUM_DOWNLOADING);
+
+		/* only emit files downloaded for DownloadPackages */
+		if (pk_backend_get_role (backend) == PK_ROLE_ENUM_DOWNLOAD_PACKAGES) {
+			gchar *path = backend_filename_make_path (backend, filename);
+			download->files = g_string_new (path);
+			g_free (path);
+		}
+	}
+}
+
+static void
+transaction_download_cb (PacmanTransaction *transaction, const gchar *filename, guint complete, guint total, gpointer user_data)
+{
+	BackendDownloadData *download;
+
+	g_return_if_fail (pacman != NULL);
+	g_return_if_fail (transaction != NULL);
+	g_return_if_fail (user_data != NULL);
+
+	download = (BackendDownloadData *) g_hash_table_lookup (downloads, transaction);
+
+	if (filename == NULL) {
+		if (download == NULL) {
+			/* start a new download */
+			download = g_new0 (BackendDownloadData, 1);
+			download->complete = complete;
+			download->total = total;
+			g_hash_table_insert (downloads, transaction, download);
+		} else {
+			/* finish the current download */
+			if (download->package != NULL) {
+				transaction_download_end (transaction, download, (PkBackend *) user_data);
+			}
+			g_hash_table_remove (downloads, transaction);
+		}
+	} else {
+		guint percentage = 100, sub_percentage = 100;
+
+		g_return_if_fail (download != NULL);
+
+		if (total > 0) {
+			sub_percentage = complete * 100 / total;
+		}
+
+		if (strstr (filename, ".db.tar.") != NULL) {
+			const PacmanList *databases = pacman_manager_get_sync_databases (pacman);
+			guint database_total = pacman_list_length (databases);
+
+			/* report download progress for databases */
+			if (database_total > 0) {
+				percentage = (sub_percentage + download->complete * 100) / database_total;
+			}
+
+			if (complete == 0) {
+				egg_debug ("pacman: downloading database %s", filename);
+				pk_backend_set_status ((PkBackend *) user_data, PK_STATUS_ENUM_REFRESH_CACHE);
+			}
+
+			if (complete == total) {
+				download->complete += 1;
+			}
+		} else {
+			/* report download progress for package or delta files */
+			if (download->total > 0) {
+				percentage = (download->complete + complete) * 100 / download->total;
+			}
+
+			if (complete == 0) {
+				egg_debug ("pacman: downloading package %s", filename);
+				pk_backend_set_status ((PkBackend *) user_data, PK_STATUS_ENUM_DOWNLOAD);
+				transaction_download_start (transaction, download, filename, (PkBackend *) user_data);
+			}
+
+			if (complete == total) {
+				download->complete += complete;
+			}
+		}
+
+		pk_backend_set_sub_percentage ((PkBackend *) user_data, sub_percentage);
+		pk_backend_set_percentage ((PkBackend *) user_data, percentage);
+	}
+}
+
+static void
+transaction_progress_cb (PacmanTransaction *transaction, PacmanTransactionProgress type, const gchar *target, guint percent, guint current, guint targets, gpointer user_data)
+{
+	g_return_if_fail (transaction != NULL);
+	g_return_if_fail (user_data != NULL);
+
+	g_return_if_fail (percent >= 0);
+	g_return_if_fail (percent <= 100);
+	g_return_if_fail (current >= 1);
+	g_return_if_fail (current <= targets);
+
+	/* update transaction progress */
+	switch (type) {
+		case PACMAN_TRANSACTION_PROGRESS_INSTALL:
+		case PACMAN_TRANSACTION_PROGRESS_UPGRADE:
+		case PACMAN_TRANSACTION_PROGRESS_REMOVE:
+		case PACMAN_TRANSACTION_PROGRESS_FILE_CONFLICT_CHECK:
+		{
+			egg_debug ("pacman: progress for %s (%u of %u) is %u%%", target, current, targets, percent);
+			pk_backend_set_sub_percentage ((PkBackend *) user_data, percent);
+			pk_backend_set_percentage ((PkBackend *) user_data, (percent + (current - 1) * 100) / targets);
+			break;
+		}
+		default:
+			egg_debug ("pacman: progress of type %d (%u of %u) is %u%%", type, current, targets, percent);
+			break;
+	}
+}
+
+static gboolean
+transaction_question_cb (PacmanTransaction *transaction, PacmanTransactionQuestion question, const gchar *message, gpointer user_data)
+{
+	g_return_val_if_fail (transaction != NULL, FALSE);
+	g_return_val_if_fail (user_data != NULL, FALSE);
+
+	switch (question) {
+		case PACMAN_TRANSACTION_QUESTION_INSTALL_IGNORE_PACKAGE:
+		{
+			PkRoleEnum role = pk_backend_get_role ((PkBackend *) user_data);
+			if (role == PK_ROLE_ENUM_INSTALL_PACKAGES) {
+				gchar *packages = pacman_package_make_list (pacman_transaction_get_marked_packages (transaction));
+				gchar *warning = g_strdup_printf ("The following packages were marked as ignored:\n%s\n", packages);
+
+				/* ignored packages are blocked in updates, can be explicitly installed */
+				egg_warning ("pacman: %s", warning);
+				backend_message ((PkBackend *) user_data, warning);
+
+				g_free (warning);
+				g_free (packages);
+				return TRUE;
+			} else if (role == PK_ROLE_ENUM_DOWNLOAD_PACKAGES || role == PK_ROLE_ENUM_SIMULATE_INSTALL_PACKAGES) {
+				return TRUE;
+			} else {
+				return FALSE;
+			}
+		}
+		case PACMAN_TRANSACTION_QUESTION_SKIP_UNRESOLVABLE_PACKAGES:
+		case PACMAN_TRANSACTION_QUESTION_REMOVE_HOLD_PACKAGES:
+		case PACMAN_TRANSACTION_QUESTION_SYNC_FIRST:
+			/* none of these actions are safe */
+			egg_warning ("pacman: ignoring question '%s'", message);
+			return FALSE;
+
+		case PACMAN_TRANSACTION_QUESTION_REPLACE_PACKAGE:
+		case PACMAN_TRANSACTION_QUESTION_REMOVE_CONFLICTING_PACKAGE:
+		case PACMAN_TRANSACTION_QUESTION_INSTALL_OLDER_PACKAGE:
+		case PACMAN_TRANSACTION_QUESTION_DELETE_CORRUPTED_PACKAGE:
+			/* these actions are mostly harmless */
+			egg_warning ("pacman: confirming question '%s'", message);
+			return TRUE;
+
+		default:
+			egg_warning ("pacman: unrecognised question '%s'", message);
+			return FALSE;
+	}
+}
+
+static void
+transaction_status_cb (PacmanTransaction *transaction, PacmanTransactionStatus status, const gchar *message, gpointer user_data)
+{
+	PkStatusEnum state;
+	PkInfoEnum info;
+
+	g_return_if_fail (transaction != NULL);
+	g_return_if_fail (user_data != NULL);
+
+	/* figure out the backend status and package info */
+	switch (status) {
+		case PACMAN_TRANSACTION_STATUS_INSTALL_START:
+			state = PK_STATUS_ENUM_INSTALL;
+			info = PK_INFO_ENUM_INSTALLING;
+			break;
+
+		case PACMAN_TRANSACTION_STATUS_UPGRADE_START:
+			if (pk_backend_get_role ((PkBackend *) user_data) == PK_ROLE_ENUM_INSTALL_FILES) {
+				state = PK_STATUS_ENUM_INSTALL;
+				info = PK_INFO_ENUM_INSTALLING;
+			} else {
+				state = PK_STATUS_ENUM_UPDATE;
+				info = PK_INFO_ENUM_UPDATING;
+			}
+			break;
+
+		case PACMAN_TRANSACTION_STATUS_REMOVE_START:
+			state = PK_STATUS_ENUM_REMOVE;
+			info = PK_INFO_ENUM_REMOVING;
+			break;
+
+		case PACMAN_TRANSACTION_STATUS_INSTALL_END:
+		case PACMAN_TRANSACTION_STATUS_UPGRADE_END:
+		case PACMAN_TRANSACTION_STATUS_REMOVE_END:
+			state = PK_STATUS_ENUM_UNKNOWN;
+			info = PK_INFO_ENUM_FINISHED;
+			break;
+
+		case PACMAN_TRANSACTION_STATUS_DEPENDENCY_CHECK_START:
+		case PACMAN_TRANSACTION_STATUS_DEPENDENCY_RESOLVE_START:
+			state = PK_STATUS_ENUM_DEP_RESOLVE;
+			info = PK_INFO_ENUM_UNKNOWN;
+			break;
+
+		case PACMAN_TRANSACTION_STATUS_FILE_CONFLICT_CHECK_START:
+		case PACMAN_TRANSACTION_STATUS_CONFLICT_CHECK_START:
+		case PACMAN_TRANSACTION_STATUS_PACKAGE_INTEGRITY_CHECK_START:
+		case PACMAN_TRANSACTION_STATUS_DELTA_INTEGRITY_CHECK_START:
+			state = PK_STATUS_ENUM_TEST_COMMIT;
+			info = PK_INFO_ENUM_UNKNOWN;
+			break;
+
+		default:
+			state = PK_STATUS_ENUM_UNKNOWN;
+			info = PK_INFO_ENUM_UNKNOWN;
+			egg_debug ("pacman: %s", message);
+			break;
+	}
+
+	/* update the backend status */
+	if (state != PK_STATUS_ENUM_UNKNOWN) {
+		pk_backend_set_status ((PkBackend *) user_data, state);
+	}
+
+	/* update the package info */
+	if (info != PK_INFO_ENUM_UNKNOWN) {
+		const PacmanList *packages;
+
+		for (packages = pacman_transaction_get_marked_packages (transaction); packages != NULL; packages = pacman_list_next (packages)) {
+			PacmanPackage *package;
+
+			/* only report the old versions */
+			if (status == PACMAN_TRANSACTION_STATUS_UPGRADE_START || status == PACMAN_TRANSACTION_STATUS_UPGRADE_END) {
+				packages = pacman_list_next (packages);
+				if (packages == NULL) {
+					break;
+				}
+			}
+
+			package = (PacmanPackage *) pacman_list_get (packages);
+			backend_package ((PkBackend *) user_data, package, info);
+		}
+	}
+}
+
+static void
+transaction_cancelled_cb (GCancellable *object, gpointer user_data)
+{
+	g_return_if_fail (user_data != NULL);
+
+	pacman_transaction_cancel ((PacmanTransaction *) user_data, NULL);
+}
+
+PacmanTransaction *
+backend_transaction_simulate (PkBackend *backend, PacmanTransactionType type, guint32 flags, const PacmanList *targets)
+{
+	PacmanTransaction *transaction;
+	GError *error = NULL;
+
+	g_return_val_if_fail (pacman != NULL, NULL);
+	g_return_val_if_fail (cancellable != NULL, NULL);
+	g_return_val_if_fail (backend != NULL, NULL);
+	g_return_val_if_fail (type < PACMAN_TRANSACTION_LAST, NULL);
+
+	switch (type) {
+		case PACMAN_TRANSACTION_INSTALL:
+			transaction = pacman_manager_install (pacman, flags, &error);
+			break;
+		case PACMAN_TRANSACTION_REMOVE:
+			transaction = pacman_manager_remove (pacman, flags, &error);
+			break;
+		case PACMAN_TRANSACTION_SYNC:
+			transaction = pacman_manager_sync (pacman, flags, &error);
+			break;
+		case PACMAN_TRANSACTION_UPDATE:
+			transaction = pacman_manager_update (pacman, flags, &error);
+			break;
+		default:
+			g_return_val_if_reached (NULL);
+	}
+
+	if (transaction == NULL) {
+		backend_error (backend, error);
+		return NULL;
+	}
+
+	g_signal_connect (transaction, "download", G_CALLBACK (transaction_download_cb), backend);
+	g_signal_connect (transaction, "progress", G_CALLBACK (transaction_progress_cb), backend);
+	g_signal_connect (transaction, "question", G_CALLBACK (transaction_question_cb), backend);
+	g_signal_connect (transaction, "status", G_CALLBACK (transaction_status_cb), backend);
+
+	if (g_cancellable_connect (cancellable, G_CALLBACK (transaction_cancelled_cb), transaction, NULL) == 0 && backend_cancelled (backend)) {
+		return transaction;
+	}
+
+	if (!pacman_transaction_prepare (transaction, targets, &error)) {
+		backend_error (backend, error);
+		g_object_unref (transaction);
+		return NULL;
+	}
+
+	return transaction;
+}
+
+PacmanTransaction *
+backend_transaction_run (PkBackend *backend, PacmanTransactionType type, guint32 flags, const PacmanList *targets)
+{
+	PacmanTransaction *transaction;
+	GError *error = NULL;
+
+	g_return_val_if_fail (backend != NULL, NULL);
+
+	transaction = backend_transaction_simulate (backend, type, flags, targets);
+
+	if (backend_cancelled (backend)) {
+		return transaction;
+	} else if (transaction != NULL) {
+		pk_backend_set_status (backend, PK_STATUS_ENUM_RUNNING);
+
+		if (!pacman_transaction_commit (transaction, &error)) {
+			backend_error (backend, error);
+			g_hash_table_remove (downloads, transaction);
+			g_object_unref (transaction);
+			return NULL;
+		}
+	}
+
+	return transaction;
+}
+
+gboolean
+backend_transaction_finished (PkBackend *backend, PacmanTransaction *transaction)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	if (transaction != NULL) {
+		g_object_unref (transaction);
+		backend_finished (backend);
+		return TRUE;
+	} else {
+		backend_finished (backend);
+		return FALSE;
+	}
+}
diff --git a/backends/pacman/backend-transaction.h b/backends/pacman/backend-transaction.h
new file mode 100644
index 0000000..dd5c317
--- /dev/null
+++ b/backends/pacman/backend-transaction.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pacman.h>
+#include <pk-backend.h>
+
+typedef enum {
+	PACMAN_TRANSACTION_INSTALL,
+	PACMAN_TRANSACTION_REMOVE,
+	PACMAN_TRANSACTION_SYNC,
+	PACMAN_TRANSACTION_UPDATE,
+	PACMAN_TRANSACTION_LAST
+} PacmanTransactionType;
+
+gboolean		 backend_initialize_downloads	(PkBackend		*backend,
+							 GError			**error);
+void			 backend_destroy_downloads	(PkBackend		*backend);
+
+PacmanTransaction	*backend_transaction_simulate	(PkBackend		*backend,
+							 PacmanTransactionType	 type,
+							 guint32		 flags,
+							 const PacmanList	*targets);
+PacmanTransaction	*backend_transaction_run	(PkBackend		*backend,
+							 PacmanTransactionType	 type,
+							 guint32		 flags,
+							 const PacmanList	*targets);
+
+gboolean		 backend_transaction_finished	(PkBackend		*backend,
+							 PacmanTransaction	*transaction);
commit 08e24e7899a9a45c59a796b356dd97fd42826665
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Sun May 2 16:32:15 2010 +1200

    pacman: add dependency lookup

diff --git a/backends/pacman/Makefile.am b/backends/pacman/Makefile.am
index 41d0b55..e5a8ded 100644
--- a/backends/pacman/Makefile.am
+++ b/backends/pacman/Makefile.am
@@ -18,7 +18,8 @@ conf_DATA = groups.list \
 plugindir = $(PK_PLUGIN_DIR)
 plugin_LTLIBRARIES = libpk_backend_pacman.la
 
-libpk_backend_pacman_la_SOURCES = backend-error.c \
+libpk_backend_pacman_la_SOURCES = backend-depends.c \
+                                  backend-error.c \
                                   backend-groups.c \
                                   backend-packages.c \
                                   backend-pacman.c \
diff --git a/backends/pacman/backend-depends.c b/backends/pacman/backend-depends.c
new file mode 100644
index 0000000..9bd2324
--- /dev/null
+++ b/backends/pacman/backend-depends.c
@@ -0,0 +1,298 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pacman.h>
+#include "backend-packages.h"
+#include "backend-pacman.h"
+#include "backend-repos.h"
+#include "backend-depends.h"
+
+static PacmanPackage *
+pacman_list_find_provider (const PacmanList *packages, PacmanDependency *depend)
+{
+	const PacmanList *list;
+
+	g_return_val_if_fail (depend != NULL, NULL);
+
+	/* find a package that provides depend */
+	for (list = packages; list != NULL; list = pacman_list_next (list)) {
+		PacmanPackage *provider = (PacmanPackage *) pacman_list_get (list);
+
+		if (pacman_dependency_satisfied_by (depend, provider)) {
+			return provider;
+		}
+	}
+
+	return NULL;
+}
+
+static PacmanPackage *
+pacman_sync_databases_find_provider (PacmanDependency *depend)
+{
+	const PacmanList *databases;
+
+	g_return_val_if_fail (pacman != NULL, NULL);
+	g_return_val_if_fail (depend != NULL, NULL);
+
+	/* find the default package that provides depend */
+	for (databases = pacman_manager_get_sync_databases (pacman); databases != NULL; databases = pacman_list_next (databases)) {
+		PacmanDatabase *database = (PacmanDatabase *) pacman_list_get (databases);
+		PacmanPackage *provider = pacman_database_find_package (database, pacman_dependency_get_name (depend));
+
+		if (provider != NULL && pacman_dependency_satisfied_by (depend, provider)) {
+			return provider;
+		}
+	}
+
+	/* find any package that provides depend */
+	for (databases = pacman_manager_get_sync_databases (pacman); databases != NULL; databases = pacman_list_next (databases)) {
+		PacmanDatabase *database = (PacmanDatabase *) pacman_list_get (databases);
+		PacmanPackage *provider = pacman_list_find_provider (pacman_database_get_packages (database), depend);
+
+		if (provider != NULL) {
+			return provider;
+		}
+	}
+
+	return NULL;
+}
+
+static gboolean
+backend_get_depends_thread (PkBackend *backend)
+{
+	guint iterator;
+	PacmanList *list, *packages = NULL;
+
+	PkBitfield filters;
+	gchar **package_ids;
+	gboolean recursive;
+
+	gboolean search_installed;
+	gboolean search_not_installed;
+
+	g_return_val_if_fail (local_database != NULL, FALSE);
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	package_ids = pk_backend_get_strv (backend, "package_ids");
+	recursive = pk_backend_get_bool (backend, "recursive");
+
+	g_return_val_if_fail (package_ids != NULL, FALSE);
+
+	filters = pk_backend_get_uint (backend, "filters");
+	search_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED);
+	search_not_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_NOT_INSTALLED);
+
+	/* construct an initial package list */
+	for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+		PacmanPackage *package = backend_get_package (backend, package_ids[iterator]);
+
+		if (backend_cancelled (backend)) {
+			break;
+		} else if (package == NULL) {
+			pacman_list_free (packages);
+			backend_finished (backend);
+			return FALSE;
+		}
+
+		packages = pacman_list_add (packages, package);
+	}
+
+	/* package list might be modified along the way but that is ok */
+	for (list = packages; list != NULL; list = pacman_list_next (list)) {
+		PacmanPackage *package = (PacmanPackage *) pacman_list_get (list);
+		const PacmanList *depends;
+
+		if (backend_cancelled (backend)) {
+			break;
+		}
+
+		for (depends = pacman_package_get_dependencies (package); depends != NULL; depends = pacman_list_next (depends)) {
+			PacmanDependency *depend = (PacmanDependency *) pacman_list_get (depends);
+			PacmanPackage *provider = pacman_list_find_provider (packages, depend);
+
+			if (backend_cancelled (backend)) {
+				break;
+			} else if (provider != NULL) {
+				continue;
+			}
+
+			/* look for installed dependencies */
+			provider = pacman_list_find_provider (pacman_database_get_packages (local_database), depend);
+			if (provider != NULL) {
+				/* don't emit when not needed... */
+				if (!search_not_installed) {
+					backend_package (backend, provider, PK_INFO_ENUM_INSTALLED);
+					/* ... and assume installed packages also have installed dependencies */
+					if (recursive) {
+						packages = pacman_list_add (packages, provider);
+					}
+				}
+				continue;
+			}
+
+			/* look for non-installed dependencies */
+			provider = pacman_sync_databases_find_provider (depend);
+			if (provider != NULL) {
+				/* don't emit when not needed... */
+				if (!search_installed) {
+					backend_package (backend, provider, PK_INFO_ENUM_AVAILABLE);
+				}
+				/* ... but keep looking for installed dependencies */
+				if (recursive) {
+					packages = pacman_list_add (packages, provider);
+				}
+			} else {
+				gchar *depend_id = pacman_dependency_to_string (depend);
+				pk_backend_error_code (backend, PK_ERROR_ENUM_DEP_RESOLUTION_FAILED, "Could not resolve dependency %s", depend_id);
+				g_free (depend_id);
+
+				pacman_list_free (packages);
+				backend_finished (backend);
+				return FALSE;
+			}
+		}
+	}
+
+	pacman_list_free (packages);
+	backend_finished (backend);
+	return TRUE;
+}
+
+/**
+ * backend_get_depends:
+ **/
+void
+backend_get_depends (PkBackend *backend, PkBitfield filters, gchar **package_ids, gboolean recursive)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (package_ids != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_depends_thread);
+}
+
+static PacmanPackage *
+pacman_list_find_package (const PacmanList *packages, const gchar *name)
+{
+	const PacmanList *list;
+
+	g_return_val_if_fail (name != NULL, NULL);
+
+	/* find a package called name */
+	for (list = packages; list != NULL; list = pacman_list_next (list)) {
+		PacmanPackage *package = (PacmanPackage *) pacman_list_get (list);
+
+		if (g_strcmp0 (name, pacman_package_get_name (package)) == 0) {
+			return package;
+		}
+	}
+
+	return NULL;
+}
+
+static gboolean
+backend_get_requires_thread (PkBackend *backend)
+{
+	guint iterator;
+	PacmanList *list, *packages = NULL;
+
+	gchar **package_ids;
+	gboolean recursive;
+
+	g_return_val_if_fail (local_database != NULL, FALSE);
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	package_ids = pk_backend_get_strv (backend, "package_ids");
+	recursive = pk_backend_get_bool (backend, "recursive");
+
+	g_return_val_if_fail (package_ids != NULL, FALSE);
+
+	/* construct an initial package list */
+	for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+		PacmanPackage *package = backend_get_package (backend, package_ids[iterator]);
+
+		if (backend_cancelled (backend)) {
+			break;
+		} else if (package == NULL) {
+			pacman_list_free (packages);
+			backend_finished (backend);
+			return FALSE;
+		}
+
+		packages = pacman_list_add (packages, package);
+	}
+
+	/* package list might be modified along the way but that is ok */
+	for (list = packages; list != NULL; list = pacman_list_next (list)) {
+		PacmanPackage *package = (PacmanPackage *) pacman_list_get (list);
+		PacmanList *requires, *required_by = pacman_package_find_required_by (package);
+
+		if (backend_cancelled (backend)) {
+			break;
+		}
+
+		for (requires = required_by; requires != NULL; requires = pacman_list_next (requires)) {
+			const gchar *name = (const gchar *) pacman_list_get (requires);
+			PacmanPackage *requirer = pacman_list_find_package (packages, name);
+
+			if (backend_cancelled (backend)) {
+				break;
+			} else if (requirer != NULL) {
+				continue;
+			}
+
+			/* look for installed requirers */
+			requirer = pacman_database_find_package (local_database, name);
+			if (requirer == NULL) {
+				pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "Could not find package %s", name);
+
+				pacman_list_free_full (required_by, g_free);
+				pacman_list_free (packages);
+				backend_finished (backend);
+				return FALSE;
+			}
+
+			backend_package (backend, requirer, PK_INFO_ENUM_INSTALLED);
+			if (recursive) {
+				packages = pacman_list_add (packages, requirer);
+			}
+		}
+
+		pacman_list_free_full (required_by, g_free);
+	}
+
+	pacman_list_free (packages);
+	backend_finished (backend);
+	return TRUE;
+}
+
+/**
+ * backend_get_requires:
+ **/
+void
+backend_get_requires (PkBackend *backend, PkBitfield filters, gchar **package_ids, gboolean recursive)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (package_ids != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_requires_thread);
+}
diff --git a/backends/pacman/backend-depends.h b/backends/pacman/backend-depends.h
new file mode 100644
index 0000000..c6f7b6a
--- /dev/null
+++ b/backends/pacman/backend-depends.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pk-backend.h>
+
+void	 backend_get_depends	(PkBackend	*backend,
+				 PkBitfield	 filters,
+				 gchar		**package_ids,
+				 gboolean	 recursive);
+void	 backend_get_requires	(PkBackend	*backend,
+				 PkBitfield	 filters,
+				 gchar		**package_ids,
+				 gboolean	 recursive);
diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
index 5671eb6..ff28575 100644
--- a/backends/pacman/backend-pacman.c
+++ b/backends/pacman/backend-pacman.c
@@ -21,6 +21,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#include "backend-depends.h"
 #include "backend-error.h"
 #include "backend-groups.h"
 #include "backend-packages.h"
@@ -208,13 +209,13 @@ PK_BACKEND_OPTIONS (
 	backend_cancel,				/* cancel */
 	NULL,					/* download_packages */
 	NULL,					/* get_categories */
-	NULL,					/* get_depends */
+	backend_get_depends,			/* get_depends */
 	backend_get_details,			/* get_details */
 	NULL,					/* get_distro_upgrades */
 	backend_get_files,			/* get_files */
 	backend_get_packages,			/* get_packages */
 	backend_get_repo_list,			/* get_repo_list */
-	NULL,					/* get_requires */
+	backend_get_requires,			/* get_requires */
 	NULL,					/* get_update_detail */
 	NULL,					/* get_updates */
 	NULL,					/* install_files */
commit a17b9b6ea942c27df9e61d0ff9af7419b8f56847
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Sun May 2 16:25:39 2010 +1200

    pacman: add searching support

diff --git a/backends/pacman/Makefile.am b/backends/pacman/Makefile.am
index 583d567..41d0b55 100644
--- a/backends/pacman/Makefile.am
+++ b/backends/pacman/Makefile.am
@@ -22,7 +22,8 @@ libpk_backend_pacman_la_SOURCES = backend-error.c \
                                   backend-groups.c \
                                   backend-packages.c \
                                   backend-pacman.c \
-                                  backend-repos.c
+                                  backend-repos.c \
+                                  backend-search.c
 libpk_backend_pacman_la_LIBADD = $(PK_PLUGIN_LIBS) \
                                  $(PACMAN_LIBS)
 libpk_backend_pacman_la_LDFLAGS = -module -avoid-version
diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
index f6455e4..5671eb6 100644
--- a/backends/pacman/backend-pacman.c
+++ b/backends/pacman/backend-pacman.c
@@ -25,6 +25,7 @@
 #include "backend-groups.h"
 #include "backend-packages.h"
 #include "backend-repos.h"
+#include "backend-search.h"
 #include "backend-pacman.h"
 
 PacmanManager *pacman = NULL;
@@ -211,7 +212,7 @@ PK_BACKEND_OPTIONS (
 	backend_get_details,			/* get_details */
 	NULL,					/* get_distro_upgrades */
 	backend_get_files,			/* get_files */
-	NULL,					/* get_packages */
+	backend_get_packages,			/* get_packages */
 	backend_get_repo_list,			/* get_repo_list */
 	NULL,					/* get_requires */
 	NULL,					/* get_update_detail */
@@ -225,13 +226,13 @@ PK_BACKEND_OPTIONS (
 	NULL,					/* repo_set_data */
 	backend_resolve,			/* resolve */
 	NULL,					/* rollback */
-	NULL,					/* search_details */
-	NULL,					/* search_files */
-	NULL,					/* search_groups */
-	NULL,					/* search_names */
+	backend_search_details,			/* search_details */
+	backend_search_files,			/* search_files */
+	backend_search_groups,			/* search_groups */
+	backend_search_names,			/* search_names */
 	NULL,					/* update_packages */
 	NULL,					/* update_system */
-	NULL,					/* what_provides */
+	backend_what_provides,			/* what_provides */
 	NULL,					/* simulate_install_files */
 	NULL,					/* simulate_install_packages */
 	NULL,					/* simulate_remove_packages */
diff --git a/backends/pacman/backend-search.c b/backends/pacman/backend-search.c
new file mode 100644
index 0000000..f819252
--- /dev/null
+++ b/backends/pacman/backend-search.c
@@ -0,0 +1,474 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include <pacman.h>
+#include "backend-error.h"
+#include "backend-groups.h"
+#include "backend-packages.h"
+#include "backend-pacman.h"
+#include "backend-repos.h"
+#include "backend-search.h"
+
+static gpointer
+backend_pattern_needle (const gchar *needle, GError **error)
+{
+	return (gpointer) needle;
+}
+
+static gpointer
+backend_pattern_regex (const gchar *needle, GError **error)
+{
+	gchar *pattern;
+	GRegex *regex;
+
+	g_return_val_if_fail (needle != NULL, NULL);
+
+	pattern = g_regex_escape_string (needle, -1);
+	regex = g_regex_new (pattern, G_REGEX_CASELESS, 0, error);
+	g_free (pattern);
+
+	return regex;
+}
+
+static gpointer
+backend_pattern_chroot (const gchar *needle, GError **error)
+{
+	g_return_val_if_fail (pacman != NULL, FALSE);
+	g_return_val_if_fail (needle != NULL, NULL);
+
+	if (G_IS_DIR_SEPARATOR (*needle)) {
+		const gchar *file = needle, *path = pacman_manager_get_root_path (pacman);
+
+		/* adjust needle to the correct prefix */
+		while (*file++ == *path++) {
+			if (*path == '\0') {
+				needle = file - 1;
+				break;
+			} else if (*file == '\0') {
+				break;
+			}
+		}
+	}
+
+	return (gpointer) needle;
+}
+
+static gboolean
+backend_match_all (PacmanPackage *package, gpointer pattern)
+{
+	g_return_val_if_fail (package != NULL, FALSE);
+	g_return_val_if_fail (pattern != NULL, FALSE);
+
+	/* match all packages */
+	return TRUE;
+}
+
+static gboolean
+backend_match_details (PacmanPackage *package, gpointer pattern)
+{
+	const gchar *description;
+	PacmanDatabase *database;
+	const PacmanList *licenses;
+
+	GRegex *regex = (GRegex *) pattern;
+
+	g_return_val_if_fail (package != NULL, FALSE);
+	g_return_val_if_fail (regex != NULL, FALSE);
+
+	/* match the name first... */
+	if (g_regex_match (regex, pacman_package_get_name (package), 0, NULL)) {
+		return TRUE;
+	}
+
+	/* ... then the description... */
+	description = pacman_package_get_description (package);
+	if (description != NULL && g_regex_match (regex, description, 0, NULL)) {
+		return TRUE;
+	}
+
+	/* ... then the database... */
+	database = pacman_package_get_database (package);
+	if (database != NULL && g_regex_match (regex, pacman_database_get_name (database), G_REGEX_MATCH_ANCHORED, NULL)) {
+		return TRUE;
+	}
+
+	/* ... then the licenses */
+	for (licenses = pacman_package_get_licenses (package); licenses != NULL; licenses = pacman_list_next (licenses)) {
+		const gchar *license = (const gchar *) pacman_list_get (licenses);
+		if (g_regex_match (regex, license, G_REGEX_MATCH_ANCHORED, NULL)) {
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+static gboolean
+backend_match_file (PacmanPackage *package, gpointer pattern)
+{
+	const PacmanList *files;
+	const gchar *needle = (const gchar *) pattern;
+
+	g_return_val_if_fail (package != NULL, FALSE);
+	g_return_val_if_fail (needle != NULL, FALSE);
+
+	/* match any file the package contains */
+	if (G_IS_DIR_SEPARATOR (*needle)) {
+		for (files = pacman_package_get_files (package); files != NULL; files = pacman_list_next (files)) {
+			const gchar *file = (const gchar *) pacman_list_get (files);
+
+			/* match the full path of file */
+			if (g_strcmp0 (file, needle + 1) == 0) {
+				return TRUE;
+			}
+		}
+	} else {
+		for (files = pacman_package_get_files (package); files != NULL; files = pacman_list_next (files)) {
+			const gchar *file = (const gchar *) pacman_list_get (files);
+			file = strrchr (file, G_DIR_SEPARATOR);
+
+			/* match the basename of file */
+			if (file != NULL && g_strcmp0 (file + 1, needle) == 0) {
+				return TRUE;
+			}
+		}
+	}
+
+	return FALSE;
+}
+
+static gboolean
+backend_match_group (PacmanPackage *package, gpointer pattern)
+{
+	const gchar *needle = (const gchar *) pattern;
+
+	g_return_val_if_fail (package != NULL, FALSE);
+	g_return_val_if_fail (needle != NULL, FALSE);
+
+	/* match the group the package is in */
+	return g_strcmp0 (needle, pacman_package_get_group (package)) == 0;
+}
+
+static gboolean
+backend_match_name (PacmanPackage *package, gpointer pattern)
+{
+	GRegex *regex = (GRegex *) pattern;
+
+	g_return_val_if_fail (package != NULL, FALSE);
+	g_return_val_if_fail (regex != NULL, FALSE);
+
+	/* match the name of the package */
+	return g_regex_match (regex, pacman_package_get_name (package), 0, NULL);
+}
+
+static gboolean
+backend_match_provides (PacmanPackage *package, gpointer pattern)
+{
+	/* TODO: implement GStreamer codecs, Pango fonts, etc. */
+	const PacmanList *provides;
+	const gchar *needle = (const gchar *) pattern;
+
+	g_return_val_if_fail (package != NULL, FALSE);
+	g_return_val_if_fail (needle != NULL, FALSE);
+
+	/* match features provided by package */
+	for (provides = pacman_package_get_provides (package); provides != NULL; provides = pacman_list_next (provides)) {
+		const gchar *name = (const gchar *) pacman_list_get (provides);
+		if (g_strcmp0 (needle, name) == 0) {
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+typedef enum {
+	SEARCH_TYPE_ALL,
+	SEARCH_TYPE_DETAILS,
+	SEARCH_TYPE_FILES,
+	SEARCH_TYPE_GROUP,
+	SEARCH_TYPE_NAME,
+	SEARCH_TYPE_PROVIDES,
+	SEARCH_TYPE_LAST
+} SearchType;
+
+typedef gpointer (*PatternFunc) (const gchar *needle, GError **error);
+typedef gboolean (*MatchFunc) (PacmanPackage *package, gpointer pattern);
+
+static PatternFunc pattern_funcs[] = {
+	backend_pattern_needle,
+	backend_pattern_regex,
+	backend_pattern_chroot,
+	backend_pattern_needle,
+	backend_pattern_regex,
+	backend_pattern_needle
+};
+
+static GDestroyNotify pattern_frees[] = {
+	NULL,
+	(GDestroyNotify) g_regex_unref,
+	NULL,
+	NULL,
+	(GDestroyNotify) g_regex_unref,
+	NULL
+};
+
+static MatchFunc match_funcs[] = {
+	backend_match_all,
+	backend_match_details,
+	backend_match_file,
+	backend_match_group,
+	backend_match_name,
+	backend_match_provides
+};
+
+static gboolean
+pacman_package_is_installed (PacmanPackage *package)
+{
+	PacmanPackage *installed;
+
+	g_return_val_if_fail (local_database != NULL, FALSE);
+	g_return_val_if_fail (package != NULL, FALSE);
+
+	/* find an installed package with the same name */
+	installed = pacman_database_find_package (local_database, pacman_package_get_name (package));
+	if (installed == NULL) {
+		return FALSE;
+	}
+
+	/* make sure the installed version is the same */
+	if (pacman_package_compare_version (pacman_package_get_version (installed), pacman_package_get_version (package)) != 0) {
+		return FALSE;
+	}
+
+	/* make sure the installed arch is the same */
+	if (g_strcmp0 (pacman_package_get_arch (installed), pacman_package_get_arch (package)) != 0) {
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+backend_search_database (PkBackend *backend, PacmanDatabase *database, MatchFunc match, const PacmanList *patterns)
+{
+	const PacmanList *packages, *list;
+
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (database != NULL);
+	g_return_if_fail (match != NULL);
+
+	/* emit packages that match all search terms */
+	for (packages = pacman_database_get_packages (database); packages != NULL; packages = pacman_list_next (packages)) {
+		PacmanPackage *package = (PacmanPackage *) pacman_list_get (packages);
+
+		if (backend_cancelled (backend)) {
+			break;
+		}
+
+		for (list = patterns; list != NULL; list = pacman_list_next (list)) {
+			if (!match (package, pacman_list_get (list))) {
+				break;
+			}
+		}
+
+		/* all search terms matched */
+		if (list == NULL) {
+			if (database == local_database) {
+				backend_package (backend, package, PK_INFO_ENUM_INSTALLED);
+			} else if (!pacman_package_is_installed (package)) {
+				backend_package (backend, package, PK_INFO_ENUM_AVAILABLE);
+			}
+		}
+	}
+}
+
+static gboolean
+backend_search_thread (PkBackend *backend)
+{
+	gchar **search;
+	SearchType search_type;
+
+	PatternFunc pattern_func;
+	GDestroyNotify pattern_free;
+	MatchFunc match_func;
+
+	PkBitfield filters;
+	gboolean search_installed;
+	gboolean search_not_installed;
+
+	guint iterator;
+	PacmanList *patterns = NULL;
+	GError *error = NULL;
+
+	g_return_val_if_fail (pacman != NULL, FALSE);
+	g_return_val_if_fail (local_database != NULL, FALSE);
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	search = pk_backend_get_strv (backend, "search");
+	search_type = (SearchType) pk_backend_get_uint (backend, "search-type");
+
+	g_return_val_if_fail (search != NULL, FALSE);
+	g_return_val_if_fail (search_type < SEARCH_TYPE_LAST, FALSE);
+
+	pattern_func = pattern_funcs[search_type];
+	pattern_free = pattern_frees[search_type];
+	match_func = match_funcs[search_type];
+
+	g_return_val_if_fail (pattern_func != NULL, FALSE);
+	g_return_val_if_fail (match_func != NULL, FALSE);
+
+	filters = pk_backend_get_uint (backend, "filters");
+	search_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED);
+	search_not_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_NOT_INSTALLED);
+
+	/* convert search terms to the pattern requested */
+	for (iterator = 0; search[iterator] != NULL; ++iterator) {
+		gpointer pattern = pattern_func (search[iterator], &error);
+
+		if (pattern != NULL) {
+			patterns = pacman_list_add (patterns, pattern);
+		} else {
+			backend_error (backend, error);
+			if (pattern_free != NULL) {
+				pacman_list_free_full (patterns, pattern_free);
+			} else {
+				pacman_list_free (patterns);
+			}
+			backend_finished (backend);
+			return FALSE;
+		}
+	}
+
+	/* find installed packages first */
+	if (!search_not_installed) {
+		backend_search_database (backend, local_database, match_func, patterns);
+	}
+
+	if (!search_installed) {
+		const PacmanList *databases;
+
+		for (databases = pacman_manager_get_sync_databases (pacman); databases != NULL; databases = pacman_list_next (databases)) {
+			PacmanDatabase *database = (PacmanDatabase *) pacman_list_get (databases);
+
+			if (backend_cancelled (backend)) {
+				break;
+			}
+
+			backend_search_database (backend, database, match_func, patterns);
+		}
+	}
+
+	if (pattern_free != NULL) {
+		pacman_list_free_full (patterns, pattern_free);
+	} else {
+		pacman_list_free (patterns);
+	}
+	backend_finished (backend);
+	return TRUE;
+}
+
+/**
+ * backend_get_packages:
+ **/
+void
+backend_get_packages (PkBackend	*backend, PkBitfield filters)
+{
+	g_return_if_fail (backend != NULL);
+
+	/* provide a dummy needle */
+	pk_backend_set_strv (backend, "search", g_strsplit ("", ";", 0));
+
+	pk_backend_set_uint (backend, "search-type", SEARCH_TYPE_ALL);
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_search_thread);
+}
+
+/**
+ * backend_search_details:
+ **/
+void
+backend_search_details (PkBackend *backend, PkBitfield filters, gchar **values)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (values != NULL);
+
+	pk_backend_set_uint (backend, "search-type", SEARCH_TYPE_DETAILS);
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_search_thread);
+}
+
+/**
+ * backend_search_files:
+ **/
+void
+backend_search_files (PkBackend *backend, PkBitfield filters, gchar **values)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (values != NULL);
+
+	/* speed up search by restricting it to local database */
+	pk_bitfield_add (filters, PK_FILTER_ENUM_INSTALLED);
+	pk_backend_set_uint (backend, "filters", filters);
+
+	pk_backend_set_uint (backend, "search-type", SEARCH_TYPE_FILES);
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_search_thread);
+}
+
+/**
+ * backend_search_groups:
+ **/
+void
+backend_search_groups (PkBackend *backend, PkBitfield filters, gchar **values)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (values != NULL);
+
+	pk_backend_set_uint (backend, "search-type", SEARCH_TYPE_GROUP);
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_search_thread);
+}
+
+/**
+ * backend_search_names:
+ **/
+void
+backend_search_names (PkBackend *backend, PkBitfield filters, gchar **values)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (values != NULL);
+
+	pk_backend_set_uint (backend, "search-type", SEARCH_TYPE_NAME);
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_search_thread);
+}
+
+/**
+ * backend_what_provides:
+ **/
+void
+backend_what_provides (PkBackend *backend, PkBitfield filters, PkProvidesEnum provides, gchar **values)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (values != NULL);
+
+	pk_backend_set_uint (backend, "search-type", SEARCH_TYPE_PROVIDES);
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_search_thread);
+}
diff --git a/backends/pacman/backend-search.h b/backends/pacman/backend-search.h
new file mode 100644
index 0000000..c2ce6a0
--- /dev/null
+++ b/backends/pacman/backend-search.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pk-backend.h>
+
+void	 backend_get_packages	(PkBackend	*backend,
+				 PkBitfield	 filters);
+void	 backend_search_details	(PkBackend	*backend,
+				 PkBitfield	 filters,
+				 gchar		**values);
+void	 backend_search_files	(PkBackend	*backend,
+				 PkBitfield	 filters,
+				 gchar		**values);
+void	 backend_search_groups	(PkBackend	*backend,
+				 PkBitfield	 filters,
+				 gchar		**values);
+void	 backend_search_names	(PkBackend	*backend,
+				 PkBitfield	 filters,
+				 gchar		**values);
+void	 backend_what_provides	(PkBackend	*backend,
+				 PkBitfield	 filters,
+				 PkProvidesEnum	 provides,
+				 gchar		**values);
commit 5d6ff45a59cc1256218fec87ccfb19a2be374dc8
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Sun May 2 14:34:55 2010 +1200

    pacman: add package-related methods and helpers

diff --git a/backends/pacman/Makefile.am b/backends/pacman/Makefile.am
index b69d6d8..583d567 100644
--- a/backends/pacman/Makefile.am
+++ b/backends/pacman/Makefile.am
@@ -20,6 +20,7 @@ plugin_LTLIBRARIES = libpk_backend_pacman.la
 
 libpk_backend_pacman_la_SOURCES = backend-error.c \
                                   backend-groups.c \
+                                  backend-packages.c \
                                   backend-pacman.c \
                                   backend-repos.c
 libpk_backend_pacman_la_LIBADD = $(PK_PLUGIN_LIBS) \
diff --git a/backends/pacman/backend-packages.c b/backends/pacman/backend-packages.c
new file mode 100644
index 0000000..af35f69
--- /dev/null
+++ b/backends/pacman/backend-packages.c
@@ -0,0 +1,346 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pacman.h>
+#include "backend-groups.h"
+#include "backend-pacman.h"
+#include "backend-repos.h"
+#include "backend-packages.h"
+
+gchar *
+pacman_package_make_id (PacmanPackage *package)
+{
+	const gchar *name, *version, *arch, *repo;
+	PacmanDatabase *database;
+
+	g_return_val_if_fail (local_database != NULL, NULL);
+	g_return_val_if_fail (package != NULL, NULL);
+
+	name = pacman_package_get_name (package);
+	version = pacman_package_get_version (package);
+
+	arch = pacman_package_get_arch (package);
+	if (arch == NULL) {
+		arch = "any";
+	}
+
+	/* PackageKit requires "local" for package files and "installed" for installed packages */
+	database = pacman_package_get_database (package);
+	if (database == NULL) {
+		repo = "local";
+	} else if (database == local_database) {
+		repo = "installed";
+	} else {
+		repo = pacman_database_get_name (database);
+	}
+
+	return pk_package_id_build (name, version, arch, repo);
+}
+
+void
+backend_package (PkBackend *backend, PacmanPackage *package, PkInfoEnum info)
+{
+	gchar *package_id;
+
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (package != NULL);
+
+	/* build and emit package id */
+	package_id = pacman_package_make_id (package);
+	pk_backend_package (backend, info, package_id, pacman_package_get_description (package));
+	g_free (package_id);
+}
+
+PacmanPackage *
+backend_get_package (PkBackend *backend, const gchar *package_id)
+{
+	gchar **package_id_data;
+	const gchar *repo;
+	PacmanDatabase *database;
+	PacmanPackage *package;
+
+	g_return_val_if_fail (pacman != NULL, NULL);
+	g_return_val_if_fail (local_database != NULL, NULL);
+	g_return_val_if_fail (backend != NULL, NULL);
+	g_return_val_if_fail (package_id != NULL, NULL);
+
+	package_id_data = pk_package_id_split (package_id);
+	repo = package_id_data[PK_PACKAGE_ID_DATA];
+
+	/* find the database to search in */
+	if (g_strcmp0 (repo, "installed") == 0) {
+		database = local_database;
+	} else {
+		database = pacman_manager_find_sync_database (pacman, repo);
+	}
+
+	if (database == NULL) {
+		pk_backend_error_code (backend, PK_ERROR_ENUM_REPO_NOT_FOUND, "Could not find repo [%s]", repo);
+		g_strfreev (package_id_data);
+		return NULL;
+	}
+
+	/* find the package in the database */
+	package = pacman_database_find_package (database, package_id_data[PK_PACKAGE_ID_NAME]);
+	if (package == NULL || g_strcmp0 (pacman_package_get_version (package), package_id_data[PK_PACKAGE_ID_VERSION]) != 0) {
+		pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "Could not find package with ID %s", package_id);
+		g_strfreev (package_id_data);
+		return NULL;
+	}
+
+	g_strfreev (package_id_data);
+	return package;
+}
+
+static gboolean
+backend_resolve_thread (PkBackend *backend)
+{
+	guint iterator;
+
+	gchar **package_ids;
+	PkBitfield filters;
+
+	gboolean search_installed;
+	gboolean search_not_installed;
+
+	g_return_val_if_fail (pacman != NULL, FALSE);
+	g_return_val_if_fail (local_database != NULL, FALSE);
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	package_ids = pk_backend_get_strv (backend, "package_ids");
+	filters = pk_backend_get_uint (backend, "filters");
+
+	g_return_val_if_fail (package_ids != NULL, FALSE);
+
+	search_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED);
+	search_not_installed = pk_bitfield_contain (filters, PK_FILTER_ENUM_NOT_INSTALLED);
+
+	for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+		if (backend_cancelled (backend)) {
+			break;
+		}
+
+		/* find a package with the given id or name */
+		if (pk_package_id_check (package_ids[iterator])) {
+			PacmanPackage *package = backend_get_package (backend, package_ids[iterator]);
+			if (package == NULL) {
+				backend_finished (backend);
+				return FALSE;
+			}
+
+			/* don't emit when not needed */
+			if (pacman_package_get_database (package) == local_database) {
+				if (!search_not_installed) {
+					backend_package (backend, package, PK_INFO_ENUM_INSTALLED);
+				}
+			} else {
+				if (!search_installed) {
+					backend_package (backend, package, PK_INFO_ENUM_AVAILABLE);
+				}
+			}
+		} else {
+			/* find installed packages first */
+			if (!search_not_installed) {
+				PacmanPackage *package = pacman_database_find_package (local_database, package_ids[iterator]);
+
+				if (package != NULL) {
+					backend_package (backend, package, PK_INFO_ENUM_INSTALLED);
+					continue;
+				}
+			}
+
+			if (!search_installed) {
+				const PacmanList *databases;
+
+				for (databases = pacman_manager_get_sync_databases (pacman); databases != NULL; databases = pacman_list_next (databases)) {
+					PacmanDatabase *database = (PacmanDatabase *) pacman_list_get (databases);
+					PacmanPackage *package = pacman_database_find_package (database, package_ids[iterator]);
+
+					if (package != NULL) {
+						backend_package (backend, package, PK_INFO_ENUM_AVAILABLE);
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	backend_finished (backend);
+	return TRUE;
+}
+
+/**
+ * backend_resolve:
+ **/
+void
+backend_resolve (PkBackend *backend, PkBitfield filters, gchar **package_ids)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (package_ids != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_resolve_thread);
+}
+
+static gboolean
+backend_get_details_thread (PkBackend *backend)
+{
+	guint iterator;
+
+	gchar **package_ids;
+
+	g_return_val_if_fail (local_database != NULL, FALSE);
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	package_ids = pk_backend_get_strv (backend, "package_ids");
+
+	g_return_val_if_fail (package_ids != NULL, FALSE);
+
+	/* collect details about packages */
+	for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+		PacmanPackage *package;
+		const PacmanList *list;
+		GString *string;
+
+		gchar *licenses;
+		PkGroupEnum group;
+		const gchar *description, *url;
+		gulong size;
+
+		if (backend_cancelled (backend)) {
+			break;
+		}
+
+		package = backend_get_package (backend, package_ids[iterator]);
+		if (package == NULL) {
+			backend_finished (backend);
+			return FALSE;
+		}
+
+		list = pacman_package_get_licenses (package);
+		if (list == NULL) {
+			string = g_string_new ("unknown");
+		} else {
+			string = g_string_new ((const gchar *) pacman_list_get (list));
+			for (list = pacman_list_next (list); list != NULL; list = pacman_list_next (list)) {
+				/* assume OR although it may not be correct */
+				g_string_append_printf (string, " or %s", (const gchar *) pacman_list_get (list));
+			}
+		}
+
+		group = pk_group_enum_from_string (pacman_package_get_group (package));
+		description = pacman_package_get_description (package);
+		url = pacman_package_get_url (package);
+
+		if (pacman_package_get_database (package) == local_database) {
+			size = pacman_package_get_installed_size (package);
+		} else {
+			/* FS#18769: change to get_download_size */
+			size = pacman_package_get_size (package);
+		}
+
+		licenses = g_string_free (string, FALSE);
+		pk_backend_details (backend, package_ids[iterator], licenses, group, description, url, size);
+		g_free (licenses);
+	}
+
+	backend_finished (backend);
+	return TRUE;
+}
+
+/**
+ * backend_get_details:
+ **/
+void
+backend_get_details (PkBackend *backend, gchar **package_ids)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (package_ids != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_details_thread);
+}
+
+static gboolean
+backend_get_files_thread (PkBackend *backend)
+{
+	guint iterator;
+
+	gchar **package_ids;
+
+	g_return_val_if_fail (pacman != NULL, FALSE);
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	package_ids = pk_backend_get_strv (backend, "package_ids");
+
+	g_return_val_if_fail (package_ids != NULL, FALSE);
+
+	/* enumerate files provided by package */
+	for (iterator = 0; package_ids[iterator] != NULL; ++iterator) {
+		PacmanPackage *package;
+		const PacmanList *list;
+
+		GString *string;
+		gchar *files;
+
+		if (backend_cancelled (backend)) {
+			break;
+		}
+
+		package = backend_get_package (backend, package_ids[iterator]);
+		if (package == NULL) {
+			backend_finished (backend);
+			return FALSE;
+		}
+
+		list = pacman_package_get_files (package);
+		if (list == NULL) {
+			string = g_string_new ("");
+		} else {
+			const gchar *root_path = pacman_manager_get_root_path (pacman);
+			string = g_string_new (root_path);
+			g_string_append (string, (const gchar *) pacman_list_get (list));
+
+			for (list = pacman_list_next (list); list != NULL; list = pacman_list_next (list)) {
+				g_string_append_printf (string, ";%s%s", root_path, (const gchar *) pacman_list_get (list));
+			}
+		}
+
+		files = g_string_free (string, FALSE);
+		pk_backend_files (backend, package_ids[iterator], files);
+		g_free (files);
+	}
+
+	backend_finished (backend);
+	return TRUE;
+}
+
+/**
+ * backend_get_files:
+ **/
+void
+backend_get_files (PkBackend *backend, gchar **package_ids)
+{
+	g_return_if_fail (pacman != NULL);
+	g_return_if_fail (backend != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_files_thread);
+}
diff --git a/backends/pacman/backend-packages.h b/backends/pacman/backend-packages.h
new file mode 100644
index 0000000..2064b89
--- /dev/null
+++ b/backends/pacman/backend-packages.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pacman.h>
+#include <pk-backend.h>
+
+gchar		*pacman_package_make_id	(PacmanPackage	*package);
+void		 backend_package	(PkBackend	*backend,
+					 PacmanPackage	*package,
+					 PkInfoEnum	 info);
+
+PacmanPackage	*backend_get_package	(PkBackend	*backend,
+					 const gchar	*package_id);
+void		 backend_resolve	(PkBackend	*backend,
+					 PkBitfield	 filters,
+					 gchar		**package_ids);
+
+void		 backend_get_details	(PkBackend	*backend,
+					 gchar		**package_ids);
+void		 backend_get_files	(PkBackend	*backend,
+					 gchar		**package_ids);
diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
index c96454c..f6455e4 100644
--- a/backends/pacman/backend-pacman.c
+++ b/backends/pacman/backend-pacman.c
@@ -23,6 +23,7 @@
 
 #include "backend-error.h"
 #include "backend-groups.h"
+#include "backend-packages.h"
 #include "backend-repos.h"
 #include "backend-pacman.h"
 
@@ -207,9 +208,9 @@ PK_BACKEND_OPTIONS (
 	NULL,					/* download_packages */
 	NULL,					/* get_categories */
 	NULL,					/* get_depends */
-	NULL,					/* get_details */
+	backend_get_details,			/* get_details */
 	NULL,					/* get_distro_upgrades */
-	NULL,					/* get_files */
+	backend_get_files,			/* get_files */
 	NULL,					/* get_packages */
 	backend_get_repo_list,			/* get_repo_list */
 	NULL,					/* get_requires */
@@ -222,7 +223,7 @@ PK_BACKEND_OPTIONS (
 	NULL,					/* remove_packages */
 	backend_repo_enable,			/* repo_enable */
 	NULL,					/* repo_set_data */
-	NULL,					/* resolve */
+	backend_resolve,			/* resolve */
 	NULL,					/* rollback */
 	NULL,					/* search_details */
 	NULL,					/* search_files */
commit f3dc5bceca79a281b1d8eb2bd59ae2facb675c13
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Sun May 2 14:28:04 2010 +1200

    pacman: add support for package groups

diff --git a/backends/pacman/Makefile.am b/backends/pacman/Makefile.am
index c1091aa..b69d6d8 100644
--- a/backends/pacman/Makefile.am
+++ b/backends/pacman/Makefile.am
@@ -1,21 +1,25 @@
 PACMAN_CONFIG_FILE = $(confdir)/pacman.conf
+PACMAN_GROUP_LIST = $(confdir)/groups.list
 PACMAN_REPO_LIST = $(confdir)/repos.list
 PACMAN_REPO_LIST_HEADER = "\# Generated by $(PACKAGE_NAME) - DO NOT MODIFY"
 PACMAN_DEFAULT_PATH = "/bin:/usr/bin:/sbin:/usr/sbin"
 
 DEFS = -DPACMAN_CONFIG_FILE=\"$(PACMAN_CONFIG_FILE)\" \
+       -DPACMAN_GROUP_LIST=\"$(PACMAN_GROUP_LIST)\" \
        -DPACMAN_REPO_LIST=\"$(PACMAN_REPO_LIST)\" \
        -DPACMAN_REPO_LIST_HEADER=\"$(PACMAN_REPO_LIST_HEADER)\" \
        -DPACMAN_DEFAULT_PATH=\"$(PACMAN_DEFAULT_PATH)\"
 
 confdir = $(PK_CONF_DIR)/pacman.d
-conf_DATA = pacman.conf \
+conf_DATA = groups.list \
+            pacman.conf \
             repos.list
 
 plugindir = $(PK_PLUGIN_DIR)
 plugin_LTLIBRARIES = libpk_backend_pacman.la
 
 libpk_backend_pacman_la_SOURCES = backend-error.c \
+                                  backend-groups.c \
                                   backend-pacman.c \
                                   backend-repos.c
 libpk_backend_pacman_la_LIBADD = $(PK_PLUGIN_LIBS) \
diff --git a/backends/pacman/backend-groups.c b/backends/pacman/backend-groups.c
new file mode 100644
index 0000000..1c785f9
--- /dev/null
+++ b/backends/pacman/backend-groups.c
@@ -0,0 +1,150 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include <gio/gio.h>
+#include "backend-error.h"
+#include "backend-groups.h"
+
+static GHashTable *group_map = NULL;
+static PkBitfield groups = 0;
+
+static GHashTable *
+group_map_new (GError **error)
+{
+	GHashTable *map;
+	GFile *file;
+
+	GFileInputStream *file_stream;
+	GDataInputStream *data_stream;
+
+	gchar *key, *value;
+	GError *e = NULL;
+
+	egg_debug ("pacman: reading groups from %s", PACMAN_GROUP_LIST);
+	file = g_file_new_for_path (PACMAN_GROUP_LIST);
+	file_stream = g_file_read (file, NULL, &e);
+
+	if (file_stream == NULL) {
+		g_object_unref (file);
+		g_propagate_error (error, e);
+		return NULL;
+	}
+
+	map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	data_stream = g_data_input_stream_new (G_INPUT_STREAM (file_stream));
+
+	/* read groups line by line, ignoring comments */
+	while ((value = g_data_input_stream_read_line (data_stream, NULL, NULL, &e)) != NULL) {
+		PkGroupEnum group;
+
+		g_strstrip (value);
+		if (*value == '\0' || *value == '#') {
+			g_free (value);
+			continue;
+		}
+
+		/* line format: alpm-group (space|tab)+ packagekit-group */
+		key = strsep (&value, " 	");
+		g_strchomp (key);
+
+		if (value == NULL) {
+			/* safe to cast as it is never freed or modified */
+			value = (gchar *) "other";
+			group = PK_GROUP_ENUM_OTHER;
+		} else {
+			g_strchug (value);
+			group = pk_group_enum_from_string (value);
+		}
+
+		if (group != PK_GROUP_ENUM_UNKNOWN) {
+			/* use replace because key and value are allocated together */
+			g_hash_table_replace (map, key, value);
+			pk_bitfield_add (groups, group);
+		}
+	}
+
+	g_object_unref (data_stream);
+	g_object_unref (file_stream);
+	g_object_unref (file);
+
+	if (e != NULL) {
+		g_hash_table_unref (map);
+		g_propagate_error (error, e);
+		return NULL;
+	} else {
+		return map;
+	}
+}
+
+gboolean
+backend_initialize_groups (PkBackend *backend, GError **error)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	group_map = group_map_new (error);
+	if (group_map == NULL) {
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+void
+backend_destroy_groups (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+
+	if (group_map != NULL) {
+		g_hash_table_unref (group_map);
+	}
+}
+
+const gchar *
+pacman_package_get_group (PacmanPackage *package)
+{
+	const PacmanList *list;
+
+	g_return_val_if_fail (group_map != NULL, NULL);
+	g_return_val_if_fail (package != NULL, NULL);
+
+	/* use the first group that we recognise */
+	for (list = pacman_package_get_groups (package); list != NULL; list = pacman_list_next (list)) {
+		gpointer value = g_hash_table_lookup (group_map, pacman_list_get (list));
+		if (value != NULL) {
+			return (const gchar *) value;
+		}
+	}
+
+	return "other";
+}
+
+/**
+ * backend_get_groups:
+ **/
+PkBitfield backend_get_groups (PkBackend *backend)
+{
+	g_return_val_if_fail (backend != NULL, 0);
+
+	return groups;
+}
diff --git a/backends/pacman/backend-groups.h b/backends/pacman/backend-groups.h
new file mode 100644
index 0000000..9642015
--- /dev/null
+++ b/backends/pacman/backend-groups.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pacman.h>
+#include <pk-backend.h>
+
+gboolean	 backend_initialize_groups	(PkBackend	*backend,
+						 GError		**error);
+void		 backend_destroy_groups		(PkBackend	*backend);
+
+const gchar	*pacman_package_get_group	(PacmanPackage	*package);
+PkBitfield	 backend_get_groups		(PkBackend	*backend);
diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
index 02cf542..c96454c 100644
--- a/backends/pacman/backend-pacman.c
+++ b/backends/pacman/backend-pacman.c
@@ -22,6 +22,7 @@
  */
 
 #include "backend-error.h"
+#include "backend-groups.h"
 #include "backend-repos.h"
 #include "backend-pacman.h"
 
@@ -85,6 +86,13 @@ backend_initialize (PkBackend *backend)
 		g_error_free (error);
 		return;
 	}
+
+	/* read the group mapping from a config file */
+	if (!backend_initialize_groups (backend, &error)) {
+		egg_error ("pacman: %s", error->message);
+		g_error_free (error);
+		return;
+	}
 }
 
 /**
@@ -97,6 +105,7 @@ backend_destroy (PkBackend *backend)
 
 	egg_debug ("pacman: cleaning up");
 
+	backend_destroy_groups (backend);
 	backend_destroy_databases (backend);
 
 	if (pacman != NULL) {
@@ -190,7 +199,7 @@ PK_BACKEND_OPTIONS (
 	"Jonathan Conder <j at skurvy.no-ip.org>",	/* author */
 	backend_initialize,			/* initialize */
 	backend_destroy,			/* destroy */
-	NULL,					/* get_groups */
+	backend_get_groups,			/* get_groups */
 	backend_get_filters,			/* get_filters */
 	NULL,					/* get_roles */
 	backend_get_mime_types,			/* get_mime_types */
diff --git a/backends/pacman/groups.list b/backends/pacman/groups.list
new file mode 100644
index 0000000..b2c02ae
--- /dev/null
+++ b/backends/pacman/groups.list
@@ -0,0 +1,65 @@
+adesklet-desklets	desktop-other
+base			system
+base-devel		programming
+bmp-io-plugins		multimedia
+bmp-plugins		multimedia
+cegcc			programming
+compiz			desktop-other
+compiz-fusion		desktop-other
+compiz-fusion-gtk	desktop-gnome
+compiz-fusion-kde	desktop-kde
+compiz-gnome		desktop-gnome
+compiz-gtk		desktop-gnome
+compiz-kde		desktop-kde
+e17-extra-svn		desktop-other
+e17-libs-svn		desktop-other
+e17-svn			desktop-other
+fprint			other
+gimp-help		other
+gimp-plugins		other
+gnome			desktop-gnome
+gnome-extra		desktop-gnome
+gnustep-core		desktop-other
+google-gadgets		desktop-other
+gstreamer0.10-plugins	multimedia
+kde			desktop-kde
+kdeaccessibility	desktop-kde
+kdeadmin		desktop-kde
+kdeartwork		desktop-kde
+kdebase			desktop-kde
+kdeedu			desktop-kde
+kde-extragear		desktop-kde
+kdegames		desktop-kde
+kdegraphics		desktop-kde
+kde-l10n		desktop-kde
+kde-meta		desktop-kde
+kdemultimedia		desktop-kde
+kdenetwork		desktop-kde
+kdepim			desktop-kde
+kdeplasma-addons	desktop-kde
+kdesdk			desktop-kde
+kdetoys			desktop-kde
+kdeutils		desktop-kde
+kdewebdev		desktop-kde
+koffice			desktop-kde
+ladspa-plugins		multimedia
+lib32			other
+lxde			other
+qtcurve			desktop-kde
+rox-desktop		desktop-other
+telepathy		other
+texlive-lang		other
+texlive-lang-doc	other
+texlive-most		other
+texlive-most-doc	other
+thunderbird-i18n	other
+thunderbird-spell-i18n	other
+vim-plugins		other
+xfce4			desktop-xfce
+xfce4-goodies		desktop-xfce
+xmms-effect-plugins	multimedia
+xmms-io-plugins		multimedia
+xmms-plugins		multimedia
+xorg			desktop-other
+xorg-input-drivers	desktop-other
+xorg-video-drivers	desktop-other
commit a0c504f2298169a7824ff5ba77fa82d992099080
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Sun May 2 14:04:40 2010 +1200

    pacman: add support for managing repos

diff --git a/backends/pacman/Makefile.am b/backends/pacman/Makefile.am
index f3bb00f..c1091aa 100644
--- a/backends/pacman/Makefile.am
+++ b/backends/pacman/Makefile.am
@@ -1,17 +1,23 @@
 PACMAN_CONFIG_FILE = $(confdir)/pacman.conf
+PACMAN_REPO_LIST = $(confdir)/repos.list
+PACMAN_REPO_LIST_HEADER = "\# Generated by $(PACKAGE_NAME) - DO NOT MODIFY"
 PACMAN_DEFAULT_PATH = "/bin:/usr/bin:/sbin:/usr/sbin"
 
 DEFS = -DPACMAN_CONFIG_FILE=\"$(PACMAN_CONFIG_FILE)\" \
+       -DPACMAN_REPO_LIST=\"$(PACMAN_REPO_LIST)\" \
+       -DPACMAN_REPO_LIST_HEADER=\"$(PACMAN_REPO_LIST_HEADER)\" \
        -DPACMAN_DEFAULT_PATH=\"$(PACMAN_DEFAULT_PATH)\"
 
 confdir = $(PK_CONF_DIR)/pacman.d
-conf_DATA = pacman.conf
+conf_DATA = pacman.conf \
+            repos.list
 
 plugindir = $(PK_PLUGIN_DIR)
 plugin_LTLIBRARIES = libpk_backend_pacman.la
 
 libpk_backend_pacman_la_SOURCES = backend-error.c \
-                                  backend-pacman.c
+                                  backend-pacman.c \
+                                  backend-repos.c
 libpk_backend_pacman_la_LIBADD = $(PK_PLUGIN_LIBS) \
                                  $(PACMAN_LIBS)
 libpk_backend_pacman_la_LDFLAGS = -module -avoid-version
@@ -19,4 +25,11 @@ libpk_backend_pacman_la_CFLAGS = $(PK_PLUGIN_CFLAGS) \
                                  $(PACMAN_CFLAGS) \
                                  $(WARNINGFLAGS_C)
 
+repos.list:
+	echo $(PACMAN_REPO_LIST_HEADER) > $@
+
+BUILT_SOURCES = repos.list
+
 EXTRA_DIST = $(conf_DATA) $(libpk_backend_pacman_la_SOURCES:.c=.h)
+
+CLEANFILES = $(BUILT_SOURCES)
diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
index 77cc4f4..02cf542 100644
--- a/backends/pacman/backend-pacman.c
+++ b/backends/pacman/backend-pacman.c
@@ -22,6 +22,7 @@
  */
 
 #include "backend-error.h"
+#include "backend-repos.h"
 #include "backend-pacman.h"
 
 PacmanManager *pacman = NULL;
@@ -78,8 +79,8 @@ backend_initialize (PkBackend *backend)
 		return;
 	}
 
-	/* read configuration from PackageKit pacman config file */
-	if (!pacman_manager_configure (pacman, PACMAN_CONFIG_FILE, &error)) {
+	/* configure and disable the relevant databases */
+	if (!backend_initialize_databases (backend, &error)) {
 		egg_error ("pacman: %s", error->message);
 		g_error_free (error);
 		return;
@@ -96,6 +97,8 @@ backend_destroy (PkBackend *backend)
 
 	egg_debug ("pacman: cleaning up");
 
+	backend_destroy_databases (backend);
+
 	if (pacman != NULL) {
 		g_object_unref (pacman);
 	}
@@ -199,7 +202,7 @@ PK_BACKEND_OPTIONS (
 	NULL,					/* get_distro_upgrades */
 	NULL,					/* get_files */
 	NULL,					/* get_packages */
-	NULL,					/* get_repo_list */
+	backend_get_repo_list,			/* get_repo_list */
 	NULL,					/* get_requires */
 	NULL,					/* get_update_detail */
 	NULL,					/* get_updates */
@@ -208,7 +211,7 @@ PK_BACKEND_OPTIONS (
 	NULL,					/* install_signature */
 	NULL,					/* refresh_cache */
 	NULL,					/* remove_packages */
-	NULL,					/* repo_enable */
+	backend_repo_enable,			/* repo_enable */
 	NULL,					/* repo_set_data */
 	NULL,					/* resolve */
 	NULL,					/* rollback */
diff --git a/backends/pacman/backend-repos.c b/backends/pacman/backend-repos.c
new file mode 100644
index 0000000..35332be
--- /dev/null
+++ b/backends/pacman/backend-repos.c
@@ -0,0 +1,298 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "backend-error.h"
+#include "backend-pacman.h"
+#include "backend-repos.h"
+
+PacmanDatabase *local_database = NULL;
+static GHashTable *disabled_repos = NULL;
+
+static GHashTable *
+disabled_repos_new (GError **error)
+{
+	GHashTable *disabled;
+	GFile *file;
+
+	GFileInputStream *file_stream;
+	GDataInputStream *data_stream;
+
+	gchar *line;
+	GError *e = NULL;
+
+	egg_debug ("pacman: reading disabled repos from %s", PACMAN_REPO_LIST);
+	file = g_file_new_for_path (PACMAN_REPO_LIST);
+	file_stream = g_file_read (file, NULL, &e);
+
+	if (file_stream == NULL) {
+		g_object_unref (file);
+		g_propagate_error (error, e);
+		return NULL;
+	}
+
+	disabled = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	data_stream = g_data_input_stream_new (G_INPUT_STREAM (file_stream));
+
+	/* read disabled repos line by line, ignoring comments */
+	while ((line = g_data_input_stream_read_line (data_stream, NULL, NULL, &e)) != NULL) {
+		g_strstrip (line);
+
+		if (*line == '\0' || *line == '#') {
+			g_free (line);
+			continue;
+		}
+
+		g_hash_table_insert (disabled, line, GINT_TO_POINTER (1));
+	}
+
+	g_object_unref (data_stream);
+	g_object_unref (file_stream);
+	g_object_unref (file);
+
+	if (e != NULL) {
+		g_hash_table_unref (disabled);
+		g_propagate_error (error, e);
+		return NULL;
+	} else {
+		return disabled;
+	}
+}
+
+static gboolean
+disabled_repos_configure (GHashTable *disabled, GError **error)
+{
+	const PacmanList *databases;
+
+	g_return_val_if_fail (pacman != NULL, FALSE);
+
+	egg_debug ("pacman: reading config from %s", PACMAN_CONFIG_FILE);
+
+	/* read configuration from pacman config file */
+	if (!pacman_manager_configure (pacman, PACMAN_CONFIG_FILE, error)) {
+		return FALSE;
+	}
+
+	local_database = pacman_manager_get_local_database (pacman);
+
+	/* disable disabled repos */
+	for (databases = pacman_manager_get_sync_databases (pacman); databases != NULL; databases = pacman_list_next (databases)) {
+		PacmanDatabase *database = (PacmanDatabase *) pacman_list_get (databases);
+		const gchar *repo = pacman_database_get_name (database);
+
+		if (g_hash_table_lookup (disabled, repo) != NULL) {
+			if (!pacman_manager_unregister_database (pacman, database, error)) {
+				return FALSE;
+			}
+
+			/* start again as the list gets invalidated */
+			databases = pacman_manager_get_sync_databases (pacman);
+		}
+	}
+
+	return TRUE;
+}
+
+static void
+disabled_repos_free (GHashTable *disabled)
+{
+	GHashTableIter iter;
+	GFile *file;
+
+	GFileOutputStream *file_stream;
+	GDataOutputStream *data_stream;
+
+	const gchar *line = PACMAN_REPO_LIST_HEADER "\n";
+
+	g_return_if_fail (disabled != NULL);
+
+	egg_debug ("pacman: storing disabled repos in %s", PACMAN_REPO_LIST);
+	file = g_file_new_for_path (PACMAN_REPO_LIST);
+	file_stream = g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL);
+
+	if (file_stream == NULL) {
+		g_object_unref (file);
+		g_hash_table_unref (disabled);
+		return;
+	}
+
+	g_hash_table_iter_init (&iter, disabled);
+	data_stream = g_data_output_stream_new (G_OUTPUT_STREAM (file_stream));
+
+	/* write header, then all disabled repos line by line */
+	if (g_data_output_stream_put_string (data_stream, line, NULL, NULL)) {
+		while (g_hash_table_iter_next (&iter, (gpointer *) &line, NULL) &&
+			g_data_output_stream_put_string (data_stream, line, NULL, NULL) &&
+			g_data_output_stream_put_string (data_stream, "\n", NULL, NULL));
+	}
+
+	g_object_unref (data_stream);
+	g_object_unref (file_stream);
+	g_object_unref (file);
+	g_hash_table_unref (disabled);
+}
+
+gboolean
+backend_initialize_databases (PkBackend *backend, GError **error)
+{
+	g_return_val_if_fail (pacman != NULL, FALSE);
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	disabled_repos = disabled_repos_new (error);
+	if (disabled_repos == NULL) {
+		return FALSE;
+	}
+
+	if (!disabled_repos_configure (disabled_repos, error)) {
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+void
+backend_destroy_databases (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+
+	if (disabled_repos != NULL) {
+		disabled_repos_free (disabled_repos);
+	}
+}
+
+static gboolean
+backend_get_repo_list_thread (PkBackend *backend)
+{
+	const PacmanList *databases;
+	GHashTableIter iter;
+	gpointer key, value;
+
+	g_return_val_if_fail (pacman != NULL, FALSE);
+	g_return_val_if_fail (disabled_repos != NULL, FALSE);
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	/* emit enabled repos */
+	for (databases = pacman_manager_get_sync_databases (pacman); databases != NULL; databases = pacman_list_next (databases)) {
+		PacmanDatabase *database = (PacmanDatabase *) pacman_list_get (databases);
+		const gchar *repo = pacman_database_get_name (database);
+
+		if (backend_cancelled (backend)) {
+			break;
+		} else {
+			pk_backend_repo_detail (backend, repo, repo, TRUE);
+		}
+	}
+
+	/* emit disabled repos */
+	g_hash_table_iter_init (&iter, disabled_repos);
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		const gchar *repo = (const gchar *) key;
+
+		if (backend_cancelled (backend)) {
+			break;
+		} else {
+			pk_backend_repo_detail (backend, repo, repo, FALSE);
+		}
+	}
+
+	backend_finished (backend);
+	return TRUE;
+}
+
+/**
+ * backend_get_repo_list:
+ **/
+void
+backend_get_repo_list (PkBackend *backend, PkBitfield filters)
+{
+	g_return_if_fail (backend != NULL);
+
+	backend_run (backend, PK_STATUS_ENUM_QUERY, backend_get_repo_list_thread);
+}
+
+static gboolean
+backend_repo_enable_thread (PkBackend *backend)
+{
+	GError *error = NULL;
+
+	const gchar *repo;
+	gboolean enabled;
+
+	g_return_val_if_fail (pacman != NULL, FALSE);
+	g_return_val_if_fail (disabled_repos != NULL, FALSE);
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	repo = pk_backend_get_string (backend, "repo_id");
+	enabled = pk_backend_get_bool (backend, "enabled");
+
+	g_return_val_if_fail (repo != NULL, FALSE);
+
+	if (enabled) {
+		/* check that repo is indeed disabled */
+		if (g_hash_table_remove (disabled_repos, repo)) {
+			/* reload configuration to preserve the correct order */
+			if (disabled_repos_configure (disabled_repos, &error)) {
+				pk_backend_repo_list_changed (backend);
+			} else {
+				backend_error (backend, error);
+				pk_backend_thread_finished (backend);
+				return FALSE;
+			}
+		} else {
+			pk_backend_error_code (backend, PK_ERROR_ENUM_REPO_NOT_FOUND, "Could not find repo [%s]", repo);
+			pk_backend_thread_finished (backend);
+			return FALSE;
+		}
+	} else {
+		PacmanDatabase *database = pacman_manager_find_sync_database (pacman, repo);
+
+		if (database != NULL) {
+			if (pacman_manager_unregister_database (pacman, database, &error)) {
+				g_hash_table_insert (disabled_repos, g_strdup (repo), GINT_TO_POINTER (1));
+			} else {
+				backend_error (backend, error);
+				pk_backend_thread_finished (backend);
+				return FALSE;
+			}
+		} else {
+			pk_backend_error_code (backend, PK_ERROR_ENUM_REPO_NOT_FOUND, "Could not find repo [%s]", repo);
+			pk_backend_thread_finished (backend);
+			return FALSE;
+		}
+	}
+
+	pk_backend_thread_finished (backend);
+	return TRUE;
+}
+
+/**
+ * backend_repo_enable:
+ **/
+void
+backend_repo_enable (PkBackend *backend, const gchar *repo, gboolean enabled)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (repo != NULL);
+
+	pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
+	pk_backend_thread_create (backend, backend_repo_enable_thread);
+}
diff --git a/backends/pacman/backend-repos.h b/backends/pacman/backend-repos.h
new file mode 100644
index 0000000..7faba0c
--- /dev/null
+++ b/backends/pacman/backend-repos.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pacman.h>
+#include <pk-backend.h>
+
+extern PacmanDatabase	*local_database;
+
+gboolean	 backend_initialize_databases	(PkBackend	*backend,
+						 GError		**error);
+void		 backend_destroy_databases	(PkBackend	*backend);
+
+void		 backend_get_repo_list		(PkBackend	*backend,
+						 PkBitfield	 filters);
+void		 backend_repo_enable		(PkBackend	*backend,
+						 const gchar	*repo,
+						 gboolean	 enabled);
commit b0d10be480615b02fcc4445e7c13f6c39c5b1458
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Sun May 2 13:57:09 2010 +1200

    pacman: add cancellation infrastructure

diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
index 2a47b3b..77cc4f4 100644
--- a/backends/pacman/backend-pacman.c
+++ b/backends/pacman/backend-pacman.c
@@ -25,6 +25,7 @@
 #include "backend-pacman.h"
 
 PacmanManager *pacman = NULL;
+GCancellable *cancellable = NULL;
 
 static void
 pacman_message_cb (const gchar *domain, GLogLevelFlags level, const gchar *message, gpointer user_data)
@@ -123,6 +124,64 @@ backend_get_mime_types (PkBackend *backend)
 	return g_strdup ("application/x-compressed-tar;application/x-xz-compressed-tar");
 }
 
+void
+backend_run (PkBackend *backend, PkStatusEnum status, PkBackendThreadFunc func)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (func != NULL);
+
+	if (cancellable != NULL) {
+		egg_warning ("pacman: cancellable was not NULL");
+		g_object_unref (cancellable);
+	}
+	cancellable = g_cancellable_new ();
+	pk_backend_set_allow_cancel (backend, TRUE);
+
+	pk_backend_set_status (backend, status);
+	pk_backend_thread_create (backend, func);
+}
+
+/**
+ * backend_cancel:
+ **/
+static void
+backend_cancel (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+
+	if (cancellable != NULL) {
+		g_cancellable_cancel (cancellable);
+	}
+}
+
+gboolean
+backend_cancelled (PkBackend *backend)
+{
+	g_return_val_if_fail (cancellable != NULL, FALSE);
+	g_return_val_if_fail (backend != NULL, FALSE);
+
+	if (g_cancellable_is_cancelled (cancellable)) {
+		pk_backend_set_status (backend, PK_STATUS_ENUM_CANCEL);
+		return TRUE;
+	} else {
+		return FALSE;
+	}
+}
+
+void
+backend_finished (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+
+	pk_backend_set_allow_cancel (backend, FALSE);
+	if (cancellable != NULL) {
+		g_object_unref (cancellable);
+		cancellable = NULL;
+	}
+
+	pk_backend_thread_finished (backend);
+}
+
 PK_BACKEND_OPTIONS (
 	"pacman",				/* description */
 	"Jonathan Conder <j at skurvy.no-ip.org>",	/* author */
@@ -132,7 +191,7 @@ PK_BACKEND_OPTIONS (
 	backend_get_filters,			/* get_filters */
 	NULL,					/* get_roles */
 	backend_get_mime_types,			/* get_mime_types */
-	NULL,					/* cancel */
+	backend_cancel,				/* cancel */
 	NULL,					/* download_packages */
 	NULL,					/* get_categories */
 	NULL,					/* get_depends */
diff --git a/backends/pacman/backend-pacman.h b/backends/pacman/backend-pacman.h
index 87b0d77..0d7b89b 100644
--- a/backends/pacman/backend-pacman.h
+++ b/backends/pacman/backend-pacman.h
@@ -21,7 +21,15 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#include <gio/gio.h>
 #include <pacman.h>
 #include <pk-backend.h>
 
 extern PacmanManager	*pacman;
+extern GCancellable	*cancellable;
+
+void		 backend_run		(PkBackend		*backend,
+					 PkStatusEnum		 status,
+					 PkBackendThreadFunc	 func);
+gboolean	 backend_cancelled	(PkBackend		*backend);
+void		 backend_finished	(PkBackend		*backend);
commit 5f1ceb316f4cc2f5512e858855818f7d307095b5
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Sun May 2 13:53:57 2010 +1200

    pacman: add trivial backend functions

diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
index dda24d3..2a47b3b 100644
--- a/backends/pacman/backend-pacman.c
+++ b/backends/pacman/backend-pacman.c
@@ -100,15 +100,38 @@ backend_destroy (PkBackend *backend)
 	}
 }
 
+/**
+ * backend_get_filters:
+ **/
+static PkBitfield
+backend_get_filters (PkBackend *backend)
+{
+	g_return_val_if_fail (backend != NULL, 0);
+
+	return pk_bitfield_from_enums (PK_FILTER_ENUM_INSTALLED, -1);
+}
+
+/**
+ * backend_get_mime_types:
+ **/
+static gchar *
+backend_get_mime_types (PkBackend *backend)
+{
+	g_return_val_if_fail (backend != NULL, NULL);
+
+	/* packages currently use .pkg.tar.gz and .pkg.tar.xz */
+	return g_strdup ("application/x-compressed-tar;application/x-xz-compressed-tar");
+}
+
 PK_BACKEND_OPTIONS (
 	"pacman",				/* description */
 	"Jonathan Conder <j at skurvy.no-ip.org>",	/* author */
 	backend_initialize,			/* initialize */
 	backend_destroy,			/* destroy */
 	NULL,					/* get_groups */
-	NULL,					/* get_filters */
+	backend_get_filters,			/* get_filters */
 	NULL,					/* get_roles */
-	NULL,					/* get_mime_types */
+	backend_get_mime_types,			/* get_mime_types */
 	NULL,					/* cancel */
 	NULL,					/* download_packages */
 	NULL,					/* get_categories */
commit a2af32b3175c32d6a4657e7afbe455ce3fd0d7ae
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Sun May 2 13:46:43 2010 +1200

    pacman: add error reporting infrastructure

diff --git a/backends/pacman/Makefile.am b/backends/pacman/Makefile.am
index 98e047b..f3bb00f 100644
--- a/backends/pacman/Makefile.am
+++ b/backends/pacman/Makefile.am
@@ -10,7 +10,8 @@ conf_DATA = pacman.conf
 plugindir = $(PK_PLUGIN_DIR)
 plugin_LTLIBRARIES = libpk_backend_pacman.la
 
-libpk_backend_pacman_la_SOURCES = backend-pacman.c
+libpk_backend_pacman_la_SOURCES = backend-error.c \
+                                  backend-pacman.c
 libpk_backend_pacman_la_LIBADD = $(PK_PLUGIN_LIBS) \
                                  $(PACMAN_LIBS)
 libpk_backend_pacman_la_LDFLAGS = -module -avoid-version
diff --git a/backends/pacman/backend-error.c b/backends/pacman/backend-error.c
new file mode 100644
index 0000000..2336508
--- /dev/null
+++ b/backends/pacman/backend-error.c
@@ -0,0 +1,185 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pacman.h>
+#include "backend-error.h"
+
+void
+backend_error (PkBackend *backend, GError *error)
+{
+	PkErrorEnum code = PK_ERROR_ENUM_INTERNAL_ERROR;
+
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (error != NULL);
+
+	/* convert error codes */
+	if (error->domain == PACMAN_ERROR) {
+		switch (error->code) {
+			case PACMAN_ERROR_MEMORY:
+				code = PK_ERROR_ENUM_OOM;
+				break;
+
+			case PACMAN_ERROR_SYSTEM:
+			case PACMAN_ERROR_INVALID_ARGS:
+			case PACMAN_ERROR_NOT_INITIALIZED:
+			case PACMAN_ERROR_DATABASE_NOT_INITIALIZED:
+			case PACMAN_ERROR_SERVER_INVALID_URL:
+			case PACMAN_ERROR_REGEX_INVALID:
+			case PACMAN_ERROR_LIBARCHIVE:
+			case PACMAN_ERROR_LIBFETCH:
+			case PACMAN_ERROR_DOWNLOAD_HANDLER:
+				code = PK_ERROR_ENUM_INTERNAL_ERROR;
+				break;
+
+			case PACMAN_ERROR_NOT_PERMITTED:
+				code = PK_ERROR_ENUM_NOT_AUTHORIZED;
+				break;
+
+			case PACMAN_ERROR_FILE_NOT_FOUND:
+			case PACMAN_ERROR_DIRECTORY_NOT_FOUND:
+				code = PK_ERROR_ENUM_FILE_NOT_FOUND;
+				break;
+
+			case PACMAN_ERROR_ALREADY_INITIALIZED:
+			case PACMAN_ERROR_DATABASE_ALREADY_INITIALIZED:
+				code = PK_ERROR_ENUM_FAILED_INITIALIZATION;
+				break;
+
+			case PACMAN_ERROR_ALREADY_RUNNING:
+				code = PK_ERROR_ENUM_CANNOT_GET_LOCK;
+				break;
+
+			case PACMAN_ERROR_DATABASE_OPEN_FAILED:
+				code = PK_ERROR_ENUM_REPO_NOT_FOUND;
+				break;
+
+			case PACMAN_ERROR_DATABASE_CREATE_FAILED:
+				code = PK_ERROR_ENUM_CANNOT_WRITE_REPO_CONFIG;
+				break;
+
+			case PACMAN_ERROR_DATABASE_NOT_FOUND:
+				code = PK_ERROR_ENUM_REPO_NOT_FOUND;
+				break;
+
+			case PACMAN_ERROR_DATABASE_UPDATE_FAILED:
+				code = PK_ERROR_ENUM_REPO_NOT_AVAILABLE;
+				break;
+
+			case PACMAN_ERROR_DATABASE_REMOVE_FAILED:
+				code = PK_ERROR_ENUM_REPO_CONFIGURATION_ERROR;
+				break;
+
+			case PACMAN_ERROR_SERVER_NONE_AVAILABLE:
+				code = PK_ERROR_ENUM_NO_MORE_MIRRORS_TO_TRY;
+				break;
+
+			case PACMAN_ERROR_TRANSACTION_ALREADY_INITIALIZED:
+			case PACMAN_ERROR_TRANSACTION_NOT_INITIALIZED:
+			case PACMAN_ERROR_TRANSACTION_DUPLICATE_TARGET:
+			case PACMAN_ERROR_TRANSACTION_NOT_READY:
+			case PACMAN_ERROR_TRANSACTION_NOT_PREPARED:
+			case PACMAN_ERROR_TRANSACTION_INVALID_OPERATION:
+			case PACMAN_ERROR_TRANSACTION_NOT_LOCKED:
+				code = PK_ERROR_ENUM_TRANSACTION_ERROR;
+				break;
+
+			case PACMAN_ERROR_TRANSACTION_ABORTED:
+				code = PK_ERROR_ENUM_TRANSACTION_CANCELLED;
+				break;
+
+			case PACMAN_ERROR_PACKAGE_NOT_FOUND:
+				code = PK_ERROR_ENUM_PACKAGE_NOT_FOUND;
+				break;
+
+			case PACMAN_ERROR_PACKAGE_IGNORED:
+				code = PK_ERROR_ENUM_PACKAGE_INSTALL_BLOCKED;
+				break;
+
+			case PACMAN_ERROR_DELTA_INVALID:
+			case PACMAN_ERROR_PACKAGE_INVALID:
+				code = PK_ERROR_ENUM_INVALID_PACKAGE_FILE;
+				break;
+
+			case PACMAN_ERROR_PACKAGE_OPEN_FAILED:
+				code = PK_ERROR_ENUM_PACKAGE_NOT_FOUND;
+				break;
+
+			case PACMAN_ERROR_PACKAGE_REMOVE_FAILED:
+				code = PK_ERROR_ENUM_PACKAGE_FAILED_TO_REMOVE;
+				break;
+
+			case PACMAN_ERROR_PACKAGE_UNKNOWN_FILENAME:
+			case PACMAN_ERROR_PACKAGE_DATABASE_NOT_FOUND:
+				code = PK_ERROR_ENUM_PACKAGE_FAILED_TO_CONFIGURE;
+				break;
+
+			case PACMAN_ERROR_DELTA_PATCH_FAILED:
+				code = PK_ERROR_ENUM_PACKAGE_FAILED_TO_BUILD;
+				break;
+
+			case PACMAN_ERROR_DEPENDENCY_UNSATISFIED:
+				code = PK_ERROR_ENUM_DEP_RESOLUTION_FAILED;
+				break;
+
+			case PACMAN_ERROR_CONFLICT:
+				code = PK_ERROR_ENUM_PACKAGE_CONFLICTS;
+				break;
+
+			case PACMAN_ERROR_FILE_CONFLICT:
+				code = PK_ERROR_ENUM_FILE_CONFLICTS;
+				break;
+
+			case PACMAN_ERROR_DOWNLOAD_FAILED:
+				code = PK_ERROR_ENUM_PACKAGE_DOWNLOAD_FAILED;
+				break;
+
+			case PACMAN_ERROR_CONFIG_INVALID:
+				code = PK_ERROR_ENUM_FAILED_CONFIG_PARSING;
+				break;
+
+			case PACMAN_ERROR_PACKAGE_HELD:
+				code = PK_ERROR_ENUM_CANNOT_REMOVE_SYSTEM_PACKAGE;
+				break;
+		}
+	}
+
+	pk_backend_error_code (backend, code, "%s", error->message);
+	g_error_free (error);
+}
+
+void
+backend_message (PkBackend *backend, const gchar *message)
+{
+	guint iterator;
+	gchar **messages = g_strsplit_set (message, "\r\n", 0);
+
+	/* display multi-line messages in a nice format */
+	for (iterator = 0; messages[iterator] != NULL; ++iterator) {
+		g_strstrip (messages[iterator]);
+		if (*messages[iterator] != '\0') {
+			pk_backend_message (backend, PK_MESSAGE_ENUM_UNKNOWN, "%s", messages[iterator]);
+		}
+	}
+
+	g_strfreev (messages);
+}
diff --git a/backends/pacman/backend-error.h b/backends/pacman/backend-error.h
new file mode 100644
index 0000000..2be8021
--- /dev/null
+++ b/backends/pacman/backend-error.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pk-backend.h>
+
+void	 backend_error		(PkBackend	*backend,
+				 GError		*error);
+void	 backend_message	(PkBackend	*backend,
+				 const gchar	*message);
diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
index 12cf961..dda24d3 100644
--- a/backends/pacman/backend-pacman.c
+++ b/backends/pacman/backend-pacman.c
@@ -21,10 +21,35 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#include "backend-error.h"
 #include "backend-pacman.h"
 
 PacmanManager *pacman = NULL;
 
+static void
+pacman_message_cb (const gchar *domain, GLogLevelFlags level, const gchar *message, gpointer user_data)
+{
+	g_return_if_fail (message != NULL);
+	g_return_if_fail (user_data != NULL);
+
+	/* report important output to PackageKit */
+	switch (level) {
+		case G_LOG_LEVEL_WARNING:
+		case G_LOG_LEVEL_MESSAGE:
+			egg_warning ("pacman: %s", message);
+			backend_message ((PkBackend *) user_data, message);
+			break;
+
+		case G_LOG_LEVEL_INFO:
+		case G_LOG_LEVEL_DEBUG:
+			egg_debug ("pacman: %s", message);
+			break;
+
+		default:
+			break;
+	}
+}
+
 /**
  * backend_initialize:
  **/
@@ -32,9 +57,13 @@ static void
 backend_initialize (PkBackend *backend)
 {
 	GError *error = NULL;
+	GLogLevelFlags flags = G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG;
 
 	g_return_if_fail (backend != NULL);
 
+	/* handle output from pacman */
+	g_log_set_handler ("Pacman", flags, pacman_message_cb, backend);
+
 	/* PATH needs to be set for install scriptlets */
 	g_setenv ("PATH", PACMAN_DEFAULT_PATH, FALSE);
 
commit 846d652ad912c15d3e342f48a8face885bc79716
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Sun May 2 13:36:44 2010 +1200

    create skeleton pacman-glib backend

diff --git a/backends/Makefile.am b/backends/Makefile.am
index 7e0439a..37d7059 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -32,6 +32,10 @@ if BACKEND_TYPE_OPKG
 SUBDIRS += opkg
 endif
 
+if BACKEND_TYPE_PACMAN
+SUBDIRS += pacman
+endif
+
 if BACKEND_TYPE_RAZOR
 SUBDIRS += razor
 endif
diff --git a/backends/pacman/Makefile.am b/backends/pacman/Makefile.am
new file mode 100644
index 0000000..98e047b
--- /dev/null
+++ b/backends/pacman/Makefile.am
@@ -0,0 +1,21 @@
+PACMAN_CONFIG_FILE = $(confdir)/pacman.conf
+PACMAN_DEFAULT_PATH = "/bin:/usr/bin:/sbin:/usr/sbin"
+
+DEFS = -DPACMAN_CONFIG_FILE=\"$(PACMAN_CONFIG_FILE)\" \
+       -DPACMAN_DEFAULT_PATH=\"$(PACMAN_DEFAULT_PATH)\"
+
+confdir = $(PK_CONF_DIR)/pacman.d
+conf_DATA = pacman.conf
+
+plugindir = $(PK_PLUGIN_DIR)
+plugin_LTLIBRARIES = libpk_backend_pacman.la
+
+libpk_backend_pacman_la_SOURCES = backend-pacman.c
+libpk_backend_pacman_la_LIBADD = $(PK_PLUGIN_LIBS) \
+                                 $(PACMAN_LIBS)
+libpk_backend_pacman_la_LDFLAGS = -module -avoid-version
+libpk_backend_pacman_la_CFLAGS = $(PK_PLUGIN_CFLAGS) \
+                                 $(PACMAN_CFLAGS) \
+                                 $(WARNINGFLAGS_C)
+
+EXTRA_DIST = $(conf_DATA) $(libpk_backend_pacman_la_SOURCES:.c=.h)
diff --git a/backends/pacman/backend-pacman.c b/backends/pacman/backend-pacman.c
new file mode 100644
index 0000000..12cf961
--- /dev/null
+++ b/backends/pacman/backend-pacman.c
@@ -0,0 +1,115 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "backend-pacman.h"
+
+PacmanManager *pacman = NULL;
+
+/**
+ * backend_initialize:
+ **/
+static void
+backend_initialize (PkBackend *backend)
+{
+	GError *error = NULL;
+
+	g_return_if_fail (backend != NULL);
+
+	/* PATH needs to be set for install scriptlets */
+	g_setenv ("PATH", PACMAN_DEFAULT_PATH, FALSE);
+
+	egg_debug ("pacman: initializing");
+
+	/* initialize pacman-glib */
+	pacman = pacman_manager_get (&error);
+	if (pacman == NULL) {
+		egg_error ("pacman: %s", error->message);
+		g_error_free (error);
+		return;
+	}
+
+	/* read configuration from PackageKit pacman config file */
+	if (!pacman_manager_configure (pacman, PACMAN_CONFIG_FILE, &error)) {
+		egg_error ("pacman: %s", error->message);
+		g_error_free (error);
+		return;
+	}
+}
+
+/**
+ * backend_destroy:
+ **/
+static void
+backend_destroy (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+
+	egg_debug ("pacman: cleaning up");
+
+	if (pacman != NULL) {
+		g_object_unref (pacman);
+	}
+}
+
+PK_BACKEND_OPTIONS (
+	"pacman",				/* description */
+	"Jonathan Conder <j at skurvy.no-ip.org>",	/* author */
+	backend_initialize,			/* initialize */
+	backend_destroy,			/* destroy */
+	NULL,					/* get_groups */
+	NULL,					/* get_filters */
+	NULL,					/* get_roles */
+	NULL,					/* get_mime_types */
+	NULL,					/* cancel */
+	NULL,					/* download_packages */
+	NULL,					/* get_categories */
+	NULL,					/* get_depends */
+	NULL,					/* get_details */
+	NULL,					/* get_distro_upgrades */
+	NULL,					/* get_files */
+	NULL,					/* get_packages */
+	NULL,					/* get_repo_list */
+	NULL,					/* get_requires */
+	NULL,					/* get_update_detail */
+	NULL,					/* get_updates */
+	NULL,					/* install_files */
+	NULL,					/* install_packages */
+	NULL,					/* install_signature */
+	NULL,					/* refresh_cache */
+	NULL,					/* remove_packages */
+	NULL,					/* repo_enable */
+	NULL,					/* repo_set_data */
+	NULL,					/* resolve */
+	NULL,					/* rollback */
+	NULL,					/* search_details */
+	NULL,					/* search_files */
+	NULL,					/* search_groups */
+	NULL,					/* search_names */
+	NULL,					/* update_packages */
+	NULL,					/* update_system */
+	NULL,					/* what_provides */
+	NULL,					/* simulate_install_files */
+	NULL,					/* simulate_install_packages */
+	NULL,					/* simulate_remove_packages */
+	NULL					/* simulate_update_packages */
+);
diff --git a/backends/pacman/backend-pacman.h b/backends/pacman/backend-pacman.h
new file mode 100644
index 0000000..87b0d77
--- /dev/null
+++ b/backends/pacman/backend-pacman.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Andreas Obergrusberger <tradiaz at yahoo.de>
+ * Copyright (C) 2008, 2009 Valeriy Lyasotskiy <onestep at ukr.net>
+ * Copyright (C) 2010 Jonathan Conder <j at skurvy.no-ip.org>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pacman.h>
+#include <pk-backend.h>
+
+extern PacmanManager	*pacman;
diff --git a/backends/pacman/pacman.conf b/backends/pacman/pacman.conf
new file mode 100644
index 0000000..40b8e4a
--- /dev/null
+++ b/backends/pacman/pacman.conf
@@ -0,0 +1,12 @@
+# PackageKit configuration for the pacman backend
+# See the pacman.conf(5) manpage for option and repository directives.
+
+[options]
+
+# Use default pacman configuration initially
+#
+Include = /etc/pacman.conf
+
+# Prevent PackageKit from removing itself
+#
+HoldPkg = packagekit
diff --git a/configure.ac b/configure.ac
index 5e857d1..8a10036 100644
--- a/configure.ac
+++ b/configure.ac
@@ -501,6 +501,7 @@ AC_ARG_ENABLE(conary, AS_HELP_STRING([--enable-conary],[use the CONARY backend])
 AC_ARG_ENABLE(dummy, AS_HELP_STRING([--enable-dummy],[use the dummy backend]),enable_dummy=$enableval,enable_dummy=yes)
 AC_ARG_ENABLE(entropy, AS_HELP_STRING([--enable-entropy],[use the entropy backend]),enable_entropy=$enableval,enable_entropy=no)
 AC_ARG_ENABLE(opkg, AS_HELP_STRING([--enable-opkg],[use the OPKG backend]),enable_opkg=$enableval,enable_opkg=no)
+AC_ARG_ENABLE(pacman, AS_HELP_STRING([--enable-pacman],[use the Pacman backend]),enable_pacman=$enableval,enable_pacman=no)
 AC_ARG_ENABLE(pisi, AS_HELP_STRING([--enable-pisi],[use the PiSi backend]),enable_pisi=$enableval,enable_pisi=no)
 AC_ARG_ENABLE(poldek, AS_HELP_STRING([--enable-poldek],[use the poldek backend]),enable_poldek=$enableval,enable_poldek=no)
 AC_ARG_ENABLE(portage, AS_HELP_STRING([--enable-portage],[use the portage backend]),enable_portage=$enableval,enable_portage=no)
@@ -521,6 +522,7 @@ AM_CONDITIONAL(BACKEND_TYPE_CONARY, [test x$enable_conary = xyes])
 AM_CONDITIONAL(BACKEND_TYPE_DUMMY, [test x$enable_dummy = xyes])
 AM_CONDITIONAL(BACKEND_TYPE_ENTROPY, [test x$enable_entropy = xyes])
 AM_CONDITIONAL(BACKEND_TYPE_OPKG, [test x$enable_opkg = xyes])
+AM_CONDITIONAL(BACKEND_TYPE_PACMAN, [test x$enable_pacman = xyes])
 AM_CONDITIONAL(BACKEND_TYPE_PISI, [test x$enable_pisi = xyes])
 AM_CONDITIONAL(BACKEND_TYPE_POLDEK, [test x$enable_poldek = xyes])
 AM_CONDITIONAL(BACKEND_TYPE_PORTAGE, [test x$enable_portage = xyes])
@@ -607,6 +609,8 @@ if test x$with_default_backend = x; then
 		with_default_backend=slapt
 	elif test -f /usr/bin/smart ; then
 		with_default_backend=smart
+	elif test -f /usr/lib/libpacman-glib.so ; then
+		with_default_backend=pacman
 	elif test -f /usr/bin/pisi ; then
 		with_default_backend=pisi
 	elif test -f /usr/bin/razor ; then
@@ -731,6 +735,12 @@ if test x$enable_alpm = xyes; then
 			[AC_MSG_WARN([No alpm headers found - falling back to dummy backend])])
 fi
 
+if test x$enable_pacman = xyes; then
+	PKG_CHECK_MODULES(PACMAN, pacman-glib >= 3.3.0)
+	AC_SUBST(PACMAN_CFLAGS)
+	AC_SUBST(PACMAN_LIBS)
+fi
+
 if test x$enable_poldek = xyes; then
 	POLDEK_CFLAGS="-I/usr/include/poldek"
 	POLDEK_LIBS="-lpoclidek -lpoldek"
@@ -807,6 +817,7 @@ backends/conary/Makefile
 backends/dummy/Makefile
 backends/entropy/Makefile
 backends/opkg/Makefile
+backends/pacman/Makefile
 backends/slapt/Makefile
 backends/smart/Makefile
 backends/test/Makefile
@@ -882,6 +893,7 @@ echo "
         Entropy backend:           ${enable_entropy}
         OPKG backend:              ${enable_opkg}
         Razor backend:             ${enable_razor}
+        Pacman backend:            ${enable_pacman}
         PiSi backend:              ${enable_pisi}
         poldek backend:            ${enable_poldek}
         Portage backend:           ${enable_portage}
commit 83460a2b07aac18ffd776e23812af89e8f9028ff
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Thu May 6 23:29:08 2010 +1200

    trivial: initialize arrays to NULL when replaying cached GetUpdates data

diff --git a/src/pk-transaction.c b/src/pk-transaction.c
index ddfa21c..a6e5adb 100644
--- a/src/pk-transaction.c
+++ b/src/pk-transaction.c
@@ -3402,8 +3402,8 @@ pk_transaction_try_emit_cache (PkTransaction *transaction)
 {
 	PkResults *results;
 	gboolean ret = FALSE;
-	GPtrArray *package_array;
-	GPtrArray *message_array;
+	GPtrArray *package_array = NULL;
+	GPtrArray *message_array = NULL;
 	PkPackage *package;
 	PkMessage *message;
 	PkExitEnum exit_enum;
commit 7cb12f937588a1cb46769e62ed94f2cb1e54ddd5
Author: Jonathan Conder <j at skurvy.no-ip.org>
Date:   Thu May 6 23:27:47 2010 +1200

    trivial: set backend role after resetting it
    
    Fixes fd#27527 for good

diff --git a/src/pk-transaction.c b/src/pk-transaction.c
index bd60170..ddfa21c 100644
--- a/src/pk-transaction.c
+++ b/src/pk-transaction.c
@@ -1653,10 +1653,6 @@ pk_transaction_set_running (PkTransaction *transaction)
 	/* set the frontend socket if it exists */
 	pk_backend_set_frontend_socket (priv->backend, priv->frontend_socket);
 
-	/* set the role */
-	pk_backend_set_role (priv->backend, priv->role);
-	egg_debug ("setting role for %s to %s", priv->tid, pk_role_enum_to_string (priv->role));
-
 	/* set proxy */
 	ret = pk_transaction_set_session_state (transaction, &error);
 	if (!ret) {
@@ -1686,6 +1682,10 @@ pk_transaction_set_running (PkTransaction *transaction)
 	/* might have to reset again if we used the backend */
 	pk_backend_reset (priv->backend);
 
+	/* set the role */
+	pk_backend_set_role (priv->backend, priv->role);
+	egg_debug ("setting role for %s to %s", priv->tid, pk_role_enum_to_string (priv->role));
+
 	/* connect up the signals */
 	priv->signal_allow_cancel =
 		g_signal_connect (priv->backend, "allow-cancel",
commit dfdd3ca4c434c85fa56ddd8df7ad206dd2ae4b75
Author: Michael Meeks <michael.meeks at novell.com>
Date:   Thu May 6 11:08:15 2010 +0100

    Cleanup: kill unpleasant g_strv_length calls.
    Re-work install_packages_thread
    	+ detect available packages that are already installed, and
    	  forbid re-installation (the PackageKit way)
    	+ emit all-packages-already-installed error
    	+ search for PoolItems using the better search-by-name iterator
    First cut at specifying packages that cannot be removed and suitably
    aborting a transaction if they are requested to be so

diff --git a/backends/zypp/pk-backend-zypp.cpp b/backends/zypp/pk-backend-zypp.cpp
index 5664cb9..dc850ae 100644
--- a/backends/zypp/pk-backend-zypp.cpp
+++ b/backends/zypp/pk-backend-zypp.cpp
@@ -130,7 +130,7 @@ backend_get_requires_thread (PkBackend *backend)
 	//TODO repair percentages
 	//pk_backend_set_percentage (backend, 0);
 
-	for (uint i = 0; i < g_strv_length(package_ids); i++) {
+	for (uint i = 0; package_ids[i]; i++) {
 		zypp::sat::Solvable solvable = zypp_get_package_by_id (package_ids[i]);
 		zypp::PoolItem package;
 
@@ -451,7 +451,7 @@ backend_get_details_thread (PkBackend *backend)
 	}
 	pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
 
-	for (uint i = 0; i < g_strv_length(package_ids); i++) {
+	for (uint i = 0; package_ids[i]; i++) {
 		gchar **id_parts = pk_package_id_split (package_ids[i]);
 
 		std::vector<zypp::sat::Solvable> *v;
@@ -716,7 +716,7 @@ backend_install_files_thread (PkBackend *backend)
 			"Could not create a temporary directory");
 	}
 
-	for (guint i = 0; i < g_strv_length (full_paths); i++) {
+	for (guint i = 0; full_paths[i]; i++) {
 
 		// check if file is really a rpm
 		zypp::Pathname rpmPath (full_paths[i]);
@@ -766,7 +766,7 @@ backend_install_files_thread (PkBackend *backend)
 			backend, PK_ERROR_ENUM_INTERNAL_ERROR, ex.asUserString ().c_str ());
 	}
 
-	for (guint i = 0; i < g_strv_length (full_paths); i++) {
+	for (guint i = 0; full_paths[i]; i++) {
 
 		zypp::Pathname rpmPath (full_paths[i]);
 		zypp::target::rpm::RpmHeader::constPtr rpmHeader = zypp::target::rpm::RpmHeader::readPackage (rpmPath, zypp::target::rpm::RpmHeader::NOSIGNATURE);
@@ -841,7 +841,7 @@ backend_get_update_detail_thread (PkBackend *backend)
 	}
 	pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
 
-	for (uint i = 0; i < g_strv_length(package_ids); i++) {
+	for (uint i = 0; package_ids[i]; i++) {
 		zypp::sat::Solvable solvable = zypp_get_package_by_id (package_ids[i]);
 
 		zypp::Capabilities obs = solvable.obsoletes ();
@@ -1009,44 +1009,67 @@ backend_install_packages_thread (PkBackend *backend)
 	{
 		zypp::ResPool pool = zypp_build_pool (TRUE);
 		pk_backend_set_percentage (backend, 10);
-		gboolean hit = false;
 		std::vector<zypp::PoolItem> *items = new std::vector<zypp::PoolItem> ();
 
-		for (guint i = 0; i < g_strv_length (package_ids); i++) {
-
+		guint to_install = 0;
+		for (guint i = 0; package_ids[i]; i++) {
 			gchar **id_parts = pk_package_id_split (package_ids[i]);
 
 			// Iterate over the selectables and mark the one with the right name
-			zypp::ui::Selectable::Ptr selectable;
-			for (zypp::ResPoolProxy::const_iterator it = zypp->poolProxy().byKindBegin <zypp::Package>();
-					it != zypp->poolProxy().byKindEnd <zypp::Package>(); it++) {
-				if (strcmp ((*it)->name ().c_str (), id_parts[PK_PACKAGE_ID_NAME]) == 0) {
-					selectable = *it;
-					break;
-				}
-			}
+			zypp::ui::Selectable::constPtr selectable;
+			std::string name = id_parts[PK_PACKAGE_ID_NAME];
+
+			// Do we have this installed ?
+			gboolean system = false;
+			for (zypp::ResPool::byName_iterator it = pool.byNameBegin (name);
+			     it != pool.byNameEnd (name); it++) {
+
+				egg_debug ("PoolItem '%s'", it->satSolvable().asString().c_str());
+
+				if (!it->satSolvable().isSystem())
+					continue;
 
-			// Choose the PoolItem with the right architecture and version
-			for (zypp::ui::Selectable::available_iterator it = selectable->availableBegin ();
-					it != selectable->availableEnd (); it++) {
 				if (zypp_ver_and_arch_equal (it->satSolvable(), id_parts[PK_PACKAGE_ID_VERSION],
 							     id_parts[PK_PACKAGE_ID_ARCH])) {
-					hit = true;
-					// set status to ToBeInstalled
-					it->status ().setToBeInstalled (zypp::ResStatus::USER);
-					items->push_back (*it);
+					system = true;
 					break;
 				}
 			}
-			g_strfreev (id_parts);
+			
+			if (!system) {
+				gboolean hit = false;
+
+				// Choose the PoolItem with the right architecture and version
+				for (zypp::ResPool::byName_iterator it = pool.byNameBegin (name);
+				     it != pool.byNameEnd (name); it++) {
+
+					if (zypp_ver_and_arch_equal (it->satSolvable(), id_parts[PK_PACKAGE_ID_VERSION],
+								     id_parts[PK_PACKAGE_ID_ARCH])) {
+						hit = true;
+						to_install++;
+						// set status to ToBeInstalled
+						it->status ().setToBeInstalled (zypp::ResStatus::USER);
+						items->push_back (*it);
+						break;
+					}
+				}
+				if (!hit) {
+					g_strfreev (id_parts);
+					return zypp_backend_finished_error (
+						backend, PK_ERROR_ENUM_PACKAGE_NOT_FOUND,
+						"Couldn't find the package '%s'.", package_ids[i]);
+				}
 
-			if (!hit) {
-				return zypp_backend_finished_error (
-					backend, PK_ERROR_ENUM_PACKAGE_NOT_FOUND,
-					"Couldn't find the package.");
 			}
+			g_strfreev (id_parts);
+		}
 
-			pk_backend_set_percentage (backend, 40);
+		pk_backend_set_percentage (backend, 40);
+
+		if (!to_install) {
+			return zypp_backend_finished_error (
+				backend, PK_ERROR_ENUM_ALL_PACKAGES_ALREADY_INSTALLED,
+				"The packages are already all installed");
 		}
 
 		// Todo: ideally we should call pk_backend_package (...
@@ -1137,7 +1160,7 @@ backend_remove_packages_thread (PkBackend *backend)
 		return zypp_backend_finished_error (
 			backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "invalid package id");
 	}
-	for (guint i = 0; i < g_strv_length (package_ids); i++) {
+	for (guint i = 0; package_ids[i]; i++) {
 		gchar **id_parts = pk_package_id_split (package_ids[i]);
 
 		// Iterate over the resolvables and mark the ones we want to remove
@@ -1206,7 +1229,7 @@ backend_resolve_thread (PkBackend *backend)
 
 	pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
 
-	for (uint i = 0; i < g_strv_length (package_ids); i++) {
+	for (uint i = 0; package_ids[i]; i++) {
 		std::vector<zypp::sat::Solvable> *v;
 
 		/* Build a list of packages with this name */
@@ -1493,7 +1516,7 @@ backend_get_files_thread (PkBackend *backend)
 			backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "invalid package id");
 	}
 
-	for(uint i = 0; i < g_strv_length(package_ids); i++) {
+	for (uint i = 0; package_ids[i]; i++) {
 		gchar **id_parts = pk_package_id_split (package_ids[i]);
 		pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
 
@@ -1605,7 +1628,7 @@ backend_update_packages_thread (PkBackend *backend)
 		pk_backend_require_restart (backend, PK_RESTART_ENUM_SESSION, "Package Management System updated - restart needed");
 		_updating_self = FALSE;
 	}
-	for (guint i = 0; i < g_strv_length (package_ids); i++) {
+	for (guint i = 0; package_ids[i]; i++) {
 		zypp::sat::Solvable solvable = zypp_get_package_by_id (package_ids[i]);
 		zypp::PoolItem item = zypp::ResPool::instance ().find (solvable);
 		item.status ().setToBeInstalled (zypp::ResStatus::USER);
diff --git a/backends/zypp/zypp-utils.cpp b/backends/zypp/zypp-utils.cpp
index 772a783..46c17b2 100644
--- a/backends/zypp/zypp-utils.cpp
+++ b/backends/zypp/zypp-utils.cpp
@@ -792,16 +792,19 @@ zypp_perform_execution (PkBackend *backend, PerformType type, gboolean force)
 
 		zypp::ResPool pool = zypp::ResPool::instance ();
 		if (simulate) {
+			ret = TRUE;
+
+			egg_debug ("simulating");
 
 			for (zypp::ResPool::const_iterator it = pool.begin (); it != pool.end (); it++) {
-				zypp_backend_pool_item_notify (backend, *it);
+				if (!zypp_backend_pool_item_notify (backend, *it, TRUE))
+					ret = FALSE;
 				it->statusReset ();
 			}
-
-			ret = TRUE;
 			goto exit;
 		}
 
+
 		// look for licenses to confirm
 
 		for (zypp::ResPool::const_iterator it = pool.begin (); it != pool.end (); it++) {
@@ -1030,20 +1033,30 @@ zypp_backend_finished_error (PkBackend  *backend, PkErrorEnum err_code,
 	return FALSE;
 }
 
-void
+gboolean
 zypp_backend_pool_item_notify (PkBackend  *backend,
-			       const zypp::PoolItem &item)
+			       const zypp::PoolItem &item,
+			       gboolean sanity_check)
 {
 	PkInfoEnum status = PK_INFO_ENUM_UNKNOWN;
 
-	if (item.status ().isToBeUninstalled ()) {
-		status = PK_INFO_ENUM_REMOVING;
-	} else if (item.status ().isToBeInstalled ()) {
-		status = PK_INFO_ENUM_INSTALLING;
-	} else if (item.status ().isToBeUninstalledDueToUpgrade ()) {
+	if (item.status ().isToBeUninstalledDueToUpgrade ()) {
 		status = PK_INFO_ENUM_UPDATING;
 	} else if (item.status ().isToBeUninstalledDueToObsolete ()) {
 		status = PK_INFO_ENUM_OBSOLETING;
+	} else if (item.status ().isToBeInstalled ()) {
+		status = PK_INFO_ENUM_INSTALLING;
+	} else if (item.status ().isToBeUninstalled ()) {
+		status = PK_INFO_ENUM_REMOVING;
+
+		const std::string &name = item.satSolvable().name();
+		egg_debug ("should we remove '%s'", name.c_str());
+		if (name == "glibc" || name == "gedit") {
+			pk_backend_error_code (backend, PK_ERROR_ENUM_CANNOT_REMOVE_SYSTEM_PACKAGE,
+					       "The package %s is essential to correct operation and cannot be removed using this tool.",
+					       name.c_str());
+			return FALSE;
+		}
 	}
 
 	// FIXME: do we need more heavy lifting here cf. zypper's
@@ -1052,6 +1065,7 @@ zypp_backend_pool_item_notify (PkBackend  *backend,
 		const std::string &summary = item.resolvable ()->summary ();
 		zypp_backend_package (backend, status, item.resolvable()->satSolvable(), summary.c_str ());
 	}
+	return TRUE;
 }
 
 gchar *
diff --git a/backends/zypp/zypp-utils.h b/backends/zypp/zypp-utils.h
index f432129..707f517 100644
--- a/backends/zypp/zypp-utils.h
+++ b/backends/zypp/zypp-utils.h
@@ -224,8 +224,9 @@ void     zypp_backend_package (PkBackend *backend, PkInfoEnum info,
 /**
   * helper to emit pk package status signals based on a ResPool object
   */
-void     zypp_backend_pool_item_notify (PkBackend  *backend,
-					const zypp::PoolItem &item);
+gboolean zypp_backend_pool_item_notify (PkBackend  *backend,
+					const zypp::PoolItem &item,
+					gboolean sanity_check = FALSE);
 
 /**
   * helper to compare a version + architecture, with source arch mangling.
commit 3e5d25c5e13074d87b7f7a45dae142a7ead3298d
Author: Michael Meeks <michael.meeks at novell.com>
Date:   Thu May 6 11:06:18 2010 +0100

    Fix problem whereby the terminal wouldn't return data to scanf from
    a read before newline; but pk_console_get_number would only consume
    the digits, leaving a '\n' malingering to break a subsequent
    pk_console_getchar_unbuffered.

diff --git a/lib/packagekit-glib2/pk-console-shared.c b/lib/packagekit-glib2/pk-console-shared.c
index ce9c658..7cfa6b7 100644
--- a/lib/packagekit-glib2/pk-console-shared.c
+++ b/lib/packagekit-glib2/pk-console-shared.c
@@ -50,11 +50,17 @@ pk_console_get_number (const gchar *question, guint maxnum)
 	g_print ("%s", question);
 
 	do {
+		char buffer[64];
+
+		/* swallow the \n at end of line too */
+		if (!fgets (buffer, 64, stdin))
+			break;
+
 		/* get a number */
-		retval = scanf("%u", &answer);
+		retval = sscanf(buffer, "%u", &answer);
 
 		/* positive */
-		if (retval == 1 && answer > 0 && answer <= (gint) maxnum)
+		if (answer > 0 && answer <= (gint) maxnum)
 			break;
 		g_print (_("Please enter a number from 1 to %i: "), maxnum);
 	} while (TRUE);
@@ -80,7 +86,7 @@ pk_console_getchar_unbuffered (void)
 	memcpy (&new_opts, &org_opts, sizeof(new_opts));
 	new_opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOKE | ICRNL);
 	tcsetattr (STDIN_FILENO, TCSANOW, &new_opts);
-	c = getchar ();
+	c = getc (stdin);
 
 	/* restore old settings */
 	res = tcsetattr (STDIN_FILENO, TCSANOW, &org_opts);


More information about the PackageKit-commit mailing list