summaryrefslogtreecommitdiff
path: root/packages/packagekit/files
diff options
context:
space:
mode:
authorJulian_chu <julian_chu@openmoko.com>2008-06-02 11:19:56 +0800
committerHolger Hans Peter Freyther <zecke@selfish.org>2008-10-28 22:48:50 +0100
commitb8842ec5493a818e72e0dd8f2e22a998466037c9 (patch)
tree4ede5d69d7442086045b9b15e9f64e28b25ea618 /packages/packagekit/files
parent3c2efdd0d3453bd42887895be26a9c76b7ae13f3 (diff)
packagekit: Add 2 patched for packagekit.
New stuff will be: * Added a new error enum to packagekit to support "corrupt-package" message. * Improve the error handling for update and install functions, with new opkg.
Diffstat (limited to 'packages/packagekit/files')
-rw-r--r--packages/packagekit/files/01_d1e096c3267c1c9492041382b954e9327bc8bbec.patch (renamed from packages/packagekit/files/d1e096c3267c1c9492041382b954e9327bc8bbec.patch)0
-rw-r--r--packages/packagekit/files/02_9ced8313fb12f0f89ad6ced7c0fdc7241ff00d77.patch13544
2 files changed, 13544 insertions, 0 deletions
diff --git a/packages/packagekit/files/d1e096c3267c1c9492041382b954e9327bc8bbec.patch b/packages/packagekit/files/01_d1e096c3267c1c9492041382b954e9327bc8bbec.patch
index f050a50002..f050a50002 100644
--- a/packages/packagekit/files/d1e096c3267c1c9492041382b954e9327bc8bbec.patch
+++ b/packages/packagekit/files/01_d1e096c3267c1c9492041382b954e9327bc8bbec.patch
diff --git a/packages/packagekit/files/02_9ced8313fb12f0f89ad6ced7c0fdc7241ff00d77.patch b/packages/packagekit/files/02_9ced8313fb12f0f89ad6ced7c0fdc7241ff00d77.patch
new file mode 100644
index 0000000000..fb617c5eda
--- /dev/null
+++ b/packages/packagekit/files/02_9ced8313fb12f0f89ad6ced7c0fdc7241ff00d77.patch
@@ -0,0 +1,13544 @@
+:000000 100644 0000000... bd0cc2e... A RELEASE
+:100644 100644 fcc8347... 20279b3... M backends/Makefile.am
+:000000 100644 0000000... c851833... A backends/apt.deprecated/.gitignore
+:000000 100644 0000000... 07b4131... A backends/apt.deprecated/Makefile.am
+:000000 100644 0000000... 0d20b64... A backends/apt.deprecated/helpers/.gitignore
+:000000 100644 0000000... 0299df2... A backends/apt.deprecated/helpers/Makefile.am
+:000000 100644 0000000... e5f78ca... A backends/apt.deprecated/helpers/aptBackend.py
+:000000 100755 0000000... 94dca4a... A backends/apt.deprecated/helpers/get-depends.py
+:000000 100755 0000000... a813640... A backends/apt.deprecated/helpers/get-details.py
+:000000 100755 0000000... 5529f72... A backends/apt.deprecated/helpers/get-repo-list.py
+:000000 100755 0000000... e581010... A backends/apt.deprecated/helpers/get-requires.py
+:000000 100755 0000000... 5524d9a... A backends/apt.deprecated/helpers/get-update-detail.py
+:000000 100755 0000000... 4f45fbf... A backends/apt.deprecated/helpers/get-updates.py
+:000000 100755 0000000... dfa024c... A backends/apt.deprecated/helpers/install-files.py
+:000000 120000 0000000... 8d22531... A backends/apt.deprecated/helpers/packagekit
+:000000 100755 0000000... 881479d... A backends/apt.deprecated/helpers/refresh-cache.py
+:000000 100755 0000000... 3cc36ae... A backends/apt.deprecated/helpers/repo-enable.py
+:000000 100755 0000000... aac34df... A backends/apt.deprecated/helpers/resolve.py
+:000000 100755 0000000... d02f1b0... A backends/apt.deprecated/helpers/search-details.py
+:000000 100755 0000000... ec60319... A backends/apt.deprecated/helpers/search-file.py
+:000000 100755 0000000... f63ee80... A backends/apt.deprecated/helpers/search-group.py
+:000000 100755 0000000... 9f73c89... A backends/apt.deprecated/helpers/search-name.py
+:000000 100644 0000000... 885275d... A backends/apt.deprecated/pk-apt-build-db.cpp
+:000000 100644 0000000... bb786a9... A backends/apt.deprecated/pk-apt-build-db.h
+:000000 100644 0000000... 5e5b4e5... A backends/apt.deprecated/pk-apt-search-plain.c
+:000000 100644 0000000... 98bdc7f... A backends/apt.deprecated/pk-apt-search-sqlite.cpp
+:000000 100644 0000000... e36e89f... A backends/apt.deprecated/pk-apt-search.h
+:000000 100644 0000000... f59cd88... A backends/apt.deprecated/pk-backend-apt.c
+:000000 100644 0000000... 1bf9a50... A backends/apt.deprecated/pk-sqlite-pkg-cache.cpp
+:000000 100644 0000000... 68fad42... A backends/apt.deprecated/pk-sqlite-pkg-cache.h
+:000000 100644 0000000... 2b99c5d... A backends/apt/HACKING
+:100644 100644 07b4131... e315ba9... M backends/apt/Makefile.am
+:000000 100644 0000000... 0a3da6e... A backends/apt/README
+:000000 100644 0000000... bee2f3d... A backends/apt/TODO
+:000000 100755 0000000... 22eb714... A backends/apt/aptDBUSBackend.py
+:100644 000000 0d20b64... 0000000... D backends/apt/helpers/.gitignore
+:100644 000000 0299df2... 0000000... D backends/apt/helpers/Makefile.am
+:100644 000000 e5f78ca... 0000000... D backends/apt/helpers/aptBackend.py
+:100755 000000 94dca4a... 0000000... D backends/apt/helpers/get-depends.py
+:100755 000000 a813640... 0000000... D backends/apt/helpers/get-details.py
+:100755 000000 5529f72... 0000000... D backends/apt/helpers/get-repo-list.py
+:100755 000000 e581010... 0000000... D backends/apt/helpers/get-requires.py
+:100755 000000 5524d9a... 0000000... D backends/apt/helpers/get-update-detail.py
+:100755 000000 4f45fbf... 0000000... D backends/apt/helpers/get-updates.py
+:100755 000000 dfa024c... 0000000... D backends/apt/helpers/install-files.py
+:100755 000000 881479d... 0000000... D backends/apt/helpers/refresh-cache.py
+:100755 000000 3cc36ae... 0000000... D backends/apt/helpers/repo-enable.py
+:100755 000000 aac34df... 0000000... D backends/apt/helpers/resolve.py
+:100755 000000 d02f1b0... 0000000... D backends/apt/helpers/search-details.py
+:100755 000000 ec60319... 0000000... D backends/apt/helpers/search-file.py
+:100755 000000 f63ee80... 0000000... D backends/apt/helpers/search-group.py
+:100755 000000 9f73c89... 0000000... D backends/apt/helpers/search-name.py
+:000000 120000 0000000... 0b64032... A backends/apt/packagekit
+:100644 000000 885275d... 0000000... D backends/apt/pk-apt-build-db.cpp
+:100644 000000 bb786a9... 0000000... D backends/apt/pk-apt-build-db.h
+:100644 000000 5e5b4e5... 0000000... D backends/apt/pk-apt-search-plain.c
+:100644 000000 98bdc7f... 0000000... D backends/apt/pk-apt-search-sqlite.cpp
+:100644 000000 e36e89f... 0000000... D backends/apt/pk-apt-search.h
+:100644 100644 f59cd88... 70836b2... M backends/apt/pk-backend-apt.c
+:100644 000000 1bf9a50... 0000000... D backends/apt/pk-sqlite-pkg-cache.cpp
+:100644 000000 68fad42... 0000000... D backends/apt/pk-sqlite-pkg-cache.h
+:000000 100644 0000000... 1b5d30f... A backends/apt/profiler.py
+:000000 100755 0000000... a1d5ffb... A backends/apt/test.py
+:100644 000000 c851833... 0000000... D backends/apt2/.gitignore
+:100644 000000 2b99c5d... 0000000... D backends/apt2/HACKING
+:100644 000000 91c0c46... 0000000... D backends/apt2/Makefile.am
+:100644 000000 0a3da6e... 0000000... D backends/apt2/README
+:100644 000000 bee2f3d... 0000000... D backends/apt2/TODO
+:100755 000000 b7fc500... 0000000... D backends/apt2/aptDBUSBackend.py
+:120000 000000 0b64032... 0000000... D backends/apt2/packagekit
+:100644 000000 4f78ec4... 0000000... D backends/apt2/pk-backend-apt2.c
+:100644 000000 1b5d30f... 0000000... D backends/apt2/profiler.py
+:100755 000000 a1d5ffb... 0000000... D backends/apt2/test.py
+:100644 100644 2df445e... 5714e9f... M backends/dummy/pk-backend-dummy.c
+:100644 100644 7649bab... 2d70108... M backends/opkg/pk-backend-opkg.c
+:100644 100644 fdc99d3... 2691414... M backends/poldek/pk-backend-poldek.c
+:000000 100644 0000000... 996fb0d... A backends/urpmi/.gitignore
+:000000 100644 0000000... 56743a1... A backends/urpmi/Makefile.am
+:000000 100644 0000000... 2f78cf5... A backends/urpmi/helpers/.gitignore
+:000000 100644 0000000... 88f144e... A backends/urpmi/helpers/Makefile.am
+:000000 100755 0000000... bf936c5... A backends/urpmi/helpers/get-depends.pl
+:000000 100755 0000000... 3207e9b... A backends/urpmi/helpers/get-details.pl
+:000000 100755 0000000... 74ae157... A backends/urpmi/helpers/get-files.pl
+:000000 100755 0000000... 9e3e525... A backends/urpmi/helpers/get-packages.pl
+:000000 100755 0000000... 0012b2a... A backends/urpmi/helpers/get-requires.pl
+:000000 100755 0000000... 69ea452... A backends/urpmi/helpers/get-update-detail.pl
+:000000 100755 0000000... 02d574c... A backends/urpmi/helpers/get-updates.pl
+:000000 100755 0000000... c9cf6c8... A backends/urpmi/helpers/install-packages.pl
+:000000 100644 0000000... 6ed63b5... A backends/urpmi/helpers/perl_packagekit/Makefile.am
+:000000 100644 0000000... 8dbb4b0... A backends/urpmi/helpers/perl_packagekit/enums.pm
+:000000 100644 0000000... 7411ca9... A backends/urpmi/helpers/perl_packagekit/prints.pm
+:000000 100755 0000000... 555a8b8... A backends/urpmi/helpers/refresh-cache.pl
+:000000 100755 0000000... 3be38ea... A backends/urpmi/helpers/remove-packages.pl
+:000000 100755 0000000... 32e0866... A backends/urpmi/helpers/resolve.pl
+:000000 100755 0000000... 3081abe... A backends/urpmi/helpers/search-details.pl
+:000000 100755 0000000... 03d348e... A backends/urpmi/helpers/search-file.pl
+:000000 100755 0000000... e5b7b92... A backends/urpmi/helpers/search-group.pl
+:000000 100755 0000000... 383921f... A backends/urpmi/helpers/search-name.pl
+:000000 100755 0000000... 88274bc... A backends/urpmi/helpers/update-packages.pl
+:000000 100644 0000000... 3eb8280... A backends/urpmi/helpers/urpmi_backend/Makefile.am
+:000000 100644 0000000... a01b893... A backends/urpmi/helpers/urpmi_backend/actions.pm
+:000000 100644 0000000... 2c2f13a... A backends/urpmi/helpers/urpmi_backend/filters.pm
+:000000 100644 0000000... d377ab2... A backends/urpmi/helpers/urpmi_backend/groups.pm
+:000000 100644 0000000... 795edc6... A backends/urpmi/helpers/urpmi_backend/open_db.pm
+:000000 100644 0000000... e078134... A backends/urpmi/helpers/urpmi_backend/tools.pm
+:000000 100644 0000000... e7b56a7... A backends/urpmi/pk-backend-urpmi.c
+:100644 100644 5b2da8f... d70d8dc... M backends/yum/helpers/yumBackend.py
+:100755 100755 29f5b03... a708a0c... M backends/yum2/helpers/yumDBUSBackend.py
+:100644 100644 15c4b4f... a971707... M backends/zypp/pk-backend-zypp.cpp
+:100644 100644 2b848f0... d81d0dd... M backends/zypp/zypp-utils.cpp
+:100644 100644 9e3bad1... 4f785cf... M backends/zypp/zypp-utils.h
+:100644 100644 5a05a8e... ec93978... M client/pk-console.c
+:100644 100644 f5be0a5... bfe364f... M client/pk-import-desktop.c
+:100644 100644 cf14cc2... bffd45b... M client/pk-import-specspo.c
+:100644 100644 f614d2b... 7510b03... M configure.ac
+:100644 100644 4d4a7e3... 61a67d1... M contrib/PackageKit.spec.in
+:100644 100644 a97fc3b... ded7799... M contrib/gnome-packagekit.spec.in
+:100644 100644 607a7a4... 7aa298b... M docs/html/pk-authors.html
+:100644 100644 0cdc85c... d276a05... M docs/html/pk-download.html
+:100644 100644 efa8344... 3e37cc1... M docs/html/pk-faq.html
+:100644 100644 0b75b10... 51a165a... M docs/spec/pk-concepts.xml
+:100644 100644 a79e647... 2970dda... M docs/spec/pk-signals.xml
+:100644 100644 8f9bd57... 7a48320... M etc/PackageKit.conf.in
+:100644 100644 dd2387b... 8fb82f1... M libpackagekit/pk-client.c
+:100644 100644 2b1d1a2... 6617159... M libpackagekit/pk-client.h
+:100644 100644 9d3cff7... 0be0e6e... M libpackagekit/pk-common.c
+:100644 100644 9908ec2... 9e5a05e... M libpackagekit/pk-common.h
+:100644 100644 f2de5ae... 5a54ccc... M libpackagekit/pk-control.c
+:100644 100644 63b30d3... c1b1be8... M libpackagekit/pk-control.h
+:100644 100644 5743dcb... 9dccdd0... M libpackagekit/pk-enum.c
+:100644 100644 e616b64... 4cc317e... M libpackagekit/pk-enum.h
+:100644 100644 7f01a4c... d0f0776... M libpackagekit/pk-extra.c
+:100644 100644 87905dc... ff4bd4e... M libpackagekit/pk-package-item.c
+:100644 100644 5d95e1b... 6bdb0d4... M libpackagekit/pk-package-list.c
+:100644 100644 9734af4... 83901ab... M libpackagekit/pk-package-list.h
+:100644 100644 dceb656... 7308a29... M libpackagekit/pk-polkit-client.c
+:100644 100644 76ab022... 3dc1db0... M libpackagekit/pk-task-list.c
+:100644 100644 6dbee0e... f87e6b3... M po/LINGUAS
+:100644 100644 33d30c1... 6e8013e... M po/de.po
+:000000 100644 0000000... ea732d0... A po/hu.po
+:100644 100644 32efce7... 4c4607d... M policy/org.freedesktop.packagekit.policy.in
+:100644 100644 5253b39... 9fd627a... M python/packagekit/daemonBackend.py
+:100644 100644 f9c9f12... 2bd416d... M src/pk-backend-spawn.c
+:100644 100644 37ed024... f0f245f... M src/pk-backend.c
+:100644 100644 fb17e3c... a7ba754... M src/pk-backend.h
+:100644 100644 028a0d0... 14ecf41... M src/pk-engine.c
+:100644 100644 c59b1f3... 668451f... M src/pk-engine.h
+:100644 100644 e9e74e1... 7290bbe... M src/pk-interface.xml
+:100644 100644 9abf992... 81332d0... M src/pk-security-polkit.c
+:100644 100644 3432095... eb55932... M src/pk-security.h
+:100644 100644 7aa183f... d42bc7a... M src/pk-transaction-db.c
+:100644 100644 0921c7c... f325f94... M src/pk-transaction-list.c
+:100644 100644 07ffdee... 15faed3... M src/pk-transaction.c
+:100755 100755 f78c891... 6521e69... M tools/add-error-enum.sh
+:100755 000000 ebbd8f7... 0000000... D tools/rpmbuild.sh
+
+diff --git a/RELEASE b/RELEASE
+new file mode 100644
+index 0000000..bd0cc2e
+--- /dev/null
++++ b/RELEASE
+@@ -0,0 +1,50 @@
++PackageKit Release Notes
++
++1. Write NEWS entries for PackageKit and gnome-packagekit in the same
++ format as usual. Ignore any trivial commits.
++
++$git-shortlog GNOME_PACKAGEKIT_0_2_1.. | grep -v trivial > NEWS.new
++
++2. Add download date to docs/html/pk-download.html, save file.
++
++3. Update library version if new ABI in configure.ac and change DEVELOPMENT_RELEASE if needed
++
++4. Commit changes in PackageKit git:
++
++$git commit -a -m "Release version 0.2.2"
++$git tag -a -f -m "Release 0.2.2" PACKAGEKIT_0_2_2
++$git push --tags
++$git push
++
++5. Commit changes in gnome-packagekit git:
++
++$git commit -a -m "Release version 0.2.2"
++$git-tag GNOME_PACKAGEKIT_0_2_2
++$git push --tags
++$git push
++
++6. Upload both tarballs to:
++
++$scp *.tar.gz packagekit.org/srv/www/html/releases/
++
++7. Do post release version bump in configure.ac
++
++8. Commit changes in both projects:
++
++$git commit -a -m "post release version bump"
++$git push
++
++9. Send an email to packagekit@lists.freedesktop.org
++
++=================================================
++Subject: PackageKit and gnome-packagekit 0.2.2 released!
++
++Today I released PackageKit and gnome-packagekit 0.2.2.
++
++PackageKit release notes: http://gitweb.freedesktop.org/?p=packagekit.git;a=blob;f=NEWS
++gnome-packagekit release notes: http://gitweb.freedesktop.org/?p=users/hughsient/gnome-packagekit.git;a=blob;f=NEWS
++
++Tarballs available here: http://people.freedesktop.org/~hughsient/releases/
++Thanks to all those who made this possible.
++=================================================
++
+diff --git a/backends/Makefile.am b/backends/Makefile.am
+index fcc8347..20279b3 100644
+--- a/backends/Makefile.am
++++ b/backends/Makefile.am
+@@ -8,10 +8,6 @@ if BACKEND_TYPE_APT
+ SUBDIRS += apt
+ endif
+
+-if BACKEND_TYPE_APT_DBUS
+-SUBDIRS += apt2
+-endif
+-
+ if BACKEND_TYPE_BOX
+ SUBDIRS += box
+ endif
+@@ -32,6 +28,10 @@ if BACKEND_TYPE_SMART
+ SUBDIRS += smart
+ endif
+
++if BACKEND_TYPE_URPMI
++SUBDIRS += urpmi
++endif
++
+ if BACKEND_TYPE_YUM
+ SUBDIRS += yum
+ endif
+diff --git a/backends/apt.deprecated/.gitignore b/backends/apt.deprecated/.gitignore
+new file mode 100644
+index 0000000..c851833
+--- /dev/null
++++ b/backends/apt.deprecated/.gitignore
+@@ -0,0 +1,10 @@
++.deps
++.libs
++Makefile
++Makefile.in
++*.la
++*.lo
++*.loT
++*.o
++*~
++
+diff --git a/backends/apt.deprecated/Makefile.am b/backends/apt.deprecated/Makefile.am
+new file mode 100644
+index 0000000..07b4131
+--- /dev/null
++++ b/backends/apt.deprecated/Makefile.am
+@@ -0,0 +1,30 @@
++NULL =
++
++SUBDIRS = helpers
++plugindir = $(PK_PLUGIN_DIR)
++plugin_LTLIBRARIES = libpk_backend_apt.la
++
++libpk_backend_apt_la_LIBADD = $(PK_PLUGIN_LIBS)
++libpk_backend_apt_la_LDFLAGS = -module -avoid-version $(APT_LIBS)
++libpk_backend_apt_la_CFLAGS = $(PK_PLUGIN_CFLAGS) $(APT_CFLAGS)
++libpk_backend_apt_la_CXXFLAGS = $(PK_PLUGIN_CFLAGS) $(APT_CFLAGS) -DPK_DB_DIR=\""$(PK_DB_DIR)"\"
++
++libpk_backend_apt_la_SOURCES = \
++ pk-backend-apt.c \
++ pk-apt-search.h \
++ $(NULL)
++
++if APT_SEARCH_PLAIN
++libpk_backend_apt_la_SOURCES += \
++ pk-apt-search-plain.c \
++ $(NULL)
++endif
++
++if APT_SEARCH_SQLITE
++libpk_backend_apt_la_SOURCES += \
++ pk-sqlite-pkg-cache.h \
++ pk-sqlite-pkg-cache.cpp \
++ pk-apt-build-db.cpp \
++ pk-apt-search-sqlite.cpp \
++ $(NULL)
++endif
+diff --git a/backends/apt.deprecated/helpers/.gitignore b/backends/apt.deprecated/helpers/.gitignore
+new file mode 100644
+index 0000000..0d20b64
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/.gitignore
+@@ -0,0 +1 @@
++*.pyc
+diff --git a/backends/apt.deprecated/helpers/Makefile.am b/backends/apt.deprecated/helpers/Makefile.am
+new file mode 100644
+index 0000000..0299df2
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/Makefile.am
+@@ -0,0 +1,29 @@
++
++helperdir = $(datadir)/PackageKit/helpers/apt
++
++NULL =
++
++dist_helper_DATA = \
++ install-files.py \
++ search-name.py \
++ search-details.py \
++ search-group.py \
++ search-file.py \
++ get-depends.py \
++ get-details.py \
++ get-repo-list.py \
++ get-requires.py \
++ get-update-detail.py \
++ get-updates.py \
++ refresh-cache.py \
++ repo-enable.py \
++ resolve.py \
++ aptBackend.py \
++ $(NULL)
++
++install-data-hook:
++ chmod a+rx $(DESTDIR)$(helperdir)/*.py
++
++clean-local :
++ rm -f *~
++
+diff --git a/backends/apt.deprecated/helpers/aptBackend.py b/backends/apt.deprecated/helpers/aptBackend.py
+new file mode 100644
+index 0000000..e5f78ca
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/aptBackend.py
+@@ -0,0 +1,536 @@
++#
++# vim: ts=4 et sts=4
++#
++# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
++# Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++import os
++import re
++
++from packagekit.backend import *
++import apt_pkg,apt_inst
++
++import warnings
++warnings.filterwarnings(action='ignore', category=FutureWarning)
++import apt
++from aptsources.distro import get_distro
++from aptsources.sourceslist import SourcesList
++from sets import Set
++from os.path import join,exists
++from urlparse import urlparse
++from apt.debfile import DebPackage
++from os import system
++
++class Package(apt.Package):
++ def __str__(self):
++ return "Package %s, version %s"%(self.name,self._version)
++
++ def _cmp_deps(self,deps, version):
++ for (v,c) in deps:
++ if not apt_pkg.CheckDep(version,c,v):
++ return False
++ return True
++
++ def __init__(self, backend, pkg, data="",version=[]):
++ apt.package.Package.__init__(self, pkg._cache, pkg._depcache,
++ pkg._records, pkg._list, pkg._pcache,
++ pkg._pkg)
++ self._version = version
++ self._data = data
++ self._backend = backend
++ wanted_ver = None
++ if self.installedVersion!=None and self._cmp_deps(version,self.installedVersion):
++ wanted_ver = self.installedVersion
++ elif self.installedVersion == None and version == []:
++ #self.markInstall(False,False)
++ wanted_ver = self.candidateVersion
++
++ for ver in pkg._pkg.VersionList:
++ #print "vers",dir(ver),version,ver
++ #print data
++ if (wanted_ver == None or wanted_ver == ver.VerStr) and self._cmp_deps(version,ver.VerStr):
++ f, index = ver.FileList.pop(0)
++ if self._data == "":
++ if f.Origin=="" and f.Archive=="now":
++ self._data = "local_install"
++ elif f.Origin!="" or f.Archive!="":
++ self._data = "%s/%s"%(f.Origin.replace("/","_"),f.Archive.replace("/","_"))
++ else:
++ self._data = "%s/unknown"%f.Site
++ self._version = ver.VerStr
++ break
++ else:
++ print "wanted",wanted_ver
++ for ver in pkg._pkg.VersionList:
++ print "vers",version,ver.VerStr
++ backend.error(ERROR_PACKAGE_NOT_FOUND, "Can't find version %s for %s"%(version,self.name))
++
++ def setVersion(self,version,compare="="):
++ if version!=None and (self.installedVersion == None or not apt_pkg.CheckDep(version,compare,self.installedVersion)):
++ self.markInstall(False,False)
++ if self.candidateVersion != version:
++ if self._data == "":
++ for ver in pkg._pkg.VersionList:
++ f, index = ver.FileList.pop(0)
++ self._data = "%s/%s"%(f.Origin,f.Archive)
++ if ver.VerStr == version:
++ break
++
++ # FIXME: this is a nasty hack, assuming that the best way to resolve
++ # deps for non-default repos is by switching the default release.
++ # We really need a better resolver (but that's hard)
++ assert self._data!=""
++ origin = self._data[self._data.find("/")+1:]
++ print "origin",origin
++ name = self.name
++ apt_pkg.Config.Set("APT::Default-Release",origin)
++ if not self._backend._caches.has_key(origin):
++ self._backend._caches[origin] = apt.Cache(PackageKitProgress(self))
++ print "new cache for %s"%origin
++ self.__setParent(self._backend._caches[origin][name])
++ self.markInstall(False,False)
++ if not apt_pkg.CheckDep(self.candidateVersion,compare,version):
++ self._backend.error(ERROR_PACKAGE_NOT_FOUND,
++ "Unable to locate package version %s (only got %s) for %s"%(version,self.candidateVersion,name))
++ return
++ self.markKeep()
++
++ @property
++ def group(self):
++ section = self.section.split('/')[-1].lower()
++ #if section in ():
++ # return GROUP_ACCESSIBILITY
++ if section in ('utils',):
++ return "accessories"
++ #if section in ():
++ # return GROUP_EDUCATION
++ if section in ('games',):
++ return "games"
++ if section in ('graphics',):
++ return "graphics"
++ if section in ('net', 'news', 'web', 'comm'):
++ return "internet"
++ if section in ('editors', 'tex'):
++ return "office"
++ if section in ('misc',):
++ return "other"
++ if section in ('devel', 'libdevel', 'interpreters', 'perl', 'python'):
++ return "programming"
++ if section in ('sound',):
++ return "multimedia"
++ if section in ('base', 'admin'):
++ return "system"
++ return "unknown"
++
++ @property
++ def isInstalled(self):
++ return super(self.__class__,self).isInstalled and self.installedVersion == self._version
++
++ @property
++ def isDevelopment(self):
++ name = self.name.lower()
++ section = self.section.split('/')[-1].lower()
++ return name.endswith('-dev') or name.endswith('-dbg') or \
++ section in ('devel', 'libdevel')
++
++ @property
++ def isGui(self):
++ section = self.section.split('/')[-1].lower()
++ return section in ('x11', 'gnome', 'kde')
++
++ _HYPHEN_PATTERN = re.compile(r'(\s|_)+')
++
++ def matchName(self, name):
++ needle = name.strip().lower()
++ haystack = self.name.lower()
++ needle = Package._HYPHEN_PATTERN.sub('-', needle)
++ haystack = Package._HYPHEN_PATTERN.sub('-', haystack)
++ if haystack.find(needle) >= 0:
++ return True
++ return False
++
++ def matchDetails(self, details):
++ if self.matchName(details):
++ return True
++ needle = details.strip().lower()
++ haystack = self.description.lower()
++ if haystack.find(needle) >= 0:
++ return True
++ return False
++
++ def matchGroup(self, name):
++ needle = name.strip().lower()
++ haystack = self.group
++ if haystack.startswith(needle):
++ return True
++ return False
++
++class PackageKitProgress(apt.progress.OpProgress, apt.progress.FetchProgress):
++ def __init__(self, backend):
++ self._backend = backend
++ apt.progress.OpProgress.__init__(self)
++ apt.progress.FetchProgress.__init__(self)
++
++ # OpProgress callbacks
++ def update(self, percent):
++ pass
++
++ def done(self):
++ pass
++
++ # FetchProgress callbacks
++ def pulse(self):
++ apt.progress.FetchProgress.pulse(self)
++ self._backend.percentage(self.percent)
++ return True
++
++ def stop(self):
++ self._backend.percentage(100)
++
++ def mediaChange(self, medium, drive):
++ # This probably should not be an error, but a Message.
++ self._backend.error(ERROR_UNKNOWN,
++ "Medium change needed")
++
++class PackageKitAptBackend(PackageKitBaseBackend):
++ def __init__(self, args):
++ PackageKitBaseBackend.__init__(self, args)
++ self.status(STATUS_SETUP)
++ self._caches = {}
++ self._apt_cache = apt.Cache(PackageKitProgress(self))
++ default = apt_pkg.Config.Find("APT::Default-Release")
++ if default=="":
++ d = get_distro()
++ if d.id == "Debian":
++ default = "stable"
++ elif d.id == "Ubuntu":
++ default = "main"
++ else:
++ raise Exception,d.id
++
++ self._caches[default] = self._apt_cache
++
++
++ def search_name(self, filters, key):
++ '''
++ Implement the {backend}-search-name functionality
++ '''
++ self.status(STATUS_INFO)
++ self.allow_cancel(True)
++ for package in self._do_search(filters,
++ lambda pkg: pkg.matchName(key)):
++ self._emit_package(package)
++
++ def search_details(self, filters, key):
++ '''
++ Implement the {backend}-search-details functionality
++ '''
++ self.status(STATUS_INFO)
++ self.allow_cancel(True)
++ for package in self._do_search(filters,
++ lambda pkg: pkg.matchDetails(key)):
++ self._emit_package(package)
++
++ def search_group(self, filters, key):
++ '''
++ Implement the {backend}-search-group functionality
++ '''
++ self.status(STATUS_INFO)
++ self.allow_cancel(True)
++ for package in self._do_search(filters,
++ lambda pkg: pkg.matchGroup(key)):
++ self._emit_package(package)
++
++ def search_file(self, filters, key):
++ '''
++ Implement the {backend}-search-file functionality
++ '''
++ self.allow_cancel(True)
++ self.percentage(None)
++
++ self.error(ERROR_NOT_SUPPORTED,
++ "This function is not implemented in this backend")
++
++ def refresh_cache(self):
++ '''
++ Implement the {backend}-refresh_cache functionality
++ '''
++ self.status(STATUS_REFRESH_CACHE)
++ try:
++ res = self._apt_cache.update(PackageKitProgress(self))
++ except Exception, error_message:
++ self.error(ERROR_UNKNOWN,
++ "Failed to fetch the following items:\n%s" % error_message)
++ return res
++
++ def get_details(self, package):
++ '''
++ Implement the {backend}-get-details functionality
++ '''
++ self.status(STATUS_INFO)
++ name, version, arch, data = self.get_package_from_id(package)
++ pkg = Package(self, self._apt_cache[name])
++ description = re.sub('\s+', ' ', pkg.description).strip()
++ self.description(package, 'unknown', pkg.group, description,
++ pkg.architecture, pkg.packageSize)
++
++ def resolve(self, name):
++ '''
++ Implement the {backend}-resolve functionality
++ '''
++ self.status(STATUS_INFO)
++ try:
++ pkg = Package(self,self._apt_cache[name])
++ self._emit_package(pkg)
++ except KeyError:
++ self.error(ERROR_PACKAGE_NOT_FOUND,"Can't find a package called '%s'"%name)
++
++ def _do_deps(self,inp,deps,recursive):
++ inp.markInstall()
++ newkeys = []
++ for x in inp.candidateDependencies:
++ n = x.or_dependencies[0].name
++ if not deps.has_key(n):
++ deps[n] = []
++ newkeys.append(n)
++ deps[n].append((x.or_dependencies[0].version,x.or_dependencies[0].relation))
++ if recursive:
++ for n in newkeys:
++ try:
++ deps = self._do_deps(Package(self,self._apt_cache[n],version=deps[n]),deps,recursive)
++ except KeyError: # FIXME: we're assuming this is a virtual package, which we can't cope with yet
++ del deps[n]
++ continue
++ return deps
++
++ def get_depends(self,filters,package, recursive):
++ '''
++ Implement the {backend}-get-depends functionality
++ '''
++ self.allow_cancel(True)
++ self.status(STATUS_INFO)
++ recursive = (recursive == "True")
++ name, version, arch, data = self.get_package_from_id(package)
++ pkg = Package(self,self._apt_cache[name],version=[(version,"=")],data=data)
++ pkg.setVersion(version)
++ deps = self._do_deps(pkg, {}, recursive)
++ for n in deps.keys():
++ self._emit_package(Package(self,self._apt_cache[n],version=deps[n]))
++
++ def _do_reqs(self,inp,pkgs,recursive):
++ extra = []
++ fails = []
++ for r in inp._pkg.RevDependsList:
++ ch = apt_pkg.CheckDep(inp._version,r.CompType,r.TargetVer)
++ v = (r.ParentPkg.Name,r.ParentVer.VerStr)
++ if not ch or v in fails:
++ #print "skip",r.TargetVer,r.CompType,r.ParentPkg.Name,r.ParentVer.VerStr
++ fails.append(v)
++ continue
++ p = Package(self,self._apt_cache[r.ParentPkg.Name],r.ParentVer.VerStr)
++ if v not in pkgs:
++ extra.append(p)
++ #print "new pkg",p
++ self._emit_package(p)
++ pkgs.add(v)
++ if recursive:
++ for e in extra:
++ pkgs = self._do_reqs(p, pkgs,recursive)
++ return pkgs
++
++ def get_requires(self,package,recursive):
++ '''
++ Implement the {backend}-get-requires functionality
++ '''
++ self.allow_cancel(True)
++ self.status(STATUS_INFO)
++ recursive = (recursive == "True")
++ name, version, arch, data = self.get_package_from_id(package)
++ pkg = Package(self,self._apt_cache[name], version=[(version,"=")], data=data)
++
++ pkgs = Set()
++ self._do_reqs(pkg,pkgs, recursive)
++
++ def _build_repo_list(self):
++ repo = {}
++
++ sources = SourcesList()
++ repo["__sources"] = sources
++
++ root = apt_pkg.Config.FindDir("Dir::State::Lists")
++ #print root
++ for entry in sources:
++ if entry.type!="":
++ url = entry.uri
++ #if entry.template!=None:
++ url +="/dists/"
++ url += entry.dist
++ url = url.replace("//dists","/dists")
++ #print url
++ path = join(root,"%s_Release"%(apt_pkg.URItoFileName(url)))
++ if not exists(path):
++ #print path
++ name = "%s/unknown"%urlparse(entry.uri)[1]
++ else:
++ lines = file(path).readlines()
++ origin = ""
++ suite = ""
++ for l in lines:
++ if l.find("Origin: ")==0:
++ origin = l.split(" ",1)[1].strip()
++ elif l.find("Suite: ")==0:
++ suite = l.split(" ",1)[1].strip()
++ assert origin!="" and suite!=""
++ name = "%s/%s"%(origin,suite)
++ if entry.type == "deb-src":
++ name += "-src"
++
++ repo[name] = {"entry":entry}
++ return repo
++
++ def get_repo_list(self, filters):
++ '''
++ Implement the {backend}-get-repo-list functionality
++ '''
++ self.allow_interrupt(True)
++ self.status(STATUS_INFO)
++ repo = self._build_repo_list()
++ for e in repo.keys():
++ if e == "__sources":
++ continue
++ self.repo_detail(repo[e]["entry"].line.strip(),e,not repo[e]["entry"].disabled)
++
++ def repo_enable(self, repoid, enable):
++ '''
++ Implement the {backend}-repo-enable functionality
++ '''
++ enable = (enable == "True")
++ repo = self._build_repo_list()
++ if not repo.has_key(repoid):
++ self.error(ERROR_REPO_NOT_FOUND,"Couldn't find repo '%s'"%repoid)
++ return
++ r = repo[repoid]
++ if not r["entry"].disabled == enable: # already there
++ return
++ r["entry"].set_enabled(enable)
++ try:
++ repo["__sources"].save()
++ except IOError,e:
++ self.error(ERROR_UNKNOWN, "Problem while trying to save repo settings to %s: %s"%(e.filename,e.strerror))
++
++ def get_updates(self, filter):
++ self._apt_cache.upgrade(False)
++ for pkg in self._apt_cache.getChanges():
++ self._emit_package(Package(self, pkg))
++
++ def get_update_detail(self, package):
++ self.allow_cancel(True)
++ self.percentage(None)
++ self.status(STATUS_INFO)
++ name, version, arch, data = self.get_package_from_id(package)
++ update = ""
++ obsolete = ""
++ cve_url = ""
++ bz_url = ""
++ vendor_url = ""
++ reboot = "none"
++ desc = self._apt_cache[name].description
++ self.update_detail(package,update,obsolete,vendor_url,bz_url,cve_url,reboot,desc)
++
++
++ def install_files (self, inst_files):
++ '''
++ Implement the {backend}-install_files functionality
++ Install the package containing the inst_file file
++ '''
++ if not exists(inst_file):
++ self.error(ERROR_PACKAGE_NOT_FOUND,"Can't find %s"%inst_file)
++ return
++ deb = DebPackage(inst_file)
++ deps = {}
++ for k in ["Depends","Recommends"]:
++ if not deb._sections.has_key(k):
++ continue
++ for items in apt_pkg.ParseDepends(deb[k]):
++ assert len(items) == 1,"Can't handle or deps properly yet"
++ (pkg,ver,comp) = items[0]
++ if not deps.has_key(pkg):
++ deps[pkg] = []
++ deps[pkg].append((ver,comp))
++ for n in deps.keys():
++ p = Package(self,self._apt_cache[n],version=deps[n])
++ if not p.isInstalled:
++ p.markInstall()
++ assert self._apt_cache.getChanges()==[],"Don't handle install changes yet"
++ # FIXME: nasty hack. Need a better way in
++ ret = system("dpkg -i %s"%inst_file)
++ if ret!=0:
++ self.error(ERROR_UNKNOWN,"Can't install package")
++
++ ### Helpers ###
++ def _emit_package(self, package):
++ id = self.get_package_id(package.name,
++ package._version,
++ package.architecture,
++ package._data)
++ if package.isInstalled:
++ status = INFO_INSTALLED
++ else:
++ status = INFO_AVAILABLE
++ summary = package.summary
++ self.package(id, status, summary)
++
++ def _do_search(self, filters, condition):
++ filters = filters.split(';')
++ size = len(self._apt_cache)
++ percentage = 0
++ for i, pkg in enumerate(self._apt_cache):
++ new_percentage = i / float(size) * 100
++ if new_percentage - percentage >= 5:
++ percentage = new_percentage
++ self.percentage(percentage)
++ package = Package(self, pkg)
++ if package.installedVersion is None and \
++ package.candidateVersion is None:
++ continue
++ if not condition(package):
++ continue
++ continue
++ vers = [x.VerStr for x in package._pkg.VersionList]
++ if package.installedVersion!=None:
++ i = package.installedVersion
++ if i in vers and vers[0]!=i:
++ del vers[vers.index(i)]
++ vers.insert(0,i)
++
++ for ver in vers:
++ p = Package(self, package, version=[[ver,"="]])
++ if self._do_filtering(p, filters):
++ yield p
++ self.percentage(100)
++
++ def _do_filtering(self, package, filters):
++ if len(filters) == 0 or filters == ['none']:
++ return True
++ if (FILTER_INSTALLED in filters) and (not package.isInstalled):
++ return False
++ if (FILTER_NOT_INSTALLED in filters) and package.isInstalled:
++ return False
++ if (FILTER_GUI in filters) and (not package.isGui):
++ return False
++ if (FILTER_NOT_GUI in filters) and package.isGui:
++ return False
++ if (FILTER_DEVELOPMENT in filters) and (not package.isDevelopment):
++ return False
++ if (FILTER_NOT_DEVELOPMENT in filters) and package.isDevelopment:
++ return False
++ return True
++
+diff --git a/backends/apt.deprecated/helpers/get-depends.py b/backends/apt.deprecated/helpers/get-depends.py
+new file mode 100755
+index 0000000..94dca4a
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/get-depends.py
+@@ -0,0 +1,20 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2007 Richard Hughes <richard@hughsie.com>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++
++from aptBackend import PackageKitAptBackend
++filters=sys.argv[1]
++package=sys.argv[2]
++recursive = sys.argv[3]
++backend = PackageKitAptBackend(sys.argv[1:])
++backend.get_depends(filters, package, recursive)
++sys.exit(0)
+diff --git a/backends/apt.deprecated/helpers/get-details.py b/backends/apt.deprecated/helpers/get-details.py
+new file mode 100755
+index 0000000..a813640
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/get-details.py
+@@ -0,0 +1,18 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++from aptBackend import PackageKitAptBackend
++
++package = sys.argv[1]
++backend = PackageKitAptBackend(sys.argv[1:])
++backend.get_details(package)
++sys.exit(0)
+diff --git a/backends/apt.deprecated/helpers/get-repo-list.py b/backends/apt.deprecated/helpers/get-repo-list.py
+new file mode 100755
+index 0000000..5529f72
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/get-repo-list.py
+@@ -0,0 +1,20 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2007 Richard Hughes <richard@hughsie.com>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++
++from aptBackend import PackageKitAptBackend
++filters = sys.argv[1]
++
++backend = PackageKitAptBackend(sys.argv[2:])
++backend.get_repo_list(filters)
++backend.unLock()
++sys.exit(0)
+diff --git a/backends/apt.deprecated/helpers/get-requires.py b/backends/apt.deprecated/helpers/get-requires.py
+new file mode 100755
+index 0000000..e581010
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/get-requires.py
+@@ -0,0 +1,20 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2007 Richard Hughes <richard@hughsie.com>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++
++from aptBackend import PackageKitAptBackend
++package = sys.argv[1]
++recursive = sys.argv[2]
++
++backend = PackageKitAptBackend(sys.argv[1:])
++backend.get_requires(package, recursive)
++sys.exit(0)
+diff --git a/backends/apt.deprecated/helpers/get-update-detail.py b/backends/apt.deprecated/helpers/get-update-detail.py
+new file mode 100755
+index 0000000..5524d9a
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/get-update-detail.py
+@@ -0,0 +1,18 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2008 Michael Vogt <mvo@ubuntu.com>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++
++from aptBackend import PackageKitAptBackend
++package=sys.argv[1]
++backend = PackageKitAptBackend(sys.argv[2:])
++backend.get_update_detail(package)
++sys.exit(0)
+diff --git a/backends/apt.deprecated/helpers/get-updates.py b/backends/apt.deprecated/helpers/get-updates.py
+new file mode 100755
+index 0000000..4f45fbf
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/get-updates.py
+@@ -0,0 +1,19 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2008 Michael Vogt <mvo@ubuntu.com>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++from aptBackend import PackageKitAptBackend
++
++filter = sys.argv[1]
++
++backend = PackageKitAptBackend(sys.argv[1:])
++backend.get_updates(filter)
++sys.exit(0)
+diff --git a/backends/apt.deprecated/helpers/install-files.py b/backends/apt.deprecated/helpers/install-files.py
+new file mode 100755
+index 0000000..dfa024c
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/install-files.py
+@@ -0,0 +1,21 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2007 Richard Hughes <richard@hughsie.com>
++# Copyright (C) 2007 Red Hat Inc, Seth Vidal <skvidal@fedoraproject.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.
++
++import sys
++
++from aptBackend import PackageKitAptBackend
++
++trusted = sys.argv[1]
++files_to_inst = sys.argv[2:]
++backend = PackageKitAptBackend(sys.argv[1:])
++backend.install_files(trusted, files_to_inst)
++sys.exit(0)
+diff --git a/backends/apt.deprecated/helpers/packagekit b/backends/apt.deprecated/helpers/packagekit
+new file mode 120000
+index 0000000..8d22531
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/packagekit
+@@ -0,0 +1 @@
++../../../python/packagekit
+\ No newline at end of file
+diff --git a/backends/apt.deprecated/helpers/refresh-cache.py b/backends/apt.deprecated/helpers/refresh-cache.py
+new file mode 100755
+index 0000000..881479d
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/refresh-cache.py
+@@ -0,0 +1,17 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++from aptBackend import PackageKitAptBackend
++
++backend = PackageKitAptBackend(sys.argv[1:])
++backend.refresh_cache()
++sys.exit(0)
+diff --git a/backends/apt.deprecated/helpers/repo-enable.py b/backends/apt.deprecated/helpers/repo-enable.py
+new file mode 100755
+index 0000000..3cc36ae
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/repo-enable.py
+@@ -0,0 +1,20 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2007 Richard Hughes <richard@hughsie.com>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++
++from aptBackend import PackageKitAptBackend
++repoid = sys.argv[1]
++state=sys.argv[2]
++backend = PackageKitAptBackend(sys.argv[2:])
++backend.repo_enable(repoid,state)
++backend.unLock()
++sys.exit(0)
+diff --git a/backends/apt.deprecated/helpers/resolve.py b/backends/apt.deprecated/helpers/resolve.py
+new file mode 100755
+index 0000000..aac34df
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/resolve.py
+@@ -0,0 +1,20 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2007 Richard Hughes <richard@hughsie.com>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++
++from aptBackend import PackageKitAptBackend
++filters = sys.argv[1]
++name=sys.argv[2]
++backend = PackageKitAptBackend(sys.argv[2:])
++backend.resolve(name)
++backend.unLock()
++sys.exit(0)
+diff --git a/backends/apt.deprecated/helpers/search-details.py b/backends/apt.deprecated/helpers/search-details.py
+new file mode 100755
+index 0000000..d02f1b0
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/search-details.py
+@@ -0,0 +1,21 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++
++options = sys.argv[1]
++searchlist = sys.argv[2]
++
++from aptBackend import PackageKitAptBackend
++
++backend = PackageKitAptBackend(sys.argv[1:])
++backend.search_details(options,searchlist)
++sys.exit(0)
+diff --git a/backends/apt.deprecated/helpers/search-file.py b/backends/apt.deprecated/helpers/search-file.py
+new file mode 100755
+index 0000000..ec60319
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/search-file.py
+@@ -0,0 +1,21 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++
++options = sys.argv[1]
++searchlist = sys.argv[2]
++
++from aptBackend import PackageKitAptBackend
++
++backend = PackageKitAptBackend(sys.argv[1:])
++backend.search_file(options,searchlist)
++sys.exit(0)
+diff --git a/backends/apt.deprecated/helpers/search-group.py b/backends/apt.deprecated/helpers/search-group.py
+new file mode 100755
+index 0000000..f63ee80
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/search-group.py
+@@ -0,0 +1,21 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++
++options = sys.argv[1]
++searchlist = sys.argv[2]
++
++from aptBackend import PackageKitAptBackend
++
++backend = PackageKitAptBackend(sys.argv[1:])
++backend.search_group(options,searchlist)
++sys.exit(0)
+diff --git a/backends/apt.deprecated/helpers/search-name.py b/backends/apt.deprecated/helpers/search-name.py
+new file mode 100755
+index 0000000..9f73c89
+--- /dev/null
++++ b/backends/apt.deprecated/helpers/search-name.py
+@@ -0,0 +1,21 @@
++#!/usr/bin/python
++#
++# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
++#
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++
++import sys
++
++options = sys.argv[1]
++searchlist = sys.argv[2]
++
++from aptBackend import PackageKitAptBackend
++
++backend = PackageKitAptBackend(sys.argv[1:])
++backend.search_name(options,searchlist)
++sys.exit(0)
+diff --git a/backends/apt.deprecated/pk-apt-build-db.cpp b/backends/apt.deprecated/pk-apt-build-db.cpp
+new file mode 100644
+index 0000000..885275d
+--- /dev/null
++++ b/backends/apt.deprecated/pk-apt-build-db.cpp
+@@ -0,0 +1,284 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++//#include "pk-backend-apt.h"
++#include <pk-backend.h>
++#include <apt-pkg/configuration.h>
++#include <sqlite3.h>
++
++typedef enum {FIELD_PKG=1,FIELD_VER,FIELD_DEPS,FIELD_ARCH,FIELD_SHORT,FIELD_LONG,FIELD_REPO} Fields;
++
++void apt_build_db(PkBackend * backend, sqlite3 *db)
++{
++ GMatchInfo *match_info;
++ GError *error = NULL;
++ gchar *contents = NULL;
++ gchar *sdir;
++ const gchar *fname;
++ GRegex *origin, *suite;
++ GDir *dir;
++ GHashTable *releases;
++ int res;
++ sqlite3_stmt *package = NULL;
++
++ pk_backend_set_status(backend, PK_STATUS_ENUM_QUERY);
++ pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
++
++ sdir = g_build_filename(_config->Find("Dir").c_str(),_config->Find("Dir::State").c_str(),_config->Find("Dir::State::lists").c_str(), NULL);
++ dir = g_dir_open(sdir,0,&error);
++ if (error!=NULL)
++ {
++ pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "can't open %s",dir);
++ g_error_free(error);
++ goto search_task_cleanup;
++ }
++
++ origin = g_regex_new("^Origin: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
++ suite = g_regex_new("^Suite: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
++
++ releases = g_hash_table_new_full(g_str_hash,g_str_equal,g_free,g_free);
++ while ((fname = g_dir_read_name(dir))!=NULL)
++ {
++ gchar *temp, *parsed_name;
++ gchar** items = g_strsplit(fname,"_",-1);
++ guint len = g_strv_length(items);
++ if(len<=3) // minimum is <source>_<type>_<group>
++ {
++ g_strfreev(items);
++ continue;
++ }
++
++ /* warning: nasty hack with g_strjoinv */
++ temp = items[len-2];
++ items[len-2] = NULL;
++ parsed_name = g_strjoinv("_",items);
++ items[len-2] = temp;
++
++ if (g_ascii_strcasecmp(items[len-1],"Release")==0 && g_ascii_strcasecmp(items[len-2],"source")!=0)
++ {
++ gchar * repo = NULL, *fullname;
++ fullname = g_build_filename(sdir,fname,NULL);
++ if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
++ {
++ pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
++ goto search_task_cleanup;
++ }
++ g_free(fullname);
++
++ g_regex_match (origin, contents, (GRegexMatchFlags)0, &match_info);
++ if (!g_match_info_matches(match_info))
++ {
++ pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "origin regex failure in %s",fname);
++ goto search_task_cleanup;
++ }
++ repo = g_match_info_fetch (match_info, 1);
++
++ g_regex_match (suite, contents, (GRegexMatchFlags)0, &match_info);
++ if (g_match_info_matches(match_info))
++ {
++ temp = g_strconcat(repo,"/",g_match_info_fetch (match_info, 1),NULL);
++ g_free(repo);
++ repo = temp;
++ }
++
++ temp = parsed_name;
++ parsed_name = g_strconcat(temp,"_",items[len-2],NULL);
++ g_free(temp);
++
++ pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
++
++ g_hash_table_insert(releases, parsed_name, repo);
++ g_free(contents);
++ contents = NULL;
++ }
++ else
++ g_free(parsed_name);
++ g_strfreev(items);
++ }
++ g_dir_close(dir);
++
++ /* and then we need to do this again, but this time we're looking for the packages */
++ dir = g_dir_open(sdir,0,&error);
++ res = sqlite3_prepare_v2(db, "insert or replace into packages values (?,?,?,?,?,?,?)", -1, &package, NULL);
++ if (res!=SQLITE_OK)
++ pk_error("sqlite error during insert prepare: %s", sqlite3_errmsg(db));
++ else
++ pk_debug("insert prepare ok for %p",package);
++ while ((fname = g_dir_read_name(dir))!=NULL)
++ {
++ gchar** items = g_strsplit(fname,"_",-1);
++ guint len = g_strv_length(items);
++ if(len<=3) // minimum is <source>_<type>_<group>
++ {
++ g_strfreev(items);
++ continue;
++ }
++
++ if (g_ascii_strcasecmp(items[len-1],"Packages")==0)
++ {
++ const gchar *repo;
++ gchar *temp=NULL, *parsed_name=NULL;
++ gchar *fullname= NULL;
++ gchar *begin=NULL, *next=NULL, *description = NULL;
++ glong count = 0;
++ gboolean haspk = FALSE;
++
++ /* warning: nasty hack with g_strjoinv */
++ if (g_str_has_prefix(items[len-2],"binary-"))
++ {
++ temp = items[len-3];
++ items[len-3] = NULL;
++ parsed_name = g_strjoinv("_",items);
++ items[len-3] = temp;
++ }
++ else
++ {
++ temp = items[len-1];
++ items[len-1] = NULL;
++ parsed_name = g_strjoinv("_",items);
++ items[len-1] = temp;
++ }
++
++ pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
++
++ repo = (const gchar *)g_hash_table_lookup(releases,parsed_name);
++ if (repo == NULL)
++ {
++ pk_debug("Can't find repo for %s, marking as \"unknown\"",parsed_name);
++ repo = g_strdup("unknown");
++ //g_assert(0);
++ }
++ else
++ pk_debug("repo for %s is %s",parsed_name,repo);
++ g_free(parsed_name);
++
++ fullname = g_build_filename(sdir,fname,NULL);
++ pk_debug("loading %s",fullname);
++ if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
++ {
++ pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
++ goto search_task_cleanup;
++ }
++ /*else
++ pk_debug("loaded");*/
++
++ res = sqlite3_bind_text(package,FIELD_REPO,repo,-1,SQLITE_TRANSIENT);
++ if (res!=SQLITE_OK)
++ pk_error("sqlite error during repo bind: %s", sqlite3_errmsg(db));
++ /*else
++ pk_debug("repo bind ok");*/
++
++ res = sqlite3_exec(db,"begin",NULL,NULL,NULL);
++ g_assert(res == SQLITE_OK);
++
++ begin = contents;
++
++ while (true)
++ {
++ next = strstr(begin,"\n");
++ if (next!=NULL)
++ {
++ next[0] = '\0';
++ next++;
++ }
++
++ if (begin[0]=='\0')
++ {
++ if (haspk)
++ {
++ if (description!=NULL)
++ {
++ res=sqlite3_bind_text(package,FIELD_LONG,description,-1,SQLITE_TRANSIENT);
++ if (res!=SQLITE_OK)
++ pk_error("sqlite error during description bind: %s", sqlite3_errmsg(db));
++ g_free(description);
++ description = NULL;
++ }
++ res = sqlite3_step(package);
++ if (res!=SQLITE_DONE)
++ pk_error("sqlite error during step: %s", sqlite3_errmsg(db));
++ sqlite3_reset(package);
++ //pk_debug("added package");
++ haspk = FALSE;
++ }
++ //g_assert(0);
++ }
++ else if (begin[0]==' ')
++ {
++ if (description == NULL)
++ description = g_strdup(&begin[1]);
++ else
++ {
++ gchar *oldval = description;
++ description = g_strconcat(oldval, "\n",&begin[1],NULL);
++ g_free(oldval);
++ }
++ }
++ else
++ {
++ gchar *colon = strchr(begin,':');
++ g_assert(colon!=NULL);
++ colon[0] = '\0';
++ colon+=2;
++ /*if (strlen(colon)>3000)
++ pk_error("strlen(colon) = %d\ncolon = %s",strlen(colon),colon);*/
++ //pk_debug("entry = '%s','%s'",begin,colon);
++ if (begin[0] == 'P' && g_strcasecmp("Package",begin)==0)
++ {
++ res=sqlite3_bind_text(package,FIELD_PKG,colon,-1,SQLITE_STATIC);
++ haspk = TRUE;
++ count++;
++ if (count%1000==0)
++ pk_debug("Package %ld (%s)",count,colon);
++ }
++ else if (begin[0] == 'V' && g_strcasecmp("Version",begin)==0)
++ res=sqlite3_bind_text(package,FIELD_VER,colon,-1,SQLITE_STATIC);
++ else if (begin[0] == 'D' && g_strcasecmp("Depends",begin)==0)
++ res=sqlite3_bind_text(package,FIELD_DEPS,colon,-1,SQLITE_STATIC);
++ else if (begin[0] == 'A' && g_strcasecmp("Architecture",begin)==0)
++ res=sqlite3_bind_text(package,FIELD_ARCH,colon,-1,SQLITE_STATIC);
++ else if (begin[0] == 'D' && g_strcasecmp("Description",begin)==0)
++ res=sqlite3_bind_text(package,FIELD_SHORT,colon,-1,SQLITE_STATIC);
++ if (res!=SQLITE_OK)
++ pk_error("sqlite error during %s bind: %s", begin, sqlite3_errmsg(db));
++ }
++ if (next == NULL)
++ break;
++ begin = next;
++ }
++ res = sqlite3_exec(db,"commit",NULL,NULL,NULL);
++ if (res!=SQLITE_OK)
++ pk_error("sqlite error during commit: %s", sqlite3_errmsg(db));
++ res = sqlite3_clear_bindings(package);
++ if (res!=SQLITE_OK)
++ pk_error("sqlite error during clear: %s", sqlite3_errmsg(db));
++ g_free(contents);
++ contents = NULL;
++ }
++ }
++ sqlite3_finalize(package);
++
++search_task_cleanup:
++ g_dir_close(dir);
++ g_free(sdir);
++ g_free(contents);
++}
++
+diff --git a/backends/apt.deprecated/pk-apt-build-db.h b/backends/apt.deprecated/pk-apt-build-db.h
+new file mode 100644
+index 0000000..bb786a9
+--- /dev/null
++++ b/backends/apt.deprecated/pk-apt-build-db.h
+@@ -0,0 +1,30 @@
++#ifndef PK_APT_BUILD_DB
++#define PK_APT_BUILD_DB
++
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++#include <sqlite3.h>
++#include <pk-backend.h>
++
++void apt_build_db(PkBackend * backend, sqlite3 *db);
++
++#endif
+diff --git a/backends/apt.deprecated/pk-apt-search-plain.c b/backends/apt.deprecated/pk-apt-search-plain.c
+new file mode 100644
+index 0000000..5e5b4e5
+--- /dev/null
++++ b/backends/apt.deprecated/pk-apt-search-plain.c
+@@ -0,0 +1,106 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++#include <gmodule.h>
++#include <glib.h>
++#include <string.h>
++#include <pk-backend.h>
++#include <pk-backend-spawn.h>
++
++extern PkBackendSpawn *spawn;
++
++/**
++ * backend_get_groups:
++ */
++static PkGroupEnum
++backend_get_groups (PkBackend *backend)
++{
++ return (PK_GROUP_ENUM_ACCESSORIES |
++ PK_GROUP_ENUM_GAMES |
++ PK_GROUP_ENUM_GRAPHICS |
++ PK_GROUP_ENUM_INTERNET |
++ PK_GROUP_ENUM_OFFICE |
++ PK_GROUP_ENUM_OTHER |
++ PK_GROUP_ENUM_PROGRAMMING |
++ PK_GROUP_ENUM_MULTIMEDIA |
++ PK_GROUP_ENUM_SYSTEM);
++}
++
++/**
++ * backend_get_filters:
++ */
++static PkFilterEnum
++backend_get_filters (PkBackend *backend)
++{
++ return (PK_FILTER_ENUM_GUI |
++ PK_FILTER_ENUM_INSTALLED |
++ PK_FILTER_ENUM_DEVELOPMENT);
++}
++
++/**
++ * backend_get_details:
++ */
++
++void
++backend_get_details (PkBackend *backend, const gchar *package_id)
++{
++ pk_backend_spawn_helper (spawn, "get-details.py", package_id, NULL);
++}
++
++/**
++ * backend_search_details:
++ */
++
++void
++backend_search_details (PkBackend *backend, PkFilterEnum filters, const gchar *search)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "search-details.py", filters_texts_text, search, NULL);
++ g_free (filters_text);
++}
++
++/**
++ * backend_search_name:
++ */
++void
++backend_search_name (PkBackend *backend, PkFilterEnum filters, const gchar *search)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "search-name.py", filters_text, search, NULL);
++ g_free (filters_text);
++}
++
++/**
++ * backend_search_group:
++ */
++void
++backend_search_group (PkBackend *backend, PkFilterEnum filters, const gchar *search)
++{
++ gchar *filters_text;
++ pk_backend_spawn_helper (spawn, "search-group.py", filters_text, search, NULL);
++ g_free (filters_text);
++}
++
++/* don't need to do any setup/finalize in the plain search mode */
++void backend_init_search(PkBackend *backend) {}
++void backend_finish_search(PkBackend *backend) {}
+diff --git a/backends/apt.deprecated/pk-apt-search-sqlite.cpp b/backends/apt.deprecated/pk-apt-search-sqlite.cpp
+new file mode 100644
+index 0000000..98bdc7f
+--- /dev/null
++++ b/backends/apt.deprecated/pk-apt-search-sqlite.cpp
+@@ -0,0 +1,135 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++#include <gmodule.h>
++#include <glib.h>
++#include <string.h>
++#include <pk-backend.h>
++#include <pk-backend-spawn.h>
++#include "pk-sqlite-pkg-cache.h"
++#include <apt-pkg/configuration.h>
++#include <apt-pkg/init.h>
++#include "pk-apt-build-db.h"
++
++static PkBackendSpawn *spawn;
++
++/**
++ * backend_get_groups:
++ */
++extern "C" PkGroupEnum
++backend_get_groups (PkBackend *backend)
++{
++ return (PK_GROUP_ENUM_ACCESSORIES |
++ PK_GROUP_ENUM_GAMES |
++ PK_GROUP_ENUM_GRAPHICS |
++ PK_GROUP_ENUM_INTERNET |
++ PK_GROUP_ENUM_OFFICE |
++ PK_GROUP_ENUM_OTHER |
++ PK_GROUP_ENUM_PROGRAMMING |
++ PK_GROUP_ENUM_MULTIMEDIA |
++ PK_GROUP_ENUM_SYSTEM);
++}
++
++/**
++ * backend_get_filters:
++ */
++extern "C" PkFilterEnum
++backend_get_filters (PkBackend *backend)
++{
++ return (PK_FILTER_ENUM_GUI |
++ PK_FILTER_ENUM_INSTALLED |
++ PK_FILTER_ENUM_DEVELOPMENT);
++}
++
++/**
++ * backend_get_details:
++ */
++
++extern "C" void
++backend_get_details (PkBackend *backend, const gchar *package_id)
++{
++ sqlite_get_details(backend,package_id);
++}
++
++/**
++ * backend_search_details:
++ */
++
++extern "C" void
++backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
++{
++ sqlite_search_details(backend,filter,search);
++}
++
++/**
++ * backend_search_name:
++ */
++extern "C" void
++backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
++{
++ sqlite_search_name(backend,filter,search);
++}
++
++/**
++ * backend_search_group:
++ */
++extern "C" void
++backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
++{
++ pk_backend_set_allow_cancel (backend, TRUE);
++ pk_backend_spawn_helper (spawn, "search-group.py", filter, search, NULL);
++}
++
++static gboolean inited = FALSE;
++
++#define APT_DB PK_DB_DIR "/apt.db"
++
++extern "C" void backend_init_search(PkBackend *backend)
++{
++ if (!inited)
++ {
++ gchar *apt_fname = NULL;
++ if (pkgInitConfig(*_config) == false)
++ pk_debug("pkginitconfig was false");
++ if (pkgInitSystem(*_config, _system) == false)
++ pk_debug("pkginitsystem was false");
++
++ apt_fname = g_strconcat(
++ _config->Find("Dir").c_str(),
++ _config->Find("Dir::Cache").c_str(),
++ _config->Find("Dir::Cache::pkgcache").c_str(),
++ NULL);
++
++ //sqlite_set_installed_check(is_installed);
++ sqlite_init_cache(backend, APT_DB, apt_fname, apt_build_db);
++ g_free(apt_fname);
++
++ spawn = pk_backend_spawn_new ();
++ pk_backend_spawn_set_name (spawn, "apt-sqlite");
++
++ inited = TRUE;
++ }
++}
++
++extern "C" void backend_finish_search(PkBackend *backend)
++{
++ sqlite_finish_cache(backend);
++}
+diff --git a/backends/apt.deprecated/pk-apt-search.h b/backends/apt.deprecated/pk-apt-search.h
+new file mode 100644
+index 0000000..e36e89f
+--- /dev/null
++++ b/backends/apt.deprecated/pk-apt-search.h
+@@ -0,0 +1,36 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __PK_APT_SEARCH_H
++#define __PK_APT_SEARCH_H
++
++#include <glib.h>
++#include <pk-backend.h>
++
++void backend_init_search(PkBackend *backend);
++void backend_finish_search(PkBackend *backend);
++
++void backend_get_details (PkBackend *backend, const gchar *package_id);
++void backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search);
++void backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search);
++void backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search);
++
++#endif
+diff --git a/backends/apt.deprecated/pk-backend-apt.c b/backends/apt.deprecated/pk-backend-apt.c
+new file mode 100644
+index 0000000..f59cd88
+--- /dev/null
++++ b/backends/apt.deprecated/pk-backend-apt.c
+@@ -0,0 +1,268 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
++ * Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++#include <gmodule.h>
++#include <glib.h>
++#include <string.h>
++#include <pk-backend.h>
++#include <pk-backend-spawn.h>
++#include <pk-package-ids.h>
++#include "pk-apt-search.h"
++#include "config.h"
++
++PkBackendSpawn *spawn;
++
++/**
++ * backend_initialize:
++ * This should only be run once per backend load, i.e. not every transaction
++ */
++static void
++backend_initialize (PkBackend *backend)
++{
++ pk_debug ("FILTER: initialize");
++ spawn = pk_backend_spawn_new ();
++ pk_backend_spawn_set_name (spawn, "apt");
++ backend_init_search (backend);
++}
++
++/**
++ * backend_destroy:
++ * This should only be run once per backend load, i.e. not every transaction
++ */
++static void
++backend_destroy (PkBackend *backend)
++{
++ pk_debug ("FILTER: destroy");
++ backend_finish_search (backend);
++ g_object_unref (spawn);
++}
++
++/**
++ * backend_get_groups:
++ */
++static PkGroupEnum
++backend_get_groups (PkBackend *backend)
++{
++ return (PK_GROUP_ENUM_ACCESSORIES |
++ PK_GROUP_ENUM_GAMES |
++ PK_GROUP_ENUM_GRAPHICS |
++ PK_GROUP_ENUM_INTERNET |
++ PK_GROUP_ENUM_OFFICE |
++ PK_GROUP_ENUM_OTHER |
++ PK_GROUP_ENUM_PROGRAMMING |
++ PK_GROUP_ENUM_MULTIMEDIA |
++ PK_GROUP_ENUM_SYSTEM);
++}
++
++/**
++ * backend_get_filters:
++ */
++static PkFilterEnum
++backend_get_filters (PkBackend *backend)
++{
++ return (PK_FILTER_ENUM_GUI |
++ PK_FILTER_ENUM_INSTALLED |
++ PK_FILTER_ENUM_DEVELOPMENT);
++}
++
++/**
++ * pk_backend_bool_to_text:
++ */
++static const gchar *
++pk_backend_bool_to_text (gboolean value)
++{
++ if (value == TRUE) {
++ return "yes";
++ }
++ return "no";
++}
++
++/**
++ * backend_get_depends:
++ */
++static void
++backend_get_depends (PkBackend *backend, PkFilterEnum filters, const gchar *package_id, gboolean recursive)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "get-depends.py", filters_text, package_id, pk_backend_bool_to_text (recursive), NULL);
++ g_free (filters_text);
++}
++
++/**
++ * backend_get_updates:
++ */
++static void
++backend_get_updates (PkBackend *backend, PkFilterEnum filters)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "get-updates.py", filters_text, NULL);
++ g_free (filters_text);
++}
++
++/**
++ * backend_get_update_detail:
++ */
++static void
++backend_get_update_detail (PkBackend *backend, const gchar *package_id)
++{
++ pk_backend_spawn_helper (spawn, "get-update-detail.py", package_id, NULL);
++}
++
++/**
++ * backend_install_packages:
++ */
++static void
++backend_install_packages (PkBackend *backend, gchar **package_ids)
++{
++ gchar *package_ids_temp;
++
++ /* check network state */
++ if (!pk_backend_is_online (backend)) {
++ pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot install when offline");
++ pk_backend_finished (backend);
++ return;
++ }
++
++ /* send the complete list as stdin */
++ package_ids_temp = pk_package_ids_to_text (package_ids, "|");
++ pk_backend_spawn_helper (spawn, "install-packages.py", package_ids_temp, NULL);
++ g_free (package_ids_temp);
++}
++
++/**
++ * backend_refresh_cache:
++ */
++static void
++backend_refresh_cache (PkBackend *backend, gboolean force)
++{
++ /* check network state */
++ if (!pk_backend_is_online (backend)) {
++ pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot refresh cache whilst offline");
++ pk_backend_finished (backend);
++ return;
++ }
++
++ pk_backend_spawn_helper (spawn, "refresh-cache.py", NULL);
++}
++
++/**
++ * pk_backend_remove_packages:
++ *
++static void
++backend_remove_packages (PkBackend *backend, gchar **package_ids, gboolean allow_deps, gboolean autoremove)
++{
++ gchar *package_ids_temp;
++ package_ids_temp = pk_package_ids_to_text (package_ids, "|");
++ pk_backend_spawn_helper (spawn, "remove-packages.py", pk_backend_bool_to_text (allow_deps), package_ids_temp, NULL);
++ g_free (package_ids_temp);
++} */
++
++/**
++ * pk_backend_update_packages:
++ */
++static void
++backend_update_packages (PkBackend *backend, gchar **package_ids)
++{
++ gchar *package_ids_temp;
++
++ /* check network state */
++ if (!pk_backend_is_online (backend)) {
++ pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot install when offline");
++ pk_backend_finished (backend);
++ return;
++ }
++
++ /* send the complete list as stdin */
++ package_ids_temp = pk_package_ids_to_text (package_ids, "|");
++ pk_backend_spawn_helper (spawn, "update-packages.py", package_ids_temp, NULL);
++ g_free (package_ids_temp);
++}
++
++/**
++ * pk_backend_update_system:
++ */
++static void
++backend_update_system (PkBackend *backend)
++{
++ pk_backend_spawn_helper (spawn, "update-system.py", NULL);
++}
++
++/**
++ * pk_backend_resolve:
++ */
++static void
++backend_resolve (PkBackend *backend, PkFilterEnum filters, const gchar *package_id)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "resolve.py", filters_text, package_id, NULL);
++ g_free (filters_text);
++}
++
++/**
++ * pk_backend_get_repo_list:
++ */
++static void
++backend_get_repo_list (PkBackend *backend, PkFilterEnum filters)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "get-repo-list.py", filters_text, NULL);
++ g_free (filters_text);
++}
++
++PK_BACKEND_OPTIONS (
++ "Apt (with " APT_SEARCH " searching)", /* description */
++ "Ali Sabil <ali.sabil@gmail.com>; Tom Parker <palfrey@tevp.net>", /* author */
++ backend_initialize, /* initalize */
++ backend_destroy, /* destroy */
++ backend_get_groups, /* get_groups */
++ backend_get_filters, /* get_filters */
++ NULL, /* cancel */
++ backend_get_depends, /* get_depends */
++ backend_get_details, /* get_details */
++ NULL, /* get_files */
++ NULL, /* get_packages */
++ backend_get_repo_list, /* get_repo_list */
++ NULL, /* get_requires */
++ backend_get_update_detail, /* get_update_detail */
++ backend_get_updates, /* get_updates */
++ NULL, /* install_files */
++ backend_install_packages, /* install_packages */
++ NULL, /* install_signature */
++ backend_refresh_cache, /* refresh_cache */
++ NULL, /* remove_packages */
++ NULL, /* repo_enable */
++ NULL, /* repo_set_data */
++ backend_resolve, /* resolve */
++ NULL, /* rollback */
++ backend_search_details, /* search_details */
++ NULL, /* search_file */
++ backend_search_group, /* search_group */
++ backend_search_name, /* search_name */
++ NULL, /* service_pack */
++ backend_update_package, /* update_package */
++ backend_update_system, /* update_system */
++ NULL /* what_provides */
++);
+diff --git a/backends/apt.deprecated/pk-sqlite-pkg-cache.cpp b/backends/apt.deprecated/pk-sqlite-pkg-cache.cpp
+new file mode 100644
+index 0000000..1bf9a50
+--- /dev/null
++++ b/backends/apt.deprecated/pk-sqlite-pkg-cache.cpp
+@@ -0,0 +1,215 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++#include <glib.h>
++#include <glib/gstdio.h>
++#include "pk-sqlite-pkg-cache.h"
++
++static sqlite3 *db = NULL;
++static PkBackend *backend;
++static gboolean(*is_installed) (const PkPackageId *) = NULL;
++
++void sqlite_set_installed_check(gboolean(*func) (const PkPackageId *))
++{
++ is_installed = func;
++}
++
++void
++sqlite_init_cache(PkBackend *backend, const char* dbname, const char *compare_fname, void (*build_db)(PkBackend *, sqlite3 *))
++{
++ int ret;
++ struct stat st;
++ time_t db_age;
++
++ ret = sqlite3_open (dbname, &db);
++ g_assert(ret == SQLITE_OK);
++ g_assert(db!=NULL);
++ ret = sqlite3_exec(db,"PRAGMA synchronous = OFF",NULL,NULL,NULL);
++ g_assert(ret == SQLITE_OK);
++
++ g_stat(dbname, &st);
++ db_age = st.st_mtime;
++ g_stat(compare_fname, &st);
++ if (db_age>=st.st_mtime)
++ {
++ ret = sqlite3_exec(db, "select value from params where name = 'build_complete'", NULL, NULL, NULL);
++ if (ret != SQLITE_ERROR)
++ return;
++ pk_debug("ages are %lu for db, and %lu for comparism",db_age,st.st_mtime);
++ }
++ ret = sqlite3_exec(db,"drop table packages",NULL,NULL,NULL); // wipe it!
++ //g_assert(ret == SQLITE_OK);
++ pk_debug("wiped db");
++ ret = sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string, primary key(name,version,arch,repo))",NULL,NULL,NULL);
++ g_assert(ret == SQLITE_OK);
++
++ build_db(backend,db);
++
++ sqlite3_exec(db,"create table params (name text primary key, value integer)", NULL, NULL, NULL);
++ sqlite3_exec(db,"insert into params values ('build_complete',1)", NULL, NULL, NULL);
++}
++
++void sqlite_finish_cache(PkBackend *backend)
++{
++ sqlite3_close(db);
++}
++
++// sqlite_search_packages_thread
++static gboolean
++sqlite_search_packages_thread (PkBackend *backend)
++{
++ int res;
++ gchar *sel;
++ const gchar *search;
++
++ pk_backend_set_status(backend, PK_STATUS_ENUM_QUERY);
++ pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
++ type = pk_backend_get_uint (backend, "type");
++ search = pk_backend_get_string (backend, "search");
++
++ pk_debug("finding %s", search);
++
++ sqlite3_stmt *package = NULL;
++ g_strdelimit(search," ",'%');
++
++ if (type == SEARCH_NAME)
++ sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%'",search);
++ else if (type == SEARCH_DETAILS)
++ sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%' or short_desc like '%%%s%%' or long_desc like '%%%s%%'",search, search, search);
++ else
++ {
++ pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "Unknown search task type");
++ goto end_search_packages;
++ }
++
++ pk_debug("statement is '%s'",sel);
++ res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
++ g_free(sel);
++ if (res!=SQLITE_OK)
++ pk_error("sqlite error during select prepare: %s", sqlite3_errmsg(db));
++ res = sqlite3_step(package);
++ while (res == SQLITE_ROW)
++ {
++ PkPackageId *pid = pk_package_id_new_from_list((const gchar*)sqlite3_column_text(package,0),
++ (const gchar*)sqlite3_column_text(package,1),
++ (const gchar*)sqlite3_column_text(package,2),
++ (const gchar*)sqlite3_column_text(package,3));
++
++ gchar *cpid = pk_package_id_to_string(pid);
++ PkInfoEnum pie = PK_INFO_ENUM_UNKNOWN;
++
++ if (is_installed != NULL)
++ pie = is_installed(pid)?PK_INFO_ENUM_INSTALLED:PK_INFO_ENUM_AVAILABLE;
++
++ pk_backend_package(backend, pie, cpid, (const gchar*)sqlite3_column_text(package,4));
++
++ g_free(cpid);
++ pk_package_id_free(pid);
++
++ if (res==SQLITE_ROW)
++ res = sqlite3_step(package);
++ }
++ if (res!=SQLITE_DONE)
++ {
++ pk_debug("sqlite error during step (%d): %s", res, sqlite3_errmsg(db));
++ g_assert(0);
++ }
++
++end_search_packages:
++ pk_backend_finished (backend);
++ return TRUE;
++}
++
++/**
++ * sqlite_search_details:
++ */
++void
++sqlite_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
++{
++ pk_backend_set_uint (backend, "type", SEARCH_DETAILS);
++ pk_backend_thread_create (backend, sqlite_search_packages_thread);
++}
++
++/**
++ * sqlite_search_name:
++ */
++void
++sqlite_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
++{
++ pk_backend_set_uint (backend, "type", SEARCH_NAME);
++ pk_backend_thread_create (backend, sqlite_search_packages_thread);
++}
++
++// sqlite_get_details_thread
++static gboolean
++sqlite_get_details_thread (PkBackend *backend)
++{
++ PkPackageId *pi;
++ const gchar *package_id;
++ int res;
++
++ package_id = pk_backend_get_string (backend, "package_id");
++ pi = pk_package_id_new_from_string(package_id);
++ if (pi == NULL)
++ {
++ pk_backend_error_code(backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "invalid package id");
++ pk_backend_finished(backend);
++ return;
++ }
++
++ pk_backend_set_status(backend, PK_STATUS_ENUM_QUERY);
++ pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
++
++ pk_debug("finding %s", pi->name);
++
++ sqlite3_stmt *package = NULL;
++ gchar *sel = g_strdup_printf("select long_desc from packages where name = '%s' and version = '%s' and repo = '%s'",pi->name,pi->version,pi->data);
++ pk_debug("statement is '%s'",sel);
++ res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
++ g_free(sel);
++ if (res!=SQLITE_OK)
++ pk_error("sqlite error during select prepare: %s", sqlite3_errmsg(db));
++ res = sqlite3_step(package);
++ pk_backend_details(backend,pi->name, "unknown", PK_GROUP_ENUM_OTHER,(const gchar*)sqlite3_column_text(package,0),"",0);
++ res = sqlite3_step(package);
++ if (res==SQLITE_ROW)
++ pk_error("multiple matches for that package!");
++ if (res!=SQLITE_DONE)
++ {
++ pk_debug("sqlite error during step (%d): %s", res, sqlite3_errmsg(db));
++ g_assert(0);
++ }
++
++ g_free(dt);
++
++ return TRUE;
++}
++
++/**
++ * sqlite_get_details:
++ */
++extern "C++" void
++sqlite_get_details (PkBackend *backend, const gchar *package_id)
++{
++ pk_backend_thread_create (backend, sqlite_get_details_thread);
++ return;
++}
++
+diff --git a/backends/apt.deprecated/pk-sqlite-pkg-cache.h b/backends/apt.deprecated/pk-sqlite-pkg-cache.h
+new file mode 100644
+index 0000000..68fad42
+--- /dev/null
++++ b/backends/apt.deprecated/pk-sqlite-pkg-cache.h
+@@ -0,0 +1,42 @@
++#ifndef SQLITE_PKT_CACHE
++#define SQLITE_PKT_CACHE
++
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++typedef enum {
++ SEARCH_NAME = 1,
++ SEARCH_DETAILS,
++ SEARCH_FILE
++} SearchDepth;
++
++#include <pk-backend.h>
++#include <sqlite3.h>
++
++void sqlite_init_cache(PkBackend *backend, const char* dbname, const char* compare_fname, void (*build_db)(PkBackend *, sqlite3 *db));
++void sqlite_finish_cache(PkBackend *backend);
++
++void sqlite_search_details (PkBackend *backend, const gchar *filter, const gchar *search);
++void sqlite_search_name (PkBackend *backend, const gchar *filter, const gchar *search);
++void backend_search_common(PkBackend * backend, const gchar * filter, const gchar * search, SearchDepth which, PkBackendThreadFunc func);
++void sqlite_get_details (PkBackend *backend, const gchar *package_id);
++
++#endif
+diff --git a/backends/apt/HACKING b/backends/apt/HACKING
+new file mode 100644
+index 0000000..2b99c5d
+--- /dev/null
++++ b/backends/apt/HACKING
+@@ -0,0 +1,5 @@
++The backend can be tested by running it as root from the source code
++repository. Make sure to kill packagekitd before to force a reintializing
++of the cache:
++
++ killall packagekitd; python aptDBUSBackend.py
+diff --git a/backends/apt/Makefile.am b/backends/apt/Makefile.am
+index 07b4131..e315ba9 100644
+--- a/backends/apt/Makefile.am
++++ b/backends/apt/Makefile.am
+@@ -1,30 +1,25 @@
+-NULL =
++NULL =
+
+-SUBDIRS = helpers
+ plugindir = $(PK_PLUGIN_DIR)
+ plugin_LTLIBRARIES = libpk_backend_apt.la
+-
++libpk_backend_apt_la_SOURCES = pk-backend-apt.c
+ libpk_backend_apt_la_LIBADD = $(PK_PLUGIN_LIBS)
+-libpk_backend_apt_la_LDFLAGS = -module -avoid-version $(APT_LIBS)
+-libpk_backend_apt_la_CFLAGS = $(PK_PLUGIN_CFLAGS) $(APT_CFLAGS)
+-libpk_backend_apt_la_CXXFLAGS = $(PK_PLUGIN_CFLAGS) $(APT_CFLAGS) -DPK_DB_DIR=\""$(PK_DB_DIR)"\"
++libpk_backend_apt_la_LDFLAGS = -module -avoid-version
++libpk_backend_apt_la_CFLAGS = $(PK_PLUGIN_CFLAGS)
++
++dbusinstancedir = $(LIBEXECDIR)
++dbusinstance_DATA = \
++ aptDBUSBackend.py \
++ $(NULL)
++
++EXTRA_DIST = \
++ $(dbusinstance_DATA) \
++ $(NULL)
+
+-libpk_backend_apt_la_SOURCES = \
+- pk-backend-apt.c \
+- pk-apt-search.h \
+- $(NULL)
++install-data-hook:
++ chmod a+rx $(DESTDIR)$(libexecdir)/*.py
+
+-if APT_SEARCH_PLAIN
+-libpk_backend_apt_la_SOURCES += \
+- pk-apt-search-plain.c \
+- $(NULL)
+-endif
++clean-local :
++ rm -f *~
++ rm -f *.pyc
+
+-if APT_SEARCH_SQLITE
+-libpk_backend_apt_la_SOURCES += \
+- pk-sqlite-pkg-cache.h \
+- pk-sqlite-pkg-cache.cpp \
+- pk-apt-build-db.cpp \
+- pk-apt-search-sqlite.cpp \
+- $(NULL)
+-endif
+diff --git a/backends/apt/README b/backends/apt/README
+new file mode 100644
+index 0000000..0a3da6e
+--- /dev/null
++++ b/backends/apt/README
+@@ -0,0 +1,23 @@
++The name of this backend is apt2.
++
++It supports apt which is mainly used by Debian and its derivates. In contrast to
++the backend called apt this one uses DBus for the communication with the
++packagekit daemon. This allows to perform actions without having to reopen
++the cache for each one.
++
++To provide a tremendously fast search function a Xapian database is used.
++It is provided by Enrico Zini's apt-xapian-index. Debtags will be used to
++enhance the quality of the search results further.
++
++A list of implemented functions are listed in the PackageKit FAQ:
++
++http://www.packagekit.org/pk-faq.html
++
++You can find packages for Ubuntu here:
++
++https://www.launchpad.net/~packagekit/+ppa
++
++Packages for Debian Unstable will be provided soon.
++
++Feel free to send comments or bug reports to the PackageKit mailing list
++or to the author.
+diff --git a/backends/apt/TODO b/backends/apt/TODO
+new file mode 100644
+index 0000000..bee2f3d
+--- /dev/null
++++ b/backends/apt/TODO
+@@ -0,0 +1,70 @@
++ISSUES:
++
++ * Support delayed or hidden debconf questions
++
++Unresolved issues can be discussed at the following wiki page:
++http://wiki.debian.org/PackageKit
++
++
++TODO:
++
++ * Implement all open backend methods. A list of implemented backend methods
++ can be found in PackageKit FAQ or in pk-backend-apt2.c.
++
++ * Blacklist packages requiring input on the terminal and try to change
++ the Debian policy in the long run. Way of automation?
++
++ * Allow to inject alternative apt.package.Package classes into the
++ cache to support PackageKit and distribution specific needs
++ (e.g. when is a package called free or supported)
++
++ * Allow to reinject debtags into the search results to get
++ similar software which not matches on the search terms
++
++ * Index file list and add properties for package name and section to
++ the xapian database to also make use of it in search group and
++ search name (do we want this?)
++
++ * Map Debian/Ubuntu sections to PackageKit groups:
++ - admin : System Administration => admin-tools
++ - base : Base System => system
++ - comm : Communication => communication
++ - devel : Development => programming
++ - doc : Documentation => ???
++ - editors : Editors => accessoires
++ - electronics : Electronics => other
++ - embedded : Embedded Devices => system
++ - games : Games and Amusement => games
++ - gnome : GNOME Desktop Environment => desktop-gnome
++ - graphics : Graphics => graphics
++ - hamradio : Amateur Radio => communication
++ - interpreters : Interpreted Computer L. => programming
++ - kde : KDE Desktop Environment => desktop-kde
++ - libdevel : Libraries - Development => programming
++ - libs : Libraries => system
++ - mail : Email => internet
++ - math : Mathematics => ??? science/education
++ - misc : Miscellaneous - Text Based => other
++ - net : Networkinga => network
++ - news : Newsgroup => internet
++ - oldlibs : Libraries - Old => legacy
++ - otherosfs : Cross Platform => system
++ - perl : Perl Programming Language => programming
++ - python : Python Programming Language => programming
++ - science : Science => ??? science/education
++ - shells : Shells => system
++ - sound : Multimedia => multimedia
++ - tex : TeX Authoring => publishing
++ - text : Word Processing => publishing
++ - utils : Utilities => accessoires
++ - web : World Wide Web => internet
++ - x11 : Miscellaneous - Graphical => desktop-other
++ - unknown : Unknown => unknown
++ - alien : Converted From RPM by Alien" => unknown
++ - translations => localization
++ The following could not be maped: science, documentation, electronics
++ Are there any derivates with additional sections?
++
++ * Fix the dbus policy. Should we require at_console for searching?
++
++DONE:
+diff --git a/backends/apt/aptDBUSBackend.py b/backends/apt/aptDBUSBackend.py
+new file mode 100755
+index 0000000..22eb714
+--- /dev/null
++++ b/backends/apt/aptDBUSBackend.py
+@@ -0,0 +1,679 @@
++#!/usr/bin/env python
++# -*- coding: utf-8 -*-
++"""
++Provides an apt backend to PackageKit
++
++Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
++Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
++Copyright (C) 2008 Sebastian Heinlein <glatzor@ubuntu.com>
++
++Licensed under the GNU General Public License Version 2
++
++This program is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation; either version 2 of the License, or
++(at your option) any later version.
++"""
++
++__author__ = "Sebastian Heinlein <devel@glatzor.de>"
++__state__ = "experimental"
++
++import os
++import pty
++import re
++import signal
++import time
++import threading
++import warnings
++
++import apt
++import apt_pkg
++import dbus
++import dbus.glib
++import dbus.service
++import dbus.mainloop.glib
++import gobject
++
++from packagekit.daemonBackend import PACKAGEKIT_DBUS_INTERFACE, PACKAGEKIT_DBUS_PATH, PackageKitBaseBackend, PackagekitProgress, pklog, threaded, async
++from packagekit.enums import *
++
++warnings.filterwarnings(action='ignore', category=FutureWarning)
++
++PACKAGEKIT_DBUS_SERVICE = 'org.freedesktop.PackageKitAptBackend'
++
++XAPIANDBPATH = os.environ.get("AXI_DB_PATH", "/var/lib/apt-xapian-index")
++XAPIANDB = XAPIANDBPATH + "/index"
++XAPIANDBVALUES = XAPIANDBPATH + "/values"
++
++# Required for daemon mode
++os.putenv("PATH",
++ "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
++# Avoid questions from the maintainer scripts as far as possible
++os.putenv("DEBIAN_FRONTEND", "noninteractive")
++os.putenv("APT_LISTCHANGES_FRONTEND", "none")
++
++# Setup threading support
++gobject.threads_init()
++dbus.glib.threads_init()
++
++class PackageKitOpProgress(apt.progress.OpProgress):
++ '''
++ Handle the cache opening process
++ '''
++ def __init__(self, backend, prange=(0,100), progress=True):
++ self._backend = backend
++ apt.progress.OpProgress.__init__(self)
++ self.steps = []
++ for v in [0.12, 0.25, 0.50, 0.75, 1.00]:
++ s = prange[0] + (prange[1] - prange[0]) * v
++ self.steps.append(s)
++ self.pstart = float(prange[0])
++ self.pend = self.steps.pop(0)
++ self.pprev = None
++ self.show_progress = progress
++
++ # OpProgress callbacks
++ def update(self, percent):
++ progress = int(self.pstart + percent / 100 * (self.pend - self.pstart))
++ if self.show_progress == True and self.pprev < progress:
++ self._backend.PercentageChanged(progress)
++ self.pprev = progress
++
++ def done(self):
++ self.pstart = self.pend
++ try:
++ self.pend = self.steps.pop(0)
++ except:
++ pklog.warning("An additional step to open the cache is required")
++
++class PackageKitFetchProgress(apt.progress.FetchProgress):
++ '''
++ Handle the package download process
++ '''
++ def __init__(self, backend, prange=(0,100)):
++ self._backend = backend
++ apt.progress.FetchProgress.__init__(self)
++ self.pstart = prange[0]
++ self.pend = prange[1]
++ self.pprev = None
++
++ # FetchProgress callbacks
++ def pulse(self):
++ if self._backend._canceled.isSet():
++ return False
++ percent = ((self.currentBytes + self.currentItems)*100.0)/float(self.totalBytes+self.totalItems)
++ progress = int(self.pstart + percent/100 * (self.pend - self.pstart))
++ if self.pprev < progress:
++ self._backend.PercentageChanged(progress)
++ self.pprev = progress
++ apt.progress.FetchProgress.pulse(self)
++ return True
++
++ def start(self):
++ self._backend.StatusChanged(STATUS_DOWNLOAD)
++ self._backend.AllowCancel(True)
++
++ def stop(self):
++ self._backend.PercentageChanged(self.pend)
++ self._backend.AllowCancel(False)
++
++ def mediaChange(self, medium, drive):
++ #FIXME: use the Message method to notify the user
++ self._backend.error(ERROR_UNKNOWN,
++ "Medium change needed")
++
++class PackageKitInstallProgress(apt.progress.InstallProgress):
++ '''
++ Handle the installation and removal process. Bits taken from
++ DistUpgradeViewNonInteractive.
++ '''
++ def __init__(self, backend, prange=(0,100)):
++ apt.progress.InstallProgress.__init__(self)
++ self._backend = backend
++ self.timeout = 900
++ self.pstart = prange[0]
++ self.pend = prange[1]
++ self.pprev = None
++
++ def statusChange(self, pkg, percent, status):
++ progress = self.pstart + percent/100 * (self.pend - self.pstart)
++ if self.pprev < progress:
++ self._backend.PercentageChanged(int(progress))
++ self.pprev = progress
++ pklog.debug("PM status: %s" % status)
++
++ def startUpdate(self):
++ self._backend.StatusChanged(STATUS_INSTALL)
++ self.last_activity = time.time()
++
++ def updateInterface(self):
++ pklog.debug("Updating interface")
++ apt.progress.InstallProgress.updateInterface(self)
++
++ def conffile(self, current, new):
++ pklog.critical("Config file prompt: '%s'" % current)
++
++def sigquit(signum, frame):
++ pklog.error("Was killed")
++ sys.exit(1)
++
++class PackageKitAptBackend(PackageKitBaseBackend):
++ '''
++ PackageKit backend for apt
++ '''
++ def __init__(self, bus_name, dbus_path):
++ pklog.info("Initializing APT backend")
++ signal.signal(signal.SIGQUIT, sigquit)
++ self._cache = None
++ self._canceled = threading.Event()
++ self._canceled.clear()
++ self._lock = threading.Lock()
++ # Check for xapian support
++ self._use_xapian = False
++ try:
++ import xapian
++ except ImportError:
++ pass
++ else:
++ if os.access(XAPIANDB, os.R_OK):
++ self._use_xapian = True
++ PackageKitBaseBackend.__init__(self, bus_name, dbus_path)
++
++ # Methods ( client -> engine -> backend )
++
++ def doInit(self):
++ pklog.info("Initializing cache")
++ self.StatusChanged(STATUS_SETUP)
++ self.AllowCancel(False)
++ self.NoPercentageUpdates()
++ self._open_cache(progress=False)
++
++ def doExit(self):
++ pass
++
++ @threaded
++ def doCancel(self):
++ pklog.info("Canceling current action")
++ self.StatusChanged(STATUS_CANCEL)
++ self._canceled.set()
++ self._canceled.wait()
++
++ @threaded
++ def doSearchName(self, filters, search):
++ '''
++ Implement the apt2-search-name functionality
++ '''
++ pklog.info("Searching for package name: %s" % search)
++ self.StatusChanged(STATUS_QUERY)
++ self.NoPercentageUpdates()
++ self._check_init(progress=False)
++ self.AllowCancel(True)
++
++ for pkg in self._cache:
++ if self._canceled.isSet():
++ self.ErrorCode(ERROR_TRANSACTION_CANCELLED,
++ "The search was canceled")
++ self.Finished(EXIT_KILL)
++ self._canceled.clear()
++ return
++ elif search in pkg.name and self._is_package_visible(pkg, filters):
++ self._emit_package(pkg)
++ self.Finished(EXIT_SUCCESS)
++
++ @threaded
++ def doSearchDetails(self, filters, search):
++ '''
++ Implement the apt2-search-details functionality
++ '''
++ pklog.info("Searching for package name: %s" % search)
++ self.StatusChanged(STATUS_QUERY)
++ self.NoPercentageUpdates()
++ self._check_init(progress=False)
++ self.AllowCancel(True)
++ results = []
++
++ if self._use_xapian == True:
++ search_flags = (xapian.QueryParser.FLAG_BOOLEAN |
++ xapian.QueryParser.FLAG_PHRASE |
++ xapian.QueryParser.FLAG_LOVEHATE |
++ xapian.QueryParser.FLAG_BOOLEAN_ANY_CASE)
++ pklog.debug("Performing xapian db based search")
++ db = xapian.Database(XAPIANDB)
++ parser = xapian.QueryParser()
++ query = parser.parse_query(unicode(search),
++ search_flags)
++ enquire = xapian.Enquire(db)
++ enquire.set_query(query)
++ matches = enquire.get_mset(0, 1000)
++ for r in map(lambda m: m[xapian.MSET_DOCUMENT].get_data(),
++ enquire.get_mset(0,1000)):
++ if self._cache.has_key(r):
++ results.append(self._cache[r])
++ else:
++ pklog.debug("Performing apt cache based search")
++ for p in self._cache._dict.values():
++ if self._check_canceled("Search was canceled"): return
++ needle = search.strip().lower()
++ haystack = p.description.lower()
++ if p.name.find(needle) >= 0 or haystack.find(needle) >= 0:
++ results.append(p)
++
++ for r in results:
++ if self._check_canceled("Search was canceled"): return
++ if self._is_package_visible(r, filters) == True:
++ self._emit_package(r)
++
++ self.Finished(EXIT_SUCCESS)
++
++ @threaded
++ @async
++ def doGetUpdates(self, filters):
++ '''
++ Implement the {backend}-get-update functionality
++ '''
++ #FIXME: Implment the basename filter
++ pklog.info("Get updates")
++ self.StatusChanged(STATUS_INFO)
++ self.AllowCancel(True)
++ self.NoPercentageUpdates()
++ self._check_init(progress=False)
++ self._cache.upgrade(False)
++ for pkg in self._cache.getChanges():
++ if self._canceled.isSet():
++ self.ErrorCode(ERROR_TRANSACTION_CANCELLED,
++ "Calculating updates was canceled")
++ self.Finished(EXIT_KILL)
++ self._canceled.clear()
++ return
++ else:
++ self._emit_package(pkg)
++ self._open_cache(progress=False)
++ self.Finished(EXIT_SUCCESS)
++
++ @threaded
++ def GetDetails(self, pkg_id):
++ '''
++ Implement the {backend}-get-details functionality
++ '''
++ pklog.info("Get details of %s" % pkg_id)
++ self.StatusChanged(STATUS_INFO)
++ self.NoPercentageUpdates()
++ self.AllowCancel(False)
++ self._check_init(progress=False)
++ name, version, arch, data = self.get_package_from_id(pkg_id)
++ if not self._cache.has_key(name):
++ self.ErrorCode(ERROR_PACKAGE_NOT_FOUND,
++ "Package %s isn't available" % name)
++ self.Finished(EXIT_FAILED)
++ return
++ pkg = self._cache[name]
++ #FIXME: should perhaps go to python-apt since we need this in
++ # several applications
++ desc = pkg.description
++ # Skip the first line - it's a duplicate of the summary
++ i = desc.find('\n')
++ desc = desc[i+1:]
++ # do some regular expression magic on the description
++ # Add a newline before each bullet
++ p = re.compile(r'^(\s|\t)*(\*|0|-)',re.MULTILINE)
++ desc = p.sub(ur'\n\u2022', desc)
++ # replace all newlines by spaces
++ p = re.compile(r'\n', re.MULTILINE)
++ desc = p.sub(" ", desc)
++ # replace all multiple spaces by newlines
++ p = re.compile(r'\s\s+', re.MULTILINE)
++ desc = p.sub('\n', desc)
++ #FIXME: group and licence information missing
++ self.Details(pkg_id, 'unknown', 'unknown', desc,
++ pkg.homepage, pkg.packageSize)
++ self.Finished(EXIT_SUCCESS)
++
++ @threaded
++ @async
++ def doUpdateSystem(self):
++ '''
++ Implement the {backend}-update-system functionality
++ '''
++ pklog.info("Upgrading system")
++ self.StatusChanged(STATUS_UPDATE)
++ self.AllowCancel(False)
++ self.PercentageChanged(0)
++ self._check_init(prange=(0,5))
++ try:
++ self._cache.upgrade(distUpgrade=False)
++ self._cache.commit(PackageKitFetchProgress(self, prange=(5,50)),
++ PackageKitInstallProgress(self, prange=(50,95)))
++ except apt.cache.FetchFailedException:
++ self._open_cache()
++ self.ErrorCode(ERROR_PACKAGE_DOWNLOAD_FAILED, "Download failed")
++ self.Finished(EXIT_FAILED)
++ return
++ except apt.cache.FetchCancelledException:
++ self._open_cache(prange=(95,100))
++ self.ErrorCode(ERROR_TRANSACTION_CANCELLED, "Download was canceled")
++ self.Finished(EXIT_KILL)
++ self._canceled.clear()
++ return
++ except:
++ self._open_cache(prange=(95,100))
++ self.ErrorCode(ERROR_UNKNOWN, "System update failed")
++ self.Finished(EXIT_FAILED)
++ return
++ self.PercentageChanged(100)
++ self.Finished(EXIT_SUCCESS)
++
++ @threaded
++ @async
++ def doRemovePackages(self, ids, deps=True, auto=False):
++ '''
++ Implement the {backend}-remove functionality
++ '''
++ pklog.info("Removing package(s): id %s" % ids)
++ self.StatusChanged(STATUS_REMOVE)
++ self.AllowCancel(False)
++ self.PercentageChanged(0)
++ self._check_init(prange=(0,10))
++ pkgs=[]
++ for id in ids:
++ pkg = self._find_package_by_id(id)
++ if pkg == None:
++ self.ErrorCode(ERROR_PACKAGE_NOT_FOUND,
++ "Package %s isn't available" % id)
++ self.Finished(EXIT_FAILED)
++ return
++ if not pkg.isInstalled:
++ self.ErrorCode(ERROR_PACKAGE_NOT_INSTALLED,
++ "Package %s isn't installed" % pkg.name)
++ self.Finished(EXIT_FAILED)
++ return
++ pkgs.append(pkg.name[:])
++ try:
++ pkg.markDelete()
++ except:
++ self._open_cache(prange=(90,99))
++ self.ErrorCode(ERROR_UNKNOWN, "Removal of %s failed" % pkg.name)
++ self.Finished(EXIT_FAILED)
++ return
++ try:
++ self._cache.commit(PackageKitFetchProgress(self, prange=(10,10)),
++ PackageKitInstallProgress(self, prange=(10,90)))
++ except:
++ self._open_cache(prange=(90,99))
++ self.ErrorCode(ERROR_UNKNOWN, "Removal failed")
++ self.Finished(EXIT_FAILED)
++ return
++ self._open_cache(prange=(90,99))
++ for p in pkgs:
++ if self._cache.has_key(p) and self._cache[p].isInstalled:
++ self.ErrorCode(ERROR_UNKNOWN, "%s is still installed" % p)
++ self.Finished(EXIT_FAILED)
++ return
++ self.PercentageChanged(100)
++ self.Finished(EXIT_SUCCESS)
++
++ @threaded
++ @async
++ def doInstallPackages(self, ids):
++ '''
++ Implement the {backend}-install functionality
++ '''
++ pklog.info("Installing package with id %s" % ids)
++ self.StatusChanged(STATUS_INSTALL)
++ self.AllowCancel(False)
++ self.PercentageChanged(0)
++ self._check_init(prange=(0,10))
++ pkgs=[]
++ for id in ids:
++ pkg = self._find_package_by_id(id)
++ if pkg == None:
++ self.ErrorCode(ERROR_PACKAGE_NOT_FOUND,
++ "Package %s isn't available" % id)
++ self.Finished(EXIT_FAILED)
++ return
++ if pkg.isInstalled:
++ self.ErrorCode(ERROR_PACKAGE_ALREADY_INSTALLED,
++ "Package %s is already installed" % pkg.name)
++ self.Finished(EXIT_FAILED)
++ return
++ pkgs.append(pkg.name[:])
++ try:
++ pkg.markInstall()
++ except:
++ self._open_cache(prange=(90,100))
++ self.ErrorCode(ERROR_UNKNOWN, "%s could not be queued for "
++ "installation" % pkg.name)
++ self.Finished(EXIT_FAILED)
++ return
++ try:
++ self._cache.commit(PackageKitFetchProgress(self, prange=(10,50)),
++ PackageKitInstallProgress(self, prange=(50,90)))
++ except:
++ self._open_cache(prange=(90,100))
++ self.ErrorCode(ERROR_UNKNOWN, "Installation failed")
++ self.Finished(EXIT_FAILED)
++ return
++ self._open_cache(prange=(90,100))
++ self.PercentageChanged(100)
++ pklog.debug("Checking success of operation")
++ for p in pkgs:
++ if not self._cache.has_key(p) or not self._cache[p].isInstalled:
++ self.ErrorCode(ERROR_UNKNOWN, "%s was not installed" % p)
++ self.Finished(EXIT_FAILED)
++ return
++ pklog.debug("Sending success signal")
++ self.Finished(EXIT_SUCCESS)
++
++ @threaded
++ @async
++ def doRefreshCache(self, force):
++ '''
++ Implement the {backend}-refresh_cache functionality
++ '''
++ pklog.info("Refresh cache")
++ self.StatusChanged(STATUS_REFRESH_CACHE)
++ self.last_action_time = time.time()
++ self.AllowCancel(False);
++ self.PercentageChanged(0)
++ self._check_init((0,10))
++ try:
++ self._cache.update(PackageKitFetchProgress(self, prange=(10,95)))
++ except apt.cache.FetchFailedException:
++ self.ErrorCode(ERROR_NO_NETWORK, "Download failed")
++ self.Finished(EXIT_FAILED)
++ return
++ except apt.cache.FetchCancelledException:
++ self._canceled.clear()
++ self.ErrorCode(ERROR_TRANSACTION_CANCELLED, "Download was canceled")
++ self.Finished(EXIT_KILL)
++ return
++ except:
++ self._open_cache(prange=(95,100))
++ self.ErrorCode(ERROR_UNKNOWN, "Refreshing cache failed")
++ self.Finished(EXIT_FAILED)
++ return
++ self.PercentageChanged(100)
++ self.Finished(EXIT_SUCCESS)
++
++ @threaded
++ def doGetPackages(self, filters):
++ '''
++ Implement the apt2-get-packages functionality
++ '''
++ pklog.info("Get all packages")
++ self.StatusChanged(STATUS_QUERY)
++ self.NoPercentageUpdates()
++ self._check_init(progress=False)
++ self.AllowCancel(True)
++
++ for pkg in self._cache:
++ if self._canceled.isSet():
++ self.ErrorCode(ERROR_TRANSACTION_CANCELLED,
++ "The search was canceled")
++ self.Finished(EXIT_KILL)
++ self._canceled.clear()
++ return
++ elif self._is_package_visible(pkg, filters):
++ self._emit_package(pkg)
++ self.Finished(EXIT_SUCCESS)
++
++ @threaded
++ def doResolve(self, filters, name):
++ '''
++ Implement the apt2-resolve functionality
++ '''
++ pklog.info("Resolve")
++ self.StatusChanged(STATUS_QUERY)
++ self.NoPercentageUpdates()
++ self._check_init(progress=False)
++ self.AllowCancel(False)
++
++ #FIXME: Support candidates
++ if self._cache.has_key(name) and self.is_package_visible(pkg, filters):
++ self._emit_package(name)
++ self.Finished(EXIT_SUCCESS)
++ else:
++ self.ErrorCode(ERROR_PACKAGE_NOT_FOUND,
++ "Package name %s could not be resolved" % name)
++ self.Finished(EXIT_FAILED)
++
++ # Helpers
++
++ def _open_cache(self, prange=(0,100), progress=True):
++ '''
++ (Re)Open the APT cache
++ '''
++ pklog.debug("Open APT cache")
++ self.StatusChanged(STATUS_REFRESH_CACHE)
++ try:
++ self._cache = apt.Cache(PackageKitOpProgress(self, prange,
++ progress))
++ except:
++ self.ErrorCode(ERROR_NO_CACHE, "Package cache could not be opened")
++ self.Finished(EXIT_FAILED)
++ self.Exit()
++ return
++ if self._cache._depcache.BrokenCount > 0:
++ self.ErrorCode(ERROR_DEP_RESOLUTION_FAILED,
++ "Not all dependecies can be satisfied")
++ self.Finished(EXIT_FAILED)
++ self.Exit()
++ return
++
++ def _lock_cache(self):
++ '''
++ Lock the cache
++ '''
++ pklog.debug("Locking cache")
++ self._locked.acquire()
++
++ def _unlock_cache(self):
++ '''
++ Unlock the cache
++ '''
++ pklog.debug("Releasing cache")
++ self._locked.release()
++
++ def _check_init(self, prange=(0,10), progress=True):
++ '''
++ Check if the backend was initialized well and try to recover from
++ a broken setup
++ '''
++ pklog.debug("Check apt cache and xapian database")
++ if not isinstance(self._cache, apt.cache.Cache) or \
++ self._cache._depcache.BrokenCount > 0:
++ self._open_cache(prange, progress)
++
++ def _check_canceled(self, msg):
++ '''
++ Check if the current transaction was canceled. If so send the
++ corresponding error message and return True
++ '''
++ if self._canceled.isSet():
++ self.ErrorCode(ERROR_TRANSACTION_CANCELLED, msg)
++ self.Finished(EXIT_KILL)
++ self._canceled.clear()
++ return True
++ return False
++
++ def get_id_from_package(self, pkg, installed=False):
++ '''
++ Return the id of the installation candidate of a core
++ apt package. If installed is set to True the id of the currently
++ installed package will be returned.
++ '''
++ origin = ''
++ if installed == False and pkg.isInstalled:
++ pkgver = pkg.installedVersion
++ else:
++ pkgver = pkg.candidateVersion
++ if pkg.candidateOrigin:
++ origin = pkg.candidateOrigin[0].label
++ id = self._get_package_id(pkg.name, pkgver, pkg.architecture, origin)
++ return id
++
++ def _emit_package(self, pkg):
++ '''
++ Send the Package signal for a given apt package
++ '''
++ id = self.get_id_from_package(pkg)
++ if pkg.isInstalled:
++ status = INFO_INSTALLED
++ else:
++ status = INFO_AVAILABLE
++ summary = pkg.summary
++ self.Package(status, id, summary)
++
++ def _is_package_visible(self, pkg, filters):
++ '''
++ Return True if the package should be shown in the user interface
++ '''
++ #FIXME: Needs to be optmized
++ if filters == 'none':
++ return True
++ if FILTER_INSTALLED in filters and not pkg.isInstalled:
++ return False
++ if FILTER_NOT_INSTALLED in filters and pkg.isInstalled:
++ return False
++ if FILTER_GUI in filters and not self._package_has_gui(pkg):
++ return False
++ if FILTER_NOT_GUI in filters and self._package_has_gui(pkg):
++ return False
++ if FILTER_DEVELOPMENT in filters and not self._package_is_devel(pkg):
++ return False
++ if FILTER_NOT_DEVELOPMENT in filters and self._package_is_devel(pkg):
++ return False
++ return True
++
++ def _package_has_gui(self, pkg):
++ #FIXME: should go to a modified Package class
++ #FIXME: take application data into account. perhaps checking for
++ # property in the xapian database
++ return pkg.section.split('/')[-1].lower() in ['x11', 'gnome', 'kde']
++
++ def _package_is_devel(self, pkg):
++ #FIXME: should go to a modified Package class
++ return pkg.name.endswith("-dev") or pkg.name.endswith("-dbg") or \
++ pkg.section.split('/')[-1].lower() in ['devel', 'libdevel']
++
++ def _find_package_by_id(self, id):
++ '''
++ Return a package matching to the given package id
++ '''
++ # FIXME: Perform more checks
++ name, version, arch, data = self.get_package_from_id(id)
++ if self._cache.has_key(name):
++ return self._cache[name]
++ else:
++ return None
++
++
++def main():
++ loop = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
++ bus = dbus.SystemBus(mainloop=loop)
++ bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, bus=bus)
++ manager = PackageKitAptBackend(bus_name, PACKAGEKIT_DBUS_PATH)
++
++if __name__ == '__main__':
++ main()
++
++# vim: ts=4 et sts=4
+diff --git a/backends/apt/helpers/.gitignore b/backends/apt/helpers/.gitignore
+deleted file mode 100644
+index 0d20b64..0000000
+--- a/backends/apt/helpers/.gitignore
++++ /dev/null
+@@ -1 +0,0 @@
+-*.pyc
+diff --git a/backends/apt/helpers/Makefile.am b/backends/apt/helpers/Makefile.am
+deleted file mode 100644
+index 0299df2..0000000
+--- a/backends/apt/helpers/Makefile.am
++++ /dev/null
+@@ -1,29 +0,0 @@
+-
+-helperdir = $(datadir)/PackageKit/helpers/apt
+-
+-NULL =
+-
+-dist_helper_DATA = \
+- install-files.py \
+- search-name.py \
+- search-details.py \
+- search-group.py \
+- search-file.py \
+- get-depends.py \
+- get-details.py \
+- get-repo-list.py \
+- get-requires.py \
+- get-update-detail.py \
+- get-updates.py \
+- refresh-cache.py \
+- repo-enable.py \
+- resolve.py \
+- aptBackend.py \
+- $(NULL)
+-
+-install-data-hook:
+- chmod a+rx $(DESTDIR)$(helperdir)/*.py
+-
+-clean-local :
+- rm -f *~
+-
+diff --git a/backends/apt/helpers/aptBackend.py b/backends/apt/helpers/aptBackend.py
+deleted file mode 100644
+index e5f78ca..0000000
+--- a/backends/apt/helpers/aptBackend.py
++++ /dev/null
+@@ -1,536 +0,0 @@
+-#
+-# vim: ts=4 et sts=4
+-#
+-# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
+-# Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-import os
+-import re
+-
+-from packagekit.backend import *
+-import apt_pkg,apt_inst
+-
+-import warnings
+-warnings.filterwarnings(action='ignore', category=FutureWarning)
+-import apt
+-from aptsources.distro import get_distro
+-from aptsources.sourceslist import SourcesList
+-from sets import Set
+-from os.path import join,exists
+-from urlparse import urlparse
+-from apt.debfile import DebPackage
+-from os import system
+-
+-class Package(apt.Package):
+- def __str__(self):
+- return "Package %s, version %s"%(self.name,self._version)
+-
+- def _cmp_deps(self,deps, version):
+- for (v,c) in deps:
+- if not apt_pkg.CheckDep(version,c,v):
+- return False
+- return True
+-
+- def __init__(self, backend, pkg, data="",version=[]):
+- apt.package.Package.__init__(self, pkg._cache, pkg._depcache,
+- pkg._records, pkg._list, pkg._pcache,
+- pkg._pkg)
+- self._version = version
+- self._data = data
+- self._backend = backend
+- wanted_ver = None
+- if self.installedVersion!=None and self._cmp_deps(version,self.installedVersion):
+- wanted_ver = self.installedVersion
+- elif self.installedVersion == None and version == []:
+- #self.markInstall(False,False)
+- wanted_ver = self.candidateVersion
+-
+- for ver in pkg._pkg.VersionList:
+- #print "vers",dir(ver),version,ver
+- #print data
+- if (wanted_ver == None or wanted_ver == ver.VerStr) and self._cmp_deps(version,ver.VerStr):
+- f, index = ver.FileList.pop(0)
+- if self._data == "":
+- if f.Origin=="" and f.Archive=="now":
+- self._data = "local_install"
+- elif f.Origin!="" or f.Archive!="":
+- self._data = "%s/%s"%(f.Origin.replace("/","_"),f.Archive.replace("/","_"))
+- else:
+- self._data = "%s/unknown"%f.Site
+- self._version = ver.VerStr
+- break
+- else:
+- print "wanted",wanted_ver
+- for ver in pkg._pkg.VersionList:
+- print "vers",version,ver.VerStr
+- backend.error(ERROR_PACKAGE_NOT_FOUND, "Can't find version %s for %s"%(version,self.name))
+-
+- def setVersion(self,version,compare="="):
+- if version!=None and (self.installedVersion == None or not apt_pkg.CheckDep(version,compare,self.installedVersion)):
+- self.markInstall(False,False)
+- if self.candidateVersion != version:
+- if self._data == "":
+- for ver in pkg._pkg.VersionList:
+- f, index = ver.FileList.pop(0)
+- self._data = "%s/%s"%(f.Origin,f.Archive)
+- if ver.VerStr == version:
+- break
+-
+- # FIXME: this is a nasty hack, assuming that the best way to resolve
+- # deps for non-default repos is by switching the default release.
+- # We really need a better resolver (but that's hard)
+- assert self._data!=""
+- origin = self._data[self._data.find("/")+1:]
+- print "origin",origin
+- name = self.name
+- apt_pkg.Config.Set("APT::Default-Release",origin)
+- if not self._backend._caches.has_key(origin):
+- self._backend._caches[origin] = apt.Cache(PackageKitProgress(self))
+- print "new cache for %s"%origin
+- self.__setParent(self._backend._caches[origin][name])
+- self.markInstall(False,False)
+- if not apt_pkg.CheckDep(self.candidateVersion,compare,version):
+- self._backend.error(ERROR_PACKAGE_NOT_FOUND,
+- "Unable to locate package version %s (only got %s) for %s"%(version,self.candidateVersion,name))
+- return
+- self.markKeep()
+-
+- @property
+- def group(self):
+- section = self.section.split('/')[-1].lower()
+- #if section in ():
+- # return GROUP_ACCESSIBILITY
+- if section in ('utils',):
+- return "accessories"
+- #if section in ():
+- # return GROUP_EDUCATION
+- if section in ('games',):
+- return "games"
+- if section in ('graphics',):
+- return "graphics"
+- if section in ('net', 'news', 'web', 'comm'):
+- return "internet"
+- if section in ('editors', 'tex'):
+- return "office"
+- if section in ('misc',):
+- return "other"
+- if section in ('devel', 'libdevel', 'interpreters', 'perl', 'python'):
+- return "programming"
+- if section in ('sound',):
+- return "multimedia"
+- if section in ('base', 'admin'):
+- return "system"
+- return "unknown"
+-
+- @property
+- def isInstalled(self):
+- return super(self.__class__,self).isInstalled and self.installedVersion == self._version
+-
+- @property
+- def isDevelopment(self):
+- name = self.name.lower()
+- section = self.section.split('/')[-1].lower()
+- return name.endswith('-dev') or name.endswith('-dbg') or \
+- section in ('devel', 'libdevel')
+-
+- @property
+- def isGui(self):
+- section = self.section.split('/')[-1].lower()
+- return section in ('x11', 'gnome', 'kde')
+-
+- _HYPHEN_PATTERN = re.compile(r'(\s|_)+')
+-
+- def matchName(self, name):
+- needle = name.strip().lower()
+- haystack = self.name.lower()
+- needle = Package._HYPHEN_PATTERN.sub('-', needle)
+- haystack = Package._HYPHEN_PATTERN.sub('-', haystack)
+- if haystack.find(needle) >= 0:
+- return True
+- return False
+-
+- def matchDetails(self, details):
+- if self.matchName(details):
+- return True
+- needle = details.strip().lower()
+- haystack = self.description.lower()
+- if haystack.find(needle) >= 0:
+- return True
+- return False
+-
+- def matchGroup(self, name):
+- needle = name.strip().lower()
+- haystack = self.group
+- if haystack.startswith(needle):
+- return True
+- return False
+-
+-class PackageKitProgress(apt.progress.OpProgress, apt.progress.FetchProgress):
+- def __init__(self, backend):
+- self._backend = backend
+- apt.progress.OpProgress.__init__(self)
+- apt.progress.FetchProgress.__init__(self)
+-
+- # OpProgress callbacks
+- def update(self, percent):
+- pass
+-
+- def done(self):
+- pass
+-
+- # FetchProgress callbacks
+- def pulse(self):
+- apt.progress.FetchProgress.pulse(self)
+- self._backend.percentage(self.percent)
+- return True
+-
+- def stop(self):
+- self._backend.percentage(100)
+-
+- def mediaChange(self, medium, drive):
+- # This probably should not be an error, but a Message.
+- self._backend.error(ERROR_UNKNOWN,
+- "Medium change needed")
+-
+-class PackageKitAptBackend(PackageKitBaseBackend):
+- def __init__(self, args):
+- PackageKitBaseBackend.__init__(self, args)
+- self.status(STATUS_SETUP)
+- self._caches = {}
+- self._apt_cache = apt.Cache(PackageKitProgress(self))
+- default = apt_pkg.Config.Find("APT::Default-Release")
+- if default=="":
+- d = get_distro()
+- if d.id == "Debian":
+- default = "stable"
+- elif d.id == "Ubuntu":
+- default = "main"
+- else:
+- raise Exception,d.id
+-
+- self._caches[default] = self._apt_cache
+-
+-
+- def search_name(self, filters, key):
+- '''
+- Implement the {backend}-search-name functionality
+- '''
+- self.status(STATUS_INFO)
+- self.allow_cancel(True)
+- for package in self._do_search(filters,
+- lambda pkg: pkg.matchName(key)):
+- self._emit_package(package)
+-
+- def search_details(self, filters, key):
+- '''
+- Implement the {backend}-search-details functionality
+- '''
+- self.status(STATUS_INFO)
+- self.allow_cancel(True)
+- for package in self._do_search(filters,
+- lambda pkg: pkg.matchDetails(key)):
+- self._emit_package(package)
+-
+- def search_group(self, filters, key):
+- '''
+- Implement the {backend}-search-group functionality
+- '''
+- self.status(STATUS_INFO)
+- self.allow_cancel(True)
+- for package in self._do_search(filters,
+- lambda pkg: pkg.matchGroup(key)):
+- self._emit_package(package)
+-
+- def search_file(self, filters, key):
+- '''
+- Implement the {backend}-search-file functionality
+- '''
+- self.allow_cancel(True)
+- self.percentage(None)
+-
+- self.error(ERROR_NOT_SUPPORTED,
+- "This function is not implemented in this backend")
+-
+- def refresh_cache(self):
+- '''
+- Implement the {backend}-refresh_cache functionality
+- '''
+- self.status(STATUS_REFRESH_CACHE)
+- try:
+- res = self._apt_cache.update(PackageKitProgress(self))
+- except Exception, error_message:
+- self.error(ERROR_UNKNOWN,
+- "Failed to fetch the following items:\n%s" % error_message)
+- return res
+-
+- def get_details(self, package):
+- '''
+- Implement the {backend}-get-details functionality
+- '''
+- self.status(STATUS_INFO)
+- name, version, arch, data = self.get_package_from_id(package)
+- pkg = Package(self, self._apt_cache[name])
+- description = re.sub('\s+', ' ', pkg.description).strip()
+- self.description(package, 'unknown', pkg.group, description,
+- pkg.architecture, pkg.packageSize)
+-
+- def resolve(self, name):
+- '''
+- Implement the {backend}-resolve functionality
+- '''
+- self.status(STATUS_INFO)
+- try:
+- pkg = Package(self,self._apt_cache[name])
+- self._emit_package(pkg)
+- except KeyError:
+- self.error(ERROR_PACKAGE_NOT_FOUND,"Can't find a package called '%s'"%name)
+-
+- def _do_deps(self,inp,deps,recursive):
+- inp.markInstall()
+- newkeys = []
+- for x in inp.candidateDependencies:
+- n = x.or_dependencies[0].name
+- if not deps.has_key(n):
+- deps[n] = []
+- newkeys.append(n)
+- deps[n].append((x.or_dependencies[0].version,x.or_dependencies[0].relation))
+- if recursive:
+- for n in newkeys:
+- try:
+- deps = self._do_deps(Package(self,self._apt_cache[n],version=deps[n]),deps,recursive)
+- except KeyError: # FIXME: we're assuming this is a virtual package, which we can't cope with yet
+- del deps[n]
+- continue
+- return deps
+-
+- def get_depends(self,filters,package, recursive):
+- '''
+- Implement the {backend}-get-depends functionality
+- '''
+- self.allow_cancel(True)
+- self.status(STATUS_INFO)
+- recursive = (recursive == "True")
+- name, version, arch, data = self.get_package_from_id(package)
+- pkg = Package(self,self._apt_cache[name],version=[(version,"=")],data=data)
+- pkg.setVersion(version)
+- deps = self._do_deps(pkg, {}, recursive)
+- for n in deps.keys():
+- self._emit_package(Package(self,self._apt_cache[n],version=deps[n]))
+-
+- def _do_reqs(self,inp,pkgs,recursive):
+- extra = []
+- fails = []
+- for r in inp._pkg.RevDependsList:
+- ch = apt_pkg.CheckDep(inp._version,r.CompType,r.TargetVer)
+- v = (r.ParentPkg.Name,r.ParentVer.VerStr)
+- if not ch or v in fails:
+- #print "skip",r.TargetVer,r.CompType,r.ParentPkg.Name,r.ParentVer.VerStr
+- fails.append(v)
+- continue
+- p = Package(self,self._apt_cache[r.ParentPkg.Name],r.ParentVer.VerStr)
+- if v not in pkgs:
+- extra.append(p)
+- #print "new pkg",p
+- self._emit_package(p)
+- pkgs.add(v)
+- if recursive:
+- for e in extra:
+- pkgs = self._do_reqs(p, pkgs,recursive)
+- return pkgs
+-
+- def get_requires(self,package,recursive):
+- '''
+- Implement the {backend}-get-requires functionality
+- '''
+- self.allow_cancel(True)
+- self.status(STATUS_INFO)
+- recursive = (recursive == "True")
+- name, version, arch, data = self.get_package_from_id(package)
+- pkg = Package(self,self._apt_cache[name], version=[(version,"=")], data=data)
+-
+- pkgs = Set()
+- self._do_reqs(pkg,pkgs, recursive)
+-
+- def _build_repo_list(self):
+- repo = {}
+-
+- sources = SourcesList()
+- repo["__sources"] = sources
+-
+- root = apt_pkg.Config.FindDir("Dir::State::Lists")
+- #print root
+- for entry in sources:
+- if entry.type!="":
+- url = entry.uri
+- #if entry.template!=None:
+- url +="/dists/"
+- url += entry.dist
+- url = url.replace("//dists","/dists")
+- #print url
+- path = join(root,"%s_Release"%(apt_pkg.URItoFileName(url)))
+- if not exists(path):
+- #print path
+- name = "%s/unknown"%urlparse(entry.uri)[1]
+- else:
+- lines = file(path).readlines()
+- origin = ""
+- suite = ""
+- for l in lines:
+- if l.find("Origin: ")==0:
+- origin = l.split(" ",1)[1].strip()
+- elif l.find("Suite: ")==0:
+- suite = l.split(" ",1)[1].strip()
+- assert origin!="" and suite!=""
+- name = "%s/%s"%(origin,suite)
+- if entry.type == "deb-src":
+- name += "-src"
+-
+- repo[name] = {"entry":entry}
+- return repo
+-
+- def get_repo_list(self, filters):
+- '''
+- Implement the {backend}-get-repo-list functionality
+- '''
+- self.allow_interrupt(True)
+- self.status(STATUS_INFO)
+- repo = self._build_repo_list()
+- for e in repo.keys():
+- if e == "__sources":
+- continue
+- self.repo_detail(repo[e]["entry"].line.strip(),e,not repo[e]["entry"].disabled)
+-
+- def repo_enable(self, repoid, enable):
+- '''
+- Implement the {backend}-repo-enable functionality
+- '''
+- enable = (enable == "True")
+- repo = self._build_repo_list()
+- if not repo.has_key(repoid):
+- self.error(ERROR_REPO_NOT_FOUND,"Couldn't find repo '%s'"%repoid)
+- return
+- r = repo[repoid]
+- if not r["entry"].disabled == enable: # already there
+- return
+- r["entry"].set_enabled(enable)
+- try:
+- repo["__sources"].save()
+- except IOError,e:
+- self.error(ERROR_UNKNOWN, "Problem while trying to save repo settings to %s: %s"%(e.filename,e.strerror))
+-
+- def get_updates(self, filter):
+- self._apt_cache.upgrade(False)
+- for pkg in self._apt_cache.getChanges():
+- self._emit_package(Package(self, pkg))
+-
+- def get_update_detail(self, package):
+- self.allow_cancel(True)
+- self.percentage(None)
+- self.status(STATUS_INFO)
+- name, version, arch, data = self.get_package_from_id(package)
+- update = ""
+- obsolete = ""
+- cve_url = ""
+- bz_url = ""
+- vendor_url = ""
+- reboot = "none"
+- desc = self._apt_cache[name].description
+- self.update_detail(package,update,obsolete,vendor_url,bz_url,cve_url,reboot,desc)
+-
+-
+- def install_files (self, inst_files):
+- '''
+- Implement the {backend}-install_files functionality
+- Install the package containing the inst_file file
+- '''
+- if not exists(inst_file):
+- self.error(ERROR_PACKAGE_NOT_FOUND,"Can't find %s"%inst_file)
+- return
+- deb = DebPackage(inst_file)
+- deps = {}
+- for k in ["Depends","Recommends"]:
+- if not deb._sections.has_key(k):
+- continue
+- for items in apt_pkg.ParseDepends(deb[k]):
+- assert len(items) == 1,"Can't handle or deps properly yet"
+- (pkg,ver,comp) = items[0]
+- if not deps.has_key(pkg):
+- deps[pkg] = []
+- deps[pkg].append((ver,comp))
+- for n in deps.keys():
+- p = Package(self,self._apt_cache[n],version=deps[n])
+- if not p.isInstalled:
+- p.markInstall()
+- assert self._apt_cache.getChanges()==[],"Don't handle install changes yet"
+- # FIXME: nasty hack. Need a better way in
+- ret = system("dpkg -i %s"%inst_file)
+- if ret!=0:
+- self.error(ERROR_UNKNOWN,"Can't install package")
+-
+- ### Helpers ###
+- def _emit_package(self, package):
+- id = self.get_package_id(package.name,
+- package._version,
+- package.architecture,
+- package._data)
+- if package.isInstalled:
+- status = INFO_INSTALLED
+- else:
+- status = INFO_AVAILABLE
+- summary = package.summary
+- self.package(id, status, summary)
+-
+- def _do_search(self, filters, condition):
+- filters = filters.split(';')
+- size = len(self._apt_cache)
+- percentage = 0
+- for i, pkg in enumerate(self._apt_cache):
+- new_percentage = i / float(size) * 100
+- if new_percentage - percentage >= 5:
+- percentage = new_percentage
+- self.percentage(percentage)
+- package = Package(self, pkg)
+- if package.installedVersion is None and \
+- package.candidateVersion is None:
+- continue
+- if not condition(package):
+- continue
+- continue
+- vers = [x.VerStr for x in package._pkg.VersionList]
+- if package.installedVersion!=None:
+- i = package.installedVersion
+- if i in vers and vers[0]!=i:
+- del vers[vers.index(i)]
+- vers.insert(0,i)
+-
+- for ver in vers:
+- p = Package(self, package, version=[[ver,"="]])
+- if self._do_filtering(p, filters):
+- yield p
+- self.percentage(100)
+-
+- def _do_filtering(self, package, filters):
+- if len(filters) == 0 or filters == ['none']:
+- return True
+- if (FILTER_INSTALLED in filters) and (not package.isInstalled):
+- return False
+- if (FILTER_NOT_INSTALLED in filters) and package.isInstalled:
+- return False
+- if (FILTER_GUI in filters) and (not package.isGui):
+- return False
+- if (FILTER_NOT_GUI in filters) and package.isGui:
+- return False
+- if (FILTER_DEVELOPMENT in filters) and (not package.isDevelopment):
+- return False
+- if (FILTER_NOT_DEVELOPMENT in filters) and package.isDevelopment:
+- return False
+- return True
+-
+diff --git a/backends/apt/helpers/get-depends.py b/backends/apt/helpers/get-depends.py
+deleted file mode 100755
+index 94dca4a..0000000
+--- a/backends/apt/helpers/get-depends.py
++++ /dev/null
+@@ -1,20 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2007 Richard Hughes <richard@hughsie.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-
+-from aptBackend import PackageKitAptBackend
+-filters=sys.argv[1]
+-package=sys.argv[2]
+-recursive = sys.argv[3]
+-backend = PackageKitAptBackend(sys.argv[1:])
+-backend.get_depends(filters, package, recursive)
+-sys.exit(0)
+diff --git a/backends/apt/helpers/get-details.py b/backends/apt/helpers/get-details.py
+deleted file mode 100755
+index a813640..0000000
+--- a/backends/apt/helpers/get-details.py
++++ /dev/null
+@@ -1,18 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-from aptBackend import PackageKitAptBackend
+-
+-package = sys.argv[1]
+-backend = PackageKitAptBackend(sys.argv[1:])
+-backend.get_details(package)
+-sys.exit(0)
+diff --git a/backends/apt/helpers/get-repo-list.py b/backends/apt/helpers/get-repo-list.py
+deleted file mode 100755
+index 5529f72..0000000
+--- a/backends/apt/helpers/get-repo-list.py
++++ /dev/null
+@@ -1,20 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2007 Richard Hughes <richard@hughsie.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-
+-from aptBackend import PackageKitAptBackend
+-filters = sys.argv[1]
+-
+-backend = PackageKitAptBackend(sys.argv[2:])
+-backend.get_repo_list(filters)
+-backend.unLock()
+-sys.exit(0)
+diff --git a/backends/apt/helpers/get-requires.py b/backends/apt/helpers/get-requires.py
+deleted file mode 100755
+index e581010..0000000
+--- a/backends/apt/helpers/get-requires.py
++++ /dev/null
+@@ -1,20 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2007 Richard Hughes <richard@hughsie.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-
+-from aptBackend import PackageKitAptBackend
+-package = sys.argv[1]
+-recursive = sys.argv[2]
+-
+-backend = PackageKitAptBackend(sys.argv[1:])
+-backend.get_requires(package, recursive)
+-sys.exit(0)
+diff --git a/backends/apt/helpers/get-update-detail.py b/backends/apt/helpers/get-update-detail.py
+deleted file mode 100755
+index 5524d9a..0000000
+--- a/backends/apt/helpers/get-update-detail.py
++++ /dev/null
+@@ -1,18 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2008 Michael Vogt <mvo@ubuntu.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-
+-from aptBackend import PackageKitAptBackend
+-package=sys.argv[1]
+-backend = PackageKitAptBackend(sys.argv[2:])
+-backend.get_update_detail(package)
+-sys.exit(0)
+diff --git a/backends/apt/helpers/get-updates.py b/backends/apt/helpers/get-updates.py
+deleted file mode 100755
+index 4f45fbf..0000000
+--- a/backends/apt/helpers/get-updates.py
++++ /dev/null
+@@ -1,19 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2008 Michael Vogt <mvo@ubuntu.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-from aptBackend import PackageKitAptBackend
+-
+-filter = sys.argv[1]
+-
+-backend = PackageKitAptBackend(sys.argv[1:])
+-backend.get_updates(filter)
+-sys.exit(0)
+diff --git a/backends/apt/helpers/install-files.py b/backends/apt/helpers/install-files.py
+deleted file mode 100755
+index dfa024c..0000000
+--- a/backends/apt/helpers/install-files.py
++++ /dev/null
+@@ -1,21 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2007 Richard Hughes <richard@hughsie.com>
+-# Copyright (C) 2007 Red Hat Inc, Seth Vidal <skvidal@fedoraproject.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.
+-
+-import sys
+-
+-from aptBackend import PackageKitAptBackend
+-
+-trusted = sys.argv[1]
+-files_to_inst = sys.argv[2:]
+-backend = PackageKitAptBackend(sys.argv[1:])
+-backend.install_files(trusted, files_to_inst)
+-sys.exit(0)
+diff --git a/backends/apt/helpers/refresh-cache.py b/backends/apt/helpers/refresh-cache.py
+deleted file mode 100755
+index 881479d..0000000
+--- a/backends/apt/helpers/refresh-cache.py
++++ /dev/null
+@@ -1,17 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-from aptBackend import PackageKitAptBackend
+-
+-backend = PackageKitAptBackend(sys.argv[1:])
+-backend.refresh_cache()
+-sys.exit(0)
+diff --git a/backends/apt/helpers/repo-enable.py b/backends/apt/helpers/repo-enable.py
+deleted file mode 100755
+index 3cc36ae..0000000
+--- a/backends/apt/helpers/repo-enable.py
++++ /dev/null
+@@ -1,20 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2007 Richard Hughes <richard@hughsie.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-
+-from aptBackend import PackageKitAptBackend
+-repoid = sys.argv[1]
+-state=sys.argv[2]
+-backend = PackageKitAptBackend(sys.argv[2:])
+-backend.repo_enable(repoid,state)
+-backend.unLock()
+-sys.exit(0)
+diff --git a/backends/apt/helpers/resolve.py b/backends/apt/helpers/resolve.py
+deleted file mode 100755
+index aac34df..0000000
+--- a/backends/apt/helpers/resolve.py
++++ /dev/null
+@@ -1,20 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2007 Richard Hughes <richard@hughsie.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-
+-from aptBackend import PackageKitAptBackend
+-filters = sys.argv[1]
+-name=sys.argv[2]
+-backend = PackageKitAptBackend(sys.argv[2:])
+-backend.resolve(name)
+-backend.unLock()
+-sys.exit(0)
+diff --git a/backends/apt/helpers/search-details.py b/backends/apt/helpers/search-details.py
+deleted file mode 100755
+index d02f1b0..0000000
+--- a/backends/apt/helpers/search-details.py
++++ /dev/null
+@@ -1,21 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-
+-options = sys.argv[1]
+-searchlist = sys.argv[2]
+-
+-from aptBackend import PackageKitAptBackend
+-
+-backend = PackageKitAptBackend(sys.argv[1:])
+-backend.search_details(options,searchlist)
+-sys.exit(0)
+diff --git a/backends/apt/helpers/search-file.py b/backends/apt/helpers/search-file.py
+deleted file mode 100755
+index ec60319..0000000
+--- a/backends/apt/helpers/search-file.py
++++ /dev/null
+@@ -1,21 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-
+-options = sys.argv[1]
+-searchlist = sys.argv[2]
+-
+-from aptBackend import PackageKitAptBackend
+-
+-backend = PackageKitAptBackend(sys.argv[1:])
+-backend.search_file(options,searchlist)
+-sys.exit(0)
+diff --git a/backends/apt/helpers/search-group.py b/backends/apt/helpers/search-group.py
+deleted file mode 100755
+index f63ee80..0000000
+--- a/backends/apt/helpers/search-group.py
++++ /dev/null
+@@ -1,21 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-
+-options = sys.argv[1]
+-searchlist = sys.argv[2]
+-
+-from aptBackend import PackageKitAptBackend
+-
+-backend = PackageKitAptBackend(sys.argv[1:])
+-backend.search_group(options,searchlist)
+-sys.exit(0)
+diff --git a/backends/apt/helpers/search-name.py b/backends/apt/helpers/search-name.py
+deleted file mode 100755
+index 9f73c89..0000000
+--- a/backends/apt/helpers/search-name.py
++++ /dev/null
+@@ -1,21 +0,0 @@
+-#!/usr/bin/python
+-#
+-# Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-import sys
+-
+-options = sys.argv[1]
+-searchlist = sys.argv[2]
+-
+-from aptBackend import PackageKitAptBackend
+-
+-backend = PackageKitAptBackend(sys.argv[1:])
+-backend.search_name(options,searchlist)
+-sys.exit(0)
+diff --git a/backends/apt/packagekit b/backends/apt/packagekit
+new file mode 120000
+index 0000000..0b64032
+--- /dev/null
++++ b/backends/apt/packagekit
+@@ -0,0 +1 @@
++../../python/packagekit/
+\ No newline at end of file
+diff --git a/backends/apt/pk-apt-build-db.cpp b/backends/apt/pk-apt-build-db.cpp
+deleted file mode 100644
+index 885275d..0000000
+--- a/backends/apt/pk-apt-build-db.cpp
++++ /dev/null
+@@ -1,284 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+- */
+-
+-//#include "pk-backend-apt.h"
+-#include <pk-backend.h>
+-#include <apt-pkg/configuration.h>
+-#include <sqlite3.h>
+-
+-typedef enum {FIELD_PKG=1,FIELD_VER,FIELD_DEPS,FIELD_ARCH,FIELD_SHORT,FIELD_LONG,FIELD_REPO} Fields;
+-
+-void apt_build_db(PkBackend * backend, sqlite3 *db)
+-{
+- GMatchInfo *match_info;
+- GError *error = NULL;
+- gchar *contents = NULL;
+- gchar *sdir;
+- const gchar *fname;
+- GRegex *origin, *suite;
+- GDir *dir;
+- GHashTable *releases;
+- int res;
+- sqlite3_stmt *package = NULL;
+-
+- pk_backend_set_status(backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
+-
+- sdir = g_build_filename(_config->Find("Dir").c_str(),_config->Find("Dir::State").c_str(),_config->Find("Dir::State::lists").c_str(), NULL);
+- dir = g_dir_open(sdir,0,&error);
+- if (error!=NULL)
+- {
+- pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "can't open %s",dir);
+- g_error_free(error);
+- goto search_task_cleanup;
+- }
+-
+- origin = g_regex_new("^Origin: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
+- suite = g_regex_new("^Suite: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
+-
+- releases = g_hash_table_new_full(g_str_hash,g_str_equal,g_free,g_free);
+- while ((fname = g_dir_read_name(dir))!=NULL)
+- {
+- gchar *temp, *parsed_name;
+- gchar** items = g_strsplit(fname,"_",-1);
+- guint len = g_strv_length(items);
+- if(len<=3) // minimum is <source>_<type>_<group>
+- {
+- g_strfreev(items);
+- continue;
+- }
+-
+- /* warning: nasty hack with g_strjoinv */
+- temp = items[len-2];
+- items[len-2] = NULL;
+- parsed_name = g_strjoinv("_",items);
+- items[len-2] = temp;
+-
+- if (g_ascii_strcasecmp(items[len-1],"Release")==0 && g_ascii_strcasecmp(items[len-2],"source")!=0)
+- {
+- gchar * repo = NULL, *fullname;
+- fullname = g_build_filename(sdir,fname,NULL);
+- if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
+- {
+- pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
+- goto search_task_cleanup;
+- }
+- g_free(fullname);
+-
+- g_regex_match (origin, contents, (GRegexMatchFlags)0, &match_info);
+- if (!g_match_info_matches(match_info))
+- {
+- pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "origin regex failure in %s",fname);
+- goto search_task_cleanup;
+- }
+- repo = g_match_info_fetch (match_info, 1);
+-
+- g_regex_match (suite, contents, (GRegexMatchFlags)0, &match_info);
+- if (g_match_info_matches(match_info))
+- {
+- temp = g_strconcat(repo,"/",g_match_info_fetch (match_info, 1),NULL);
+- g_free(repo);
+- repo = temp;
+- }
+-
+- temp = parsed_name;
+- parsed_name = g_strconcat(temp,"_",items[len-2],NULL);
+- g_free(temp);
+-
+- pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
+-
+- g_hash_table_insert(releases, parsed_name, repo);
+- g_free(contents);
+- contents = NULL;
+- }
+- else
+- g_free(parsed_name);
+- g_strfreev(items);
+- }
+- g_dir_close(dir);
+-
+- /* and then we need to do this again, but this time we're looking for the packages */
+- dir = g_dir_open(sdir,0,&error);
+- res = sqlite3_prepare_v2(db, "insert or replace into packages values (?,?,?,?,?,?,?)", -1, &package, NULL);
+- if (res!=SQLITE_OK)
+- pk_error("sqlite error during insert prepare: %s", sqlite3_errmsg(db));
+- else
+- pk_debug("insert prepare ok for %p",package);
+- while ((fname = g_dir_read_name(dir))!=NULL)
+- {
+- gchar** items = g_strsplit(fname,"_",-1);
+- guint len = g_strv_length(items);
+- if(len<=3) // minimum is <source>_<type>_<group>
+- {
+- g_strfreev(items);
+- continue;
+- }
+-
+- if (g_ascii_strcasecmp(items[len-1],"Packages")==0)
+- {
+- const gchar *repo;
+- gchar *temp=NULL, *parsed_name=NULL;
+- gchar *fullname= NULL;
+- gchar *begin=NULL, *next=NULL, *description = NULL;
+- glong count = 0;
+- gboolean haspk = FALSE;
+-
+- /* warning: nasty hack with g_strjoinv */
+- if (g_str_has_prefix(items[len-2],"binary-"))
+- {
+- temp = items[len-3];
+- items[len-3] = NULL;
+- parsed_name = g_strjoinv("_",items);
+- items[len-3] = temp;
+- }
+- else
+- {
+- temp = items[len-1];
+- items[len-1] = NULL;
+- parsed_name = g_strjoinv("_",items);
+- items[len-1] = temp;
+- }
+-
+- pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
+-
+- repo = (const gchar *)g_hash_table_lookup(releases,parsed_name);
+- if (repo == NULL)
+- {
+- pk_debug("Can't find repo for %s, marking as \"unknown\"",parsed_name);
+- repo = g_strdup("unknown");
+- //g_assert(0);
+- }
+- else
+- pk_debug("repo for %s is %s",parsed_name,repo);
+- g_free(parsed_name);
+-
+- fullname = g_build_filename(sdir,fname,NULL);
+- pk_debug("loading %s",fullname);
+- if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
+- {
+- pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
+- goto search_task_cleanup;
+- }
+- /*else
+- pk_debug("loaded");*/
+-
+- res = sqlite3_bind_text(package,FIELD_REPO,repo,-1,SQLITE_TRANSIENT);
+- if (res!=SQLITE_OK)
+- pk_error("sqlite error during repo bind: %s", sqlite3_errmsg(db));
+- /*else
+- pk_debug("repo bind ok");*/
+-
+- res = sqlite3_exec(db,"begin",NULL,NULL,NULL);
+- g_assert(res == SQLITE_OK);
+-
+- begin = contents;
+-
+- while (true)
+- {
+- next = strstr(begin,"\n");
+- if (next!=NULL)
+- {
+- next[0] = '\0';
+- next++;
+- }
+-
+- if (begin[0]=='\0')
+- {
+- if (haspk)
+- {
+- if (description!=NULL)
+- {
+- res=sqlite3_bind_text(package,FIELD_LONG,description,-1,SQLITE_TRANSIENT);
+- if (res!=SQLITE_OK)
+- pk_error("sqlite error during description bind: %s", sqlite3_errmsg(db));
+- g_free(description);
+- description = NULL;
+- }
+- res = sqlite3_step(package);
+- if (res!=SQLITE_DONE)
+- pk_error("sqlite error during step: %s", sqlite3_errmsg(db));
+- sqlite3_reset(package);
+- //pk_debug("added package");
+- haspk = FALSE;
+- }
+- //g_assert(0);
+- }
+- else if (begin[0]==' ')
+- {
+- if (description == NULL)
+- description = g_strdup(&begin[1]);
+- else
+- {
+- gchar *oldval = description;
+- description = g_strconcat(oldval, "\n",&begin[1],NULL);
+- g_free(oldval);
+- }
+- }
+- else
+- {
+- gchar *colon = strchr(begin,':');
+- g_assert(colon!=NULL);
+- colon[0] = '\0';
+- colon+=2;
+- /*if (strlen(colon)>3000)
+- pk_error("strlen(colon) = %d\ncolon = %s",strlen(colon),colon);*/
+- //pk_debug("entry = '%s','%s'",begin,colon);
+- if (begin[0] == 'P' && g_strcasecmp("Package",begin)==0)
+- {
+- res=sqlite3_bind_text(package,FIELD_PKG,colon,-1,SQLITE_STATIC);
+- haspk = TRUE;
+- count++;
+- if (count%1000==0)
+- pk_debug("Package %ld (%s)",count,colon);
+- }
+- else if (begin[0] == 'V' && g_strcasecmp("Version",begin)==0)
+- res=sqlite3_bind_text(package,FIELD_VER,colon,-1,SQLITE_STATIC);
+- else if (begin[0] == 'D' && g_strcasecmp("Depends",begin)==0)
+- res=sqlite3_bind_text(package,FIELD_DEPS,colon,-1,SQLITE_STATIC);
+- else if (begin[0] == 'A' && g_strcasecmp("Architecture",begin)==0)
+- res=sqlite3_bind_text(package,FIELD_ARCH,colon,-1,SQLITE_STATIC);
+- else if (begin[0] == 'D' && g_strcasecmp("Description",begin)==0)
+- res=sqlite3_bind_text(package,FIELD_SHORT,colon,-1,SQLITE_STATIC);
+- if (res!=SQLITE_OK)
+- pk_error("sqlite error during %s bind: %s", begin, sqlite3_errmsg(db));
+- }
+- if (next == NULL)
+- break;
+- begin = next;
+- }
+- res = sqlite3_exec(db,"commit",NULL,NULL,NULL);
+- if (res!=SQLITE_OK)
+- pk_error("sqlite error during commit: %s", sqlite3_errmsg(db));
+- res = sqlite3_clear_bindings(package);
+- if (res!=SQLITE_OK)
+- pk_error("sqlite error during clear: %s", sqlite3_errmsg(db));
+- g_free(contents);
+- contents = NULL;
+- }
+- }
+- sqlite3_finalize(package);
+-
+-search_task_cleanup:
+- g_dir_close(dir);
+- g_free(sdir);
+- g_free(contents);
+-}
+-
+diff --git a/backends/apt/pk-apt-build-db.h b/backends/apt/pk-apt-build-db.h
+deleted file mode 100644
+index bb786a9..0000000
+--- a/backends/apt/pk-apt-build-db.h
++++ /dev/null
+@@ -1,30 +0,0 @@
+-#ifndef PK_APT_BUILD_DB
+-#define PK_APT_BUILD_DB
+-
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+- */
+-
+-#include <sqlite3.h>
+-#include <pk-backend.h>
+-
+-void apt_build_db(PkBackend * backend, sqlite3 *db);
+-
+-#endif
+diff --git a/backends/apt/pk-apt-search-plain.c b/backends/apt/pk-apt-search-plain.c
+deleted file mode 100644
+index 5e5b4e5..0000000
+--- a/backends/apt/pk-apt-search-plain.c
++++ /dev/null
+@@ -1,106 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+- */
+-
+-#include <gmodule.h>
+-#include <glib.h>
+-#include <string.h>
+-#include <pk-backend.h>
+-#include <pk-backend-spawn.h>
+-
+-extern PkBackendSpawn *spawn;
+-
+-/**
+- * backend_get_groups:
+- */
+-static PkGroupEnum
+-backend_get_groups (PkBackend *backend)
+-{
+- return (PK_GROUP_ENUM_ACCESSORIES |
+- PK_GROUP_ENUM_GAMES |
+- PK_GROUP_ENUM_GRAPHICS |
+- PK_GROUP_ENUM_INTERNET |
+- PK_GROUP_ENUM_OFFICE |
+- PK_GROUP_ENUM_OTHER |
+- PK_GROUP_ENUM_PROGRAMMING |
+- PK_GROUP_ENUM_MULTIMEDIA |
+- PK_GROUP_ENUM_SYSTEM);
+-}
+-
+-/**
+- * backend_get_filters:
+- */
+-static PkFilterEnum
+-backend_get_filters (PkBackend *backend)
+-{
+- return (PK_FILTER_ENUM_GUI |
+- PK_FILTER_ENUM_INSTALLED |
+- PK_FILTER_ENUM_DEVELOPMENT);
+-}
+-
+-/**
+- * backend_get_details:
+- */
+-
+-void
+-backend_get_details (PkBackend *backend, const gchar *package_id)
+-{
+- pk_backend_spawn_helper (spawn, "get-details.py", package_id, NULL);
+-}
+-
+-/**
+- * backend_search_details:
+- */
+-
+-void
+-backend_search_details (PkBackend *backend, PkFilterEnum filters, const gchar *search)
+-{
+- gchar *filters_text;
+- filters_text = pk_filter_enums_to_text (filters);
+- pk_backend_spawn_helper (spawn, "search-details.py", filters_texts_text, search, NULL);
+- g_free (filters_text);
+-}
+-
+-/**
+- * backend_search_name:
+- */
+-void
+-backend_search_name (PkBackend *backend, PkFilterEnum filters, const gchar *search)
+-{
+- gchar *filters_text;
+- filters_text = pk_filter_enums_to_text (filters);
+- pk_backend_spawn_helper (spawn, "search-name.py", filters_text, search, NULL);
+- g_free (filters_text);
+-}
+-
+-/**
+- * backend_search_group:
+- */
+-void
+-backend_search_group (PkBackend *backend, PkFilterEnum filters, const gchar *search)
+-{
+- gchar *filters_text;
+- pk_backend_spawn_helper (spawn, "search-group.py", filters_text, search, NULL);
+- g_free (filters_text);
+-}
+-
+-/* don't need to do any setup/finalize in the plain search mode */
+-void backend_init_search(PkBackend *backend) {}
+-void backend_finish_search(PkBackend *backend) {}
+diff --git a/backends/apt/pk-apt-search-sqlite.cpp b/backends/apt/pk-apt-search-sqlite.cpp
+deleted file mode 100644
+index 98bdc7f..0000000
+--- a/backends/apt/pk-apt-search-sqlite.cpp
++++ /dev/null
+@@ -1,135 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+- */
+-
+-#include <gmodule.h>
+-#include <glib.h>
+-#include <string.h>
+-#include <pk-backend.h>
+-#include <pk-backend-spawn.h>
+-#include "pk-sqlite-pkg-cache.h"
+-#include <apt-pkg/configuration.h>
+-#include <apt-pkg/init.h>
+-#include "pk-apt-build-db.h"
+-
+-static PkBackendSpawn *spawn;
+-
+-/**
+- * backend_get_groups:
+- */
+-extern "C" PkGroupEnum
+-backend_get_groups (PkBackend *backend)
+-{
+- return (PK_GROUP_ENUM_ACCESSORIES |
+- PK_GROUP_ENUM_GAMES |
+- PK_GROUP_ENUM_GRAPHICS |
+- PK_GROUP_ENUM_INTERNET |
+- PK_GROUP_ENUM_OFFICE |
+- PK_GROUP_ENUM_OTHER |
+- PK_GROUP_ENUM_PROGRAMMING |
+- PK_GROUP_ENUM_MULTIMEDIA |
+- PK_GROUP_ENUM_SYSTEM);
+-}
+-
+-/**
+- * backend_get_filters:
+- */
+-extern "C" PkFilterEnum
+-backend_get_filters (PkBackend *backend)
+-{
+- return (PK_FILTER_ENUM_GUI |
+- PK_FILTER_ENUM_INSTALLED |
+- PK_FILTER_ENUM_DEVELOPMENT);
+-}
+-
+-/**
+- * backend_get_details:
+- */
+-
+-extern "C" void
+-backend_get_details (PkBackend *backend, const gchar *package_id)
+-{
+- sqlite_get_details(backend,package_id);
+-}
+-
+-/**
+- * backend_search_details:
+- */
+-
+-extern "C" void
+-backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
+-{
+- sqlite_search_details(backend,filter,search);
+-}
+-
+-/**
+- * backend_search_name:
+- */
+-extern "C" void
+-backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
+-{
+- sqlite_search_name(backend,filter,search);
+-}
+-
+-/**
+- * backend_search_group:
+- */
+-extern "C" void
+-backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
+-{
+- pk_backend_set_allow_cancel (backend, TRUE);
+- pk_backend_spawn_helper (spawn, "search-group.py", filter, search, NULL);
+-}
+-
+-static gboolean inited = FALSE;
+-
+-#define APT_DB PK_DB_DIR "/apt.db"
+-
+-extern "C" void backend_init_search(PkBackend *backend)
+-{
+- if (!inited)
+- {
+- gchar *apt_fname = NULL;
+- if (pkgInitConfig(*_config) == false)
+- pk_debug("pkginitconfig was false");
+- if (pkgInitSystem(*_config, _system) == false)
+- pk_debug("pkginitsystem was false");
+-
+- apt_fname = g_strconcat(
+- _config->Find("Dir").c_str(),
+- _config->Find("Dir::Cache").c_str(),
+- _config->Find("Dir::Cache::pkgcache").c_str(),
+- NULL);
+-
+- //sqlite_set_installed_check(is_installed);
+- sqlite_init_cache(backend, APT_DB, apt_fname, apt_build_db);
+- g_free(apt_fname);
+-
+- spawn = pk_backend_spawn_new ();
+- pk_backend_spawn_set_name (spawn, "apt-sqlite");
+-
+- inited = TRUE;
+- }
+-}
+-
+-extern "C" void backend_finish_search(PkBackend *backend)
+-{
+- sqlite_finish_cache(backend);
+-}
+diff --git a/backends/apt/pk-apt-search.h b/backends/apt/pk-apt-search.h
+deleted file mode 100644
+index e36e89f..0000000
+--- a/backends/apt/pk-apt-search.h
++++ /dev/null
+@@ -1,36 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+- */
+-
+-#ifndef __PK_APT_SEARCH_H
+-#define __PK_APT_SEARCH_H
+-
+-#include <glib.h>
+-#include <pk-backend.h>
+-
+-void backend_init_search(PkBackend *backend);
+-void backend_finish_search(PkBackend *backend);
+-
+-void backend_get_details (PkBackend *backend, const gchar *package_id);
+-void backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search);
+-void backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search);
+-void backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search);
+-
+-#endif
+diff --git a/backends/apt/pk-backend-apt.c b/backends/apt/pk-backend-apt.c
+index f59cd88..70836b2 100644
+--- a/backends/apt/pk-backend-apt.c
++++ b/backends/apt/pk-backend-apt.c
+@@ -20,16 +20,12 @@
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+-#include <gmodule.h>
+-#include <glib.h>
+-#include <string.h>
+ #include <pk-backend.h>
+-#include <pk-backend-spawn.h>
+-#include <pk-package-ids.h>
+-#include "pk-apt-search.h"
+-#include "config.h"
++#include <pk-backend-dbus.h>
+
+-PkBackendSpawn *spawn;
++static PkBackendDbus *dbus;
++
++#define PK_DBUS_BACKEND_SERVICE_APT "org.freedesktop.PackageKitAptBackend"
+
+ /**
+ * backend_initialize:
+@@ -39,9 +35,8 @@ static void
+ backend_initialize (PkBackend *backend)
+ {
+ pk_debug ("FILTER: initialize");
+- spawn = pk_backend_spawn_new ();
+- pk_backend_spawn_set_name (spawn, "apt");
+- backend_init_search (backend);
++ dbus = pk_backend_dbus_new ();
++ pk_backend_dbus_set_name (dbus, PK_DBUS_BACKEND_SERVICE_APT);
+ }
+
+ /**
+@@ -52,8 +47,8 @@ static void
+ backend_destroy (PkBackend *backend)
+ {
+ pk_debug ("FILTER: destroy");
+- backend_finish_search (backend);
+- g_object_unref (spawn);
++ pk_backend_dbus_kill (dbus);
++ g_object_unref (dbus);
+ }
+
+ /**
+@@ -85,184 +80,144 @@ backend_get_filters (PkBackend *backend)
+ }
+
+ /**
+- * pk_backend_bool_to_text:
++ * backend_get_updates:
+ */
+-static const gchar *
+-pk_backend_bool_to_text (gboolean value)
++static void
++backend_get_updates (PkBackend *backend, PkFilterEnum filters)
+ {
+- if (value == TRUE) {
+- return "yes";
+- }
+- return "no";
++ pk_backend_dbus_get_updates (dbus, filters);
+ }
+
+ /**
+- * backend_get_depends:
+- */
++ * backend_refresh_cache:
++ * */
+ static void
+-backend_get_depends (PkBackend *backend, PkFilterEnum filters, const gchar *package_id, gboolean recursive)
++backend_refresh_cache (PkBackend *backend, gboolean force)
+ {
+- gchar *filters_text;
+- filters_text = pk_filter_enums_to_text (filters);
+- pk_backend_spawn_helper (spawn, "get-depends.py", filters_text, package_id, pk_backend_bool_to_text (recursive), NULL);
+- g_free (filters_text);
++ // check network state
++ if (!pk_backend_is_online (backend)) {
++ pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot refresh cache whilst offline");
++ pk_backend_finished (backend);
++ return;
++ }
++
++ pk_backend_dbus_refresh_cache(dbus, force);
+ }
+
+ /**
+- * backend_get_updates:
+- */
++ * pk_backend_update_system:
++ * */
+ static void
+-backend_get_updates (PkBackend *backend, PkFilterEnum filters)
++backend_update_system (PkBackend *backend)
+ {
+- gchar *filters_text;
+- filters_text = pk_filter_enums_to_text (filters);
+- pk_backend_spawn_helper (spawn, "get-updates.py", filters_text, NULL);
+- g_free (filters_text);
++ pk_backend_dbus_update_system (dbus);
+ }
+
+ /**
+- * backend_get_update_detail:
+- */
++ * backend_install_packages
++ * */
+ static void
+-backend_get_update_detail (PkBackend *backend, const gchar *package_id)
++backend_install_packages (PkBackend *backend, gchar **package_ids)
+ {
+- pk_backend_spawn_helper (spawn, "get-update-detail.py", package_id, NULL);
++ pk_backend_dbus_install_packages (dbus, package_ids);
+ }
+
+ /**
+- * backend_install_packages:
+- */
++ * backend_remove_packages
++ * */
+ static void
+-backend_install_packages (PkBackend *backend, gchar **package_ids)
++backend_remove_packages (PkBackend *backend, gchar **package_ids, gboolean allow_deps, gboolean autoremove)
+ {
+- gchar *package_ids_temp;
+-
+- /* check network state */
+- if (!pk_backend_is_online (backend)) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot install when offline");
+- pk_backend_finished (backend);
+- return;
+- }
+-
+- /* send the complete list as stdin */
+- package_ids_temp = pk_package_ids_to_text (package_ids, "|");
+- pk_backend_spawn_helper (spawn, "install-packages.py", package_ids_temp, NULL);
+- g_free (package_ids_temp);
++ pk_backend_dbus_remove_packages (dbus, package_ids, allow_deps, autoremove);
+ }
+
+ /**
+- * backend_refresh_cache:
+- */
++ * backend_get_details:
++ * */
+ static void
+-backend_refresh_cache (PkBackend *backend, gboolean force)
++backend_get_details (PkBackend *backend, const gchar *package_id)
+ {
+- /* check network state */
+- if (!pk_backend_is_online (backend)) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot refresh cache whilst offline");
+- pk_backend_finished (backend);
+- return;
+- }
+-
+- pk_backend_spawn_helper (spawn, "refresh-cache.py", NULL);
++ pk_backend_dbus_get_details (dbus, package_id);
+ }
+
+ /**
+- * pk_backend_remove_packages:
+- *
++ * * pk_backend_search_details:
++ * */
+ static void
+-backend_remove_packages (PkBackend *backend, gchar **package_ids, gboolean allow_deps, gboolean autoremove)
++backend_search_details (PkBackend *backend, PkFilterEnum filters, const gchar *search)
+ {
+- gchar *package_ids_temp;
+- package_ids_temp = pk_package_ids_to_text (package_ids, "|");
+- pk_backend_spawn_helper (spawn, "remove-packages.py", pk_backend_bool_to_text (allow_deps), package_ids_temp, NULL);
+- g_free (package_ids_temp);
+-} */
++ pk_backend_dbus_search_details (dbus, filters, search);
++}
+
+ /**
+- * pk_backend_update_packages:
+- */
++ * * pk_backend_search_name:
++ * */
+ static void
+-backend_update_packages (PkBackend *backend, gchar **package_ids)
++backend_search_name (PkBackend *backend, PkFilterEnum filters, const gchar *search)
+ {
+- gchar *package_ids_temp;
+-
+- /* check network state */
+- if (!pk_backend_is_online (backend)) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot install when offline");
+- pk_backend_finished (backend);
+- return;
+- }
+-
+- /* send the complete list as stdin */
+- package_ids_temp = pk_package_ids_to_text (package_ids, "|");
+- pk_backend_spawn_helper (spawn, "update-packages.py", package_ids_temp, NULL);
+- g_free (package_ids_temp);
++ pk_backend_dbus_search_name (dbus, filters, search);
+ }
+
+ /**
+- * pk_backend_update_system:
+- */
++ * * pk_backend_cancel:
++ * */
+ static void
+-backend_update_system (PkBackend *backend)
++backend_cancel (PkBackend *backend)
+ {
+- pk_backend_spawn_helper (spawn, "update-system.py", NULL);
++ pk_backend_dbus_cancel (dbus);
+ }
+
+ /**
+- * pk_backend_resolve:
+- */
++ * * pk_backend_resolve:
++ * */
+ static void
+ backend_resolve (PkBackend *backend, PkFilterEnum filters, const gchar *package_id)
+ {
+- gchar *filters_text;
+- filters_text = pk_filter_enums_to_text (filters);
+- pk_backend_spawn_helper (spawn, "resolve.py", filters_text, package_id, NULL);
+- g_free (filters_text);
++ pk_backend_dbus_resolve (dbus, filters, package_id);
+ }
+
+ /**
+- * pk_backend_get_repo_list:
+- */
++ * * pk_backend_get_packages:
++ * */
+ static void
+-backend_get_repo_list (PkBackend *backend, PkFilterEnum filters)
++backend_get_packages (PkBackend *backend, PkFilterEnum filters)
+ {
+- gchar *filters_text;
+- filters_text = pk_filter_enums_to_text (filters);
+- pk_backend_spawn_helper (spawn, "get-repo-list.py", filters_text, NULL);
+- g_free (filters_text);
++ pk_backend_dbus_get_packages (dbus, filters);
+ }
+
++
++
+ PK_BACKEND_OPTIONS (
+- "Apt (with " APT_SEARCH " searching)", /* description */
+- "Ali Sabil <ali.sabil@gmail.com>; Tom Parker <palfrey@tevp.net>", /* author */
++ "Apt", /* description */
++ "Ali Sabil <ali.sabil@gmail.com>; Tom Parker <palfrey@tevp.net>; Sebastian Heinlein <glatzor@ubuntu.com>", /* author */
+ backend_initialize, /* initalize */
+ backend_destroy, /* destroy */
+ backend_get_groups, /* get_groups */
+ backend_get_filters, /* get_filters */
+- NULL, /* cancel */
+- backend_get_depends, /* get_depends */
++ backend_cancel, /* cancel */
++ NULL, /* get_depends */
+ backend_get_details, /* get_details */
+ NULL, /* get_files */
+- NULL, /* get_packages */
+- backend_get_repo_list, /* get_repo_list */
++ backend_get_packages, /* get_packages */
++ NULL, /* get_repo_list */
+ NULL, /* get_requires */
+- backend_get_update_detail, /* get_update_detail */
++ NULL, /* get_update_detail */
+ backend_get_updates, /* get_updates */
+ NULL, /* install_files */
+ backend_install_packages, /* install_packages */
+ NULL, /* install_signature */
+ backend_refresh_cache, /* refresh_cache */
+- NULL, /* remove_packages */
++ backend_remove_packages, /* remove_packages */
+ NULL, /* repo_enable */
+ NULL, /* repo_set_data */
+ backend_resolve, /* resolve */
+ NULL, /* rollback */
+ backend_search_details, /* search_details */
+ NULL, /* search_file */
+- backend_search_group, /* search_group */
++ NULL, /* search_group */
+ backend_search_name, /* search_name */
+ NULL, /* service_pack */
+- backend_update_package, /* update_package */
++ NULL, /* update_packages */
+ backend_update_system, /* update_system */
+ NULL /* what_provides */
+ );
+diff --git a/backends/apt/pk-sqlite-pkg-cache.cpp b/backends/apt/pk-sqlite-pkg-cache.cpp
+deleted file mode 100644
+index 1bf9a50..0000000
+--- a/backends/apt/pk-sqlite-pkg-cache.cpp
++++ /dev/null
+@@ -1,215 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+- */
+-
+-#include <glib.h>
+-#include <glib/gstdio.h>
+-#include "pk-sqlite-pkg-cache.h"
+-
+-static sqlite3 *db = NULL;
+-static PkBackend *backend;
+-static gboolean(*is_installed) (const PkPackageId *) = NULL;
+-
+-void sqlite_set_installed_check(gboolean(*func) (const PkPackageId *))
+-{
+- is_installed = func;
+-}
+-
+-void
+-sqlite_init_cache(PkBackend *backend, const char* dbname, const char *compare_fname, void (*build_db)(PkBackend *, sqlite3 *))
+-{
+- int ret;
+- struct stat st;
+- time_t db_age;
+-
+- ret = sqlite3_open (dbname, &db);
+- g_assert(ret == SQLITE_OK);
+- g_assert(db!=NULL);
+- ret = sqlite3_exec(db,"PRAGMA synchronous = OFF",NULL,NULL,NULL);
+- g_assert(ret == SQLITE_OK);
+-
+- g_stat(dbname, &st);
+- db_age = st.st_mtime;
+- g_stat(compare_fname, &st);
+- if (db_age>=st.st_mtime)
+- {
+- ret = sqlite3_exec(db, "select value from params where name = 'build_complete'", NULL, NULL, NULL);
+- if (ret != SQLITE_ERROR)
+- return;
+- pk_debug("ages are %lu for db, and %lu for comparism",db_age,st.st_mtime);
+- }
+- ret = sqlite3_exec(db,"drop table packages",NULL,NULL,NULL); // wipe it!
+- //g_assert(ret == SQLITE_OK);
+- pk_debug("wiped db");
+- ret = sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string, primary key(name,version,arch,repo))",NULL,NULL,NULL);
+- g_assert(ret == SQLITE_OK);
+-
+- build_db(backend,db);
+-
+- sqlite3_exec(db,"create table params (name text primary key, value integer)", NULL, NULL, NULL);
+- sqlite3_exec(db,"insert into params values ('build_complete',1)", NULL, NULL, NULL);
+-}
+-
+-void sqlite_finish_cache(PkBackend *backend)
+-{
+- sqlite3_close(db);
+-}
+-
+-// sqlite_search_packages_thread
+-static gboolean
+-sqlite_search_packages_thread (PkBackend *backend)
+-{
+- int res;
+- gchar *sel;
+- const gchar *search;
+-
+- pk_backend_set_status(backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
+- type = pk_backend_get_uint (backend, "type");
+- search = pk_backend_get_string (backend, "search");
+-
+- pk_debug("finding %s", search);
+-
+- sqlite3_stmt *package = NULL;
+- g_strdelimit(search," ",'%');
+-
+- if (type == SEARCH_NAME)
+- sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%'",search);
+- else if (type == SEARCH_DETAILS)
+- sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%' or short_desc like '%%%s%%' or long_desc like '%%%s%%'",search, search, search);
+- else
+- {
+- pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "Unknown search task type");
+- goto end_search_packages;
+- }
+-
+- pk_debug("statement is '%s'",sel);
+- res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
+- g_free(sel);
+- if (res!=SQLITE_OK)
+- pk_error("sqlite error during select prepare: %s", sqlite3_errmsg(db));
+- res = sqlite3_step(package);
+- while (res == SQLITE_ROW)
+- {
+- PkPackageId *pid = pk_package_id_new_from_list((const gchar*)sqlite3_column_text(package,0),
+- (const gchar*)sqlite3_column_text(package,1),
+- (const gchar*)sqlite3_column_text(package,2),
+- (const gchar*)sqlite3_column_text(package,3));
+-
+- gchar *cpid = pk_package_id_to_string(pid);
+- PkInfoEnum pie = PK_INFO_ENUM_UNKNOWN;
+-
+- if (is_installed != NULL)
+- pie = is_installed(pid)?PK_INFO_ENUM_INSTALLED:PK_INFO_ENUM_AVAILABLE;
+-
+- pk_backend_package(backend, pie, cpid, (const gchar*)sqlite3_column_text(package,4));
+-
+- g_free(cpid);
+- pk_package_id_free(pid);
+-
+- if (res==SQLITE_ROW)
+- res = sqlite3_step(package);
+- }
+- if (res!=SQLITE_DONE)
+- {
+- pk_debug("sqlite error during step (%d): %s", res, sqlite3_errmsg(db));
+- g_assert(0);
+- }
+-
+-end_search_packages:
+- pk_backend_finished (backend);
+- return TRUE;
+-}
+-
+-/**
+- * sqlite_search_details:
+- */
+-void
+-sqlite_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
+-{
+- pk_backend_set_uint (backend, "type", SEARCH_DETAILS);
+- pk_backend_thread_create (backend, sqlite_search_packages_thread);
+-}
+-
+-/**
+- * sqlite_search_name:
+- */
+-void
+-sqlite_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
+-{
+- pk_backend_set_uint (backend, "type", SEARCH_NAME);
+- pk_backend_thread_create (backend, sqlite_search_packages_thread);
+-}
+-
+-// sqlite_get_details_thread
+-static gboolean
+-sqlite_get_details_thread (PkBackend *backend)
+-{
+- PkPackageId *pi;
+- const gchar *package_id;
+- int res;
+-
+- package_id = pk_backend_get_string (backend, "package_id");
+- pi = pk_package_id_new_from_string(package_id);
+- if (pi == NULL)
+- {
+- pk_backend_error_code(backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "invalid package id");
+- pk_backend_finished(backend);
+- return;
+- }
+-
+- pk_backend_set_status(backend, PK_STATUS_ENUM_QUERY);
+- pk_backend_set_percentage (backend, PK_BACKEND_PERCENTAGE_INVALID);
+-
+- pk_debug("finding %s", pi->name);
+-
+- sqlite3_stmt *package = NULL;
+- gchar *sel = g_strdup_printf("select long_desc from packages where name = '%s' and version = '%s' and repo = '%s'",pi->name,pi->version,pi->data);
+- pk_debug("statement is '%s'",sel);
+- res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
+- g_free(sel);
+- if (res!=SQLITE_OK)
+- pk_error("sqlite error during select prepare: %s", sqlite3_errmsg(db));
+- res = sqlite3_step(package);
+- pk_backend_details(backend,pi->name, "unknown", PK_GROUP_ENUM_OTHER,(const gchar*)sqlite3_column_text(package,0),"",0);
+- res = sqlite3_step(package);
+- if (res==SQLITE_ROW)
+- pk_error("multiple matches for that package!");
+- if (res!=SQLITE_DONE)
+- {
+- pk_debug("sqlite error during step (%d): %s", res, sqlite3_errmsg(db));
+- g_assert(0);
+- }
+-
+- g_free(dt);
+-
+- return TRUE;
+-}
+-
+-/**
+- * sqlite_get_details:
+- */
+-extern "C++" void
+-sqlite_get_details (PkBackend *backend, const gchar *package_id)
+-{
+- pk_backend_thread_create (backend, sqlite_get_details_thread);
+- return;
+-}
+-
+diff --git a/backends/apt/pk-sqlite-pkg-cache.h b/backends/apt/pk-sqlite-pkg-cache.h
+deleted file mode 100644
+index 68fad42..0000000
+--- a/backends/apt/pk-sqlite-pkg-cache.h
++++ /dev/null
+@@ -1,42 +0,0 @@
+-#ifndef SQLITE_PKT_CACHE
+-#define SQLITE_PKT_CACHE
+-
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+- */
+-
+-typedef enum {
+- SEARCH_NAME = 1,
+- SEARCH_DETAILS,
+- SEARCH_FILE
+-} SearchDepth;
+-
+-#include <pk-backend.h>
+-#include <sqlite3.h>
+-
+-void sqlite_init_cache(PkBackend *backend, const char* dbname, const char* compare_fname, void (*build_db)(PkBackend *, sqlite3 *db));
+-void sqlite_finish_cache(PkBackend *backend);
+-
+-void sqlite_search_details (PkBackend *backend, const gchar *filter, const gchar *search);
+-void sqlite_search_name (PkBackend *backend, const gchar *filter, const gchar *search);
+-void backend_search_common(PkBackend * backend, const gchar * filter, const gchar * search, SearchDepth which, PkBackendThreadFunc func);
+-void sqlite_get_details (PkBackend *backend, const gchar *package_id);
+-
+-#endif
+diff --git a/backends/apt/profiler.py b/backends/apt/profiler.py
+new file mode 100644
+index 0000000..1b5d30f
+--- /dev/null
++++ b/backends/apt/profiler.py
+@@ -0,0 +1,40 @@
++#!/usr/bin/env python
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++
++# Copyright (C) 2008
++# Sebastian Heinlein <sebi@glatzor.de>
++
++"""
++Allows to start the apt2 backend in a profling mode
++"""
++
++__author__ = "Sebastian Heinlein <devel@glatzor.de>"
++
++
++import hotshot
++import sys
++
++from aptDBUSBackend import main
++
++if len(sys.argv) == 2:
++ profile = sys.argv[1]
++else:
++ profile = "profile"
++
++prof = hotshot.Profile(profile)
++print prof.runcall(main)
++prof.close()
+diff --git a/backends/apt/test.py b/backends/apt/test.py
+new file mode 100755
+index 0000000..a1d5ffb
+--- /dev/null
++++ b/backends/apt/test.py
+@@ -0,0 +1,98 @@
++#!/usr/bin/python
++# Licensed under the GNU General Public License Version 2
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++
++# Copyright (C) 2007
++# Tim Lauridsen <timlau@fedoraproject.org>
++
++import sys
++import dbus
++from packagekit.enums import *
++
++PACKAGEKIT_DBUS_SERVICE = 'org.freedesktop.PackageKitAptBackend'
++PACKAGEKIT_DBUS_INTERFACE = 'org.freedesktop.PackageKitBackend'
++PACKAGEKIT_DBUS_PATH = '/org/freedesktop/PackageKitBackend'
++PKG_ID = 'xterm;232-1;i386;Debian'
++
++try:
++ bus = dbus.SystemBus()
++except dbus.DBusException, e:
++ print "Unable to connect to dbus"
++ print "%s" %(e,)
++ sys.exit(1)
++
++try:
++ proxy = bus.get_object(PACKAGEKIT_DBUS_SERVICE, PACKAGEKIT_DBUS_PATH)
++ iface = dbus.Interface(proxy, PACKAGEKIT_DBUS_INTERFACE)
++ cmd = sys.argv[1]
++ if cmd == 'init' or cmd == 'all':
++ print "Testing Init()"
++ iface.Init()
++ if cmd == 'cancel':
++ print "Canceling"
++ iface.Cancel()
++ if cmd == 'get-updates' or cmd == 'all':
++ print "Testing GetUpdate()"
++ iface.GetUpdates()
++ if cmd == 'search-name' or cmd == 'all':
++ print "Testing SearchName(FILTER_NONE,'apt')"
++ iface.SearchName(FILTER_NONE,'apt')
++ if cmd == 'search-details' or cmd == 'all':
++ print "SearchDetails(FILTER_NONE,'dbus')"
++ iface.SearchDetails(FILTER_NONE,'dbus')
++ if cmd == 'search-group' or cmd == 'all':
++ print "Testing SearchGroup(FILTER_NONE,GROUP_GAMES)"
++ iface.SearchGroup(FILTER_NONE,GROUP_GAMES)
++ if cmd == 'search-file' or cmd == 'all':
++ print "Testing SearchFile(FILTER_NONE,'/usr/bin/yum')"
++ iface.SearchFile(FILTER_NONE,'/usr/bin/yum')
++ if cmd == 'get-requires' or cmd == 'all':
++ print "Testing GetRequires(PKG_ID,False)"
++ iface.GetRequires(PKG_ID,False)
++ if cmd == 'get-depends' or cmd == 'all':
++ print "Testing GetDepends(PKG_ID,False)"
++ iface.GetDepends(PKG_ID,False)
++ if cmd == 'refresh-cache' or cmd == 'all':
++ print "Testing RefreshCache()"
++ iface.RefreshCache()
++ if cmd == 'resolve' or cmd == 'all':
++ print "Testing Resolve(FILTER_NONE,'yum')"
++ iface.Resolve(FILTER_NONE,'yum')
++ if cmd == 'get-details' or cmd == 'all':
++ print "Testing GetDetails(PKG_ID)"
++ iface.GetDetails(PKG_ID)
++ if cmd == 'get-files' or cmd == 'all':
++ print "Testing GetFiles(PKG_ID)"
++ iface.GetFiles(PKG_ID)
++ if cmd == 'get-packages' or cmd == 'all':
++ print "Testing GetPackages(FILTER_INSTALLED,'no')"
++ iface.GetPackages(FILTER_INSTALLED,'no')
++ if cmd == 'get-repolist' or cmd == 'all':
++ print "Testing GetRepoList()"
++ iface.GetRepoList()
++ if cmd == 'get-updatedetail' or cmd == 'all':
++ print "Testing GetUpdateDetail(PKG_ID)"
++ iface.GetUpdateDetail(PKG_ID)
++ #print "Testing "
++ #iface.
++ if cmd == 'exit' or cmd == 'all':
++ print "Testing Exit()"
++ iface.Exit()
++
++except dbus.DBusException, e:
++ print "Unable to send message on dbus"
++ print "%s" %(e,)
++ sys.exit(1)
+diff --git a/backends/apt2/.gitignore b/backends/apt2/.gitignore
+deleted file mode 100644
+index c851833..0000000
+--- a/backends/apt2/.gitignore
++++ /dev/null
+@@ -1,10 +0,0 @@
+-.deps
+-.libs
+-Makefile
+-Makefile.in
+-*.la
+-*.lo
+-*.loT
+-*.o
+-*~
+-
+diff --git a/backends/apt2/HACKING b/backends/apt2/HACKING
+deleted file mode 100644
+index 2b99c5d..0000000
+--- a/backends/apt2/HACKING
++++ /dev/null
+@@ -1,5 +0,0 @@
+-The backend can be tested by running it as root from the source code
+-repository. Make sure to kill packagekitd before to force a reintializing
+-of the cache:
+-
+- killall packagekitd; python aptDBUSBackend.py
+diff --git a/backends/apt2/Makefile.am b/backends/apt2/Makefile.am
+deleted file mode 100644
+index 91c0c46..0000000
+--- a/backends/apt2/Makefile.am
++++ /dev/null
+@@ -1,25 +0,0 @@
+-NULL =
+-
+-plugindir = $(PK_PLUGIN_DIR)
+-plugin_LTLIBRARIES = libpk_backend_apt2.la
+-libpk_backend_apt2_la_SOURCES = pk-backend-apt2.c
+-libpk_backend_apt2_la_LIBADD = $(PK_PLUGIN_LIBS)
+-libpk_backend_apt2_la_LDFLAGS = -module -avoid-version
+-libpk_backend_apt2_la_CFLAGS = $(PK_PLUGIN_CFLAGS)
+-
+-dbusinstancedir = $(LIBEXECDIR)
+-dbusinstance_DATA = \
+- aptDBUSBackend.py \
+- $(NULL)
+-
+-EXTRA_DIST = \
+- $(dbusinstance_DATA) \
+- $(NULL)
+-
+-install-data-hook:
+- chmod a+rx $(DESTDIR)$(libexecdir)/*.py
+-
+-clean-local :
+- rm -f *~
+- rm -f *.pyc
+-
+diff --git a/backends/apt2/README b/backends/apt2/README
+deleted file mode 100644
+index 0a3da6e..0000000
+--- a/backends/apt2/README
++++ /dev/null
+@@ -1,23 +0,0 @@
+-The name of this backend is apt2.
+-
+-It supports apt which is mainly used by Debian and its derivates. In contrast to
+-the backend called apt this one uses DBus for the communication with the
+-packagekit daemon. This allows to perform actions without having to reopen
+-the cache for each one.
+-
+-To provide a tremendously fast search function a Xapian database is used.
+-It is provided by Enrico Zini's apt-xapian-index. Debtags will be used to
+-enhance the quality of the search results further.
+-
+-A list of implemented functions are listed in the PackageKit FAQ:
+-
+-http://www.packagekit.org/pk-faq.html
+-
+-You can find packages for Ubuntu here:
+-
+-https://www.launchpad.net/~packagekit/+ppa
+-
+-Packages for Debian Unstable will be provided soon.
+-
+-Feel free to send comments or bug reports to the PackageKit mailing list
+-or to the author.
+diff --git a/backends/apt2/TODO b/backends/apt2/TODO
+deleted file mode 100644
+index bee2f3d..0000000
+--- a/backends/apt2/TODO
++++ /dev/null
+@@ -1,70 +0,0 @@
+-ISSUES:
+-
+- * Support delayed or hidden debconf questions
+-
+-Unresolved issues can be discussed at the following wiki page:
+-http://wiki.debian.org/PackageKit
+-
+-
+-TODO:
+-
+- * Implement all open backend methods. A list of implemented backend methods
+- can be found in PackageKit FAQ or in pk-backend-apt2.c.
+-
+- * Blacklist packages requiring input on the terminal and try to change
+- the Debian policy in the long run. Way of automation?
+-
+- * Allow to inject alternative apt.package.Package classes into the
+- cache to support PackageKit and distribution specific needs
+- (e.g. when is a package called free or supported)
+-
+- * Allow to reinject debtags into the search results to get
+- similar software which not matches on the search terms
+-
+- * Index file list and add properties for package name and section to
+- the xapian database to also make use of it in search group and
+- search name (do we want this?)
+-
+- * Map Debian/Ubuntu sections to PackageKit groups:
+- - admin : System Administration => admin-tools
+- - base : Base System => system
+- - comm : Communication => communication
+- - devel : Development => programming
+- - doc : Documentation => ???
+- - editors : Editors => accessoires
+- - electronics : Electronics => other
+- - embedded : Embedded Devices => system
+- - games : Games and Amusement => games
+- - gnome : GNOME Desktop Environment => desktop-gnome
+- - graphics : Graphics => graphics
+- - hamradio : Amateur Radio => communication
+- - interpreters : Interpreted Computer L. => programming
+- - kde : KDE Desktop Environment => desktop-kde
+- - libdevel : Libraries - Development => programming
+- - libs : Libraries => system
+- - mail : Email => internet
+- - math : Mathematics => ??? science/education
+- - misc : Miscellaneous - Text Based => other
+- - net : Networkinga => network
+- - news : Newsgroup => internet
+- - oldlibs : Libraries - Old => legacy
+- - otherosfs : Cross Platform => system
+- - perl : Perl Programming Language => programming
+- - python : Python Programming Language => programming
+- - science : Science => ??? science/education
+- - shells : Shells => system
+- - sound : Multimedia => multimedia
+- - tex : TeX Authoring => publishing
+- - text : Word Processing => publishing
+- - utils : Utilities => accessoires
+- - web : World Wide Web => internet
+- - x11 : Miscellaneous - Graphical => desktop-other
+- - unknown : Unknown => unknown
+- - alien : Converted From RPM by Alien" => unknown
+- - translations => localization
+- The following could not be maped: science, documentation, electronics
+- Are there any derivates with additional sections?
+-
+- * Fix the dbus policy. Should we require at_console for searching?
+-
+-DONE:
+diff --git a/backends/apt2/aptDBUSBackend.py b/backends/apt2/aptDBUSBackend.py
+deleted file mode 100755
+index b7fc500..0000000
+--- a/backends/apt2/aptDBUSBackend.py
++++ /dev/null
+@@ -1,628 +0,0 @@
+-#!/usr/bin/env python
+-# -*- coding: utf-8 -*-
+-"""
+-Provides an apt backend to PackageKit
+-
+-Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
+-Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
+-Copyright (C) 2008 Sebastian Heinlein <glatzor@ubuntu.com>
+-
+-Licensed under the GNU General Public License Version 2
+-
+-This program is free software; you can redistribute it and/or modify
+-it under the terms of the GNU General Public License as published by
+-the Free Software Foundation; either version 2 of the License, or
+-(at your option) any later version.
+-"""
+-
+-__author__ = "Sebastian Heinlein <devel@glatzor.de>"
+-__state__ = "experimental"
+-
+-import os
+-import pty
+-import re
+-import signal
+-import time
+-import threading
+-import warnings
+-
+-import apt
+-import apt_pkg
+-import dbus
+-import dbus.glib
+-import dbus.service
+-import dbus.mainloop.glib
+-import gobject
+-import xapian
+-
+-from packagekit.daemonBackend import PACKAGEKIT_DBUS_INTERFACE, PACKAGEKIT_DBUS_PATH, PackageKitBaseBackend, PackagekitProgress, pklog, threaded
+-from packagekit.enums import *
+-
+-warnings.filterwarnings(action='ignore', category=FutureWarning)
+-
+-PACKAGEKIT_DBUS_SERVICE = 'org.freedesktop.PackageKitAptBackend'
+-
+-XAPIANDBPATH = os.environ.get("AXI_DB_PATH", "/var/lib/apt-xapian-index")
+-XAPIANDB = XAPIANDBPATH + "/index"
+-XAPIANDBVALUES = XAPIANDBPATH + "/values"
+-DEFAULT_SEARCH_FLAGS = (xapian.QueryParser.FLAG_BOOLEAN |
+- xapian.QueryParser.FLAG_PHRASE |
+- xapian.QueryParser.FLAG_LOVEHATE |
+- xapian.QueryParser.FLAG_BOOLEAN_ANY_CASE)
+-
+-# Required for daemon mode
+-os.putenv("PATH",
+- "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
+-# Avoid questions from the maintainer scripts as far as possible
+-os.putenv("DEBIAN_FRONTEND", "noninteractive")
+-os.putenv("APT_LISTCHANGES_FRONTEND", "none")
+-
+-# Setup threading support
+-gobject.threads_init()
+-dbus.glib.threads_init()
+-
+-class PackageKitOpProgress(apt.progress.OpProgress):
+- '''
+- Handle the cache opening process
+- '''
+- def __init__(self, backend, prange=(0,100), progress=True):
+- self._backend = backend
+- apt.progress.OpProgress.__init__(self)
+- self.steps = []
+- for v in [0.12, 0.25, 0.50, 0.75, 1.00]:
+- s = prange[0] + (prange[1] - prange[0]) * v
+- self.steps.append(s)
+- self.pstart = float(prange[0])
+- self.pend = self.steps.pop(0)
+- self.pprev = None
+- self.show_progress = progress
+-
+- # OpProgress callbacks
+- def update(self, percent):
+- progress = int(self.pstart + percent / 100 * (self.pend - self.pstart))
+- if self.show_progress == True and self.pprev < progress:
+- self._backend.PercentageChanged(progress)
+- self.pprev = progress
+-
+- def done(self):
+- self.pstart = self.pend
+- try:
+- self.pend = self.steps.pop(0)
+- except:
+- pklog.warning("An additional step to open the cache is required")
+-
+-class PackageKitFetchProgress(apt.progress.FetchProgress):
+- '''
+- Handle the package download process
+- '''
+- def __init__(self, backend, prange=(0,100)):
+- self._backend = backend
+- apt.progress.FetchProgress.__init__(self)
+- self.pstart = prange[0]
+- self.pend = prange[1]
+- self.pprev = None
+-
+- # FetchProgress callbacks
+- def pulse(self):
+- if self._backend._canceled.isSet():
+- return False
+- percent = ((self.currentBytes + self.currentItems)*100.0)/float(self.totalBytes+self.totalItems)
+- progress = int(self.pstart + percent/100 * (self.pend - self.pstart))
+- if self.pprev < progress:
+- self._backend.PercentageChanged(progress)
+- self.pprev = progress
+- apt.progress.FetchProgress.pulse(self)
+- return True
+-
+- def start(self):
+- self._backend.StatusChanged(STATUS_DOWNLOAD)
+- self._backend.AllowCancel(True)
+-
+- def stop(self):
+- self._backend.PercentageChanged(self.pend)
+- self._backend.AllowCancel(False)
+-
+- def mediaChange(self, medium, drive):
+- #FIXME: use the Message method to notify the user
+- self._backend.error(ERROR_UNKNOWN,
+- "Medium change needed")
+-
+-class PackageKitInstallProgress(apt.progress.InstallProgress):
+- '''
+- Handle the installation and removal process. Bits taken from
+- DistUpgradeViewNonInteractive.
+- '''
+- def __init__(self, backend, prange=(0,100)):
+- apt.progress.InstallProgress.__init__(self)
+- self._backend = backend
+- self.timeout = 900
+- self.pstart = prange[0]
+- self.pend = prange[1]
+- self.pprev = None
+-
+- def statusChange(self, pkg, percent, status):
+- progress = self.pstart + percent/100 * (self.pend - self.pstart)
+- if self.pprev < progress:
+- self._backend.PercentageChanged(int(progress))
+- self.pprev = progress
+- pklog.debug("PM status: %s" % status)
+-
+- def startUpdate(self):
+- self._backend.StatusChanged(STATUS_INSTALL)
+- self.last_activity = time.time()
+-
+- def updateInterface(self):
+- pklog.debug("Updating interface")
+- apt.progress.InstallProgress.updateInterface(self)
+-
+- def conffile(self, current, new):
+- pklog.critical("Config file prompt: '%s'" % current)
+-
+-def sigquit(signum, frame):
+- pklog.error("Was killed")
+- sys.exit(1)
+-
+-class PackageKitAptBackend(PackageKitBaseBackend):
+- '''
+- PackageKit backend for apt
+- '''
+-
+- def locked(func):
+- '''
+- Decorator to run a method with a lock
+- '''
+- def wrapper(*args, **kwargs):
+- backend = args[0]
+- backend._lock_cache()
+- ret = func(*args, **kwargs)
+- backend._unlock_cache()
+- return ret
+- wrapper.__name__ = func.__name__
+- return wrapper
+-
+- def __init__(self, bus_name, dbus_path):
+- pklog.info("Initializing APT backend")
+- signal.signal(signal.SIGQUIT, sigquit)
+- self._cache = None
+- self._xapian = None
+- self._canceled = threading.Event()
+- self._canceled.clear()
+- self._locked = threading.Lock()
+- PackageKitBaseBackend.__init__(self, bus_name, dbus_path)
+-
+- # Methods ( client -> engine -> backend )
+-
+- def doInit(self):
+- pklog.info("Initializing cache")
+- self.StatusChanged(STATUS_SETUP)
+- self.AllowCancel(False)
+- self.NoPercentageUpdates()
+- self._open_cache(progress=False)
+-
+- def doExit(self):
+- pass
+-
+- @threaded
+- def doCancel(self):
+- pklog.info("Canceling current action")
+- self.StatusChanged(STATUS_CANCEL)
+- self._canceled.set()
+- self._canceled.wait()
+-
+- @threaded
+- def doSearchName(self, filters, search):
+- '''
+- Implement the apt2-search-name functionality
+- '''
+- pklog.info("Searching for package name: %s" % search)
+- self.StatusChanged(STATUS_QUERY)
+- self.NoPercentageUpdates()
+- self._check_init(progress=False)
+- self.AllowCancel(True)
+-
+- for pkg in self._cache:
+- if self._canceled.isSet():
+- self.ErrorCode(ERROR_TRANSACTION_CANCELLED,
+- "The search was canceled")
+- self.Finished(EXIT_KILL)
+- self._canceled.clear()
+- return
+- elif search in pkg.name and self._is_package_visible(pkg, filters):
+- self._emit_package(pkg)
+- self.Finished(EXIT_SUCCESS)
+-
+- @threaded
+- def doSearchDetails(self, filters, search):
+- '''
+- Implement the apt2-search-details functionality
+- '''
+- pklog.info("Searching for package name: %s" % search)
+- self.StatusChanged(STATUS_QUERY)
+- self.NoPercentageUpdates()
+- self._check_init(progress=False)
+- self.AllowCancel(True)
+- results = []
+-
+- if os.access(XAPIANDB, os.R_OK):
+- pklog.debug("Performing xapian db based search")
+- db = xapian.Database(XAPIANDB)
+- parser = xapian.QueryParser()
+- query = parser.parse_query(unicode(search),
+- DEFAULT_SEARCH_FLAGS)
+- enquire = xapian.Enquire(db)
+- enquire.set_query(query)
+- matches = enquire.get_mset(0, 1000)
+- for r in map(lambda m: m[xapian.MSET_DOCUMENT].get_data(),
+- enquire.get_mset(0,1000)):
+- if self._cache.has_key(r):
+- results.append(self._cache[r])
+- else:
+- pklog.debug("Performing apt cache based search")
+- for p in self._cache._dict.values():
+- if self._check_canceled("Search was canceled"): return
+- needle = search.strip().lower()
+- haystack = p.description.lower()
+- if p.name.find(needle) >= 0 or haystack.find(needle) >= 0:
+- results.append(p)
+-
+- for r in results:
+- if self._check_canceled("Search was canceled"): return
+- if self._is_package_visible(r, filters) == True:
+- self._emit_package(r)
+-
+- self.Finished(EXIT_SUCCESS)
+-
+- @threaded
+- @locked
+- def doGetUpdates(self, filters):
+- '''
+- Implement the {backend}-get-update functionality
+- '''
+- #FIXME: Implment the basename filter
+- pklog.info("Get updates")
+- self.StatusChanged(STATUS_INFO)
+- self.AllowCancel(True)
+- self.NoPercentageUpdates()
+- self._check_init(progress=False)
+- self._cache.upgrade(False)
+- for pkg in self._cache.getChanges():
+- if self._canceled.isSet():
+- self.ErrorCode(ERROR_TRANSACTION_CANCELLED,
+- "Calculating updates was canceled")
+- self.Finished(EXIT_KILL)
+- self._canceled.clear()
+- return
+- else:
+- self._emit_package(pkg)
+- self._open_cache(progress=False)
+- self.Finished(EXIT_SUCCESS)
+-
+- @threaded
+- def GetDetails(self, pkg_id):
+- '''
+- Implement the {backend}-get-details functionality
+- '''
+- pklog.info("Get details of %s" % pkg_id)
+- self.StatusChanged(STATUS_INFO)
+- self.NoPercentageUpdates()
+- self.AllowCancel(False)
+- self._check_init(progress=False)
+- name, version, arch, data = self.get_package_from_id(pkg_id)
+- if not self._cache.has_key(name):
+- self.ErrorCode(ERROR_PACKAGE_NOT_FOUND,
+- "Package %s isn't available" % name)
+- self.Finished(EXIT_FAILED)
+- return
+- pkg = self._cache[name]
+- #FIXME: should perhaps go to python-apt since we need this in
+- # several applications
+- desc = pkg.description
+- # Skip the first line - it's a duplicate of the summary
+- i = desc.find('\n')
+- desc = desc[i+1:]
+- # do some regular expression magic on the description
+- # Add a newline before each bullet
+- p = re.compile(r'^(\s|\t)*(\*|0|-)',re.MULTILINE)
+- desc = p.sub(ur'\n\u2022', desc)
+- # replace all newlines by spaces
+- p = re.compile(r'\n', re.MULTILINE)
+- desc = p.sub(" ", desc)
+- # replace all multiple spaces by newlines
+- p = re.compile(r'\s\s+', re.MULTILINE)
+- desc = p.sub('\n', desc)
+- #FIXME: group and licence information missing
+- self.Details(pkg_id, 'unknown', 'unknown', desc,
+- pkg.homepage, pkg.packageSize)
+- self.Finished(EXIT_SUCCESS)
+-
+- @threaded
+- @locked
+- def doUpdateSystem(self):
+- '''
+- Implement the {backend}-update-system functionality
+- '''
+- #FIXME: Better exception and error handling
+- #FIXME: Distupgrade or Upgrade?
+- #FIXME: Handle progress in a more sane way
+- pklog.info("Upgrading system")
+- self.StatusChanged(STATUS_UPDATE)
+- self.AllowCancel(False)
+- self.PercentageChanged(0)
+- self._check_init(prange=(0,5))
+- try:
+- self._cache.upgrade(distUpgrade=True)
+- self._cache.commit(PackageKitFetchProgress(self, prange=(5,50)),
+- PackageKitInstallProgress(self, prange=(50,95)))
+- except apt.cache.FetchFailedException:
+- self._open_cache()
+- self.ErrorCode(ERROR_PACKAGE_DOWNLOAD_FAILED, "Download failed")
+- self.Finished(EXIT_FAILED)
+- return
+- except apt.cache.FetchCancelledException:
+- self._open_cache(prange=(95,100))
+- self.ErrorCode(ERROR_TRANSACTION_CANCELLED, "Download was canceled")
+- self.Finished(EXIT_KILL)
+- self._canceled.clear()
+- return
+- except:
+- self._open_cache(prange=(95,100))
+- self.ErrorCode(ERROR_UNKNOWN, "System update failed")
+- self.Finished(EXIT_FAILED)
+- return
+- self.PercentageChanged(100)
+- self.Finished(EXIT_SUCCESS)
+-
+- @threaded
+- @locked
+- def doRemovePackages(self, ids, deps=True, auto=False):
+- '''
+- Implement the {backend}-remove functionality
+- '''
+- #FIXME: Handle progress in a more sane way
+- pklog.info("Removing package with id %s" % id)
+- self.StatusChanged(STATUS_REMOVE)
+- self.AllowCancel(False)
+- self.PercentageChanged(0)
+- self._check_init(prange=(0,10))
+- pkg = self._find_package_by_id(id)
+- if pkg == None:
+- self.ErrorCode(ERROR_PACKAGE_NOT_FOUND,
+- "Package %s isn't available" % pkg.name)
+- self.Finished(EXIT_FAILED)
+- return
+- if not pkg.isInstalled:
+- self.ErrorCode(ERROR_PACKAGE_NOT_INSTALLED,
+- "Package %s isn't installed" % pkg.name)
+- self.Finished(EXIT_FAILED)
+- return
+- name = pkg.name[:]
+- try:
+- pkg.markDelete()
+- self._cache.commit(PackageKitFetchProgress(self, prange=(10,10)),
+- PackageKitInstallProgress(self, prange=(10,90)))
+- except:
+- self._open_cache(prange=(90,100))
+- self.ErrorCode(ERROR_UNKNOWN, "Removal failed")
+- self.Finished(EXIT_FAILED)
+- return
+- self._open_cache(prange=(90,100))
+- self.PercentageChanged(100)
+- if not self._cache.has_key(name) or not self._cache[name].isInstalled:
+- self.Finished(EXIT_SUCCESS)
+- else:
+- self.ErrorCode(ERROR_UNKNOWN, "Package is still installed")
+- self.Finished(EXIT_FAILED)
+-
+- @threaded
+- @locked
+- def doInstallPackages(self, ids):
+- '''
+- Implement the {backend}-install functionality
+- '''
+- #FIXME: Handle progress in a more sane way
+- pklog.info("Installing package with id %s" % id)
+- self.StatusChanged(STATUS_INSTALL)
+- self.AllowCancel(False)
+- self.PercentageChanged(0)
+- self._check_init(prange=(0,10))
+- pkg = self._find_package_by_id(id)
+- if pkg == None:
+- self.ErrorCode(ERROR_PACKAGE_NOT_FOUND,
+- "Package %s isn't available" % pkg.name)
+- self.Finished(EXIT_FAILED)
+- return
+- if pkg.isInstalled:
+- self.ErrorCode(ERROR_PACKAGE_ALREADY_INSTALLED,
+- "Package %s is already installed" % pkg.name)
+- self.Finished(EXIT_FAILED)
+- return
+- name = pkg.name[:]
+- try:
+- pkg.markInstall()
+- self._cache.commit(PackageKitFetchProgress(self, prange=(10,50)),
+- PackageKitInstallProgress(self, prange=(50,90)))
+- except:
+- self._open_cache(prange=(90,100))
+- self.ErrorCode(ERROR_UNKNOWN, "Installation failed")
+- self.Finished(EXIT_FAILED)
+- return
+- self._open_cache(prange=(90,100))
+- self.PercentageChanged(100)
+- if self._cache.has_key(name) and self._cache[name].isInstalled:
+- self.Finished(EXIT_SUCCESS)
+- else:
+- self.ErrorCode(ERROR_UNKNOWN, "Installation failed")
+- self.Finished(EXIT_FAILED)
+-
+- @threaded
+- @locked
+- def doRefreshCache(self, force):
+- '''
+- Implement the {backend}-refresh_cache functionality
+- '''
+- pklog.info("Refresh cache")
+- self.StatusChanged(STATUS_REFRESH_CACHE)
+- self.last_action_time = time.time()
+- self.AllowCancel(False);
+- self.PercentageChanged(0)
+- self._check_init((0,10))
+- try:
+- self._cache.update(PackageKitFetchProgress(self, prange=(10,95)))
+- except apt.cache.FetchFailedException:
+- self.ErrorCode(ERROR_NO_NETWORK, "Download failed")
+- self.Finished(EXIT_FAILED)
+- return
+- except apt.cache.FetchCancelledException:
+- self._canceled.clear()
+- self.ErrorCode(ERROR_TRANSACTION_CANCELLED, "Download was canceled")
+- self.Finished(EXIT_KILL)
+- return
+- except:
+- self._open_cache(prange=(95,100))
+- self.ErrorCode(ERROR_UNKNOWN, "Refreshing cache failed")
+- self.Finished(EXIT_FAILED)
+- return
+- self.PercentageChanged(100)
+- self.Finished(EXIT_SUCCESS)
+-
+- # Helpers
+-
+- def _open_cache(self, prange=(0,100), progress=True):
+- '''
+- (Re)Open the APT cache
+- '''
+- pklog.debug("Open APT cache")
+- self.StatusChanged(STATUS_REFRESH_CACHE)
+- try:
+- self._cache = apt.Cache(PackageKitOpProgress(self, prange,
+- progress))
+- except:
+- self.ErrorCode(ERROR_NO_CACHE, "Package cache could not be opened")
+- self.Finished(EXIT_FAILED)
+- self.Exit()
+- return
+- if self._cache._depcache.BrokenCount > 0:
+- self.ErrorCode(ERROR_DEP_RESOLUTION_FAILED,
+- "Not all dependecies can be satisfied")
+- self.Finished(EXIT_FAILED)
+- self.Exit()
+- return
+-
+- def _lock_cache(self):
+- '''
+- Lock the cache
+- '''
+- pklog.debug("Locking cache")
+- self._locked.acquire()
+-
+- def _unlock_cache(self):
+- '''
+- Unlock the cache
+- '''
+- pklog.debug("Releasing cache")
+- self._locked.release()
+-
+- def _check_init(self, prange=(0,10), progress=True):
+- '''
+- Check if the backend was initialized well and try to recover from
+- a broken setup
+- '''
+- pklog.debug("Check apt cache and xapian database")
+- if not isinstance(self._cache, apt.cache.Cache) or \
+- self._cache._depcache.BrokenCount > 0:
+- self._open_cache(prange, progress)
+-
+- def _check_canceled(self, msg):
+- '''
+- Check if the current transaction was canceled. If so send the
+- corresponding error message and return True
+- '''
+- if self._canceled.isSet():
+- self.ErrorCode(ERROR_TRANSACTION_CANCELLED, msg)
+- self.Finished(EXIT_KILL)
+- self._canceled.clear()
+- return True
+- return False
+-
+- def get_id_from_package(self, pkg, installed=False):
+- '''
+- Return the id of the installation candidate of a core
+- apt package. If installed is set to True the id of the currently
+- installed package will be returned.
+- '''
+- origin = ''
+- if installed == False and pkg.isInstalled:
+- pkgver = pkg.installedVersion
+- else:
+- pkgver = pkg.candidateVersion
+- if pkg.candidateOrigin:
+- origin = pkg.candidateOrigin[0].label
+- id = self._get_package_id(pkg.name, pkgver, pkg.architecture, origin)
+- return id
+-
+- def _emit_package(self, pkg):
+- '''
+- Send the Package signal for a given apt package
+- '''
+- id = self.get_id_from_package(pkg)
+- if pkg.isInstalled:
+- status = INFO_INSTALLED
+- else:
+- status = INFO_AVAILABLE
+- summary = pkg.summary
+- self.Package(status, id, summary)
+-
+- def _is_package_visible(self, pkg, filters):
+- '''
+- Return True if the package should be shown in the user interface
+- '''
+- #FIXME: Needs to be optmized
+- if filters == 'none':
+- return True
+- if FILTER_INSTALLED in filters and not pkg.isInstalled:
+- return False
+- if FILTER_NOT_INSTALLED in filters and pkg.isInstalled:
+- return False
+- if FILTER_GUI in filters and not self._package_has_gui(pkg):
+- return False
+- if FILTER_NOT_GUI in filters and self._package_has_gui(pkg):
+- return False
+- if FILTER_DEVELOPMENT in filters and not self._package_is_devel(pkg):
+- return False
+- if FILTER_NOT_DEVELOPMENT in filters and self._package_is_devel(pkg):
+- return False
+- return True
+-
+- def _package_has_gui(self, pkg):
+- #FIXME: should go to a modified Package class
+- #FIXME: take application data into account. perhaps checking for
+- # property in the xapian database
+- return pkg.section.split('/')[-1].lower() in ['x11', 'gnome', 'kde']
+-
+- def _package_is_devel(self, pkg):
+- #FIXME: should go to a modified Package class
+- return pkg.name.endswith("-dev") or pkg.name.endswith("-dbg") or \
+- pkg.section.split('/')[-1].lower() in ['devel', 'libdevel']
+-
+- def _find_package_by_id(self, id):
+- '''
+- Return a package matching to the given package id
+- '''
+- # FIXME: Perform more checks
+- name, version, arch, data = self.get_package_from_id(id)
+- if self._cache.has_key(name):
+- return self._cache[name]
+- else:
+- return None
+-
+-
+-def main():
+- loop = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+- bus = dbus.SystemBus(mainloop=loop)
+- bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, bus=bus)
+- manager = PackageKitAptBackend(bus_name, PACKAGEKIT_DBUS_PATH)
+-
+-if __name__ == '__main__':
+- main()
+-
+-# vim: ts=4 et sts=4
+diff --git a/backends/apt2/pk-backend-apt2.c b/backends/apt2/pk-backend-apt2.c
+deleted file mode 100644
+index 4f78ec4..0000000
+--- a/backends/apt2/pk-backend-apt2.c
++++ /dev/null
+@@ -1,204 +0,0 @@
+-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+- *
+- * Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
+- * Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
+- *
+- * Licensed under the GNU General Public License Version 2
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+- */
+-
+-#include <pk-backend.h>
+-#include <pk-backend-dbus.h>
+-
+-static PkBackendDbus *dbus;
+-
+-#define PK_DBUS_BACKEND_SERVICE_APT "org.freedesktop.PackageKitAptBackend"
+-
+-/**
+- * backend_initialize:
+- * This should only be run once per backend load, i.e. not every transaction
+- */
+-static void
+-backend_initialize (PkBackend *backend)
+-{
+- pk_debug ("FILTER: initialize");
+- dbus = pk_backend_dbus_new ();
+- pk_backend_dbus_set_name (dbus, PK_DBUS_BACKEND_SERVICE_APT);
+-}
+-
+-/**
+- * backend_destroy:
+- * This should only be run once per backend load, i.e. not every transaction
+- */
+-static void
+-backend_destroy (PkBackend *backend)
+-{
+- pk_debug ("FILTER: destroy");
+- pk_backend_dbus_kill (dbus);
+- g_object_unref (dbus);
+-}
+-
+-/**
+- * backend_get_groups:
+- */
+-static PkGroupEnum
+-backend_get_groups (PkBackend *backend)
+-{
+- return (PK_GROUP_ENUM_ACCESSORIES |
+- PK_GROUP_ENUM_GAMES |
+- PK_GROUP_ENUM_GRAPHICS |
+- PK_GROUP_ENUM_INTERNET |
+- PK_GROUP_ENUM_OFFICE |
+- PK_GROUP_ENUM_OTHER |
+- PK_GROUP_ENUM_PROGRAMMING |
+- PK_GROUP_ENUM_MULTIMEDIA |
+- PK_GROUP_ENUM_SYSTEM);
+-}
+-
+-/**
+- * backend_get_filters:
+- */
+-static PkFilterEnum
+-backend_get_filters (PkBackend *backend)
+-{
+- return (PK_FILTER_ENUM_GUI |
+- PK_FILTER_ENUM_INSTALLED |
+- PK_FILTER_ENUM_DEVELOPMENT);
+-}
+-
+-/**
+- * backend_get_updates:
+- */
+-static void
+-backend_get_updates (PkBackend *backend, PkFilterEnum filters)
+-{
+- pk_backend_dbus_get_updates (dbus, filters);
+-}
+-
+-/**
+- * backend_refresh_cache:
+- * */
+-static void
+-backend_refresh_cache (PkBackend *backend, gboolean force)
+-{
+- // check network state
+- if (!pk_backend_is_online (backend)) {
+- pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot refresh cache whilst offline");
+- pk_backend_finished (backend);
+- return;
+- }
+-
+- pk_backend_dbus_refresh_cache(dbus, force);
+-}
+-
+-/**
+- * pk_backend_update_system:
+- * */
+-static void
+-backend_update_system (PkBackend *backend)
+-{
+- pk_backend_dbus_update_system (dbus);
+-}
+-
+-/**
+- * backend_install_packages
+- * */
+-static void
+-backend_install_packages (PkBackend *backend, gchar **package_ids)
+-{
+- pk_backend_dbus_install_packages (dbus, package_ids);
+-}
+-
+-/**
+- * backend_remove_packages
+- * */
+-static void
+-backend_remove_packages (PkBackend *backend, gchar **package_ids, gboolean allow_deps, gboolean autoremove)
+-{
+- pk_backend_dbus_remove_packages (dbus, package_ids, allow_deps, autoremove);
+-}
+-
+-/**
+- * backend_get_details:
+- * */
+-static void
+-backend_get_details (PkBackend *backend, const gchar *package_id)
+-{
+- pk_backend_dbus_get_details (dbus, package_id);
+-}
+-
+-/**
+- * * pk_backend_search_details:
+- * */
+-static void
+-backend_search_details (PkBackend *backend, PkFilterEnum filters, const gchar *search)
+-{
+- pk_backend_dbus_search_details (dbus, filters, search);
+-}
+-
+-/**
+- * * pk_backend_search_name:
+- * */
+-static void
+-backend_search_name (PkBackend *backend, PkFilterEnum filters, const gchar *search)
+-{
+- pk_backend_dbus_search_name (dbus, filters, search);
+-}
+-
+-/**
+- * * pk_backend_cancel:
+- * */
+-static void
+-backend_cancel (PkBackend *backend)
+-{
+- pk_backend_dbus_cancel (dbus);
+-}
+-
+-
+-PK_BACKEND_OPTIONS (
+- "Apt", /* description */
+- "Ali Sabil <ali.sabil@gmail.com>; Tom Parker <palfrey@tevp.net>; Sebastian Heinlein <glatzor@ubuntu.com>", /* author */
+- backend_initialize, /* initalize */
+- backend_destroy, /* destroy */
+- backend_get_groups, /* get_groups */
+- backend_get_filters, /* get_filters */
+- backend_cancel, /* cancel */
+- NULL, /* get_depends */
+- backend_get_details, /* get_details */
+- NULL, /* get_files */
+- NULL, /* get_packages */
+- NULL, /* get_repo_list */
+- NULL, /* get_requires */
+- NULL, /* get_update_detail */
+- backend_get_updates, /* get_updates */
+- NULL, /* install_files */
+- backend_install_packages, /* install_packages */
+- NULL, /* install_signature */
+- backend_refresh_cache, /* refresh_cache */
+- backend_remove_packages, /* remove_packages */
+- NULL, /* repo_enable */
+- NULL, /* repo_set_data */
+- NULL, /* resolve */
+- NULL, /* rollback */
+- backend_search_details, /* search_details */
+- NULL, /* search_file */
+- NULL, /* search_group */
+- backend_search_name, /* search_name */
+- NULL, /* service_pack */
+- NULL, /* update_packages */
+- backend_update_system, /* update_system */
+- NULL /* what_provides */
+-);
+diff --git a/backends/apt2/profiler.py b/backends/apt2/profiler.py
+deleted file mode 100644
+index 1b5d30f..0000000
+--- a/backends/apt2/profiler.py
++++ /dev/null
+@@ -1,40 +0,0 @@
+-#!/usr/bin/env python
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+-# Copyright (C) 2008
+-# Sebastian Heinlein <sebi@glatzor.de>
+-
+-"""
+-Allows to start the apt2 backend in a profling mode
+-"""
+-
+-__author__ = "Sebastian Heinlein <devel@glatzor.de>"
+-
+-
+-import hotshot
+-import sys
+-
+-from aptDBUSBackend import main
+-
+-if len(sys.argv) == 2:
+- profile = sys.argv[1]
+-else:
+- profile = "profile"
+-
+-prof = hotshot.Profile(profile)
+-print prof.runcall(main)
+-prof.close()
+diff --git a/backends/apt2/test.py b/backends/apt2/test.py
+deleted file mode 100755
+index a1d5ffb..0000000
+--- a/backends/apt2/test.py
++++ /dev/null
+@@ -1,98 +0,0 @@
+-#!/usr/bin/python
+-# Licensed under the GNU General Public License Version 2
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+-
+-# Copyright (C) 2007
+-# Tim Lauridsen <timlau@fedoraproject.org>
+-
+-import sys
+-import dbus
+-from packagekit.enums import *
+-
+-PACKAGEKIT_DBUS_SERVICE = 'org.freedesktop.PackageKitAptBackend'
+-PACKAGEKIT_DBUS_INTERFACE = 'org.freedesktop.PackageKitBackend'
+-PACKAGEKIT_DBUS_PATH = '/org/freedesktop/PackageKitBackend'
+-PKG_ID = 'xterm;232-1;i386;Debian'
+-
+-try:
+- bus = dbus.SystemBus()
+-except dbus.DBusException, e:
+- print "Unable to connect to dbus"
+- print "%s" %(e,)
+- sys.exit(1)
+-
+-try:
+- proxy = bus.get_object(PACKAGEKIT_DBUS_SERVICE, PACKAGEKIT_DBUS_PATH)
+- iface = dbus.Interface(proxy, PACKAGEKIT_DBUS_INTERFACE)
+- cmd = sys.argv[1]
+- if cmd == 'init' or cmd == 'all':
+- print "Testing Init()"
+- iface.Init()
+- if cmd == 'cancel':
+- print "Canceling"
+- iface.Cancel()
+- if cmd == 'get-updates' or cmd == 'all':
+- print "Testing GetUpdate()"
+- iface.GetUpdates()
+- if cmd == 'search-name' or cmd == 'all':
+- print "Testing SearchName(FILTER_NONE,'apt')"
+- iface.SearchName(FILTER_NONE,'apt')
+- if cmd == 'search-details' or cmd == 'all':
+- print "SearchDetails(FILTER_NONE,'dbus')"
+- iface.SearchDetails(FILTER_NONE,'dbus')
+- if cmd == 'search-group' or cmd == 'all':
+- print "Testing SearchGroup(FILTER_NONE,GROUP_GAMES)"
+- iface.SearchGroup(FILTER_NONE,GROUP_GAMES)
+- if cmd == 'search-file' or cmd == 'all':
+- print "Testing SearchFile(FILTER_NONE,'/usr/bin/yum')"
+- iface.SearchFile(FILTER_NONE,'/usr/bin/yum')
+- if cmd == 'get-requires' or cmd == 'all':
+- print "Testing GetRequires(PKG_ID,False)"
+- iface.GetRequires(PKG_ID,False)
+- if cmd == 'get-depends' or cmd == 'all':
+- print "Testing GetDepends(PKG_ID,False)"
+- iface.GetDepends(PKG_ID,False)
+- if cmd == 'refresh-cache' or cmd == 'all':
+- print "Testing RefreshCache()"
+- iface.RefreshCache()
+- if cmd == 'resolve' or cmd == 'all':
+- print "Testing Resolve(FILTER_NONE,'yum')"
+- iface.Resolve(FILTER_NONE,'yum')
+- if cmd == 'get-details' or cmd == 'all':
+- print "Testing GetDetails(PKG_ID)"
+- iface.GetDetails(PKG_ID)
+- if cmd == 'get-files' or cmd == 'all':
+- print "Testing GetFiles(PKG_ID)"
+- iface.GetFiles(PKG_ID)
+- if cmd == 'get-packages' or cmd == 'all':
+- print "Testing GetPackages(FILTER_INSTALLED,'no')"
+- iface.GetPackages(FILTER_INSTALLED,'no')
+- if cmd == 'get-repolist' or cmd == 'all':
+- print "Testing GetRepoList()"
+- iface.GetRepoList()
+- if cmd == 'get-updatedetail' or cmd == 'all':
+- print "Testing GetUpdateDetail(PKG_ID)"
+- iface.GetUpdateDetail(PKG_ID)
+- #print "Testing "
+- #iface.
+- if cmd == 'exit' or cmd == 'all':
+- print "Testing Exit()"
+- iface.Exit()
+-
+-except dbus.DBusException, e:
+- print "Unable to send message on dbus"
+- print "%s" %(e,)
+- sys.exit(1)
+diff --git a/backends/dummy/pk-backend-dummy.c b/backends/dummy/pk-backend-dummy.c
+index 2df445e..5714e9f 100644
+--- a/backends/dummy/pk-backend-dummy.c
++++ b/backends/dummy/pk-backend-dummy.c
+@@ -187,6 +187,7 @@ backend_get_update_detail_timeout (gpointer data)
+ "", PK_RESTART_ENUM_NONE, "Update to newest upstream source");
+ } else if (pk_strequal (_package_id, "kernel;2.6.23-0.115.rc3.git1.fc8;i386;installed")) {
+ pk_backend_update_detail (backend, "kernel;2.6.23-0.115.rc3.git1.fc8;i386;available",
++ "kernel;2.6.22-0.104.rc3.git6.fc8;i386;installed^"
+ "kernel;2.6.22-0.105.rc3.git7.fc8;i386;installed", "",
+ "http://www.distro-update.org/page?moo;Bugfix release for kernel",
+ "http://bgzilla.fd.org/result.php?#12344;Freedesktop Bugzilla #12344;"
+@@ -199,7 +200,11 @@ backend_get_update_detail_timeout (gpointer data)
+ "http://www.distro-update.org/page?moo;Bugfix release for gtkhtml",
+ "http://bgzilla.gnome.org/result.php?#9876;GNOME Bugzilla #9876",
+ NULL,
+- PK_RESTART_ENUM_SESSION, "Update to latest whizz bang version");
++ PK_RESTART_ENUM_SESSION,
++ "Update to latest whizz bang version\n"
++ "* support this new thing\n"
++ "* something else\n"
++ "- and that new thing");
+ } else {
+ pk_backend_message (backend, PK_MESSAGE_ENUM_DAEMON, "Got unexpected package_id '%s'", _package_id);
+ }
+diff --git a/backends/opkg/pk-backend-opkg.c b/backends/opkg/pk-backend-opkg.c
+index 7649bab..2d70108 100644
+--- a/backends/opkg/pk-backend-opkg.c
++++ b/backends/opkg/pk-backend-opkg.c
+@@ -115,6 +115,39 @@ opkg_check_tag (opkg_package_t *pkg, gchar *tag)
+ return FALSE;
+ }
+
++static void
++handle_install_error (PkBackend *backend, int err)
++{
++ switch (err)
++ {
++ case OPKG_NO_ERROR:
++ break;
++ case OPKG_PACKAGE_NOT_INSTALLED:
++ pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_NOT_INSTALLED, NULL);
++ break;
++ case OPKG_PACKAGE_ALREADY_INSTALLED:
++ pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_ALREADY_INSTALLED, NULL);
++ break;
++ case OPKG_GPG_ERROR:
++ pk_backend_error_code (backend, PK_ERROR_ENUM_GPG_FAILURE, NULL);
++ break;
++ case OPKG_DOWNLOAD_FAILED:
++ pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_DOWNLOAD_FAILED, NULL);
++ break;
++ case OPKG_DEPENDENCIES_FAILED:
++ pk_backend_error_code (backend, PK_ERROR_ENUM_DEP_RESOLUTION_FAILED, NULL);
++ break;
++ case OPKG_MD5_ERROR:
++ pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_CORRUPT, NULL);
++ break;
++ case OPKG_PACKAGE_NOT_AVAILABLE:
++ pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, NULL);
++ break;
++ default:
++ opkg_unknown_error (backend, err, "Update package");
++ }
++}
++
+ /**
+ * backend_initialize:
+ */
+@@ -387,22 +420,9 @@ backend_install_packages_thread (PkBackend *backend)
+ pi = pk_package_id_new_from_string (package_ids[0]);
+
+ err = opkg_install_package (opkg, pi->name, pk_opkg_progress_cb, backend);
+- switch (err)
+- {
+- case OPKG_NO_ERROR:
+- break;
+- case OPKG_DEPENDANCIES_FAILED:
+- pk_backend_error_code (backend, PK_ERROR_ENUM_DEP_RESOLUTION_FAILED, NULL);
+- break;
+- case OPKG_PACKAGE_ALREADY_INSTALLED:
+- pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_ALREADY_INSTALLED, NULL);
+- break;
+- case OPKG_PACKAGE_NOT_AVAILABLE:
+- pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, NULL);
+- break;
+- default:
+- opkg_unknown_error (backend, err, "Install");
+- }
++ if (err)
++ handle_install_error (backend, err);
++
+ pk_package_id_free (pi);
+ if (err != 0)
+ break;
+@@ -551,16 +571,9 @@ backend_update_package_thread (PkBackend *backend)
+ }
+
+ err = opkg_upgrade_package (opkg, pi->name, pk_opkg_progress_cb, backend);
+- switch (err)
+- {
+- case OPKG_NO_ERROR:
+- break;
+- case OPKG_PACKAGE_NOT_INSTALLED:
+- pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_NOT_INSTALLED, NULL);
+- break;
+- default:
+- opkg_unknown_error (backend, err, "Update package");
+- }
++ if (err)
++ handle_install_error (backend, err);
++
+
+ pk_package_id_free (pi);
+ pk_backend_finished (backend);
+diff --git a/backends/poldek/pk-backend-poldek.c b/backends/poldek/pk-backend-poldek.c
+index fdc99d3..2691414 100644
+--- a/backends/poldek/pk-backend-poldek.c
++++ b/backends/poldek/pk-backend-poldek.c
+@@ -53,7 +53,33 @@ enum {
+ SEARCH_ENUM_NAME,
+ SEARCH_ENUM_GROUP,
+ SEARCH_ENUM_DETAILS,
+- SEARCH_ENUM_FILE
++ SEARCH_ENUM_FILE,
++ SEARCH_ENUM_PROVIDES
++};
++
++typedef struct {
++ PkGroupEnum group;
++ const gchar *regex;
++} PLDGroupRegex;
++
++static PLDGroupRegex group_perlre[] = {
++ {PK_GROUP_ENUM_ACCESSORIES, "/.*Archiving\\|.*Dictionaries/"},
++ {PK_GROUP_ENUM_ADMIN_TOOLS, "/.*Databases.*\\|.*Admin/"},
++ {PK_GROUP_ENUM_COMMUNICATION, "/.*Communications/"},
++ {PK_GROUP_ENUM_EDUCATION, "/.*Engineering\\|.*Math\\|.*Science/"},
++ {PK_GROUP_ENUM_FONTS, "/Fonts/"},
++ {PK_GROUP_ENUM_GAMES, "/.*Games.*/"},
++ {PK_GROUP_ENUM_GRAPHICS, "/.*Graphics/"},
++ {PK_GROUP_ENUM_LOCALIZATION, "/I18n/"},
++ {PK_GROUP_ENUM_MULTIMEDIA, "/.*Multimedia\\|.*Sound/"},
++ {PK_GROUP_ENUM_NETWORK, "/.*Networking.*\\|/.*Mail\\|.*News\\|.*WWW/"},
++ {PK_GROUP_ENUM_OFFICE, "/.*Editors.*\\|.*Spreadsheets/"},
++ {PK_GROUP_ENUM_OTHER, "/^Applications$\\|.*Console\\|.*Emulators\\|.*File\\|.*Printing\\|.*Terminal\\|.*Text\\|Documentation\\|^Libraries.*\\|^Themes.*\\|^X11$\\|.*Amusements\\|^X11\\/Applications$\\|^X11\\/Libraries$\\|.*Window\\ Managers.*/"},
++ {PK_GROUP_ENUM_PROGRAMMING, "/.*Development.*/"},
++ {PK_GROUP_ENUM_PUBLISHING, "/.*Publishing.*/"},
++ {PK_GROUP_ENUM_SERVERS, "/Daemons\\|.*Servers/"},
++ {PK_GROUP_ENUM_SYSTEM, "/.*Shells\\|.*System\\|Base.*/"},
++ {0, NULL}
+ };
+
+ typedef struct {
+@@ -501,6 +527,79 @@ poldek_pkg_set_installed (struct pkg *pkg, gboolean installed) {
+ }
+
+ /**
++ * pld_group_to_enum:
++ *
++ * Converts PLD RPM group to PkGroupEnum.
++ **/
++static PkGroupEnum
++pld_group_to_enum (const gchar *group)
++{
++ g_return_val_if_fail (group != NULL, PK_GROUP_ENUM_OTHER);
++
++ if (strstr (group, "Archiving") != NULL ||
++ strstr (group, "Dictionaries") != NULL)
++ return PK_GROUP_ENUM_ACCESSORIES;
++ else if (strstr (group, "Databases") != NULL ||
++ strstr (group, "Admin") != NULL)
++ return PK_GROUP_ENUM_ADMIN_TOOLS;
++ else if (strstr (group, "Communications") != NULL)
++ return PK_GROUP_ENUM_COMMUNICATION;
++ else if (strstr (group, "Engineering") != NULL ||
++ strstr (group, "Math") != NULL ||
++ strstr (group, "Science") != NULL)
++ return PK_GROUP_ENUM_EDUCATION;
++ else if (strcmp (group, "Fonts") == 0)
++ return PK_GROUP_ENUM_FONTS;
++ else if (strstr (group, "Games") != NULL)
++ return PK_GROUP_ENUM_GAMES;
++ else if (strstr (group, "Graphics") != NULL)
++ return PK_GROUP_ENUM_GRAPHICS;
++ else if (strcmp (group, "I18n") == 0)
++ return PK_GROUP_ENUM_LOCALIZATION;
++ else if (strstr (group, "Multimedia") != NULL ||
++ strstr (group, "Sound") != NULL)
++ return PK_GROUP_ENUM_MULTIMEDIA;
++ else if (strstr (group, "Networking") != NULL ||
++ strstr (group, "Mail") != NULL ||
++ strstr (group, "News") != NULL ||
++ strstr (group, "WWW") != NULL)
++ return PK_GROUP_ENUM_NETWORK;
++ else if (strstr (group, "Editors") != NULL ||
++ strstr (group, "Spreadsheets") != NULL)
++ return PK_GROUP_ENUM_OFFICE;
++ else if (strstr (group, "Development") != NULL)
++ return PK_GROUP_ENUM_PROGRAMMING;
++ else if (strstr (group, "Publishing") != NULL)
++ return PK_GROUP_ENUM_PUBLISHING;
++ else if (strstr (group, "Daemons") != NULL ||
++ strstr (group, "Servers") != NULL)
++ return PK_GROUP_ENUM_SERVERS;
++ else if (strstr (group, "Shells") != NULL ||
++ strstr (group, "System") != NULL ||
++ strstr (group, "Base") != NULL)
++ return PK_GROUP_ENUM_SYSTEM;
++ else
++ return PK_GROUP_ENUM_OTHER;
++}
++
++/**
++ * pld_group_get_regex_from_enum:
++ **/
++static const gchar*
++pld_group_get_regex_from_enum (PkGroupEnum value)
++{
++ gint i;
++
++ for (i = 0;; i++) {
++ if (group_perlre[i].regex == NULL)
++ return NULL;
++
++ if (group_perlre[i].group == value)
++ return group_perlre[i].regex;
++ }
++}
++
++/**
+ * poldek_pkg_evr:
+ */
+ static gchar*
+@@ -916,7 +1015,8 @@ poldek_pkg_is_gui (struct pkg *pkg)
+ static gboolean
+ search_package_thread (PkBackend *backend)
+ {
+- PkFilterEnum filters;
++ PkFilterEnum filters;
++ PkProvidesEnum provides;
+ gchar *search_cmd = NULL;
+ struct poclidek_rcmd *cmd = NULL;
+ const gchar *search;
+@@ -930,30 +1030,38 @@ search_package_thread (PkBackend *backend)
+ search = pk_backend_get_string (backend, "search");
+ filters = pk_backend_get_uint (backend, "filters");
+
+- switch (mode) {
+- /* GetPackages */
+- case SEARCH_ENUM_NONE:
+- search_cmd = g_strdup ("ls -q");
+- break;
+- /* SearchName */
+- case SEARCH_ENUM_NAME:
+- search_cmd = g_strdup_printf ("ls -q *%s*", search);
+- break;
+- /* SearchGroup */
+- case SEARCH_ENUM_GROUP:
+- search_cmd = g_strdup_printf ("search -qg *%s*", search);
+- break;
+- /* SearchDetails */
+- case SEARCH_ENUM_DETAILS:
+- search_cmd = g_strdup_printf ("search -dsq *%s*", search);
+- break;
+- /* SearchFile */
+- case SEARCH_ENUM_FILE:
+- search_cmd = g_strdup_printf ("search -qlf *%s*", search);
+- break;
+- default:
+- /* Error */
+- break;
++ /* GetPackages*/
++ if (mode == SEARCH_ENUM_NONE) {
++ search_cmd = g_strdup ("ls -q");
++ /* SearchName */
++ } else if (mode == SEARCH_ENUM_NAME) {
++ search_cmd = g_strdup_printf ("ls -q *%s*", search);
++ /* SearchGroup */
++ } else if (mode == SEARCH_ENUM_GROUP) {
++ PkGroupEnum group;
++ const gchar *regex;
++
++ group = pk_group_enum_from_text (search);
++ regex = pld_group_get_regex_from_enum (group);
++
++ search_cmd = g_strdup_printf ("search -qg --perlre %s", regex);
++ /* SearchDetails */
++ } else if (mode == SEARCH_ENUM_DETAILS) {
++ search_cmd = g_strdup_printf ("search -dsq *%s*", search);
++ /* SearchFile */
++ } else if (mode == SEARCH_ENUM_FILE) {
++ search_cmd = g_strdup_printf ("search -qlf *%s*", search);
++ /* WhatProvides */
++ } else if (mode == SEARCH_ENUM_PROVIDES) {
++ provides = pk_backend_get_uint (backend, "provides");
++
++ if (provides == PK_PROVIDES_ENUM_ANY) {
++ search_cmd = g_strdup_printf ("search -qp %s", search);
++ } else if (provides == PK_PROVIDES_ENUM_MODALIAS) {
++ } else if (provides == PK_PROVIDES_ENUM_CODEC) {
++ } else if (provides == PK_PROVIDES_ENUM_MIMETYPE) {
++ search_cmd = g_strdup_printf ("search -qp mimetype(%s)", search);
++ }
+ }
+
+ if (cmd != NULL && search_cmd)
+@@ -1307,6 +1415,30 @@ backend_destroy (PkBackend *backend)
+ }
+
+ /**
++ * backend_get_groups:
++ **/
++static PkGroupEnum
++backend_get_groups (PkBackend *backend)
++{
++ return (PK_GROUP_ENUM_ACCESSORIES |
++ PK_GROUP_ENUM_ADMIN_TOOLS |
++ PK_GROUP_ENUM_COMMUNICATION |
++ PK_GROUP_ENUM_EDUCATION |
++ PK_GROUP_ENUM_FONTS |
++ PK_GROUP_ENUM_GAMES |
++ PK_GROUP_ENUM_GRAPHICS |
++ PK_GROUP_ENUM_LOCALIZATION |
++ PK_GROUP_ENUM_MULTIMEDIA |
++ PK_GROUP_ENUM_NETWORK |
++ PK_GROUP_ENUM_OFFICE |
++ PK_GROUP_ENUM_OTHER |
++ PK_GROUP_ENUM_PROGRAMMING |
++ PK_GROUP_ENUM_PUBLISHING |
++ PK_GROUP_ENUM_SERVERS |
++ PK_GROUP_ENUM_SYSTEM);
++}
++
++/**
+ * backend_get_filters:
+ */
+ static PkFilterEnum
+@@ -1398,14 +1530,17 @@ backend_get_details_thread (PkBackend *backend)
+ if (pkg)
+ {
+ struct pkguinf *pkgu = NULL;
++ PkGroupEnum group;
+
+ pkgu = pkg_uinf (pkg);
+
++ group = pld_group_to_enum (pkg_group (pkg));
++
+ if (pkgu) {
+ pk_backend_details (backend,
+ package_id,
+ pkguinf_get (pkgu, PKGUINF_LICENSE),
+- PK_GROUP_ENUM_OTHER,
++ group,
+ pkguinf_get (pkgu, PKGUINF_DESCRIPTION),
+ pkguinf_get (pkgu, PKGUINF_URL),
+ pkg->size);
+@@ -1414,7 +1549,7 @@ backend_get_details_thread (PkBackend *backend)
+ pk_backend_details (backend,
+ package_id,
+ "",
+- PK_GROUP_ENUM_OTHER,
++ group,
+ "",
+ "",
+ pkg->size);
+@@ -2213,12 +2348,26 @@ backend_get_repo_list (PkBackend *backend, PkFilterEnum filters)
+ pk_backend_finished (backend);
+ }
+
++/**
++ * backend_what_provides:
++ **/
++static void
++backend_what_provides (PkBackend *backend, PkFilterEnum filters, PkProvidesEnum provides, const gchar *search)
++{
++ pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
++ poldek_backend_set_allow_cancel (backend, TRUE, TRUE);
++ pb_error_clean ();
++
++ pk_backend_set_uint (backend, "mode", SEARCH_ENUM_PROVIDES);
++ pk_backend_thread_create (backend, search_package_thread);
++}
++
+ PK_BACKEND_OPTIONS (
+ "poldek", /* description */
+ "Marcin Banasiak <megabajt@pld-linux.org>", /* author */
+ backend_initalize, /* initalize */
+ backend_destroy, /* destroy */
+- NULL, /* get_groups */
++ backend_get_groups, /* get_groups */
+ backend_get_filters, /* get_filters */
+ backend_get_cancel, /* cancel */
+ backend_get_depends, /* get_depends */
+@@ -2245,6 +2394,6 @@ PK_BACKEND_OPTIONS (
+ NULL, /* service pack */
+ backend_update_packages, /* update_packages */
+ backend_update_system, /* update_system */
+- NULL /* what_provides */
++ backend_what_provides /* what_provides */
+ );
+
+diff --git a/backends/urpmi/.gitignore b/backends/urpmi/.gitignore
+new file mode 100644
+index 0000000..996fb0d
+--- /dev/null
++++ b/backends/urpmi/.gitignore
+@@ -0,0 +1,14 @@
++.deps
++.libs
++Makefile
++Makefile.in
++*.la
++*.lo
++*.loT
++*.o
++*~
++*.gcov
++*.gcda
++*.gcno
++*.out
++
+diff --git a/backends/urpmi/Makefile.am b/backends/urpmi/Makefile.am
+new file mode 100644
+index 0000000..56743a1
+--- /dev/null
++++ b/backends/urpmi/Makefile.am
+@@ -0,0 +1,11 @@
++SUBDIRS = helpers
++plugindir = $(PK_PLUGIN_DIR)
++plugin_LTLIBRARIES = libpk_backend_urpmi.la
++libpk_backend_urpmi_la_SOURCES = pk-backend-urpmi.c
++libpk_backend_urpmi_la_LIBADD = $(PK_PLUGIN_LIBS)
++libpk_backend_urpmi_la_LDFLAGS = -module -avoid-version
++libpk_backend_urpmi_la_CFLAGS = $(PK_PLUGIN_CFLAGS)
++
++clean-local:
++ rm -f *.gcno
++
+diff --git a/backends/urpmi/helpers/.gitignore b/backends/urpmi/helpers/.gitignore
+new file mode 100644
+index 0000000..2f78cf5
+--- /dev/null
++++ b/backends/urpmi/helpers/.gitignore
+@@ -0,0 +1,2 @@
++*.pyc
++
+diff --git a/backends/urpmi/helpers/Makefile.am b/backends/urpmi/helpers/Makefile.am
+new file mode 100644
+index 0000000..88f144e
+--- /dev/null
++++ b/backends/urpmi/helpers/Makefile.am
+@@ -0,0 +1,31 @@
++SUBDIRS = perl_packagekit urpmi_backend
++
++helperdir = $(datadir)/PackageKit/helpers/urpmi
++
++NULL =
++
++dist_helper_DATA = \
++ search-name.pl \
++ get-details.pl \
++ get-depends.pl \
++ get-files.pl \
++ get-updates.pl \
++ get-update-detail.pl \
++ refresh-cache.pl \
++ install-packages.pl \
++ remove-packages.pl \
++ search-group.pl \
++ get-packages.pl \
++ get-requires.pl \
++ search-details.pl \
++ search-file.pl \
++ resolve.pl \
++ update-packages.pl \
++ $(NULL)
++
++install-data-hook:
++ chmod a+rx $(DESTDIR)$(helperdir)/*.pl
++
++clean-local :
++ rm -f *~
++
+diff --git a/backends/urpmi/helpers/get-depends.pl b/backends/urpmi/helpers/get-depends.pl
+new file mode 100755
+index 0000000..bf936c5
+--- /dev/null
++++ b/backends/urpmi/helpers/get-depends.pl
+@@ -0,0 +1,85 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use URPM;
++use urpm;
++use urpm::args;
++use urpm::media;
++use urpm::select;
++
++use urpmi_backend::open_db;
++use urpmi_backend::tools;
++
++use perl_packagekit::enums;
++use perl_packagekit::prints;
++
++# Two arguments (filter, package id)
++exit if($#ARGV != 2);
++
++my @filters = split(/;/, $ARGV[0]);
++my @pkgid = split(/;/, $ARGV[1]);
++my $recursive_option = 0;
++$recursive_option = 1 if($ARGV[2] eq "yes");
++
++# Only recursive option is supported
++# So, if user set no tu recursive option,
++# backend will return error
++if(!$recursive_option) {
++ printf("error\tnot-supported\tOnly recursive option to yes is supported\n");
++ exit;
++}
++
++pk_print_status(PK_STATUS_ENUM_DEP_RESOLVE);
++
++my $urpm = urpm->new_parse_cmdline;
++urpm::media::configure($urpm);
++
++my %requested;
++my @names = (@pkgid[0]);
++my $results = urpm::select::search_packages($urpm, \%requested, \@names,
++ fuzzy => 0,
++ caseinsensitive => 0,
++ all => 0
++);
++
++exit if !$results;
++my @requested_keys = keys %requested;
++my $package_id = pop @requested_keys;
++
++my %resolv_request = ();
++%resolv_request->{$package_id} = 1;
++
++my $empty_db = new URPM;
++my $state = {};
++$urpm->resolve_requested($empty_db,
++ $state,
++ \%resolv_request,
++);
++
++my $db = open_rpm_db();
++$urpm->compute_installed_flags($db);
++
++my %selected = %{$state->{selected}};
++my @selected_keys = keys %selected;
++my @depslist = @{$urpm->{depslist}};
++
++foreach(sort {@depslist[$b]->flag_installed <=> @depslist[$a]->flag_installed} @selected_keys) {
++ my $pkg = @depslist[$_];
++ if($pkg->flag_installed) {
++ next if(grep(/^${\FILTER_NOT_INSTALLED}$/, @filters));
++ pk_print_package(INFO_INSTALLED, get_package_id($pkg), $pkg->summary);
++ }
++ else {
++ next if(grep(/^${\FILTER_INSTALLED}$/, @filters));
++ pk_print_package(INFO_AVAILABLE, get_package_id($pkg), $pkg->summary);
++ }
++}
++
+diff --git a/backends/urpmi/helpers/get-details.pl b/backends/urpmi/helpers/get-details.pl
+new file mode 100755
+index 0000000..3207e9b
+--- /dev/null
++++ b/backends/urpmi/helpers/get-details.pl
+@@ -0,0 +1,48 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::args;
++use urpm::media;
++use urpmi_backend::tools;
++use MDK::Common;
++
++use perl_packagekit::prints;
++
++# One argument (package id)
++exit if($#ARGV != 0);
++
++my $urpm = urpm->new_parse_cmdline;
++urpm::media::configure($urpm);
++
++my $pkg = get_package_by_package_id($urpm, $ARGV[0]);
++
++my $medium = pkg2medium($pkg, $urpm);
++my $xml_info = 'info';
++my $xml_info_file = urpm::media::any_xml_info($urpm, $medium, $xml_info, undef, undef);
++
++if(!$xml_info_file) {
++ pk_print_details(get_package_id($pkg), "N/A", $pkg->group, "N/A", "N/A", 0);
++ exit 0;
++}
++
++require urpm::xml_info;
++require urpm::xml_info_pkg;
++my $name = urpm_name($pkg);
++my %nodes = eval { urpm::xml_info::get_nodes($xml_info, $xml_info_file, [ $name ]) };
++my %xml_info_pkgs;
++put_in_hash($xml_info_pkgs{$name} ||= {}, $nodes{$name});
++my $description = $xml_info_pkgs{$name}{description};
++$description =~ s/\n/;/g;
++$description =~ s/\t/ /g;
++
++pk_print_details(get_package_id($pkg), "N/A", $pkg->group, ensure_utf8($description), "N/A", $pkg->size);
++
+diff --git a/backends/urpmi/helpers/get-files.pl b/backends/urpmi/helpers/get-files.pl
+new file mode 100755
+index 0000000..74ae157
+--- /dev/null
++++ b/backends/urpmi/helpers/get-files.pl
+@@ -0,0 +1,40 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::args;
++use urpm::media;
++use urpmi_backend::tools;
++use MDK::Common;
++
++use perl_packagekit::prints;
++
++# One argument (package id)
++exit if($#ARGV != 0);
++
++
++my $urpm = urpm->new_parse_cmdline;
++urpm::media::configure($urpm);
++
++my $pkg = get_package_by_package_id($urpm, $ARGV[0]);
++
++my $medium = pkg2medium($pkg, $urpm);
++my $xml_info = 'files';
++my $xml_info_file = urpm::media::any_xml_info($urpm, $medium, $xml_info, undef, undef);
++require urpm::xml_info;
++require urpm::xml_info_pkg;
++my $name = urpm_name($pkg);
++my %nodes = eval { urpm::xml_info::get_nodes($xml_info, $xml_info_file, [ $name ]) };
++my %xml_info_pkgs;
++put_in_hash($xml_info_pkgs{$name} ||= {}, $nodes{$name});
++my @files = map { chomp_($_) } split("\n", $xml_info_pkgs{$name}{files});
++
++pk_print_files(get_package_id($pkg), join(';', @files));
+diff --git a/backends/urpmi/helpers/get-packages.pl b/backends/urpmi/helpers/get-packages.pl
+new file mode 100755
+index 0000000..9e3e525
+--- /dev/null
++++ b/backends/urpmi/helpers/get-packages.pl
+@@ -0,0 +1,53 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::media;
++use urpm::args;
++
++use urpmi_backend::open_db;
++use urpmi_backend::tools;
++use urpmi_backend::filters;
++
++use perl_packagekit::enums;
++use perl_packagekit::prints;
++
++# One argument (the filter)
++exit if ($#ARGV != 0);
++my @filters = split(/;/, $ARGV[0]);
++
++my $urpm = urpm->new_parse_cmdline;
++
++urpm::media::configure($urpm);
++
++my $db = open_rpm_db();
++$urpm->compute_installed_flags($db);
++
++# Here we display installed packages
++if(not grep(/^${\FILTER_NOT_INSTALLED}$/, @filters)) {
++ $db->traverse(sub {
++ my ($pkg) = @_;
++ if(filter($pkg, \@filters, {FILTER_DEVELOPMENT => 1, FILTER_GUI => 1})) {
++ pk_print_package(INFO_INSTALLED, get_package_id($pkg), ensure_utf8($pkg->summary));
++ }
++ });
++}
++
++# Here are package which can be installed
++if(not grep(/^${\FILTER_INSTALLED}$/, @filters)) {
++ foreach my $pkg(@{$urpm->{depslist}}) {
++ if($pkg->flag_upgrade) {
++ if(filter($pkg, \@filters, {FILTER_DEVELOPMENT => 1, FILTER_GUI => 1})) {
++ pk_print_package(INFO_AVAILABLE, get_package_id($pkg), ensure_utf8($pkg->summary));
++ }
++ }
++ }
++}
+diff --git a/backends/urpmi/helpers/get-requires.pl b/backends/urpmi/helpers/get-requires.pl
+new file mode 100755
+index 0000000..0012b2a
+--- /dev/null
++++ b/backends/urpmi/helpers/get-requires.pl
+@@ -0,0 +1,54 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::args;
++use urpm::media;
++use urpm::select;
++use urpmi_backend::tools;
++use urpmi_backend::actions;
++use urpmi_backend::filters;
++use perl_packagekit::enums;
++use perl_packagekit::prints;
++
++# 3 arguments
++# (filter, packageid, and recursive option)
++exit if($#ARGV != 2);
++
++my @filters = split(/;/, $ARGV[0]);
++my $pkgid = $ARGV[1];
++my $recursive_option = 0;
++$recursive_option = 1 if($ARGV[2] eq "yes");
++
++my $urpm = urpm->new_parse_cmdline;
++urpm::media::configure($urpm);
++
++my $pkg = get_package_by_package_id($urpm, $pkgid);
++if(!$pkg) {
++ pk_print_error(PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "Requested package wasn't found");
++ exit;
++}
++# print "Checking requires of the package : ", urpm_name($pkg), "\n";
++pk_print_status(PK_STATUS_ENUM_DEP_RESOLVE);
++my @requires = perform_requires_search($urpm, $pkg, $recursive_option);
++
++foreach(@requires) {
++ if(filter($_, \@filters, { FILTER_GUI => 1, FILTER_DEVELOPMENT => 1 })) {
++ if(package_version_is_installed($_)) {
++ !grep(/^${\FILTER_NOT_INSTALLED}$/, @filters) and pk_print_package(INFO_INSTALLED, get_package_id($_), $_->summary);
++ }
++ else {
++ !grep(/^${\FILTER_INSTALLED}$/, @filters) and pk_print_package(INFO_AVAILABLE, get_package_id($_), $_->summary);
++ }
++ }
++}
++pk_print_status(PK_STATUS_ENUM_FINISHED);
++
+diff --git a/backends/urpmi/helpers/get-update-detail.pl b/backends/urpmi/helpers/get-update-detail.pl
+new file mode 100755
+index 0000000..69ea452
+--- /dev/null
++++ b/backends/urpmi/helpers/get-update-detail.pl
+@@ -0,0 +1,88 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::args;
++use urpm::media;
++use urpm::select;
++use urpmi_backend::tools;
++use urpmi_backend::open_db;
++use perl_packagekit::enums;
++use perl_packagekit::prints;
++use MDK::Common;
++
++# One argument (package id)
++exit if($#ARGV != 0);
++
++my $urpm = urpm->new_parse_cmdline;
++urpm::media::configure($urpm);
++
++my $pkg = get_package_by_package_id($urpm, @ARGV[0]);
++
++if(!$pkg) {
++ pk_print_error(PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "Requested package was not found");
++ exit;
++}
++
++my %requested;
++$requested{$pkg->id} = 1;
++
++if(!find_installed_version($pkg)) {
++ pk_print_error(PK_ERROR_ENUM_PACKAGE_NOT_INSTALLED, "The selected package isn't installed on your system");
++}
++elsif(package_version_is_installed($pkg)) {
++ pk_print_error(PK_ERROR_ENUM_PACKAGE_ALREADY_INSTALLED, "The selected package is already at the latest version");
++}
++else {
++ my $state = {};
++ my $restart = urpm::select::resolve_dependencies($urpm, $state, \%requested);
++ my %selected = %{$state->{selected}};
++ my @ask_unselect = urpm::select::unselected_packages($urpm, $state);
++ my @to_remove = urpm::select::removed_packages($urpm, $state);
++ my @to_install = @{$urpm->{depslist}}[sort { $a <=> $b } keys %{$state->{selected}}];
++ my ($src, $binary) = partition { $_->arch eq 'src' } @to_install;
++ @to_install = @$binary;
++ my $updates_descr = urpm::get_updates_description($urpm);
++ my $updesc = $updates_descr->{URPM::pkg2media($urpm->{media}, $pkg)->{name}}{$pkg->name};
++ my $desc;
++ if($updesc) {
++ $desc = $updesc->{pre};
++ $desc =~ s/\n/;/g;
++ }
++
++ my @to_upgrade_pkids;
++ foreach(@to_install) {
++ my $pkid = get_installed_version_pkid($_);
++ push @to_upgrade_pkids, $pkid if $pkid;
++ }
++
++ if($restart) {
++ pk_print_update_detail(get_package_id($pkg),
++ join("^", @to_upgrade_pkids),
++ join("^", map(fullname_to_package_id($_), @to_remove)),
++ "http://qa.mandriva.com",
++ "http://qa.mandriva.com",
++ "http://qa.mandriva.com",
++ PK_RESTART_ENUM_SYSTEM,
++ $desc);
++ }
++ else {
++ pk_print_update_detail(get_package_id($pkg),
++ join("^", @to_upgrade_pkids),
++ join("^", map(fullname_to_package_id($_), @to_remove)),
++ "http://qa.mandriva.com",
++ "http://qa.mandriva.com",
++ "http://qa.mandriva.com",
++ PK_RESTART_ENUM_APPLICATION,
++ $desc);
++ }
++
++}
+diff --git a/backends/urpmi/helpers/get-updates.pl b/backends/urpmi/helpers/get-updates.pl
+new file mode 100755
+index 0000000..02d574c
+--- /dev/null
++++ b/backends/urpmi/helpers/get-updates.pl
+@@ -0,0 +1,46 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::args;
++use urpm::media;
++use urpm::select;
++use MDK::Common;
++use urpmi_backend::tools;
++use perl_packagekit::enums;
++use perl_packagekit::prints;
++
++# On argument (filter)
++exit if($#ARGV != 0);
++# Fix me
++# Filter are to be implemented.
++
++my $urpm = urpm->new_parse_cmdline;
++urpm::media::configure($urpm);
++
++my $state = {};
++my %requested;
++my $restart = urpm::select::resolve_dependencies($urpm, $state, \%requested,
++ auto_select => 1);
++
++my %selected = %{$state->{selected} || {}};
++my @ask_unselect = urpm::select::unselected_packages($urpm, $state);
++my @to_remove = urpm::select::removed_packages($urpm, $state);
++my @to_install = @{$urpm->{depslist}}[sort { $a <=> $b } keys %{$state->{selected}}];
++my ($src, $binary) = partition { $_->arch eq 'src' } @to_install;
++@to_install = @$binary;
++
++foreach(@to_install) {
++ # Fix me
++ # Be default, we set to bugfix info type
++ # Need to be implemented, see urpmq source.
++ pk_print_package(INFO_BUGFIX, get_package_id($_), $_->summary);
++}
+diff --git a/backends/urpmi/helpers/install-packages.pl b/backends/urpmi/helpers/install-packages.pl
+new file mode 100755
+index 0000000..c9cf6c8
+--- /dev/null
++++ b/backends/urpmi/helpers/install-packages.pl
+@@ -0,0 +1,40 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::media;
++use urpm::select;
++
++use urpmi_backend::actions;
++use urpmi_backend::tools;
++
++# One argument (package id)
++exit if($#ARGV != 0);
++
++my @pkg_ids = split(/\|/, pop @ARGV);
++my @names;
++foreach(@pkg_ids) {
++ my @pkg_id = (split(/;/, $_));
++ push @names, $pkg_id[0];
++}
++
++
++my $urpm = urpm->new_parse_cmdline;
++urpm::media::configure($urpm);
++
++my %requested;
++
++urpm::select::search_packages($urpm, \%requested, \@names,
++ fuzzy => 0,
++ caseinsensitive => 0,
++ all => 0);
++
++perform_installation($urpm, \%requested);
+diff --git a/backends/urpmi/helpers/perl_packagekit/Makefile.am b/backends/urpmi/helpers/perl_packagekit/Makefile.am
+new file mode 100644
+index 0000000..6ed63b5
+--- /dev/null
++++ b/backends/urpmi/helpers/perl_packagekit/Makefile.am
+@@ -0,0 +1,12 @@
++helperdir = $(datadir)/PackageKit/helpers/urpmi/perl_packagekit/
++
++NULL =
++
++dist_helper_DATA = \
++ enums.pm \
++ prints.pm \
++ $(NULL)
++
++clean-local :
++ rm -f *~
++
+diff --git a/backends/urpmi/helpers/perl_packagekit/enums.pm b/backends/urpmi/helpers/perl_packagekit/enums.pm
+new file mode 100644
+index 0000000..8dbb4b0
+--- /dev/null
++++ b/backends/urpmi/helpers/perl_packagekit/enums.pm
+@@ -0,0 +1,293 @@
++package perl_packagekit::enums;
++
++use Exporter;
++
++our @ISA = qw(Exporter);
++our @EXPORT = qw(
++ FILTER_BASENAME
++ FILTER_DEVELOPMENT
++ FILTER_FREE
++ FILTER_GUI
++ FILTER_INSTALLED
++ FILTER_NEWEST
++ FILTER_NONE
++ FILTER_NOT_BASENAME
++ FILTER_NOT_DEVELOPMENT
++ FILTER_NOT_FREE
++ FILTER_NOT_GUI
++ FILTER_NOT_INSTALLED
++ FILTER_NOT_NEWEST
++ FILTER_NOT_SUPPORTED
++ FILTER_NOT_VISIBLE
++ FILTER_SUPPORTED
++ FILTER_UNKNOWN
++ FILTER_VISIBLE
++
++ GROUP_ACCESSIBILITY
++ GROUP_ACCESSORIES
++ GROUP_ADMIN_TOOLS
++ GROUP_COMMUNICATION
++ GROUP_DESKTOP_GNOME
++ GROUP_DESKTOP_KDE
++ GROUP_DESKTOP_OTHER
++ GROUP_DESKTOP_XFCE
++ GROUP_EDUCATION
++ GROUP_FONTS
++ GROUP_GAMES
++ GROUP_GRAPHICS
++ GROUP_INTERNET
++ GROUP_LEGACY
++ GROUP_LOCALIZATION
++ GROUP_MAPS
++ GROUP_MULTIMEDIA
++ GROUP_NETWORK
++ GROUP_OFFICE
++ GROUP_OTHER
++ GROUP_POWER_MANAGEMENT
++ GROUP_PROGRAMMING
++ GROUP_PUBLISHING
++ GROUP_REPOS
++ GROUP_SECURITY
++ GROUP_SERVERS
++ GROUP_SYSTEM
++ GROUP_UNKNOWN
++ GROUP_VIRTUALIZATION
++
++ INFO_AVAILABLE
++ INFO_BLOCKED
++ INFO_BUGFIX
++ INFO_CLEANUP
++ INFO_DOWNLOADING
++ INFO_ENHANCEMENT
++ INFO_IMPORTANT
++ INFO_INSTALLED
++ INFO_INSTALLING
++ INFO_LOW
++ INFO_NORMAL
++ INFO_OBSOLETING
++ INFO_REMOVING
++ INFO_SECURITY
++ INFO_UNKNOWN
++ INFO_UPDATING
++
++ PK_ERROR_ENUM_UNKNOWN
++ PK_ERROR_ENUM_OOM
++ PK_ERROR_ENUM_NO_CACHE
++ PK_ERROR_ENUM_NO_NETWORK
++ PK_ERROR_ENUM_NOT_SUPPORTED
++ PK_ERROR_ENUM_INTERNAL_ERROR
++ PK_ERROR_ENUM_GPG_FAILURE
++ PK_ERROR_ENUM_FILTER_INVALID
++ PK_ERROR_ENUM_PACKAGE_ID_INVALID
++ PK_ERROR_ENUM_TRANSACTION_ERROR
++ PK_ERROR_ENUM_TRANSACTION_CANCELLED
++ PK_ERROR_ENUM_PACKAGE_NOT_INSTALLED
++ PK_ERROR_ENUM_PACKAGE_NOT_FOUND
++ PK_ERROR_ENUM_PACKAGE_ALREADY_INSTALLED
++ PK_ERROR_ENUM_PACKAGE_DOWNLOAD_FAILED
++ PK_ERROR_ENUM_GROUP_NOT_FOUND
++ PK_ERROR_ENUM_GROUP_LIST_INVALID
++ PK_ERROR_ENUM_DEP_RESOLUTION_FAILED
++ PK_ERROR_ENUM_CREATE_THREAD_FAILED
++ PK_ERROR_ENUM_REPO_NOT_FOUND
++ PK_ERROR_ENUM_CANNOT_REMOVE_SYSTEM_PACKAGE
++ PK_ERROR_ENUM_PROCESS_KILL
++ PK_ERROR_ENUM_FAILED_INITIALIZATION
++ PK_ERROR_ENUM_FAILED_FINALISE
++ PK_ERROR_ENUM_FAILED_CONFIG_PARSING
++ PK_ERROR_ENUM_CANNOT_CANCEL
++ PK_ERROR_ENUM_CANNOT_GET_LOCK
++ PK_ERROR_ENUM_NO_PACKAGES_TO_UPDATE
++ PK_ERROR_ENUM_CANNOT_WRITE_REPO_CONFIG
++ PK_ERROR_ENUM_LOCAL_INSTALL_FAILED
++ PK_ERROR_ENUM_BAD_GPG_SIGNATURE
++ PK_ERROR_ENUM_MISSING_GPG_SIGNATURE
++ PK_ERROR_ENUM_CANNOT_INSTALL_SOURCE_PACKAGE
++ PK_ERROR_ENUM_REPO_CONFIGURATION_ERROR
++ PK_ERROR_ENUM_NO_LICENSE_AGREEMENT
++ PK_ERROR_ENUM_FILE_CONFLICTS
++ PK_ERROR_ENUM_REPO_NOT_AVAILABLE
++ PK_ERROR_ENUM_INVALID_PACKAGE_FILE
++ PK_ERROR_ENUM_PACKAGE_INSTALL_BLOCKED
++
++ PK_RESTART_ENUM_UNKNOWN
++ PK_RESTART_ENUM_NONE
++ PK_RESTART_ENUM_SYSTEM
++ PK_RESTART_ENUM_SESSION
++ PK_RESTART_ENUM_APPLICATION
++
++ PK_STATUS_ENUM_UNKNOWN
++ PK_STATUS_ENUM_WAIT
++ PK_STATUS_ENUM_SETUP
++ PK_STATUS_ENUM_RUNNING
++ PK_STATUS_ENUM_QUERY
++ PK_STATUS_ENUM_INFO
++ PK_STATUS_ENUM_REFRESH_CACHE
++ PK_STATUS_ENUM_REMOVE
++ PK_STATUS_ENUM_DOWNLOAD
++ PK_STATUS_ENUM_INSTALL
++ PK_STATUS_ENUM_UPDATE
++ PK_STATUS_ENUM_CLEANUP
++ PK_STATUS_ENUM_OBSOLETE
++ PK_STATUS_ENUM_DEP_RESOLVE
++ PK_STATUS_ENUM_SIG_CHECK
++ PK_STATUS_ENUM_ROLLBACK
++ PK_STATUS_ENUM_TEST_COMMIT
++ PK_STATUS_ENUM_COMMIT
++ PK_STATUS_ENUM_REQUEST
++ PK_STATUS_ENUM_FINISHED
++ PK_STATUS_ENUM_CANCEL
++ PK_STATUS_ENUM_DOWNLOAD_REPOSITORY
++ PK_STATUS_ENUM_DOWNLOAD_PACKAGELIST
++ PK_STATUS_ENUM_DOWNLOAD_FILELIST
++ PK_STATUS_ENUM_DOWNLOAD_CHANGELOG
++ PK_STATUS_ENUM_DOWNLOAD_GROUP
++ PK_STATUS_ENUM_DOWNLOAD_UPDATEINFO
++
++ );
++
++use constant {
++ FILTER_BASENAME => "basename",
++ FILTER_DEVELOPMENT => "devel",
++ FILTER_FREE => "free",
++ FILTER_GUI => "gui",
++ FILTER_INSTALLED => "installed",
++ FILTER_NEWEST => "newest",
++ FILTER_NONE => "none",
++ FILTER_NOT_BASENAME => "~basename",
++ FILTER_NOT_DEVELOPMENT => "~devel",
++ FILTER_NOT_FREE => "~free",
++ FILTER_NOT_GUI => "~gui",
++ FILTER_NOT_INSTALLED => "~installed",
++ FILTER_NOT_NEWEST => "~newest",
++ FILTER_NOT_SUPPORTED => "~supported",
++ FILTER_NOT_VISIBLE => "~visible",
++ FILTER_SUPPORTED => "supported",
++ FILTER_UNKNOWN => "unknown",
++ FILTER_VISIBLE => "visible",
++
++ GROUP_ACCESSIBILITY => "accessibility",
++ GROUP_ACCESSORIES => "accessories",
++ GROUP_ADMIN_TOOLS => "admin-tools",
++ GROUP_COMMUNICATION => "communication",
++ GROUP_DESKTOP_GNOME => "desktop-gnome",
++ GROUP_DESKTOP_KDE => "desktop-kde",
++ GROUP_DESKTOP_OTHER => "desktop-other",
++ GROUP_DESKTOP_XFCE => "desktop-xfce",
++ GROUP_EDUCATION => "education",
++ GROUP_FONTS => "fonts",
++ GROUP_GAMES => "games",
++ GROUP_GRAPHICS => "graphics",
++ GROUP_INTERNET => "internet",
++ GROUP_LEGACY => "legacy",
++ GROUP_LOCALIZATION => "localization",
++ GROUP_MAPS => "maps",
++ GROUP_MULTIMEDIA => "multimedia",
++ GROUP_NETWORK => "network",
++ GROUP_OFFICE => "office",
++ GROUP_OTHER => "other",
++ GROUP_POWER_MANAGEMENT => "power-management",
++ GROUP_PROGRAMMING => "programming",
++ GROUP_PUBLISHING => "publishing",
++ GROUP_REPOS => "repos",
++ GROUP_SECURITY => "security",
++ GROUP_SERVERS => "servers",
++ GROUP_SYSTEM => "system",
++ GROUP_UNKNOWN => "unknown",
++ GROUP_VIRTUALIZATION => "virtualization",
++
++ INFO_AVAILABLE => "available",
++ INFO_BLOCKED => "blocked",
++ INFO_BUGFIX => "bugfix",
++ INFO_CLEANUP => "cleanup",
++ INFO_DOWNLOADING => "downloading",
++ INFO_ENHANCEMENT => "enhancement",
++ INFO_IMPORTANT => "important",
++ INFO_INSTALLED => "installed",
++ INFO_INSTALLING => "installing",
++ INFO_LOW => "low",
++ INFO_NORMAL => "normal",
++ INFO_OBSOLETING => "obsoleting",
++ INFO_REMOVING => "removing",
++ INFO_SECURITY => "security",
++ INFO_UNKNOWN => "unknown",
++ INFO_UPDATING => "updating",
++
++ PK_ERROR_ENUM_UNKNOWN => "unknown",
++ PK_ERROR_ENUM_OOM => "out-of-memory",
++ PK_ERROR_ENUM_NO_CACHE => "no-cache",
++ PK_ERROR_ENUM_NO_NETWORK => "no-network",
++ PK_ERROR_ENUM_NOT_SUPPORTED => "not-supported",
++ PK_ERROR_ENUM_INTERNAL_ERROR => "internal-error",
++ PK_ERROR_ENUM_GPG_FAILURE => "gpg-failure",
++ PK_ERROR_ENUM_FILTER_INVALID => "filter-invalid",
++ PK_ERROR_ENUM_PACKAGE_ID_INVALID => "package-id-invalid",
++ PK_ERROR_ENUM_TRANSACTION_ERROR => "transaction-error",
++ PK_ERROR_ENUM_TRANSACTION_CANCELLED => "transaction-cancelled",
++ PK_ERROR_ENUM_PACKAGE_NOT_INSTALLED => "package-not-installed",
++ PK_ERROR_ENUM_PACKAGE_NOT_FOUND => "package-not-found",
++ PK_ERROR_ENUM_PACKAGE_ALREADY_INSTALLED => "package-already-installed",
++ PK_ERROR_ENUM_PACKAGE_DOWNLOAD_FAILED => "package-download-failed",
++ PK_ERROR_ENUM_GROUP_NOT_FOUND => "group-not-found",
++ PK_ERROR_ENUM_GROUP_LIST_INVALID => "group-list-invalid",
++ PK_ERROR_ENUM_DEP_RESOLUTION_FAILED => "dep-resolution-failed",
++ PK_ERROR_ENUM_CREATE_THREAD_FAILED => "create-thread-failed",
++ PK_ERROR_ENUM_REPO_NOT_FOUND => "repo-not-found",
++ PK_ERROR_ENUM_CANNOT_REMOVE_SYSTEM_PACKAGE => "cannot-remove-system-package",
++ PK_ERROR_ENUM_PROCESS_KILL => "process-kill",
++ PK_ERROR_ENUM_FAILED_INITIALIZATION => "failed-initialization",
++ PK_ERROR_ENUM_FAILED_FINALISE => "failed-finalise",
++ PK_ERROR_ENUM_FAILED_CONFIG_PARSING => "failed-config-parsing",
++ PK_ERROR_ENUM_CANNOT_CANCEL => "cannot-cancel",
++ PK_ERROR_ENUM_CANNOT_GET_LOCK => "cannot-get-lock",
++ PK_ERROR_ENUM_NO_PACKAGES_TO_UPDATE => "no-packages-to-update",
++ PK_ERROR_ENUM_CANNOT_WRITE_REPO_CONFIG => "cannot-write-repo-config",
++ PK_ERROR_ENUM_LOCAL_INSTALL_FAILED => "local-install-failed",
++ PK_ERROR_ENUM_BAD_GPG_SIGNATURE => "bad-gpg-signature",
++ PK_ERROR_ENUM_MISSING_GPG_SIGNATURE => "missing-gpg-signature",
++ PK_ERROR_ENUM_CANNOT_INSTALL_SOURCE_PACKAGE => "cannot-install-source-package",
++ PK_ERROR_ENUM_REPO_CONFIGURATION_ERROR => "repo-configuration-error",
++ PK_ERROR_ENUM_NO_LICENSE_AGREEMENT => "no-license-agreement",
++ PK_ERROR_ENUM_FILE_CONFLICTS => "file-conflicts",
++ PK_ERROR_ENUM_REPO_NOT_AVAILABLE => "repo-not-available",
++ PK_ERROR_ENUM_INVALID_PACKAGE_FILE => "invalid-package-file",
++ PK_ERROR_ENUM_PACKAGE_INSTALL_BLOCKED => "package-install-blocked",
++
++ PK_RESTART_ENUM_UNKNOWN => "unknown",
++ PK_RESTART_ENUM_NONE => "none",
++ PK_RESTART_ENUM_SYSTEM => "system",
++ PK_RESTART_ENUM_SESSION => "session",
++ PK_RESTART_ENUM_APPLICATION => "application",
++
++ PK_STATUS_ENUM_UNKNOWN => "unknown",
++ PK_STATUS_ENUM_WAIT => "wait",
++ PK_STATUS_ENUM_SETUP => "setup",
++ PK_STATUS_ENUM_RUNNING => "running",
++ PK_STATUS_ENUM_QUERY => "query",
++ PK_STATUS_ENUM_INFO => "info",
++ PK_STATUS_ENUM_REFRESH_CACHE => "refresh-cache",
++ PK_STATUS_ENUM_REMOVE => "remove",
++ PK_STATUS_ENUM_DOWNLOAD => "download",
++ PK_STATUS_ENUM_INSTALL => "install",
++ PK_STATUS_ENUM_UPDATE => "update",
++ PK_STATUS_ENUM_CLEANUP => "cleanup",
++ PK_STATUS_ENUM_OBSOLETE => "obsolete",
++ PK_STATUS_ENUM_DEP_RESOLVE => "dep-resolve",
++ PK_STATUS_ENUM_SIG_CHECK => "sig-check",
++ PK_STATUS_ENUM_ROLLBACK => "rollback",
++ PK_STATUS_ENUM_TEST_COMMIT => "test-commit",
++ PK_STATUS_ENUM_COMMIT => "commit",
++ PK_STATUS_ENUM_REQUEST => "request",
++ PK_STATUS_ENUM_FINISHED => "finished",
++ PK_STATUS_ENUM_CANCEL => "cancel",
++ PK_STATUS_ENUM_DOWNLOAD_REPOSITORY => "download-repository",
++ PK_STATUS_ENUM_DOWNLOAD_PACKAGELIST => "download-package",
++ PK_STATUS_ENUM_DOWNLOAD_FILELIST => "download-filelist",
++ PK_STATUS_ENUM_DOWNLOAD_CHANGELOG => "download-changelog",
++ PK_STATUS_ENUM_DOWNLOAD_GROUP => "download-group",
++ PK_STATUS_ENUM_DOWNLOAD_UPDATEINFO => "download-updateinfo",
++
++
++};
++
++1;
+diff --git a/backends/urpmi/helpers/perl_packagekit/prints.pm b/backends/urpmi/helpers/perl_packagekit/prints.pm
+new file mode 100644
+index 0000000..7411ca9
+--- /dev/null
++++ b/backends/urpmi/helpers/perl_packagekit/prints.pm
+@@ -0,0 +1,95 @@
++package perl_packagekit::prints;
++
++use Exporter;
++
++our @ISA = qw(Exporter);
++our @EXPORT = qw(
++ pk_print_package
++ pk_print_status
++ pk_print_details
++ pk_print_files
++ pk_print_update_detail
++ pk_print_require_restart
++ pk_print_error
++ pk_print_percentage
++ pk_print_sub_percentage
++ );
++
++sub pk_print_package {
++ # send 'package' signal
++ # @param info: the enumerated INFO_* string
++ # @param id: The package ID name, e.g. openoffice-clipart;2.6.22;ppc64;fedora
++ # @param summary: The package Summary
++ my ($info, $id, $summary) = @_;
++ printf("package\t%s\t%s\t%s\n", $info, $id, $summary);
++}
++
++sub pk_print_status {
++ # send 'status' signal
++ # @param state: STATUS_*
++ my ($status) = @_;
++ printf("status\t%s\n", $status);
++}
++
++sub pk_print_details {
++ # Send 'details' signal
++ # @param id: The package ID name, e.g. openoffice-clipart;2.6.22;ppc64;fedora
++ # @param license: The license of the package
++ # @param group: The enumerated group
++ # @param desc: The multi line package description
++ # @param url: The upstream project homepage
++ # @param bytes: The size of the package, in bytes
++ my ($id, $license, $group, $desc, $url, $bytes) = @_;
++ printf("details\t%s\t%s\t%s\t%s\t%s\t%ld\n", $id, $license, $group, $desc, $url, $bytes);
++}
++
++sub pk_print_files {
++ # Send 'files' signal
++ # @param file_list: List of the files in the package, separated by ';'
++ my ($id, $file_list) = @_;
++ printf("files\t%s\t%s\n", $id, $file_list);
++}
++
++sub pk_print_update_detail {
++ # Send 'updatedetail' signal
++ # @param id: The package ID name, e.g. openoffice-clipart;2.6.22;ppc64;fedora
++ # @param updates:
++ # @param obsoletes:
++ # @param vendor_url:
++ # @param bugzilla_url:
++ # @param cve_url:
++ # @param restart:
++ # @param update_text:
++ my ($id, $updates, $obsoletes, $vendor_url, $bugzilla_url, $cve_url, $restart, $update_text) = @_;
++ printf("updatedetail\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", $id, $updates, $obsoletes, $vendor_url, $bugzilla_url, $cve_url, $restart, $update_text);
++}
++
++sub pk_print_require_restart {
++ # Send 'requirerestart' signal
++ # @param restart_type: RESTART_SYSTEM, RESTART_APPLICATION,RESTART_SESSION
++ # @param details: Optional details about the restart
++ my ($restart_type, $details) = @_;
++ printf("requirerestart\t%s\t%s\n", $restart_type, $details);
++}
++
++sub pk_print_error {
++ # send 'error'
++ # @param err: Error Type ERROR_*
++ # @param description: Error description
++ # @param exit: exit application with rc=1, if true
++ my ($err, $description) = @_;
++ printf("error\t%s\t%s\n", $err, $description);
++ exit if($exit);
++}
++
++sub pk_print_percentage {
++ my ($percentage) = @_;
++ printf("percentage\t%i\n", $percentage);
++}
++
++sub pk_print_sub_percentage {
++ my ($sub_percentage) = @_;
++ printf("subpercentage\t%i\n", $sub_percentage);
++}
++
++1;
+diff --git a/backends/urpmi/helpers/refresh-cache.pl b/backends/urpmi/helpers/refresh-cache.pl
+new file mode 100755
+index 0000000..555a8b8
+--- /dev/null
++++ b/backends/urpmi/helpers/refresh-cache.pl
+@@ -0,0 +1,33 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::media;
++use urpm::select;
++use urpm::args;
++use urpmi_backend::actions;
++
++# No arguments
++exit if($#ARGV != -1);
++
++#my $urpm = urpm->new_parse_cmdline;
++my $urpm = urpm->new_parse_cmdline;
++my $urpmi_lock = urpm::lock::urpmi_db($urpm, 'exclusive', wait => 0);
++urpm::media::read_config($urpm);
++
++my @entries = map { $_->{name} } @{$urpm->{media}};
++@entries == 0 and die N("nothing to update (use urpmi.addmedia to add a media)\n");
++
++my %options = ( all => 1 );
++
++my $ok = urpm::media::update_media($urpm, %options,
++ quiet => 0);
++exit($ok ? 0 : 1);
+diff --git a/backends/urpmi/helpers/remove-packages.pl b/backends/urpmi/helpers/remove-packages.pl
+new file mode 100755
+index 0000000..3be38ea
+--- /dev/null
++++ b/backends/urpmi/helpers/remove-packages.pl
+@@ -0,0 +1,90 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::args;
++use urpm::media;
++use urpm::select;
++use urpm::install;
++use urpmi_backend::tools;
++use perl_packagekit::enums;
++use perl_packagekit::prints;
++
++my $notfound = 0;
++my @breaking_pkgs = ();
++my $allowdeps_option = 0;
++my @pkgid;
++my $state = {};
++my $notfound_callback = sub {
++ $notfound = 1;
++};
++
++# This script call only be called with two arguments (allow_deps (yes/no) and a package id)
++exit if($#ARGV != 1);
++
++my $urpm = urpm->new_parse_cmdline;
++my $urpmi_lock = urpm::lock::urpmi_db($urpm, 'exclusive', wait => 1);
++urpm::media::configure($urpm);
++
++$allowdeps_option = 1 if($ARGV[0] eq "yes");
++
++my @pkg_ids = split(/\|/, pop @ARGV);
++my @names;
++foreach(@pkg_ids) {
++ my @pkg_id = (split(/;/, $_));
++ push @names, $pkg_id[0];
++}
++
++pk_print_status(PK_STATUS_ENUM_DEP_RESOLVE);
++
++my @to_remove = urpm::select::find_packages_to_remove($urpm,
++ $state,
++ \@names,
++ callback_notfound => $notfound_callback,
++ callback_fuzzy => $notfound_callback,
++ callback_base => sub {
++ my $urpm = shift @_;
++ push @breaking_pkgs, @_;
++ }
++);
++
++if($notfound) {
++ # printf("Error: package %s not found\n", $pkgid[0]);
++ pk_print_error(PK_ERROR_ENUM_PACKAGE_NOT_INSTALLED, "Selected package isn't installed on your system");
++}
++elsif(@breaking_pkgs) {
++ # printf("Error: These packages will break your system = \n\t%s\n", join("\n\t", @breaking_pkgs));
++ pk_print_error(PK_ERROR_ENUM_CANNOT_REMOVE_SYSTEM_PACKAGE, "Removing selected packages will break your system");
++}
++else {
++ # printf("It's ok, I will remove %s NOW !\n", $pkgid[0]);
++ # printf("To remove list = \n\t%s\n", join("\n\t", @to_remove));
++ if(!$allowdeps_option && $#to_remove > 1) {
++ pk_print_error(PK_ERROR_ENUM_TRANSACTION_ERROR, "Packages can't be removed because dependencies remove is forbidden");
++ # printf("I can't remove, because you don't allow deps remove :'(\n");
++ }
++ else {
++ # printf("Let's go for removing ...\n");
++ pk_print_status(PK_STATUS_ENUM_REMOVE);
++ urpm::install::install($urpm,
++ \@to_remove, {}, {},
++ callback_report_uninst => sub {
++ my @return = split(/ /, $_[0]);
++ # printf("Package\tRemoving\t%s\n", fullname_to_package_id($return[$#return]));
++ pk_print_package(INFO_REMOVING, fullname_to_package_id($return[$#return]), "");
++ }
++ );
++ }
++}
++
++$urpmi_lock->unlock;
++
++pk_print_status(PK_STATUS_ENUM_FINISHED);
+diff --git a/backends/urpmi/helpers/resolve.pl b/backends/urpmi/helpers/resolve.pl
+new file mode 100755
+index 0000000..32e0866
+--- /dev/null
++++ b/backends/urpmi/helpers/resolve.pl
+@@ -0,0 +1,64 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::args;
++use urpm::media;
++use urpmi_backend::open_db;
++use urpmi_backend::tools;
++use urpmi_backend::filters;
++use perl_packagekit::enums;
++use perl_packagekit::prints;
++
++# Two arguments (filter and package name)
++exit if ($#ARGV != 1);
++my @filters = split(/;/, $ARGV[0]);
++my $search_term = $ARGV[1];
++
++my $urpm = urpm->new_parse_cmdline;
++urpm::media::configure($urpm);
++
++my @names = ( $search_term );
++my %requested;
++my $result = urpm::select::search_packages($urpm, \%requested, \@names,
++ fuzzy => 0,
++ caseinsensitive => 0,
++ all => 0
++);
++
++if($result) {
++ my @requested_keys = keys %requested;
++ my $db = open_rpm_db();
++ $urpm->compute_installed_flags($db);
++ my $pkg = @{$urpm->{depslist}}[$requested_keys[0]];
++
++ # We exit the script if found package does not match with
++ # specified filters
++ if(!filter($pkg, \@filters, {FILTER_DEVELOPMENT => 1, FILTER_GUI => 1})) {
++ exit;
++ }
++ if($pkg->version."-".$pkg->release eq find_installed_version($pkg)) {
++ if(grep(/^${\FILTER_NOT_INSTALLED}$/, @filters)) {
++ exit;
++ }
++ pk_print_package(INFO_INSTALLED, get_package_id($pkg), $pkg->summary);
++ }
++ else {
++ if(grep(/^${\FILTER_INSTALLED}$/, @filters)) {
++ exit;
++ }
++ pk_print_package(INFO_AVAILABLE, get_package_id($pkg), $pkg->summary);
++ }
++}
++else {
++ pk_print_error(PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "Can't find any package for the specified name");
++}
++
+diff --git a/backends/urpmi/helpers/search-details.pl b/backends/urpmi/helpers/search-details.pl
+new file mode 100755
+index 0000000..3081abe
+--- /dev/null
++++ b/backends/urpmi/helpers/search-details.pl
+@@ -0,0 +1,57 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::media;
++use urpm::args;
++
++use urpmi_backend::open_db;
++use urpmi_backend::tools;
++use urpmi_backend::filters;
++
++use perl_packagekit::enums;
++use perl_packagekit::prints;
++
++# Two arguments (filterand search term)
++exit if ($#ARGV != 1);
++my @filters = split(/;/, $ARGV[0]);
++my $search_term = $ARGV[1];
++
++my $urpm = urpm->new_parse_cmdline;
++urpm::media::configure($urpm);
++
++my $db = open_rpm_db();
++$urpm->compute_installed_flags($db);
++
++# Here we display installed packages
++if(not grep(/^${\FILTER_NOT_INSTALLED}$/, @filters)) {
++ $db->traverse(sub {
++ my ($pkg) = @_;
++ if(filter($pkg, \@filters, {FILTER_DEVELOPMENT => 1, FILTER_GUI => 1})) {
++ if($pkg->name =~ /$search_term/ || $pkg->summary =~ /$search_term/ || $pkg->url =~ /$search_term/) {
++ pk_print_package(INFO_INSTALLED, get_package_id($pkg), ensure_utf8($pkg->summary));
++ }
++ }
++ });
++}
++
++# Here are package which can be installed
++if(not grep(/^${\FILTER_INSTALLED}$/, @filters)) {
++ foreach my $pkg(@{$urpm->{depslist}}) {
++ if($pkg->flag_upgrade) {
++ if(filter($pkg, \@filters, {FILTER_DEVELOPMENT => 1, FILTER_GUI => 1})) {
++ if($pkg->name =~ /$search_term/ || $pkg->summary =~ /$search_term/ || $pkg->url =~ /$search_term/) {
++ pk_print_package(INFO_AVAILABLE, get_package_id($pkg), ensure_utf8($pkg->summary));
++ }
++ }
++ }
++ }
++}
+diff --git a/backends/urpmi/helpers/search-file.pl b/backends/urpmi/helpers/search-file.pl
+new file mode 100755
+index 0000000..03d348e
+--- /dev/null
++++ b/backends/urpmi/helpers/search-file.pl
+@@ -0,0 +1,48 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::media;
++
++use urpmi_backend::actions;
++use urpmi_backend::filters;
++use urpmi_backend::tools;
++use perl_packagekit::prints;
++use perl_packagekit::enums;
++
++# Two arguments (filter and search term)
++exit if ($#ARGV != 1);
++my @filters = split(/;/, $ARGV[0]);
++my $search_term = $ARGV[1];
++
++my $urpm = urpm->new_parse_cmdline;
++urpm::media::configure($urpm);
++
++my %requested;
++
++pk_print_status(PK_STATUS_ENUM_QUERY);
++
++perform_file_search($urpm, \%requested, $search_term, fuzzy => 1);
++
++foreach(keys %requested) {
++ my $p = @{$urpm->{depslist}}[$_];
++ if(filter($p, \@filters, { FILTER_INSTALLED => 1, FILTER_DEVELOPMENT=> 1, FILTER_GUI => 1})) {
++ my $version = find_installed_version($p);
++ if($version eq $p->version."-".$p->release) {
++ pk_print_package(INFO_INSTALLED, get_package_id($p), ensure_utf8($p->summary));
++ }
++ else {
++ pk_print_package(INFO_AVAILABLE, get_package_id($p), ensure_utf8($p->summary));
++ }
++ }
++}
++
++pk_print_status(PK_STATUS_ENUM_FINISHED);
+diff --git a/backends/urpmi/helpers/search-group.pl b/backends/urpmi/helpers/search-group.pl
+new file mode 100755
+index 0000000..e5b7b92
+--- /dev/null
++++ b/backends/urpmi/helpers/search-group.pl
+@@ -0,0 +1,58 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::media;
++use urpm::args;
++
++use urpmi_backend::open_db;
++use urpmi_backend::tools;
++use urpmi_backend::filters;
++use urpmi_backend::groups;
++
++use perl_packagekit::enums;
++use perl_packagekit::prints;
++
++# Two arguments (filter and packagekit group)
++exit if ($#ARGV != 1);
++my @filters = split(/;/, $ARGV[0]);
++my $pk_group = $ARGV[1];
++
++my $urpm = urpm->new_parse_cmdline;
++urpm::media::configure($urpm);
++
++my $db = open_rpm_db();
++$urpm->compute_installed_flags($db);
++
++# Here we display installed packages
++if(not grep(/^${\FILTER_NOT_INSTALLED}$/, @filters)) {
++ $db->traverse(sub {
++ my ($pkg) = @_;
++ if(filter($pkg, \@filters, {FILTER_DEVELOPMENT => 1, FILTER_GUI => 1})) {
++ if(package_belongs_to_pk_group($pkg, $pk_group)) {
++ pk_print_package(INFO_INSTALLED, get_package_id($pkg), ensure_utf8($pkg->summary));
++ }
++ }
++ });
++}
++
++# Here are package which can be installed
++if(not grep(/^${\FILTER_INSTALLED}$/, @filters)) {
++ foreach my $pkg(@{$urpm->{depslist}}) {
++ if($pkg->flag_upgrade) {
++ if(filter($pkg, \@filters, {FILTER_DEVELOPMENT => 1, FILTER_GUI => 1})) {
++ if(package_belongs_to_pk_group($pkg, $pk_group)) {
++ pk_print_package(INFO_AVAILABLE, get_package_id($pkg), ensure_utf8($pkg->summary));
++ }
++ }
++ }
++ }
++}
+diff --git a/backends/urpmi/helpers/search-name.pl b/backends/urpmi/helpers/search-name.pl
+new file mode 100755
+index 0000000..383921f
+--- /dev/null
++++ b/backends/urpmi/helpers/search-name.pl
+@@ -0,0 +1,64 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::media;
++use urpm::args;
++
++use urpmi_backend::open_db;
++use urpmi_backend::tools;
++use urpmi_backend::filters;
++
++use perl_packagekit::enums;
++use perl_packagekit::prints;
++
++# Two arguments (filter, search term)
++exit if ($#ARGV != 1);
++
++my @filters = split(/;/, $ARGV[0]);
++my $search_term = $ARGV[1];
++
++my $basename_option = FILTER_BASENAME;
++$basename_option = grep(/$basename_option/, @filters);
++
++my $urpm = urpm->new_parse_cmdline;
++
++urpm::media::configure($urpm);
++
++my $db = open_rpm_db();
++$urpm->compute_installed_flags($db);
++
++# Here we display installed packages
++if(not grep(/^${\FILTER_NOT_INSTALLED}$/, @filters)) {
++ $db->traverse(sub {
++ my ($pkg) = @_;
++ if(filter($pkg, \@filters, {FILTER_DEVELOPMENT => 1, FILTER_GUI => 1})) {
++ if( (!$basename_option && $pkg->name =~ /$search_term/)
++ || $pkg->name =~ /^$search_term$/ ) {
++ pk_print_package(INFO_INSTALLED, get_package_id($pkg), ensure_utf8($pkg->summary));
++ }
++ }
++ });
++}
++
++# Here are packages which can be installed
++if(grep(/^${\FILTER_INSTALLED}$/, @filters)) {
++ exit 0;
++}
++
++foreach my $pkg(@{$urpm->{depslist}}) {
++ if($pkg->flag_upgrade && filter($pkg, \@filters, {FILTER_DEVELOPMENT => 1, FILTER_GUI => 1})) {
++ if( (!$basename_option && $pkg->name =~ /$search_term/)
++ || $pkg->name =~ /^$search_term$/ ) {
++ pk_print_package(INFO_AVAILABLE, get_package_id($pkg), ensure_utf8($pkg->summary));
++ }
++ }
++}
+diff --git a/backends/urpmi/helpers/update-packages.pl b/backends/urpmi/helpers/update-packages.pl
+new file mode 100755
+index 0000000..88274bc
+--- /dev/null
++++ b/backends/urpmi/helpers/update-packages.pl
+@@ -0,0 +1,50 @@
++#!/usr/bin/perl
++
++use strict;
++
++use lib;
++use File::Basename;
++
++BEGIN {
++ push @INC, dirname($0);
++}
++
++use urpm;
++use urpm::media;
++use urpm::select;
++use urpm::args;
++use urpmi_backend::tools;
++use urpmi_backend::open_db;
++use urpmi_backend::actions;
++
++# This script call only be called with one argument (the package id)
++exit if($#ARGV != 0);
++
++my @names;
++foreach(split(/\|/, $ARGV[0])) {
++ my @pkgid = split(/;/, $_);
++ push @names, $pkgid[0];
++}
++
++my $urpm = urpm->new_parse_cmdline;
++urpm::media::configure($urpm);
++
++my $db = open_rpm_db();
++$urpm->compute_installed_flags($db);
++
++my %requested;
++
++my @depslist = @{$urpm->{depslist}};
++my $pkg = undef;
++foreach my $depslistpkg (@depslist) {
++ foreach my $name (@names) {
++ if($depslistpkg->name =~ /^$name$/ && $depslistpkg->flag_upgrade) {
++ $requested{$depslistpkg->id} = 1;
++ goto tonext;
++ }
++ }
++ tonext:
++}
++
++perform_installation($urpm, \%requested);
++
+diff --git a/backends/urpmi/helpers/urpmi_backend/Makefile.am b/backends/urpmi/helpers/urpmi_backend/Makefile.am
+new file mode 100644
+index 0000000..3eb8280
+--- /dev/null
++++ b/backends/urpmi/helpers/urpmi_backend/Makefile.am
+@@ -0,0 +1,15 @@
++helperdir = $(datadir)/PackageKit/helpers/urpmi/urpmi_backend/
++
++NULL =
++
++dist_helper_DATA = \
++ actions.pm \
++ filters.pm \
++ groups.pm \
++ open_db.pm \
++ tools.pm \
++ $(NULL)
++
++clean-local :
++ rm -f *~
++
+diff --git a/backends/urpmi/helpers/urpmi_backend/actions.pm b/backends/urpmi/helpers/urpmi_backend/actions.pm
+new file mode 100644
+index 0000000..a01b893
+--- /dev/null
++++ b/backends/urpmi/helpers/urpmi_backend/actions.pm
+@@ -0,0 +1,297 @@
++package urpmi_backend::actions;
++
++use strict;
++
++use urpm;
++use urpm::args;
++use urpm::msg;
++use urpm::main_loop;
++use urpm::lock;
++use urpmi_backend::tools;
++use urpmi_backend::open_db;
++use MDK::Common;
++use perl_packagekit::enums;
++use perl_packagekit::prints;
++
++use Exporter;
++our @ISA = qw(Exporter);
++our @EXPORT = qw(
++ perform_installation
++ perform_file_search
++ perform_requires_search
++);
++
++sub perform_installation {
++ my ($urpm, $requested, %options) = @_;
++ my $state = {};
++ my $restart;
++ my $no_remove = 0;
++
++ # Here we lock urpmi & rpm databases
++ # In third argument we can specified if the script must wait until urpmi or rpm
++ # databases are locked
++ my $lock = urpm::lock::urpmi_db($urpm, undef, wait => 0);
++ my $rpm_lock = urpm::lock::rpm_db($urpm, 'exclusive');
++
++ pk_print_status(PK_STATUS_ENUM_DEP_RESOLVE);
++
++ $restart = urpm::select::resolve_dependencies($urpm, $state, $requested, auto_select => $options{auto_select});
++ my %selected = %{$state->{selected} || {}};
++
++ print "Dependencies = \n\t";
++ print join("\n\t", map(@{$urpm->{depslist}}[$_]->name, keys %selected)), "\n";
++
++ # Here we have packages which cannot be installed because of dependencies
++ my @unselected_uninstalled = @{$state->{unselected_uninstalled} || []};
++ if(@unselected_uninstalled) {
++ my $list = join "\n", map { $_->name . '-' . $_->version . '-' . $_->release } @unselected_uninstalled;
++ }
++ # Fix me !
++ # Display warning (With pk enum?) which warning the user
++ # that the following packages can't be installed because they depend
++ # on packages that are older than the installed ones (copy/paste from
++ # the diplayed message in urpmi)
++
++ # Here we have packages which cannot be installed
++ my @ask_unselect = urpm::select::unselected_packages($urpm, $state);
++ if (@ask_unselect) {
++ my $list = urpm::select::translate_why_unselected($urpm, $state, @ask_unselect);
++ }
++ # Fix me !
++ # Display warning (With pk enum?) which warning the user
++ # that the following packages can't be installed (copy/paste from
++ # the diplayed message in urpmi)
++
++ my @ask_remove = urpm::select::removed_packages($urpm, $state);
++ if(@ask_remove) {
++ my $db = urpm::db_open_or_die($urpm, $urpm->{root});
++ urpm::select::find_removed_from_basesystem($urpm, $db, $state, sub {
++ my $urpm = shift @_;
++ foreach (@_) {
++ # Fix me
++ # Someting like that. With a clean pk error enum.
++ # printf ("removing package %s will break your system", $_);
++ }
++ @_ and $no_remove = 1;
++ });
++ my $list = urpm::select::translate_why_removed($urpm, $state, @ask_remove);
++ if($no_remove) {
++ # Fix me
++ # Display message to prevent that the installation cannot continue because some
++ # packages has to be removed for others to be upgraded.
++ exit 0;
++ }
++ # Else, it's ok.
++ # Here we can display $list, which describe packages which has to be removed for
++ # others to be upgraded.
++ printf("Following package(s) will be removed for others to be upgraded:\n%s\n", $list);
++ }
++
++ # sorted by medium for format_selected_packages
++ my @to_install = @{$urpm->{depslist}}[sort { $a <=> $b } keys %{$state->{selected}}];
++ my ($src, $binary) = partition { $_->arch eq 'src' } @to_install;
++ # With packagekit, we will never install src packages.
++ @to_install = @$binary;
++
++ print "\@to_install debug : \n\t";
++ print join("\n\t", map(urpm_name($_), @to_install)), "\n";
++
++ my $nb_to_install = $#to_install + 1;
++ my $percentage = 0;
++
++ $urpm->{nb_install} = @to_install;
++ # For debug issue, we will display sizes
++ my ($size, $filesize) = $urpm->selected_size_filesize($state);
++ printf("%s of additional disk space will be used.\n", formatXiB($size));
++ printf("%s of packages will be retrieved.\n", formatXiB($filesize));
++
++ my $callback_inst = sub {
++ my ($urpm, $type, $id, $subtype, $amount, $total) = @_;
++ my $pkg = defined $id ? $urpm->{depslist}[$id] : undef;
++ if ($subtype eq 'start') {
++ if ($type eq 'trans') {
++ print "Preparing packages installation ...\n";
++ pk_print_status(PK_STATUS_ENUM_INSTALL);
++ }
++ elsif (defined $pkg) {
++ printf("Installing package %s ...\n", $pkg->name);
++ pk_print_package(INFO_INSTALLING, get_package_id($pkg), $pkg->summary);
++ }
++ }
++ elsif ($subtype eq 'progress') {
++ print "($type) Progress : total = ", $total, " ; amount/total = ", $amount/$total, " ; amount = ", $amount, "\n";
++ if($type eq "inst") {
++ pk_print_percentage($percentage + ($amount/$total)*(100/$nb_to_install));
++ if(($amount/$total) == 1) {
++ $percentage = $percentage + ($amount/$total)*(100/$nb_to_install);
++ }
++ }
++ }
++ };
++
++ # Now, the script will call the urpmi main loop to make installation
++ my $exit_code = urpm::main_loop::run($urpm, $state, undef, \@ask_unselect, $requested, {
++ inst => $callback_inst,
++ trans => $callback_inst,
++ trans_log => sub {
++ my ($mode, $file, $percent, $total, $eta, $speed) = @_;
++ # Transfer log need to be improved.
++ if($mode eq "progress") {
++ pk_print_status(PK_STATUS_ENUM_DOWNLOAD);
++ }
++ print "Install current mode = ", $mode, "\n";
++ },
++ bad_signature => sub {
++ # Here we display a message (with PK enum) to warn the user
++ # about a bad signature, then we exit
++ exit 1;
++ },
++ ask_yes_or_no => sub {
++ # Return 1 = Return Yes
++ return 1;
++ },
++ need_restart => sub {
++ my ($need_restart_formatted) = @_;
++ print "$_\n" foreach values %$need_restart_formatted;
++ },
++ completed => sub {
++ undef $lock;
++ undef $rpm_lock;
++ pk_print_status(PK_STATUS_ENUM_FINISHED);
++ },
++ post_download => sub {
++ # Fix me !
++ # At this point, we need to refuse cancel action
++ },
++ }
++ );
++}
++
++sub perform_file_search {
++ my ($urpm, $requested, $search_term, %options) = @_;
++ my $db = open_rpm_db();
++ $urpm->compute_installed_flags($db);
++
++ my $xml_info = 'files';
++ my %result_hash;
++
++ # - For each medium, we browse the xml info file,
++ # while looking for files which matched with the
++ # search term given in argument. We store results
++ # in a hash.
++ foreach my $medium (urpm::media::non_ignored_media($urpm)) {
++ my $xml_info_file = urpm::media::any_xml_info($urpm, $medium, ( "files", "summary" ), undef, undef);
++ $xml_info_file or next;
++ require urpm::xml_info;
++ require urpm::xml_info_pkg;
++ my $F = urpm::xml_info::open_lzma($xml_info_file);
++ my $fn;
++ local $_;
++ while (<$F>) {
++ if (m!^<!) {
++ ($fn) = /fn="(.*)"/;
++ }
++ elsif ( (!$options{'fuzzy'} && $_ =~ /^$search_term$/)
++ || ($options{'fuzzy'} && $_ =~ /$search_term/) ) {
++ # Fix me : Replace with pk error enum.
++ # $fn or $urpm->{fatal}("fast algorithm is broken, please report a bug");
++ my $pkg = urpm::xml_info_pkg->new({ fn => $fn });
++ $result_hash{$pkg->name} = $pkg;
++ }
++ }
++ }
++
++ # - In order to get package summaries, we need to
++ # use the search package method from perl-URPM
++ # which return Package type on which we can call
++ # methods to create the printing output.
++ # (It's about the same code as search-name.pl)
++ my @names = keys %result_hash;
++
++ urpm::select::search_packages($urpm, $requested, \@names,
++ fuzzy => 0,
++ caseinsensitive => 0,
++ all => 0,);
++}
++
++sub perform_requires_search {
++
++ my ($urpm, $pkg, $recursive_option) = @_;
++
++ my (@properties, %requires, %properties, $dep);
++ my %requested;
++ urpm::select::search_packages($urpm,
++ \%requested, [ $pkg->name ],
++ use_provides => 0,
++ fuzzy => 0,
++ all => 0
++ );
++ @properties = keys %requested;
++ my $state = {};
++
++ foreach my $pkg (@{$urpm->{depslist}}) {
++ foreach ($pkg->requires_nosense) {
++ $requires{$_}{$pkg->id} = undef;
++ }
++ }
++
++ while (defined ($dep = shift @properties)) {
++ my $packages = $urpm->find_candidate_packages($dep);
++ foreach (values %$packages) {
++ my ($best_requested, $best);
++ foreach (@$_) {
++ if ($best_requested || exists $requested{$_->id}) {
++ if ($best_requested && $best_requested != $_) {
++ $_->compare_pkg($best_requested) > 0 and $best_requested = $_;
++ } else {
++ $best_requested = $_;
++ }
++ } elsif ($best && $best != $_) {
++ $_->compare_pkg($best) > 0 and $best = $_;
++ } else {
++ $best = $_;
++ }
++ }
++
++ my $pkg = $best_requested || $best or next;
++ exists $state->{selected}{$pkg->id} and next;
++ $state->{selected}{$pkg->id} = undef;
++
++ next if !$requested{$dep} && !$recursive_option;
++
++ #- for all provides of package, look up what is requiring them.
++ foreach ($pkg->provides) {
++ if (my ($n, $s) = /^([^\s\[]*)(?:\[\*\])?\[?([^\s\]]*\s*[^\s\]]*)/) {
++ if (my @l = grep { $_ ne $pkg->name } map { $_->name } $urpm->packages_providing($n)) {
++ #- If another package provides this requirement,
++ #- then don't bother finding stuff that needs it as it will be invalid
++ # $urpm->{log}(sprintf "skipping package(s) requiring %s via %s, since %s is also provided by %s", $pkg->name, $n, $n, join(' ', @l));
++ next;
++ }
++
++ foreach (map { $urpm->{depslist}[$_] }
++ grep { ! exists $state->{selected}{$_} && ! exists $properties{$_} }
++ keys %{$requires{$n} || {}}) {
++ if (grep { URPM::ranges_overlap("$n $s", $_) } $_->requires) {
++ push @properties, $_->id;
++ # $urpm->{debug} and $urpm->{debug}(sprintf "adding package %s (requires %s%s)", $_->name, $pkg->name, $n eq $pkg->name ? '' : " via $n");
++ $properties{$_->id} = undef;
++ }
++ }
++ }
++ }
++ }
++ }
++
++ my @depslist = @{$urpm->{depslist}};
++ my @requires = ();
++ foreach(@depslist) {
++ my $pkgid = $_->id;
++ if(grep(/^$pkgid$/, keys %{$state->{selected}})) {
++ push @requires, $_;
++ }
++ }
++
++ @requires;
++
++}
+diff --git a/backends/urpmi/helpers/urpmi_backend/filters.pm b/backends/urpmi/helpers/urpmi_backend/filters.pm
+new file mode 100644
+index 0000000..2c2f13a
+--- /dev/null
++++ b/backends/urpmi/helpers/urpmi_backend/filters.pm
+@@ -0,0 +1,78 @@
++package urpmi_backend::filters;
++
++use MDK::Common;
++use perl_packagekit::enums;
++use urpmi_backend::tools;
++
++use Exporter;
++our @ISA = qw(Exporter);
++our @EXPORT = qw(filter);
++
++my @gui_pkgs = map { chomp; $_ } cat_('/usr/share/rpmdrake/gui.lst');
++
++sub filter {
++ my ($pkg, $filters, $enabled_filters) = @_;
++
++ my %e_filters = %{$enabled_filters};
++
++ foreach my $filter (@{$filters}) {
++ if($filter eq FILTER_INSTALLED || $filter eq FILTER_NOT_INSTALLED) {
++ if($e_filters{FILTER_INSTALLED}) {
++ return 0 if not filter_installed($pkg, $filter);
++ }
++ }
++ elsif($filter eq FILTER_DEVELOPMENT || $filter eq FILTER_NOT_DEVELOPMENT) {
++ if($e_filters{FILTER_DEVELOPMENT}) {
++ return 0 if not filter_devel($pkg, $filter);
++ }
++ }
++ elsif($filter eq FILTER_GUI || $filter eq FILTER_NOT_GUI) {
++ if($e_filters{FILTER_GUI}) {
++ return 0 if not filter_gui($pkg, $filter);
++ }
++ }
++ }
++ return 1;
++}
++
++sub filter_installed {
++ my ($pkg, $filter) = @_;
++ my $installed;
++ $installed = 1 if(find_installed_version($pkg));
++ if($filter eq FILTER_INSTALLED && $installed) {
++ return 1;
++ }
++ if($filter eq FILTER_NOT_INSTALLED && !$installed) {
++ return 1;
++ }
++ return 0;
++}
++
++sub filter_devel {
++ my ($pkg, $filter) = @_;
++ my $pkgname = $pkg->name;
++ my $devel = ($pkgname =~ /-devel$/);
++ if($filter eq FILTER_DEVELOPMENT && $devel) {
++ return 1;
++ }
++ if($filter eq FILTER_NOT_DEVELOPMENT && !$devel) {
++ return 1;
++ }
++ return 0;
++}
++
++sub filter_gui {
++ my ($pkg, $filter) = @_;
++ my $pkgname = $pkg->name;
++ my $gui = member($pkgname, @gui_pkgs);
++
++ if($filter eq FILTER_NOT_GUI && !$gui) {
++ return 1;
++ }
++ if($filter eq FILTER_GUI && $gui) {
++ return 1;
++ }
++ return 0;
++}
++
++1;
+diff --git a/backends/urpmi/helpers/urpmi_backend/groups.pm b/backends/urpmi/helpers/urpmi_backend/groups.pm
+new file mode 100644
+index 0000000..d377ab2
+--- /dev/null
++++ b/backends/urpmi/helpers/urpmi_backend/groups.pm
+@@ -0,0 +1,129 @@
++package urpmi_backend::groups;
++
++use strict;
++
++use perl_packagekit::enums;
++use Exporter;
++
++our @ISA = qw(Exporter);
++our @EXPORT = qw(
++ MDV_GROUPS
++ get_mdv_groups
++ get_pk_group
++ package_belongs_to_pk_group
++);
++
++use constant MDV_GROUPS => {
++ 'Accessibility' => GROUP_ACCESSIBILITY,
++ 'Archiving/Backup' => GROUP_OTHER,
++ 'Archiving/Cd burning' => GROUP_MULTIMEDIA,
++ 'Archiving/Compression' => GROUP_ACCESSORIES,
++ 'Archiving/Other' => GROUP_OTHER,
++ 'Books/Computer books' => GROUP_OTHER,
++ 'Books/Faqs' => GROUP_OTHER,
++ 'Books/Howtos' => GROUP_OTHER,
++ 'Books/Literature' => GROUP_OTHER,
++ 'Books/Other' => GROUP_OTHER,
++ 'Communications' => GROUP_COMMUNICATION,
++ 'Databases' => GROUP_PROGRAMMING,
++ 'Development/C' => GROUP_PROGRAMMING,
++ 'Development/C++' => GROUP_PROGRAMMING,
++ 'Development/Databases' => GROUP_PROGRAMMING,
++ 'Development/GNOME and GTK+' => GROUP_PROGRAMMING,
++ 'Development/Java' => GROUP_PROGRAMMING,
++ 'Development/KDE and Qt' => GROUP_PROGRAMMING,
++ 'Development/Kernel' => GROUP_PROGRAMMING,
++ 'Development/Other' => GROUP_PROGRAMMING,
++ 'Development/Perl' => GROUP_PROGRAMMING,
++ 'Development/PHP' => GROUP_PROGRAMMING,
++ 'Development/Python' => GROUP_PROGRAMMING,
++ 'Development/Ruby' => GROUP_PROGRAMMING,
++ 'Development/X11' => GROUP_PROGRAMMING,
++ 'Editors' => GROUP_ACCESSORIES,
++ 'Education' => GROUP_EDUCATION,
++ 'Emulators' => GROUP_VIRTUALIZATION,
++ 'File tools' => GROUP_ACCESSORIES,
++ 'Games/Adventure' => GROUP_GAMES,
++ 'Games/Arcade' => GROUP_GAMES,
++ 'Games/Boards' => GROUP_GAMES,
++ 'Games/Cards' => GROUP_GAMES,
++ 'Games/Other' => GROUP_GAMES,
++ 'Games/Puzzles' => GROUP_GAMES,
++ 'Games/Sports' => GROUP_GAMES,
++ 'Games/Strategy' => GROUP_GAMES,
++ 'Graphical desktop/Enlightenment' => GROUP_DESKTOP_OTHER,
++ 'Graphical desktop/FVWM based' => GROUP_DESKTOP_OTHER,
++ 'Graphical desktop/GNOME' => GROUP_DESKTOP_GNOME,
++ 'Graphical desktop/Icewm' => GROUP_DESKTOP_OTHER,
++ 'Graphical desktop/KDE' => GROUP_DESKTOP_KDE,
++ 'Graphical desktop/Other' => GROUP_DESKTOP_OTHER,
++ 'Graphical desktop/Sawfish' => GROUP_DESKTOP_OTHER,
++ 'Graphical desktop/WindowMaker' => GROUP_DESKTOP_OTHER,
++ 'Graphical desktop/Xfce' => GROUP_DESKTOP_XFCE,
++ 'Graphics' => GROUP_GRAPHICS,
++ 'Monitoring' => GROUP_NETWORK,
++ 'Networking/Chat' => GROUP_INTERNET,
++ 'Networking/File transfer' => GROUP_INTERNET,
++ 'Networking/IRC' => GROUP_INTERNET,
++ 'Networking/Instant messaging' => GROUP_INTERNET,
++ 'Networking/Mail' => GROUP_INTERNET,
++ 'Networking/News' => GROUP_INTERNET,
++ 'Networking/Other' => GROUP_INTERNET,
++ 'Networking/Remote access' => GROUP_INTERNET,
++ 'Networking/WWW' => GROUP_INTERNET,
++ 'Office' => GROUP_OFFICE,
++ 'Publishing' => GROUP_PUBLISHING,
++ 'Sciences/Astronomy' => GROUP_OTHER,
++ 'Sciences/Biology' => GROUP_OTHER,
++ 'Sciences/Chemistry' => GROUP_OTHER,
++ 'Sciences/Computer science' => GROUP_OTHER,
++ 'Sciences/Geosciences' => GROUP_OTHER,
++ 'Sciences/Mathematics' => GROUP_OTHER,
++ 'Sciences/Other' => GROUP_OTHER,
++ 'Sciences/Physics' => GROUP_OTHER,
++ 'Shells' => GROUP_SYSTEM,
++ 'Sound' => GROUP_MULTIMEDIA,
++ 'System/Base' => GROUP_SYSTEM,
++ 'System/Cluster' => GROUP_SYSTEM,
++ 'System/Configuration/Boot and Init' => GROUP_SYSTEM,
++ 'System/Configuration/Hardware' => GROUP_SYSTEM,
++ 'System/Configuration/Networking' => GROUP_SYSTEM,
++ 'System/Configuration/Other' => GROUP_SYSTEM,
++ 'System/Configuration/Packaging' => GROUP_SYSTEM,
++ 'System/Configuration/Printing' => GROUP_SYSTEM,
++ 'System/Fonts/Console' => GROUP_FONTS,
++ 'System/Fonts/True type' => GROUP_FONTS,
++ 'System/Fonts/Type1' => GROUP_FONTS,
++ 'System/Fonts/X11 bitmap' => GROUP_FONTS,
++ 'System/Internationalization' => GROUP_LOCALIZATION,
++ 'System/Kernel and hardware' => GROUP_SYSTEM,
++ 'System/Libraries' => GROUP_SYSTEM,
++ 'System/Printing' => GROUP_SYSTEM,
++ 'System/Servers' => GROUP_SYSTEM,
++ 'System/X11' => GROUP_SYSTEM,
++ 'Terminals' => GROUP_SYSTEM,
++ 'Text tools' => GROUP_ACCESSORIES,
++ 'Toys' => GROUP_GAMES,
++ 'Video' => GROUP_MULTIMEDIA
++ };
++
++sub get_mdv_groups {
++ my ($pk_group) = @_;
++ my @groups = ();
++ foreach(keys %{(MDV_GROUPS)}) {
++ if(%{(MDV_GROUPS)}->{$_} eq $pk_group) {
++ push @groups, $_;
++ }
++ }
++ return @groups;
++}
++
++sub package_belongs_to_pk_group {
++ my ($pkg, $pk_group) = @_;
++ my @groups = get_mdv_groups($pk_group);
++ my $pkg_group = $pkg->group;
++ return grep(/$pkg_group/, @groups);
++}
++
++1;
++
+diff --git a/backends/urpmi/helpers/urpmi_backend/open_db.pm b/backends/urpmi/helpers/urpmi_backend/open_db.pm
+new file mode 100644
+index 0000000..795edc6
+--- /dev/null
++++ b/backends/urpmi/helpers/urpmi_backend/open_db.pm
+@@ -0,0 +1,48 @@
++package urpmi_backend::open_db;
++
++use strict;
++
++use MDK::Common;
++
++use urpm;
++use urpm::media;
++use urpm::select;
++
++use URPM;
++
++use Exporter;
++our @ISA = qw(Exporter);
++our @EXPORT = qw(fast_open_urpmi_db open_urpmi_db open_rpm_db);
++
++# Note that most part of this perl module
++# is extracted from Rpmdrake
++
++sub fast_open_urpmi_db() {
++ my $urpm = urpm->new;
++ $urpm->get_global_options;
++ urpm::media::read_config($urpm);
++ $urpm;
++}
++
++sub open_urpmi_db {
++ my (%urpmi_options) = @_;
++ my $urpm = fast_open_urpmi_db();
++ my $media = ''; # See Rpmdrake source code for more information.
++
++ my $searchmedia = $urpmi_options{update} ? undef : join(',', get_inactive_backport_media($urpm));
++ $urpm->{lock} = urpm::lock::urpmi_db($urpm, undef, wait => $urpm->{options}{wait_lock});
++ my $previous = ''; # Same as $media above.
++ urpm::select::set_priority_upgrade_option($urpm, (ref $previous ? join(',', @$previous) : ()));
++ urpm::media::configure($urpm, media => $media, if_($searchmedia, searchmedia => $searchmedia), %urpmi_options);
++ $urpm;
++}
++
++sub get_inactive_backport_media {
++ my ($urpm) = @_;
++ map { $_->{name} } grep { $_->{ignore} && $_->{name} =~ /backport/i } @{$urpm->{media}};
++}
++
++sub open_rpm_db {
++ URPM::DB::open() or die "Couldn't open RPM DB";
++}
++
+diff --git a/backends/urpmi/helpers/urpmi_backend/tools.pm b/backends/urpmi/helpers/urpmi_backend/tools.pm
+new file mode 100644
+index 0000000..e078134
+--- /dev/null
++++ b/backends/urpmi/helpers/urpmi_backend/tools.pm
+@@ -0,0 +1,151 @@
++package urpmi_backend::tools;
++
++use strict;
++
++use URPM;
++use urpmi_backend::open_db;
++
++use Exporter;
++our @ISA = qw(Exporter);
++our @EXPORT = qw(
++ get_update_medias
++ rpm_description
++ urpm_name
++ find_installed_version
++ get_package_id
++ ensure_utf8
++ pkg2medium
++ fullname_to_package_id
++ get_package_by_package_id
++ package_version_is_installed
++ get_package_upgrade
++ get_installed_version
++ get_installed_version_pkid
++);
++
++sub get_update_medias {
++ my ($urpm) = @_;
++ grep { !$_->{ignore} && $_->{update} } @{$urpm->{media}};
++}
++
++sub rpm_description {
++ my ($description) = @_;
++ ensure_utf8($description);
++ my ($t, $tmp);
++ foreach (split "\n", $description) {
++ s/^\s*//;
++ if (/^$/ || /^\s*(-|\*|\+|o)\s/) {
++ $t || $tmp and $t .= "$tmp\n";
++ $tmp = $_;
++ } else {
++ $tmp = ($tmp ? "$tmp " : ($t && "\n") . $tmp) . $_;
++ }
++ }
++ "$t$tmp\n";
++}
++
++sub urpm_name {
++ return '?-?-?.?' unless ref $_[0];
++ my ($name, $version, $release, $arch) = $_[0]->fullname;
++ "$name-$version-$release.$arch";
++}
++
++sub ensure_utf8 {
++ my ($s) = @_;
++ require Encode;
++ Encode::_utf8_on($s); #- this is done on the copy
++ if (!Encode::is_utf8($s, 1)) {
++ Encode::_utf8_off($_[0]);
++ Encode::from_to($_[0], 'iso-8859-15', 'utf8'); # most probable
++ }
++ Encode::_utf8_on($_[0]); #- now we know it is valid utf8
++ $_[0];
++}
++
++sub find_installed_version {
++ my ($p) = @_;
++ my @version;
++ URPM::DB::open()->traverse_tag('name', [ $p->name ], sub { push @version, $_[0]->version . '-' . $_[0]->release });
++ @version ? join(',', sort @version) : "";
++}
++
++sub get_package_id {
++ my ($pkg) = @_;
++ return $pkg->name.";".$pkg->version."-".$pkg->release.";".$pkg->arch.";mandriva";
++}
++
++sub pkg2medium {
++ my ($p, $urpm) = @_;
++ return if !ref $p;
++ return { name => N("None (installed)") } if !$p->id; # if installed
++ URPM::pkg2media($urpm->{media}, $p) || undef;
++}
++
++sub fullname_to_package_id {
++ # fullname, ie 'xeyes-1.0.1-5mdv2008.1.i586'
++ my ($pkg_string) = @_;
++ chomp($pkg_string);
++ $pkg_string =~ /^(.*)-([^-]*)-([^-]*)\.([^\.]*)$/;
++ my %pkg = (
++ name => $1,
++ version => $2,
++ release => $3,
++ arch => $4
++ );
++ return $pkg{name}.";".$pkg{version}."-".$pkg{release}.";".$pkg{arch}.";mandriva";
++}
++
++sub get_package_by_package_id {
++ my ($urpm, $package_id) = @_;
++ my @depslist = @{$urpm->{depslist}};
++ foreach(@depslist) {
++ if(get_package_id($_) eq $package_id) {
++ return $_;
++ }
++ }
++ return;
++}
++
++sub package_version_is_installed {
++ my ($pkg) = @_;
++ return $pkg->version."-".$pkg->release eq find_installed_version($pkg);
++}
++
++sub get_package_upgrade {
++ my ($urpm, $pkg) = @_;
++ my $db = open_rpm_db();
++ $urpm->compute_installed_flags($db);
++ my @depslist = @{$urpm->{depslist}};
++ my $pkgname = $pkg->name;
++ foreach(@depslist) {
++ if($_->name =~ /^$pkgname$/ && $_->flag_upgrade) {
++ return $_;
++ }
++ }
++}
++
++sub get_installed_version {
++ my ($urpm, $pkg) = @_;
++ my @depslist = @{$urpm->{depslist}};
++ my $pkgname = $pkg->name;
++ foreach $_ (@depslist) {
++ if($_->name =~ /^$pkgname$/ && package_version_is_installed($_)) {
++ return $_;
++ }
++ }
++ return;
++}
++
++sub get_installed_version_pkid {
++ my ($pkg) = @_;
++ my $pkgname = $pkg->name;
++ my $db = open_rpm_db();
++ my $installed_pkid;
++ $db->traverse(sub {
++ my ($pkg) = @_;
++ if($pkg->name =~ /^$pkgname$/) {
++ $installed_pkid = get_package_id($pkg);
++ }
++ });
++ return $installed_pkid;
++}
+diff --git a/backends/urpmi/pk-backend-urpmi.c b/backends/urpmi/pk-backend-urpmi.c
+new file mode 100644
+index 0000000..e7b56a7
+--- /dev/null
++++ b/backends/urpmi/pk-backend-urpmi.c
+@@ -0,0 +1,355 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
++ *
++ * Copyright (C) 2007-2008 Richard Hughes <richard@hughsie.com>
++ *
++ * Licensed under the GNU General Public License Version 2
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++#include <pk-backend.h>
++#include <pk-backend-spawn.h>
++#include <pk-package-ids.h>
++
++static PkBackendSpawn *spawn;
++
++/**
++ * backend_initialize:
++ * This should only be run once per backend load, i.e. not every transaction
++ */
++static void
++backend_initialize (PkBackend *backend)
++{
++ pk_debug ("FILTER: initialize");
++ spawn = pk_backend_spawn_new ();
++ pk_backend_spawn_set_name (spawn, "urpmi");
++}
++
++/**
++ * backend_destroy:
++ * This should only be run once per backend load, i.e. not every transaction
++ */
++static void
++backend_destroy (PkBackend *backend)
++{
++ pk_debug ("FILTER: destroy");
++ g_object_unref (spawn);
++}
++
++/**
++ * backend_get_groups:
++ */
++static PkGroupEnum
++backend_get_groups (PkBackend *backend)
++{
++ return(PK_GROUP_ENUM_UNKNOWN |
++ PK_GROUP_ENUM_ACCESSIBILITY |
++ PK_GROUP_ENUM_ACCESSORIES |
++ PK_GROUP_ENUM_EDUCATION |
++ PK_GROUP_ENUM_GAMES |
++ PK_GROUP_ENUM_GRAPHICS |
++ PK_GROUP_ENUM_INTERNET |
++ PK_GROUP_ENUM_OFFICE |
++ PK_GROUP_ENUM_OTHER |
++ PK_GROUP_ENUM_PROGRAMMING |
++ PK_GROUP_ENUM_MULTIMEDIA |
++ PK_GROUP_ENUM_SYSTEM |
++ PK_GROUP_ENUM_DESKTOP_GNOME |
++ PK_GROUP_ENUM_DESKTOP_KDE |
++ PK_GROUP_ENUM_DESKTOP_XFCE |
++ PK_GROUP_ENUM_DESKTOP_OTHER |
++ PK_GROUP_ENUM_PUBLISHING |
++ PK_GROUP_ENUM_SERVERS |
++ PK_GROUP_ENUM_FONTS |
++ PK_GROUP_ENUM_ADMIN_TOOLS |
++ PK_GROUP_ENUM_LEGACY |
++ PK_GROUP_ENUM_LOCALIZATION |
++ PK_GROUP_ENUM_VIRTUALIZATION |
++ PK_GROUP_ENUM_POWER_MANAGEMENT |
++ PK_GROUP_ENUM_SECURITY |
++ PK_GROUP_ENUM_COMMUNICATION |
++ PK_GROUP_ENUM_NETWORK |
++ PK_GROUP_ENUM_MAPS |
++ PK_GROUP_ENUM_REPOS);
++}
++
++/**
++ * backend_get_filters:
++ */
++static PkFilterEnum
++backend_get_filters (PkBackend *backend)
++{
++ return (PK_FILTER_ENUM_GUI |
++ PK_FILTER_ENUM_INSTALLED |
++ PK_FILTER_ENUM_DEVELOPMENT);
++}
++
++/**
++ * pk_backend_bool_to_text:
++ */
++static const gchar *
++pk_backend_bool_to_text (gboolean value)
++{
++ if (value == TRUE) {
++ return "yes";
++ }
++ return "no";
++}
++
++
++/**
++ * pk_backend_search_name:
++ */
++static void
++backend_search_name (PkBackend *backend, PkFilterEnum filters, const gchar *search)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "search-name.pl", filters_text, search, NULL);
++ g_free (filters_text);
++}
++
++/**
++ * backend_get_details:
++ */
++static void
++backend_get_details (PkBackend *backend, const gchar *package_id)
++{
++ pk_backend_spawn_helper (spawn, "get-details.pl", package_id, NULL);
++}
++
++/**
++ * backend_get_files:
++ */
++static void
++backend_get_files (PkBackend *backend, const gchar *package_id)
++{
++ pk_backend_spawn_helper (spawn, "get-files.pl", package_id, NULL);
++}
++
++/**
++ * backend_get_depends:
++ */
++static void
++backend_get_depends (PkBackend *backend, PkFilterEnum filters, const gchar *package_id, gboolean recursive)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "get-depends.pl", filters_text, package_id, pk_backend_bool_to_text (recursive), NULL);
++ g_free (filters_text);
++}
++
++/**
++ * backend_get_updates:
++ */
++static void
++backend_get_updates (PkBackend *backend, PkFilterEnum filters)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "get-updates.pl", filters_text, NULL);
++ g_free (filters_text);
++}
++
++/**
++ * backend_get_update_detail:
++ */
++static void
++backend_get_update_detail (PkBackend *backend, const gchar *package_id)
++{
++ pk_backend_spawn_helper (spawn, "get-update-detail.pl", package_id, NULL);
++}
++
++/**
++ * backend_refresh_cache:
++ */
++static void
++backend_refresh_cache (PkBackend *backend, gboolean force)
++{
++ /* check network state */
++ if (!pk_backend_is_online (backend)) {
++ pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot refresh cache whilst offline");
++ pk_backend_finished (backend);
++ return;
++ }
++
++ pk_backend_spawn_helper (spawn, "refresh-cache.pl", NULL);
++}
++
++/**
++ * backend_install_packages:
++ */
++static void
++backend_install_packages (PkBackend *backend, gchar **package_ids)
++{
++ gchar *package_ids_temp;
++
++ /* check network state */
++ if (!pk_backend_is_online (backend)) {
++ pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot install when offline");
++ pk_backend_finished (backend);
++ return;
++ }
++
++ /* send the complete list as stdin */
++ package_ids_temp = pk_package_ids_to_text (package_ids, "|");
++ pk_backend_spawn_helper (spawn, "install-packages.pl", package_ids_temp, NULL);
++ g_free (package_ids_temp);
++}
++
++/**
++ * pk_backend_remove_packages:
++ */
++static void
++backend_remove_packages (PkBackend *backend, gchar **package_ids, gboolean allow_deps, gboolean autoremove)
++{
++ gchar *package_ids_temp;
++
++ /* send the complete list as stdin */
++ package_ids_temp = pk_package_ids_to_text (package_ids, "|");
++ pk_backend_spawn_helper (spawn, "remove-packages.pl", pk_backend_bool_to_text (allow_deps), package_ids_temp, NULL);
++ g_free (package_ids_temp);
++}
++
++/**
++ * pk_backend_search_group:
++ */
++static void
++backend_search_group (PkBackend *backend, PkFilterEnum filters, const gchar *search)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "search-group.pl", filters_text, search, NULL);
++ g_free (filters_text);
++}
++
++/**
++ * backend_get_packages:
++ */
++static void
++backend_get_packages (PkBackend *backend, PkFilterEnum filters)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "get-packages.pl", filters_text, NULL);
++ g_free (filters_text);
++}
++
++/**
++ * backend_get_requires:
++ */
++static void
++backend_get_requires (PkBackend *backend, PkFilterEnum filters, const gchar *package_id, gboolean recursive)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "get-requires.pl", filters_text, package_id, pk_backend_bool_to_text (recursive), NULL);
++ g_free (filters_text);
++}
++
++/**
++ * pk_backend_search_details:
++ */
++static void
++backend_search_details (PkBackend *backend, PkFilterEnum filters, const gchar *search)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "search-details.pl", filters_text, search, NULL);
++ g_free (filters_text);
++}
++
++/**
++ * pk_backend_search_file:
++ */
++static void
++backend_search_file (PkBackend *backend, PkFilterEnum filters, const gchar *search)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "search-file.pl", filters_text, search, NULL);
++ g_free (filters_text);
++}
++
++/**
++ * pk_backend_resolve:
++ */
++static void
++backend_resolve (PkBackend *backend, PkFilterEnum filters, const gchar *package_id)
++{
++ gchar *filters_text;
++ filters_text = pk_filter_enums_to_text (filters);
++ pk_backend_spawn_helper (spawn, "resolve.pl", filters_text, package_id, NULL);
++ g_free (filters_text);
++}
++
++/**
++ * pk_backend_update_packages:
++ */
++static void
++backend_update_packages (PkBackend *backend, gchar **package_ids)
++{
++ gchar *package_ids_temp;
++
++
++ /* check network state */
++ if (!pk_backend_is_online (backend)) {
++ pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot install when offline");
++ pk_backend_finished (backend);
++ return;
++ }
++
++ /* send the complete list as stdin */
++ package_ids_temp = pk_package_ids_to_text (package_ids, "|");
++ pk_backend_spawn_helper (spawn, "update-packages.pl", package_ids_temp, NULL);
++ g_free (package_ids_temp);
++}
++
++
++PK_BACKEND_OPTIONS (
++ "URPMI", /* description */
++ "Aurelien Lefebvre <alefebvre@mandriva.com>", /* author */
++ backend_initialize, /* initalize */
++ backend_destroy, /* destroy */
++ backend_get_groups, /* get_groups */
++ backend_get_filters, /* get_filters */
++ NULL, /* cancel */
++ backend_get_depends, /* get_depends */
++ backend_get_details, /* get_details */
++ backend_get_files, /* get_files */
++ backend_get_packages, /* get_packages */
++ NULL, /* get_repo_list */
++ backend_get_requires, /* get_requires */
++ backend_get_update_detail, /* get_update_detail */
++ backend_get_updates, /* get_updates */
++ NULL, /* install_files */
++ backend_install_packages, /* install_packages */
++ NULL, /* install_signature */
++ backend_refresh_cache, /* refresh_cache */
++ backend_remove_packages, /* remove_packages */
++ NULL, /* repo_enable */
++ NULL, /* repo_set_data */
++ backend_resolve, /* resolve */
++ NULL, /* rollback */
++ backend_search_details, /* search_details */
++ backend_search_file, /* search_file */
++ backend_search_group, /* search_group */
++ backend_search_name, /* search_name */
++ NULL, /* service_pack */
++ backend_update_packages, /* update_packages */
++ NULL, /* update_system */
++ NULL /* what_provides */
++);
++
+diff --git a/backends/yum/helpers/yumBackend.py b/backends/yum/helpers/yumBackend.py
+index 5b2da8f..d70d8dc 100644
+--- a/backends/yum/helpers/yumBackend.py
++++ b/backends/yum/helpers/yumBackend.py
+@@ -901,14 +901,16 @@ class PackageKitYumBackend(PackageKitBaseBackend):
+ if pkg and not inst:
+ repo = self.yumbase.repos.getRepo(pkg.repoid)
+ if not already_warned and not repo.gpgcheck:
+- self.message(MESSAGE_WARNING,"The package %s was installed untrusted from %s." % (pkg.name, repo))
++ self.message(MESSAGE_WARNING,"The untrusted package %s will be installed from %s." % (pkg.name, repo))
+ already_warned = True
+ txmbr = self.yumbase.install(name=pkg.name)
+ txmbrs.extend(txmbr)
++ if inst:
++ self.error(ERROR_PACKAGE_ALREADY_INSTALLED,"The package %s is already installed", pkg.name)
+ if txmbrs:
+ self._runYumTransaction()
+ else:
+- self.error(ERROR_PACKAGE_ALREADY_INSTALLED,"The package is already installed")
++ self.error(ERROR_PACKAGE_ALREADY_INSTALLED,"The packages failed to be installed")
+
+ def _checkForNewer(self,po):
+ pkgs = self.yumbase.pkgSack.returnNewestByName(name=po.name)
+@@ -927,6 +929,10 @@ class PackageKitYumBackend(PackageKitBaseBackend):
+ if inst_file.endswith('.src.rpm'):
+ self.error(ERROR_CANNOT_INSTALL_SOURCE_PACKAGE,'Backend will not install a src rpm file')
+ return
++ for inst_file in inst_files:
++ if not inst_file.endswith('.rpm'):
++ self.error(ERROR_INVALID_PACKAGE_FILE,'Only rpm packages are supported')
++ return
+ self._check_init()
+ self.allow_cancel(False);
+ self.percentage(0)
+@@ -1056,8 +1062,11 @@ class PackageKitYumBackend(PackageKitBaseBackend):
+
+ def _format_msgs(self,msgs):
+ if isinstance(msgs,basestring):
+- msgs = msgs.split('\n')
+- return ";".join(msgs)
++ msgs = msgs.split('\n')
++ text = ";".join(msgs)
++ text = text.replace("Missing Dependency: ","")
++ text = text.replace(" (installed)","")
++ return text
+
+ def _runYumTransaction(self,removedeps=None):
+ '''
+@@ -1092,16 +1101,19 @@ class PackageKitYumBackend(PackageKitBaseBackend):
+ if not keyData:
+ self.error(ERROR_BAD_GPG_SIGNATURE,
+ "GPG key not imported, and no GPG information was found.")
+-
+ id = self._pkg_to_id(keyData['po'])
++ fingerprint = keyData['fingerprint']
++ hex_fingerprint = "%02x" * len(fingerprint) % tuple(map(ord, fingerprint))
++ # Borrowed from http://mail.python.org/pipermail/python-list/2000-September/053490.html
++
+ self.repo_signature_required(id,
+ keyData['po'].repoid,
+- keyData['keyurl'],
++ keyData['keyurl'].replace("file://",""),
+ keyData['userid'],
+ keyData['hexkeyid'],
+- keyData['fingerprint'],
+- keyData['timestamp'],
+- 'GPG')
++ hex_fingerprint,
++ time.ctime(keyData['timestamp']),
++ 'gpg')
+ self.error(ERROR_GPG_FAILURE,"GPG key %s required" % keyData['hexkeyid'])
+ except yum.Errors.YumBaseError,ye:
+ message = self._format_msgs(ye.value)
+@@ -1110,7 +1122,7 @@ class PackageKitYumBackend(PackageKitBaseBackend):
+ else:
+ self.error(ERROR_TRANSACTION_ERROR,message)
+
+- def remove(self,allowdep,package):
++ def remove_packages(self,allowdep,package):
+ '''
+ Implement the {backend}-remove functionality
+ Needed to be implemented in a sub class
+@@ -1394,6 +1406,10 @@ class PackageKitYumBackend(PackageKitBaseBackend):
+ typ = ref['type']
+ href = ref['href']
+ title = ref['title'] or ""
++
++ # Description can sometimes have ';' in them, and we use that as the delimiter
++ title = title.replace(";",",")
++
+ if href:
+ if typ in ('bugzilla','cve'):
+ urls[typ].append("%s;%s" % (href,title))
+@@ -1555,11 +1571,7 @@ class DownloadCallback(BaseMeter):
+ '''
+ Get the name of the package being downloaded
+ '''
+- if self.text and type(self.text) == type(""):
+- name = self.text
+- else:
+- name = self.basename
+- return name
++ return self.basename
+
+ def updateProgress(self,name,frac,fread,ftime):
+ '''
+diff --git a/backends/yum2/helpers/yumDBUSBackend.py b/backends/yum2/helpers/yumDBUSBackend.py
+index 29f5b03..a708a0c 100755
+--- a/backends/yum2/helpers/yumDBUSBackend.py
++++ b/backends/yum2/helpers/yumDBUSBackend.py
+@@ -823,15 +823,24 @@ class PackageKitYumBackend(PackageKitBaseBackend):
+ self.PercentageChanged(0)
+ self.StatusChanged(STATUS_RUNNING)
+
+- pkg,inst = self._findPackage(package)
+- if pkg:
++ txmbrs = []
++ already_warned = False
++ for package in packages:
++ pkg,inst = self._findPackage(package)
++ if pkg and not inst:
++ repo = self.yumbase.repos.getRepo(pkg.repoid)
++ if not already_warned and not repo.gpgcheck:
++ self.message(MESSAGE_WARNING,"The untrusted package %s will be installed from %s." % (pkg.name, repo))
++ already_warned = True
++ txmbr = self.yumbase.install(name=pkg.name)
++ txmbrs.extend(txmbr)
+ if inst:
+ self._unlock_yum()
+- self.ErrorCode(ERROR_PACKAGE_ALREADY_INSTALLED,'Package already installed')
++ self.ErrorCode(ERROR_PACKAGE_ALREADY_INSTALLED,"The package %s is already installed", pkg.name)
+ self.Finished(EXIT_FAILED)
+ return
++ if txmbrs:
+ try:
+- txmbr = self.yumbase.install(name=pkg.name)
+ successful = self._runYumTransaction()
+ if not successful:
+ # _runYumTransaction unlocked yum, set the error code, and called Finished.
+@@ -844,7 +853,7 @@ class PackageKitYumBackend(PackageKitBaseBackend):
+ return
+ else:
+ self._unlock_yum()
+- self.ErrorCode(ERROR_PACKAGE_NOT_FOUND,"Package was not found")
++ self.ErrorCode(ERROR_PACKAGE_ALREADY_INSTALLED,"The packages failed to be installed")
+ self.Finished(EXIT_FAILED)
+ return
+
+@@ -1761,13 +1770,15 @@ class PackageKitYumBackend(PackageKitBaseBackend):
+ "GPG key not imported, but no GPG information received from Yum.")
+ self.Finished(EXIT_FAILED)
+ return False
+- self.RepoSignatureRequired(keyData['po'].repoid,
+- keyData['keyurl'],
++ id = self._pkg_to_id(keyData['po'])
++ self.RepoSignatureRequired(id,
++ keyData['po'].repoid,
++ keyData['keyurl'].replace("file://",""),
+ keyData['userid'],
+ keyData['hexkeyid'],
+ keyData['fingerprint'],
+- keyData['timestamp'],
+- SIGTYE_GPG)
++ time.ctime(keyData['timestamp']),
++ SIGTYPE_GPG)
+ self._unlock_yum()
+ self.ErrorCode(ERROR_GPG_FAILURE,"GPG key not imported.")
+ self.Finished(EXIT_FAILED)
+@@ -1893,6 +1904,10 @@ class PackageKitYumBackend(PackageKitBaseBackend):
+ type_ = ref['type']
+ href = ref['href']
+ title = ref['title'] or ""
++
++ # Description can sometimes have ';' in them, and we use that as the delimiter
++ title = title.replace(";",",")
++
+ if href:
+ if type_ in ('bugzilla', 'cve'):
+ urls[type_].append("%s;%s" % (href, title))
+diff --git a/backends/zypp/pk-backend-zypp.cpp b/backends/zypp/pk-backend-zypp.cpp
+index 15c4b4f..a971707 100644
+--- a/backends/zypp/pk-backend-zypp.cpp
++++ b/backends/zypp/pk-backend-zypp.cpp
+@@ -26,6 +26,7 @@
+ #include <pk-debug.h>
+ #include <string>
+ #include <set>
++#include <glib/gi18n.h>
+
+ #include <zypp/ZYppFactory.h>
+ #include <zypp/ResObject.h>
+@@ -47,7 +48,6 @@
+ #include <zypp/target/rpm/RpmDb.h>
+ #include <zypp/target/rpm/RpmHeader.h>
+ #include <zypp/target/rpm/RpmException.h>
+-#include <zypp/base/LogControl.h>
+ #include <zypp/TmpPath.h>
+
+ #include <zypp/sat/Solvable.h>
+@@ -90,12 +90,13 @@ std::map<PkBackend *, std::vector<std::string> *> _signatures;
+ static void
+ backend_initialize (PkBackend *backend)
+ {
+- zypp::base::LogControl::instance ().logfile("/var/log/pk_backend_zypp");
++ zypp_logging ();
+ pk_debug ("zypp_backend_initialize");
+ EventDirector *eventDirector = new EventDirector (backend);
+ _eventDirectors [backend] = eventDirector;
+ std::vector<std::string> *signature = new std::vector<std::string> ();
+ _signatures [backend] = signature;
++ _updating_self = FALSE;
+ }
+
+ /**
+@@ -287,7 +288,9 @@ backend_get_filters (PkBackend *backend)
+ return (PkFilterEnum) (PK_FILTER_ENUM_INSTALLED |
+ PK_FILTER_ENUM_NOT_INSTALLED |
+ PK_FILTER_ENUM_ARCH |
+- PK_FILTER_ENUM_NOT_ARCH);
++ PK_FILTER_ENUM_NOT_ARCH |
++ PK_FILTER_ENUM_SOURCE |
++ PK_FILTER_ENUM_NOT_SOURCE);
+ }
+
+ static gboolean
+@@ -403,7 +406,7 @@ backend_get_depends_thread (PkBackend *backend)
+ package_id_temp = pk_package_id_build (it->second.name ().c_str(),
+ it->second.edition ().asString ().c_str(),
+ it->second.arch ().c_str(),
+- it->second.repository ().name ().c_str());
++ it->second.repository ().alias ().c_str());
+
+ zypp::PoolItem item = zypp::ResPool::instance ().find (it->second);
+
+@@ -570,6 +573,32 @@ backend_refresh_cache (PkBackend *backend, gboolean force)
+ pk_backend_thread_create (backend, backend_refresh_cache_thread);
+ }
+
++/* If a critical self update (see qualifying steps below) is available then only show/install that update first.
++ 1. there is a patch available with the <restart_suggested> tag set
++ 2. The patch contains the package "PackageKit" or "gnome-packagekit
++*/
++/*static gboolean
++check_for_self_update (PkBackend *backend, std::set<zypp::PoolItem> *candidates)
++{
++ std::set<zypp::PoolItem>::iterator cb = candidates->begin (), ce = candidates->end (), ci;
++ for (ci = cb; ci != ce; ++ci) {
++ zypp::ResObject::constPtr res = ci->resolvable();
++ if (zypp::isKind<zypp::Patch>(res)) {
++ zypp::Patch::constPtr patch = zypp::asKind<zypp::Patch>(res);
++ //pk_debug ("restart_suggested is %d",(int)patch->restartSuggested());
++ if (patch->restartSuggested ()) {
++ if (!strcmp (PACKAGEKIT_RPM_NAME, res->satSolvable ().name ().c_str ()) ||
++ !strcmp (GNOME_PACKAGKEKIT_RPM_NAME, res->satSolvable ().name ().c_str ())) {
++ g_free (update_self_patch_name);
++ update_self_patch_name = zypp_build_package_id_from_resolvable (res->satSolvable ());
++ return TRUE;
++ }
++ }
++ }
++ }
++ return FALSE;
++}*/
++
+ static gboolean
+ backend_get_updates_thread (PkBackend *backend)
+ {
+@@ -586,12 +615,23 @@ backend_get_updates_thread (PkBackend *backend)
+ pk_backend_set_percentage (backend, 40);
+
+ // get all Packages and Patches for Update
+- std::set<zypp::PoolItem> *candidates = zypp_get_updates ();
+- std::set<zypp::PoolItem> *candidates2 = zypp_get_patches ();
++ 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 ();
++ }
++
++ candidates2 = zypp_get_updates (patchRepo);
+
+- candidates->insert (candidates2->begin (), candidates2->end ());
++ candidates->insert (candidates2->begin (), candidates2->end ());
++ }
+
+ pk_backend_set_percentage (backend, 80);
++
+ std::set<zypp::PoolItem>::iterator cb = candidates->begin (), ce = candidates->end (), ci;
+ for (ci = cb; ci != ce; ++ci) {
+ zypp::ResObject::constPtr res = ci->resolvable();
+@@ -716,7 +756,7 @@ backend_install_files_thread (PkBackend *backend)
+ gboolean found = FALSE;
+
+ for (std::vector<zypp::sat::Solvable>::iterator it = solvables->begin (); it != solvables->end (); it ++) {
+- if (it->repository ().name () == "PK_TMP_DIR") {
++ if (it->repository ().alias () == "PK_TMP_DIR") {
+ item = new zypp::PoolItem(*it);
+ found = TRUE;
+ break;
+@@ -861,14 +901,28 @@ backend_update_system_thread (PkBackend *backend)
+ zypp::ResPool pool = zypp_build_pool (TRUE);
+ pk_backend_set_percentage (backend, 40);
+
+- // get all Packages for Update
+- std::set<zypp::PoolItem> *candidates = zypp_get_updates ();
+ //get all Patches for Update
+- std::set<zypp::PoolItem> *candidates2 = zypp_get_patches ();
++ std::set<zypp::PoolItem> *candidates = zypp_get_patches ();
++ std::set<zypp::PoolItem> *candidates2 = new std::set<zypp::PoolItem> ();
++
++ if (_updating_self) {
++ pk_backend_require_restart (backend, PK_RESTART_ENUM_SESSION, "Package Management System updated - restart needed");
++ _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
++ //concatenate these sets
+
+- candidates->insert (candidates->begin (), candidates->end ());
++ candidates->insert (candidates2->begin (), candidates2->end ());
++ }
+
+ pk_backend_set_percentage (backend, 80);
+ std::set<zypp::PoolItem>::iterator cb = candidates->begin (), ce = candidates->end (), ci;
+@@ -1332,6 +1386,10 @@ backend_repo_enable (PkBackend *backend, const gchar *rid, gboolean enabled)
+ repo = manager.getRepositoryInfo (rid);
+ repo.setEnabled (enabled);
+ manager.modifyRepository (rid, repo);
++ if (!enabled) {
++ zypp::Repository repository = zypp::sat::Pool::instance ().reposFind (repo.alias ());
++ repository.eraseFromPool ();
++ }
+ } catch (const zypp::repo::RepoNotFoundException &ex) {
+ pk_backend_error_code (backend, PK_ERROR_ENUM_REPO_NOT_FOUND, "Couldn't find the specified repository");
+ pk_backend_finished (backend);
+@@ -1463,6 +1521,13 @@ backend_update_packages_thread (PkBackend *backend)
+ gchar **package_ids;
+ package_ids = pk_backend_get_strv (backend, "package_ids");
+
++ zypp_get_patches (); // make shure _updating_self is set
++
++ if (_updating_self) {
++ pk_debug ("updating self and setting restart");
++ 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++) {
+ zypp::sat::Solvable solvable = zypp_get_package_by_id (package_ids[i]);
+ zypp::PoolItem item = zypp::ResPool::instance ().find (solvable);
+diff --git a/backends/zypp/zypp-utils.cpp b/backends/zypp/zypp-utils.cpp
+index 2b848f0..d81d0dd 100644
+--- a/backends/zypp/zypp-utils.cpp
++++ b/backends/zypp/zypp-utils.cpp
+@@ -25,6 +25,8 @@
+ #include <sstream>
+ #include <stdlib.h>
+ #include <glib.h>
++#include <glib/gstdio.h>
++#include <glib/gi18n.h>
+ #include <zypp/ZYpp.h>
+ #include <zypp/ZYppFactory.h>
+ #include <zypp/RepoManager.h>
+@@ -45,6 +47,7 @@
+ #include <zypp/target/rpm/RpmDb.h>
+ #include <zypp/target/rpm/RpmHeader.h>
+ #include <zypp/target/rpm/librpmDb.h>
++#include <zypp/base/LogControl.h>
+
+ #include <zypp/base/Logger.h>
+
+@@ -53,6 +56,7 @@
+ #include "zypp-utils.h"
+
+ gchar * _repoName;
++gboolean _updating_self = FALSE;
+ /**
+ * Collect items, select best edition. This is used to find the best
+ * available or installed. The name of the class is a bit misleading though ...
+@@ -98,6 +102,34 @@ get_zypp ()
+ return zypp;
+ }
+
++/**
++ * Enable and rotate zypp logging
++ */
++gboolean
++zypp_logging ()
++{
++ gchar *file = g_strdup ("/var/log/pk_backend_zypp");
++ gchar *file_old = g_strdup ("/var/log/pk_backend_zypp-1");
++
++ if (g_file_test (file, G_FILE_TEST_EXISTS)) {
++ struct stat buffer;
++ g_stat (file, &buffer);
++ // if the file is bigger than 10 MB rotate
++ if ((guint)buffer.st_size > 10485760) {
++ if (g_file_test (file_old, G_FILE_TEST_EXISTS))
++ g_remove (file_old);
++ g_rename (file, file_old);
++ }
++ }
++
++ zypp::base::LogControl::instance ().logfile(file);
++
++ g_free (file);
++ g_free (file_old);
++
++ return TRUE;
++}
++
+ gboolean
+ zypp_is_changeable_media (const zypp::Url &url)
+ {
+@@ -120,13 +152,13 @@ zypp_build_pool (gboolean include_local)
+ zypp::ZYpp::Ptr zypp = get_zypp ();
+
+ if (include_local == TRUE) {
+- //FIXME have to wait for fix in zypp (repeated loading of target)
+- if (zypp::sat::Pool::instance().reposFind( zypp::sat::Pool::systemRepoName() ).solvablesEmpty ())
+- {
+- // Add local resolvables
+- zypp::Target_Ptr target = zypp->target ();
+- target->load ();
+- }
++ //FIXME have to wait for fix in zypp (repeated loading of target)
++ if (zypp::sat::Pool::instance().reposFind( zypp::sat::Pool::systemRepoAlias() ).solvablesEmpty ())
++ {
++ // Add local resolvables
++ zypp::Target_Ptr target = zypp->target ();
++ target->load ();
++ }
+ }
+
+ // Add resolvables from enabled repos
+@@ -163,16 +195,16 @@ zypp_build_pool (gboolean include_local)
+ zypp::ResPool
+ zypp_build_local_pool ()
+ {
+- zypp::sat::Pool pool = zypp::sat::Pool::instance ();
++ zypp::sat::Pool pool = zypp::sat::Pool::instance ();
+ zypp::ZYpp::Ptr zypp = get_zypp ();
+
+ try {
+ for (zypp::detail::RepositoryIterator it = pool.reposBegin (); it != pool.reposEnd (); it++){
+ if (! it->isSystemRepo ())
+- pool.reposErase(it->name ());
++ pool.reposErase(it->alias ());
+ }
+
+- if (zypp::sat::Pool::instance().reposFind( zypp::sat::Pool::systemRepoName() ).solvablesEmpty ())
++ if (zypp::sat::Pool::instance().reposFind( zypp::sat::Pool::systemRepoAlias() ).solvablesEmpty ())
+ {
+ // Add local resolvables
+ zypp::Target_Ptr target = zypp->target ();
+@@ -371,27 +403,49 @@ zypp_build_package_id_from_resolvable (zypp::sat::Solvable resolvable)
+ package_id = pk_package_id_build (resolvable.name ().c_str (),
+ resolvable.edition ().asString ().c_str (),
+ resolvable.arch ().asString ().c_str (),
+- resolvable.repository (). name().c_str ());
++ resolvable.repository (). alias().c_str ());
+
+ return package_id;
+ }
+
++zypp::RepoInfo
++zypp_get_Repository (PkBackend *backend, const gchar *alias)
++{
++ zypp::RepoInfo info;
++
++ try {
++ zypp::RepoManager manager;
++ info = manager.getRepositoryInfo (alias);
++ } catch (const zypp::repo::RepoNotFoundException &ex) {
++ pk_backend_error_code (backend, PK_ERROR_ENUM_REPO_NOT_FOUND, ex.asUserString().c_str() );
++ return zypp::RepoInfo ();
++ }
++
++ return info;
++}
++
+ gboolean
+ zypp_signature_required (PkBackend *backend, const zypp::PublicKey &key)
+ {
+ gboolean ok = FALSE;
+
+ if (std::find (_signatures[backend]->begin (), _signatures[backend]->end (), key.id ()) == _signatures[backend]->end ()) {
++ zypp::RepoInfo info = zypp_get_Repository (backend, _repoName);
++ if (info.type () == zypp::repo::RepoType::NONE) {
++ pk_backend_error_code (backend, PK_ERROR_ENUM_INTERNAL_ERROR, "Repository unknown");
++ return FALSE;
++ }
++
+ pk_backend_repo_signature_required (backend,
+ "dummy;0.0.1;i386;data",
+ _repoName,
+- key.path ().c_str (),
+- key.id ().c_str (),
++ info.baseUrlsBegin ()->asString ().c_str (),
++ key.name ().c_str (),
+ key.id ().c_str (),
+ key.fingerprint ().c_str (),
+ key.created ().asString ().c_str (),
+ PK_SIGTYPE_ENUM_GPG);
+- pk_backend_error_code (backend, PK_ERROR_ENUM_GPG_FAILURE, "Repo signature verification failed");
++ pk_backend_error_code (backend, PK_ERROR_ENUM_GPG_FAILURE, "Signature verification for Repository %s failed", _repoName);
+ }else{
+ ok = TRUE;
+ }
+@@ -405,16 +459,22 @@ zypp_signature_required (PkBackend *backend, const std::string &file, const std:
+ gboolean ok = FALSE;
+
+ if (std::find (_signatures[backend]->begin (), _signatures[backend]->end (), id) == _signatures[backend]->end ()) {
++ zypp::RepoInfo info = zypp_get_Repository (backend, _repoName);
++ if (info.type () == zypp::repo::RepoType::NONE) {
++ pk_backend_error_code (backend, PK_ERROR_ENUM_INTERNAL_ERROR, "Repository unknown");
++ return FALSE;
++ }
++
+ pk_backend_repo_signature_required (backend,
+ "dummy;0.0.1;i386;data",
+ _repoName,
+- file.c_str (),
++ info.baseUrlsBegin ()->asString ().c_str (),
+ id.c_str (),
+ id.c_str (),
+ "UNKNOWN",
+ "UNKNOWN",
+ PK_SIGTYPE_ENUM_GPG);
+- pk_backend_error_code (backend, PK_ERROR_ENUM_GPG_FAILURE, "Repo signature verification failed");
++ pk_backend_error_code (backend, PK_ERROR_ENUM_GPG_FAILURE, "Signature verification for Repository %s failed", _repoName);
+ }else{
+ ok = TRUE;
+ }
+@@ -428,16 +488,22 @@ zypp_signature_required (PkBackend *backend, const std::string &file)
+ gboolean ok = FALSE;
+
+ if (std::find (_signatures[backend]->begin (), _signatures[backend]->end (), file) == _signatures[backend]->end ()) {
+- pk_backend_repo_signature_required (backend,
++ zypp::RepoInfo info = zypp_get_Repository (backend, _repoName);
++ if (info.type () == zypp::repo::RepoType::NONE) {
++ pk_backend_error_code (backend, PK_ERROR_ENUM_INTERNAL_ERROR, "Repository unknown");
++ return FALSE;
++ }
++
++ pk_backend_repo_signature_required (backend,
+ "dummy;0.0.1;i386;data",
+ _repoName,
+- file.c_str (),
++ info.baseUrlsBegin ()->asString ().c_str (),
+ "UNKNOWN",
+ file.c_str (),
+ "UNKNOWN",
+ "UNKNOWN",
+ PK_SIGTYPE_ENUM_GPG);
+- pk_backend_error_code (backend, PK_ERROR_ENUM_GPG_FAILURE, "Repo signature verification failed");
++ pk_backend_error_code (backend, PK_ERROR_ENUM_GPG_FAILURE, "Signature verification for Repository %s failed", _repoName);
+ }else{
+ ok = TRUE;
+ }
+@@ -481,6 +547,12 @@ zypp_emit_packages_in_list (PkBackend *backend, std::vector<zypp::sat::Solvable>
+ system_and_package_are_x86 (*it))
+ print = FALSE;
+ }
++ if (i == PK_FILTER_ENUM_SOURCE && !(zypp::isKind<zypp::SrcPackage>(*it))) {
++ print = FALSE;
++ }
++ if (i == PK_FILTER_ENUM_NOT_SOURCE && zypp::isKind<zypp::SrcPackage>(*it)) {
++ print = FALSE;
++ }
+ //const gchar * myarch = zypp::ZConfig::defaultSystemArchitecture().asString().c_str();
+ //pk_debug ("my default arch is %s", myarch);
+ }
+@@ -527,7 +599,7 @@ zypp_find_arch_update_item (const zypp::ResPool & pool, zypp::PoolItem item)
+ }
+
+ std::set<zypp::PoolItem> *
+-zypp_get_updates ()
++zypp_get_updates (std::string repo)
+ {
+ std::set<zypp::PoolItem> *pks = new std::set<zypp::PoolItem> ();
+ zypp::ResPool pool = zypp::ResPool::instance ();
+@@ -542,7 +614,12 @@ zypp_get_updates ()
+ zypp::PoolItem candidate = zypp_find_arch_update_item (pool, *it);
+ if (!candidate.resolvable ())
+ continue;
+- pks->insert (candidate);
++ if (repo.empty ()) {
++ pks->insert (candidate);
++ }else{
++ if (candidate->repoInfo ().alias ().compare (repo) != 0)
++ pks->insert (candidate);
++ }
+ }
+
+ return pks;
+@@ -552,6 +629,7 @@ std::set<zypp::PoolItem> *
+ zypp_get_patches ()
+ {
+ std::set<zypp::PoolItem> *patches = new std::set<zypp::PoolItem> ();
++ _updating_self = FALSE;
+
+ zypp::ZYpp::Ptr zypp;
+ zypp = get_zypp ();
+@@ -561,8 +639,18 @@ zypp_get_patches ()
+ for (zypp::ResPoolProxy::const_iterator it = zypp->poolProxy ().byKindBegin<zypp::Patch>();
+ it != zypp->poolProxy ().byKindEnd<zypp::Patch>(); it ++) {
+ // check if patch is needed
+- if((*it)->candidateObj ().isBroken())
++ if((*it)->candidateObj ().isBroken()) {
+ patches->insert ((*it)->candidateObj ());
++ zypp::Patch::constPtr patch = zypp::asKind<zypp::Patch>((*it)->candidateObj ().resolvable ());
++
++ // check if the patch updates libzypp or packageKit and show only this one
++ if (patch->restartSuggested ()) {
++ _updating_self = TRUE;
++ patches->clear ();
++ patches->insert ((*it)->candidateObj ());
++ break;
++ }
++ }
+
+ }
+
+diff --git a/backends/zypp/zypp-utils.h b/backends/zypp/zypp-utils.h
+index 9e3bad1..4f785cf 100644
+--- a/backends/zypp/zypp-utils.h
++++ b/backends/zypp/zypp-utils.h
+@@ -62,6 +62,11 @@ typedef enum {
+ */
+ extern std::map<PkBackend *, std::vector<std::string> *> _signatures;
+
++/** Used to show/install only an update to ourself. This way if we find a critical bug
++ * in the way we update packages we will install the fix before any other updates.
++ */
++extern gboolean _updating_self;
++
+ /** A string to store the last refreshed repo
+ * this is needed for gpg-key handling stuff (UGLY HACK)
+ * FIXME
+@@ -70,6 +75,11 @@ extern gchar *_repoName;
+
+ zypp::ZYpp::Ptr get_zypp ();
+
++/**
++ * Enable and rotate logging
++ */
++gboolean zypp_logging ();
++
+ gboolean zypp_is_changeable_media (const zypp::Url &url);
+
+ /**
+@@ -125,6 +135,12 @@ zypp::sat::Solvable zypp_get_package_by_id (const gchar *package_id);
+ gchar * zypp_build_package_id_from_resolvable (zypp::sat::Solvable resolvable);
+
+ /**
++ * Get the RepoInfo
++ */
++zypp::RepoInfo
++zypp_get_Repository (PkBackend *backend, const gchar *alias);
++
++/**
+ * Ask the User if it is OK to import an GPG-Key for a repo
+ */
+ gboolean zypp_signature_required (PkBackend *backend, const zypp::PublicKey &key);
+@@ -145,9 +161,9 @@ 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
++ * Returns a set of all packages the could be updated (you're able to exclude a repo)
+ */
+-std::set<zypp::PoolItem> * zypp_get_updates ();
++std::set<zypp::PoolItem> * zypp_get_updates (std::string repo);
+
+ /**
+ * Returns a set of all patches the could be installed
+diff --git a/client/pk-console.c b/client/pk-console.c
+index 5a05a8e..ec93978 100644
+--- a/client/pk-console.c
++++ b/client/pk-console.c
+@@ -76,7 +76,6 @@ pk_console_bar (guint subpercentage)
+ return;
+ }
+ if (!has_output_bar) {
+- pk_warning ("no bar");
+ return;
+ }
+ /* restore cursor */
+@@ -487,6 +486,7 @@ pk_console_perhaps_resolve (PkClient *client, PkFilterEnum filter, const gchar *
+ guint i;
+ guint length;
+ PkPackageItem *item;
++ PkPackageList *list;
+
+ /* have we passed a complete package_id? */
+ valid = pk_package_id_check (package);
+@@ -508,7 +508,9 @@ pk_console_perhaps_resolve (PkClient *client, PkFilterEnum filter, const gchar *
+ }
+
+ /* get length of items found */
+- length = pk_client_package_buffer_get_size (client_task);
++ list = pk_client_get_package_list (client_task);
++ length = pk_package_list_get_size (list);
++ g_object_unref (list);
+
+ /* didn't resolve to anything, try to get a provide */
+ if (length == 0) {
+@@ -524,8 +526,9 @@ pk_console_perhaps_resolve (PkClient *client, PkFilterEnum filter, const gchar *
+ }
+ }
+
+- /* get length of items found again (we might have has success) */
+- length = pk_client_package_buffer_get_size (client_task);
++ /* get length of items found again (we might have had success) */
++ list = pk_client_get_package_list (client_task);
++ length = pk_package_list_get_size (list);
+ if (length == 0) {
+ pk_warning (_("Could not find a package match"));
+ return NULL;
+@@ -533,7 +536,7 @@ pk_console_perhaps_resolve (PkClient *client, PkFilterEnum filter, const gchar *
+
+ /* only found one, great! */
+ if (length == 1) {
+- item = pk_client_package_buffer_get_item (client_task, 0);
++ item = pk_package_list_get_item (list, 0);
+ return g_strdup (item->package_id);
+ }
+
+@@ -543,14 +546,16 @@ pk_console_perhaps_resolve (PkClient *client, PkFilterEnum filter, const gchar *
+ }
+ g_print ("%s\n", _("There are multiple package matches"));
+ for (i=0; i<length; i++) {
+- item = pk_client_package_buffer_get_item (client_task, i);
++ item = pk_package_list_get_item (list, i);
+ g_print ("%i. %s\n", i+1, item->package_id);
+ }
+
+ /* find out what package the user wants to use */
+ i = pk_console_get_number (_("Please enter the package number: "), length);
+- item = pk_client_package_buffer_get_item (client_task, i-1);
++ item = pk_package_list_get_item (list, i-1);
+ pk_debug ("package_id = %s", item->package_id);
++ g_object_unref (list);
++
+ return g_strdup (item->package_id);
+ }
+
+@@ -574,7 +579,8 @@ pk_console_install_stuff (PkClient *client, gchar **packages, GError **error)
+ array_files = g_ptr_array_new ();
+ length = g_strv_length (packages);
+ for (i=2; i<length; i++) {
+- is_local = g_file_test (packages[i], G_FILE_TEST_EXISTS);
++ /* are we a local file */
++ is_local = g_file_test (packages[i], G_FILE_TEST_EXISTS & G_FILE_TEST_IS_REGULAR);
+ if (is_local) {
+ g_ptr_array_add (array_files, g_strdup (packages[i]));
+ } else {
+@@ -720,6 +726,7 @@ pk_console_remove_packages (PkClient *client, gchar **packages, GError **error)
+ GPtrArray *array;
+ gchar **package_ids = NULL;
+ PkPackageList *list;
++ PkPackageList *list_single;
+
+ array = g_ptr_array_new ();
+ list = pk_package_list_new ();
+@@ -769,11 +776,13 @@ pk_console_remove_packages (PkClient *client, gchar **packages, GError **error)
+ }
+
+ /* see how many packages there are */
+- size = pk_client_package_buffer_get_size (client_task);
++ list_single = pk_client_get_package_list (client_task);
++ size = pk_package_list_get_size (list_single);
+ for (j=0; j<size; j++) {
+- item = pk_client_package_buffer_get_item (client_task, j);
++ item = pk_package_list_get_item (list_single, j);
+ pk_package_list_add_item (list, item);
+ }
++ g_object_unref (list_single);
+ }
+
+ /* one of the get-requires failed */
+diff --git a/client/pk-import-desktop.c b/client/pk-import-desktop.c
+index f5be0a5..bfe364f 100644
+--- a/client/pk-import-desktop.c
++++ b/client/pk-import-desktop.c
+@@ -44,53 +44,58 @@ static gchar *
+ pk_desktop_get_name_for_file (const gchar *filename)
+ {
+ guint size;
+- gchar *name;
++ gchar *name = NULL;
+ PkPackageItem *item;
+ PkPackageId *pid;
+ gboolean ret;
+ GError *error = NULL;
++ PkPackageList *list = NULL;
+
+ /* use PK to find the correct package */
+ ret = pk_client_reset (client, &error);
+ if (!ret) {
+ pk_warning ("failed to reset client: %s", error->message);
+ g_error_free (error);
+- return NULL;
++ goto out;
+ }
+
+ ret = pk_client_search_file (client, PK_FILTER_ENUM_INSTALLED, filename, &error);
+ if (!ret) {
+ pk_warning ("failed to search file: %s", error->message);
+ g_error_free (error);
+- return NULL;
++ goto out;
+ }
+
+ /* check that we only matched one package */
+- size = pk_client_package_buffer_get_size (client);
++ list = pk_client_get_package_list (client);
++ size = pk_package_list_get_size (list);
+ if (size != 1) {
+ pk_warning ("not correct size, %i", size);
+- return NULL;
++ goto out;
+ }
+
+ /* get the item */
+- item = pk_client_package_buffer_get_item (client, 0);
++ item = pk_package_list_get_item (list, 0);
+ if (item == NULL) {
+ pk_error ("cannot get item");
+- return NULL;
++ goto out;
+ }
+
+ /* get the package name */
+ pid = pk_package_id_new_from_string (item->package_id);
+ if (pid == NULL) {
+ pk_error ("cannot allocate package id");
+- return NULL;
++ goto out;
+ }
+
+ /* strip the name */
+ name = g_strdup (pid->name);
+ pk_package_id_free (pid);
+
+- /* return a copy */
++out:
++ if (list != NULL) {
++ g_object_unref (list);
++ }
+ return name;
+ }
+
+diff --git a/client/pk-import-specspo.c b/client/pk-import-specspo.c
+index cf14cc2..bffd45b 100644
+--- a/client/pk-import-specspo.c
++++ b/client/pk-import-specspo.c
+@@ -56,6 +56,7 @@ pk_import_specspo_get_summary (const gchar *name)
+ gboolean ret;
+ PkPackageItem *item;
+ GError *error = NULL;
++ PkPackageList *list;
+
+ ret = pk_client_reset (client, &error);
+ if (!ret) {
+@@ -74,18 +75,21 @@ pk_import_specspo_get_summary (const gchar *name)
+ }
+
+ /* check that we only matched one package */
+- size = pk_client_package_buffer_get_size (client);
++ list = pk_client_get_package_list (client);
++ size = pk_package_list_get_size (list);
+ if (size != 1) {
+ pk_warning ("not correct size, %i", size);
+ return NULL;
+ }
+
+ /* get the item */
+- item = pk_client_package_buffer_get_item (client, 0);
++ item = pk_package_list_get_item (list, 0);
+ if (item == NULL) {
+ pk_error ("cannot get item");
++ g_object_unref (list);
+ return NULL;
+ }
++ g_object_unref (list);
+
+ return item->summary;
+ }
+diff --git a/configure.ac b/configure.ac
+index f614d2b..7510b03 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -223,7 +223,6 @@ AC_ARG_ENABLE(gprof, AS_HELP_STRING([--enable-gprof],[compile with gprof support
+ # backends
+ AC_ARG_ENABLE(alpm, AS_HELP_STRING([--enable-alpm],[use the ALPM backend]),enable_alpm=$enableval,enable_alpm=no)
+ AC_ARG_ENABLE(apt, AS_HELP_STRING([--enable-apt],[use the APT backend]),enable_apt=$enableval,enable_apt=no)
+-AC_ARG_ENABLE(apt2, AS_HELP_STRING([--enable-apt2],[use the DBus based APT backend]),enable_apt2=$enableval,enable_apt2=no)
+ AC_ARG_ENABLE(box, AS_HELP_STRING([--enable-box],[use the BOX backend]),enable_box=$enableval,enable_box=no)
+ AC_ARG_ENABLE(conary, AS_HELP_STRING([--enable-conary],[use the CONARY backend]),enable_conary=$enableval,enable_conary=no)
+ AC_ARG_ENABLE(dummy, AS_HELP_STRING([--enable-dummy],[use the dummy backend]),enable_dummy=$enableval,enable_dummy=yes)
+@@ -231,6 +230,7 @@ AC_ARG_ENABLE(opkg, AS_HELP_STRING([--enable-opkg],[use the OPKG backend]),enabl
+ 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(smart, AS_HELP_STRING([--enable-smart],[use the SMART backend]),enable_smart=$enableval,enable_smart=no)
++AC_ARG_ENABLE(urpmi, AS_HELP_STRING([--enable-urpmi],[use the URPMI backend]),enable_urpmi=$enableval,enable_urpmi=no)
+ AC_ARG_ENABLE(yum, AS_HELP_STRING([--enable-yum],[use the YUM backend]),enable_yum=$enableval,enable_yum=no)
+ AC_ARG_ENABLE(yum2, AS_HELP_STRING([--enable-yum2],[use the YUM DBUS backend]),enable_yum2=$enableval,enable_yum2=no)
+ AC_ARG_ENABLE(zypp, AS_HELP_STRING([--enable-zypp],[use the Zypp backend]),enable_zypp=$enableval,enable_zypp=no)
+@@ -238,7 +238,6 @@ AC_ARG_ENABLE(zypp, AS_HELP_STRING([--enable-zypp],[use the Zypp backend]),enabl
+ # export to Makefile.am's
+ AM_CONDITIONAL(BACKEND_TYPE_ALPM, [test x$enable_alpm = xyes], [using ALPM backend])
+ AM_CONDITIONAL(BACKEND_TYPE_APT, [test x$enable_apt = xyes], [using APT backend])
+-AM_CONDITIONAL(BACKEND_TYPE_APT_DBUS, [test x$enable_apt2 = xyes], [using DBus based APT backend])
+ AM_CONDITIONAL(BACKEND_TYPE_BOX, [test x$enable_box = xyes], [using BOX backend])
+ AM_CONDITIONAL(BACKEND_TYPE_CONARY, [test x$enable_conary = xyes], [using CONARY backend])
+ AM_CONDITIONAL(BACKEND_TYPE_DUMMY, [test x$enable_dummy = xyes], [using dummy backend])
+@@ -246,6 +245,7 @@ AM_CONDITIONAL(BACKEND_TYPE_OPKG, [test x$enable_opkg = xyes], [using OPKG backe
+ AM_CONDITIONAL(BACKEND_TYPE_PISI, [test x$enable_pisi = xyes], [using PiSi backend])
+ AM_CONDITIONAL(BACKEND_TYPE_POLDEK, [test x$enable_poldek = xyes], [using poldek backend])
+ AM_CONDITIONAL(BACKEND_TYPE_SMART, [test x$enable_smart = xyes], [using SMART backend])
++AM_CONDITIONAL(BACKEND_TYPE_URPMI, [test x$enable_urpmi = xyes], [using URPMI backend])
+ AM_CONDITIONAL(BACKEND_TYPE_YUM, [test x$enable_yum = xyes], [using YUM backend])
+ AM_CONDITIONAL(BACKEND_TYPE_YUM2, [test x$enable_yum2 = xyes], [using YUM DBUS backend])
+ AM_CONDITIONAL(BACKEND_TYPE_ZYPP, [test x$enable_zypp = xyes], [using Zypp backend])
+@@ -369,7 +369,7 @@ dnl ---------------------------------------------------------------------------
+ AC_ARG_WITH([default_backend],
+ AS_HELP_STRING([--with-default-backend=<option>],
+ [Default backend to use
+- alpm,apt,apt2,box,conary,dummy,smart,yum,pisi,zypp,opkg (dummy)]))
++ alpm,apt,box,conary,dummy,smart,urpmi,yum,pisi,zypp,opkg (dummy)]))
+ # default to a sane option for the installed tool
+ if test x$with_default_backend = x; then
+ if test -f /usr/bin/yum ; then
+@@ -388,6 +388,8 @@ if test x$with_default_backend = x; then
+ with_default_backend=pisi
+ elif test -f /usr/bin/poldek ; then
+ with_default_backend=poldek
++ elif test -f /usr/bin/urpmq ; then
++ with_default_backend=urpmi
+ elif test -f /usr/bin/zypper ; then
+ with_default_backend=zypp
+ else
+@@ -398,134 +400,8 @@ fi
+ AC_DEFINE_UNQUOTED(DEFAULT_BACKEND, "$with_default_backend", [default backend prefix])
+ AC_SUBST(DEFAULT_BACKEND, "$with_default_backend")
+
+-AC_DEFUN([APT_BACKEND],
+-[
+- if test "$APT_PKG_TYPE" == "" ; then
+- AC_LANG_PUSH(C++)
+- _libaptpkg_save_cppflags=$CPPFLAGS
+- CPPFLAGS="$APT_CFLAGS $CPPFLAGS"
+- _APT_save_libs=$LIBS
+- LIBS="$APT_LIBS $LIBS"
+-
+- AC_MSG_CHECKING([for apt support for $1 packages])
+- AC_RUN_IFELSE(AC_LANG_PROGRAM([
+- #include <apt-pkg/configuration.h>
+- #include <apt-pkg/pkgsystem.h>
+- #include <apt-pkg/init.h>
+- #include <stdio.h>
+- ],[
+- if (pkgInitConfig(*_config) == false)
+- {
+- fprintf(stderr,"pkginitconfig was false");
+- return -1;
+- }
+- if (pkgInitSystem(*_config, _system) == false)
+- {
+- fprintf(stderr,"pkginitsystem was false");
+- return -1;
+- }
+- if (_system->ArchiveSupported("$1"))
+- return 0;
+- else
+- return 1;
+- ]),[
+- APT_PKG_TYPE=$1
+- AC_MSG_RESULT([yes])
+- AC_DEFINE(APT_PKG_$2,1,[apt-pkg support files of type $1])
+- ],)
+- AC_LANG_POP(C++)
+- CPPFLAGS=$_libaptpkg_save_cppflags
+- LIBS=$_libaptpkg_save_libs
+- unset _libaptpkg_save_cppflags
+- unset _libaptpkg_save_libs
+- fi
+-])
+-
+ if test x$enable_apt = xyes; then
+ PY_CHECK_MOD([apt_pkg],,,AC_MSG_ERROR([Apt backend needs python-apt]))
+-
+- AC_ARG_WITH([apt_search],
+- AS_HELP_STRING([--with-apt-search=<option>],
+- [Apt search type to use - plain,sqlite (plain)]))
+-
+- if test x$with_apt_search = x; then
+- with_apt_search=plain
+- fi
+- AC_MSG_NOTICE([using $with_apt_search for apt searching])
+- AC_DEFINE_UNQUOTED(APT_SEARCH, "$with_apt_search", [apt search type])
+- AC_SUBST(APT_SEARCH, $with_apt_search)
+- AM_CONDITIONAL(APT_SEARCH_PLAIN, [test x$with_apt_search = xplain], [using plain apt search])
+- AM_CONDITIONAL(APT_SEARCH_SQLITE, [test x$with_apt_search = xsqlite], [using sqlite apt search])
+-
+- AC_ARG_WITH(libapt-pkg-lib,
+- AC_HELP_STRING([--with-libapt-pkg-lib=DIR],[look for the libapt-pkg library in DIR]),
+- [_libaptpkg_with_lib=$withval],[_libaptpkg_with_lib=no])
+- if test "$_libaptpkg_with_lib" == "no" ; then
+- APT_LIBS="-lapt-pkg"
+- else
+- APT_LIBS="-L$withval -lapt-pkg"
+- fi
+-
+- AC_ARG_WITH(libapt-pkg-includes,
+- AC_HELP_STRING([--with-libapt-pkg-includes=DIR],[look for the libapt-pkg includes in DIR]),
+- [_libaptpkg_with_inc=$withval],[_libaptpkg_with_inc=no])
+- if test "$_libaptpkg_with_inc" == "no" ; then
+- APT_CFLAGS="-I/usr/include/apt-pkg"
+- else
+- APT_CFLAGS="-I$withval"
+- fi
+-
+- AC_CACHE_CHECK([whether libapt-pkg is usable],
+- [libaptpkg_usable],
+- [
+- _libaptpkg_save_cppflags=$CPPFLAGS
+- CPPFLAGS="$APT_CFLAGS $CPPFLAGS"
+- _APT_save_libs=$LIBS
+- LIBS="$APT_LIBS $LIBS"
+-
+- AC_LANG_PUSH(C++)
+- AC_LINK_IFELSE(AC_LANG_PROGRAM([
+- #include <apt-pkg/configuration.h>
+- #include <apt-pkg/pkgsystem.h>
+- #include <apt-pkg/init.h>
+- #include <stdio.h>
+- ],[
+- if (pkgInitConfig(*_config) == false)
+- {
+- fprintf(stderr,"pkginitconfig was false");
+- return -1;
+- }
+- if (pkgInitSystem(*_config, _system) == false)
+- {
+- fprintf(stderr,"pkginitsystem was false");
+- return -1;
+- }
+- return 0;
+-]),libaptpkg_usable=yes,AC_MSG_ERROR([libapt-pkg not found]))
+-
+- CPPFLAGS=$_libaptpkg_save_cppflags
+- LIBS=$_libaptpkg_save_libs
+- unset _libaptpkg_save_cppflags
+- unset _libaptpkg_save_libs
+- ])
+- AC_LANG_POP(C++)
+-
+- APT_BACKEND(deb,DEB)
+- APT_BACKEND(rpm,RPM)
+- if test "$APT_PKG_TYPE" == "" ; then
+- AC_MSG_ERROR([Couldn't find support for any type of packages that we know about for Apt!])
+- fi
+-
+- AC_SUBST(APT_CFLAGS)
+- AC_SUBST(APT_LIBS)
+- AC_SUBST(APT_PKG_TYPE)
+-else
+- AM_CONDITIONAL(APT_SEARCH_PLAIN, [false])
+- AM_CONDITIONAL(APT_SEARCH_SQLITE, [false])
+-fi
+-
+-if test x$enable_apt2 = xyes; then
+- PY_CHECK_MOD([apt_pkg],,,AC_MSG_ERROR([Apt backend needs python-apt]))
+ fi
+
+ if test x$enable_box = xyes; then
+@@ -535,7 +411,7 @@ if test x$enable_box = xyes; then
+ fi
+
+ if test x$enable_opkg = xyes; then
+- PKG_CHECK_MODULES(OPKG, libopkg = 0.1.4)
++ PKG_CHECK_MODULES(OPKG, libopkg = 0.1.5)
+ AC_SUBST(OPKG_CFLAGS)
+ AC_SUBST(OPKG_LIBS)
+ fi
+@@ -555,7 +431,7 @@ if test x$enable_poldek = xyes; then
+ fi
+
+ if test x$enable_zypp = xyes; then
+- PKG_CHECK_MODULES(ZYPP, libzypp >= 4.14.0)
++ PKG_CHECK_MODULES(ZYPP, libzypp >= 4.25.0)
+ AC_SUBST(ZYPP_CFLAGS)
+ AC_SUBST(ZYPP_LIBS)
+ fi
+@@ -568,11 +444,6 @@ AC_SUBST(PK_PLUGIN_DIR, "\$(libdir)/packagekit-backend")
+ AC_SUBST(PK_PLUGIN_CFLAGS, "-I\$(top_srcdir)/src -I\$(top_srcdir)/libpackagekit $GLIB_CFLAGS $DBUS_CFLAGS $GMODULE_CFLAGS")
+ AC_SUBST(PK_PLUGIN_LIBS, "$GLIB_LIBS $DBUS_LIBS $GMODULE_LIBS")
+
+-if test x$with_default_backend = xapt; then
+- # now we've done the conditionals, rename for searching backend
+- with_default_backend="apt (with $with_apt_search searching)"
+-fi
+-
+ dnl ---------------------------------------------------------------------------
+ dnl - Makefiles, etc.
+ dnl ---------------------------------------------------------------------------
+@@ -592,8 +463,6 @@ contrib/yum-packagekit/Makefile
+ backends/Makefile
+ backends/alpm/Makefile
+ backends/apt/Makefile
+-backends/apt/helpers/Makefile
+-backends/apt2/Makefile
+ backends/box/Makefile
+ backends/conary/Makefile
+ backends/conary/helpers/Makefile
+@@ -603,6 +472,10 @@ backends/smart/Makefile
+ backends/smart/helpers/Makefile
+ backends/test/Makefile
+ backends/test/helpers/Makefile
++backends/urpmi/Makefile
++backends/urpmi/helpers/Makefile
++backends/urpmi/helpers/perl_packagekit/Makefile
++backends/urpmi/helpers/urpmi_backend/Makefile
+ backends/yum/Makefile
+ backends/yum/helpers/Makefile
+ backends/yum2/Makefile
+@@ -650,7 +523,6 @@ echo "
+ Backends:
+ ALPM backend: ${enable_alpm}
+ APT backend: ${enable_apt}
+- APT DBus backend: ${enable_apt2}
+ BOX backend: ${enable_box}
+ CONARY backend: ${enable_conary}
+ dummy backend: ${enable_dummy}
+@@ -658,6 +530,7 @@ echo "
+ PiSi backend: ${enable_pisi}
+ poldek backend: ${enable_poldek}
+ SMART backend: ${enable_smart}
++ URPMI backend: ${enable_urpmi}
+ YUM backend: ${enable_yum}
+ YUM2 backend: ${enable_yum2}
+ Zypp backend: ${enable_zypp}
+diff --git a/contrib/PackageKit.spec.in b/contrib/PackageKit.spec.in
+index 4d4a7e3..61a67d1 100644
+--- a/contrib/PackageKit.spec.in
++++ b/contrib/PackageKit.spec.in
+@@ -10,6 +10,7 @@ Summary: System daemon that is a DBUS abstraction layer for packages
+ Name: PackageKit
+ Version: #VERSION#
+ Release: 0.#BUILD#%{?alphatag}%{?dist}
++Epoch: 1
+ License: GPLv2+
+ Group: System Environment/Libraries
+ URL: http://packagekit.freedesktop.org
+@@ -17,8 +18,8 @@ Source0: http://people.freedesktop.org/~hughsient/releases/%{name}-%{version}.
+ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+
+ Requires: dbus >= %{dbus_version}
+-Requires: PackageKit-libs = %{version}-%{release}
+-Requires: yum-packagekit = %{version}-%{release}
++Requires: PackageKit-libs = %{epoch}:%{version}-%{release}
++Requires: yum-packagekit = %{epoch}:%{version}-%{release}
+ Requires: yum >= 3.2.6
+
+ BuildRequires: glib2-devel >= %{glib2_version}
+@@ -69,7 +70,7 @@ will almost instantly update itself to reflect this.
+ Summary: Libraries for accessing PackageKit
+ Group: Development/Libraries
+ Requires: dbus >= %{dbus_version}
+-Requires: %{name} = %{version}-%{release}
++Requires: %{name} = %{epoch}:%{version}-%{release}
+
+ %description libs
+ Libraries for accessing PackageKit.
+@@ -78,7 +79,7 @@ Libraries for accessing PackageKit.
+ Summary: Cron job and related utilities for PackageKit
+ Group: System Environment/Base
+ Requires: cronie
+-Requires: %{name} = %{version}-%{release}
++Requires: %{name} = %{epoch}:%{version}-%{release}
+
+ %description cron
+ Crontab and utilities for running PackageKit as a cron job.
+@@ -86,7 +87,7 @@ Crontab and utilities for running PackageKit as a cron job.
+ %package devel
+ Summary: Libraries and headers for PackageKit
+ Group: Development/Libraries
+-Requires: %{name} = %{version}-%{release}
++Requires: %{name} = %{epoch}:%{version}-%{release}
+ Requires: dbus-devel >= %{dbus_version}
+ Requires: pkgconfig
+ Requires: sqlite-devel
+diff --git a/contrib/gnome-packagekit.spec.in b/contrib/gnome-packagekit.spec.in
+index a97fc3b..ded7799 100644
+--- a/contrib/gnome-packagekit.spec.in
++++ b/contrib/gnome-packagekit.spec.in
+@@ -6,6 +6,7 @@ Summary: GNOME PackageKit Client
+ Name: gnome-packagekit
+ Version: #VERSION#
+ Release: 0.#BUILD#%{?alphatag}%{?dist}
++Epoch: 1
+ License: GPLv2+
+ Group: Applications/System
+ URL: http://www.packagekit.org
+diff --git a/docs/html/pk-authors.html b/docs/html/pk-authors.html
+index 607a7a4..7aa298b 100644
+--- a/docs/html/pk-authors.html
++++ b/docs/html/pk-authors.html
+@@ -262,6 +262,22 @@
+ </td>
+ </tr>
+
++<tr>
++ <td>
++ <img src="img/author-unknown.png" alt=""/><!-- image should be 120px wide -->
++ </td>
++ <td>
++ <h2>Aurelien Lefebvre</h2>
++ <p>
++ Aurelien works for <a href="http://www.mandriva.org">Mandriva</a>.
++ He works on the urpmi backend of PackageKit.
++ </p>
++ <p>
++ <b>Responsible for: urpmi backend</b>
++ </p>
++ </td>
++</tr>
++
+ </table>
+
+ <p>Back to the <a href="index.html">main page</a></p>
+diff --git a/docs/html/pk-download.html b/docs/html/pk-download.html
+index 0cdc85c..d276a05 100644
+--- a/docs/html/pk-download.html
++++ b/docs/html/pk-download.html
+@@ -44,7 +44,7 @@ easier to install.
+ <h2>Released Versions</h2>
+ <p>
+ Released versions are found on
+-<a href="http://people.freedesktop.org/~hughsient/releases/">people.freedesktop.org</a>.
++<a href="http://www.packagekit.org/releases/">http://www.packagekit.org/releases/</a>.
+ </p>
+ <table>
+ <tr><td><b>Version</b></td><td>&nbsp;&nbsp;</td><td><b>Date</b></td></tr>
+diff --git a/docs/html/pk-faq.html b/docs/html/pk-faq.html
+index efa8344..3e37cc1 100644
+--- a/docs/html/pk-faq.html
++++ b/docs/html/pk-faq.html
+@@ -22,6 +22,7 @@
+ <h2>Table Of Contents</h2>
+ <ul>
+ <li><a href="#how-complete">How complete are the backends?</a></li>
++<li><a href="#1-click-install">Does PackageKit support 1-Click Install?</a></li>
+ <li><a href="#run-as-root">When run as root, gpk-application and pkcon do not work!</a></li>
+ <li><a href="#session-system">Why is there a session service and and a system service?</a></li>
+ <li><a href="#session-methods">How do I use PackageKit in my application?</a></li>
+@@ -52,7 +53,6 @@
+ <tr>
+ <td width="150px">&nbsp;</td>
+ <td><center>apt</center></td>
+-<td><center>apt2</center></td>
+ <td><center>alpm</center></td>
+ <td><center>box</center></td>
+ <td><center>conary</center></td>
+@@ -60,14 +60,14 @@
+ <td><center>pisi</center></td>
+ <td><center>poldek</center></td>
+ <td><center>smart</center></td>
++<td><center>urpmi</center></td>
+ <td><center>yum</center></td>
+ <td><center>yum2</center></td>
+ <td><center>zypp</center></td>
+ </tr>
+ <tr>
+ <td><b>Resolve</b></td>
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+@@ -75,6 +75,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-bad.png" alt="[no]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -82,7 +83,6 @@
+ <tr>
+ <td><b>RefreshCache</b></td>
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+@@ -90,14 +90,14 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+ </tr>
+ <tr>
+ <td><b>GetUpdates</b></td>
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt2 -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+@@ -105,14 +105,14 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+ </tr>
+ <tr>
+ <td><b>UpdateSystem</b></td>
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt2 -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+@@ -120,6 +120,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-bad.png" alt="[no]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -127,7 +128,6 @@
+ <tr>
+ <td><b>SearchName</b></td>
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+@@ -135,6 +135,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -142,7 +143,6 @@
+ <tr>
+ <td><b>SearchDetails</b></td>
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+@@ -150,6 +150,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -157,7 +158,6 @@
+ <tr>
+ <td><b>SearchFile</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+@@ -165,6 +165,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -172,22 +173,21 @@
+ <tr>
+ <td><b>SearchGroup</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- opkg -->
+ <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-good.png" alt="[yes]"/></td><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+ </tr>
+ <tr>
+ <td><b>InstallPackages</b></td>
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt2 -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+@@ -195,6 +195,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -202,7 +203,6 @@
+ <tr>
+ <td><b>InstallFiles</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+@@ -210,14 +210,14 @@
+ <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-good.png" alt="[yes]"/></td><!-- smart -->
++<td><img src="img/status-bad.png" alt="[no]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+ </tr>
+ <tr>
+ <td><b>RemovePackages</b></td>
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt2 -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+@@ -225,6 +225,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -232,7 +233,6 @@
+ <tr>
+ <td><b>UpdatePackage</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+@@ -240,6 +240,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-bad.png" alt="[no]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -247,7 +248,6 @@
+ <tr>
+ <td><b>GetDepends</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+@@ -255,6 +255,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -262,7 +263,6 @@
+ <tr>
+ <td><b>GetRequires</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+@@ -270,6 +270,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -277,7 +278,6 @@
+ <tr>
+ <td><b>GetDetails</b></td>
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+-<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+@@ -285,6 +285,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -292,7 +293,6 @@
+ <tr>
+ <td><b>GetFiles</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+@@ -300,6 +300,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -307,7 +308,6 @@
+ <tr>
+ <td><b>GetUpdateDetail</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+@@ -315,6 +315,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- zypp -->
+@@ -322,7 +323,6 @@
+ <tr>
+ <td><b>GetRepoList</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+@@ -330,6 +330,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-bad.png" alt="[no]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -337,7 +338,6 @@
+ <tr>
+ <td><b>RepoEnable</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+@@ -345,6 +345,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-bad.png" alt="[no]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -352,7 +353,6 @@
+ <tr>
+ <td><b>RepoSetData</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+@@ -360,6 +360,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-bad.png" alt="[no]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -367,7 +368,6 @@
+ <tr>
+ <td><b>Cancel</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+@@ -375,6 +375,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-bad.png" alt="[no]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- zypp -->
+@@ -382,7 +383,6 @@
+ <tr>
+ <td><b>ServicePack</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+@@ -390,6 +390,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-bad.png" alt="[no]"/></td><!-- urpmi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- yum -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- yum2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- zypp -->
+@@ -397,22 +398,21 @@
+ <tr>
+ <td><b>WhatProvides</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+ <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><!-- poldek -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- smart -->
++<td><img src="img/status-bad.png" alt="[no]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+ </tr>
+ <tr>
+ <td><b>GetPackages</b></td>
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- apt -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+@@ -420,6 +420,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[good]"/></td><!-- zypp -->
+@@ -431,7 +432,6 @@
+ <tr>
+ <td width="150px">&nbsp;</td>
+ <td><center>apt</center></td>
+-<td><center>apt2</center></td>
+ <td><center>alpm</center></td>
+ <td><center>box</center></td>
+ <td><center>conary</center></td>
+@@ -439,6 +439,7 @@
+ <td><center>pisi</center></td>
+ <td><center>poldek</center></td>
+ <td><center>smart</center></td>
++<td><center>urpmi</center></td>
+ <td><center>yum</center></td>
+ <td><center>yum2</center></td>
+ <td><center>zypp</center></td>
+@@ -446,7 +447,6 @@
+ <tr>
+ <td><b>Installed</b></td>
+ <td><img src="img/status-good.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-good.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-good.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- conary -->
+@@ -454,6 +454,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- zypp -->
+@@ -461,7 +462,6 @@
+ <tr>
+ <td><b>Development</b></td>
+ <td><img src="img/status-good.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-good.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+@@ -469,6 +469,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- zypp -->
+@@ -476,7 +477,6 @@
+ <tr>
+ <td><b>GUI</b></td>
+ <td><img src="img/status-good.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-good.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+@@ -484,6 +484,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-good.png" alt="[yes]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- zypp -->
+@@ -491,7 +492,6 @@
+ <tr>
+ <td><b>Free</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+@@ -499,6 +499,7 @@
+ <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><!-- smart -->
++<td><img src="img/status-bad.png" alt="[no]"/></td><!-- urpmi -->
+ <td><img src="img/status-good.png" alt="[yes]"/></td><!-- yum -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- yum2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- zypp -->
+@@ -506,13 +507,13 @@
+ <tr>
+ <td><b>Visible</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+ <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><!-- urpmi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- smart -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- yum -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- yum2 -->
+@@ -521,13 +522,13 @@
+ <tr>
+ <td><b>Supported</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+ <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><!-- urpmi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- smart -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- yum -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- yum2 -->
+@@ -536,13 +537,13 @@
+ <tr>
+ <td><b>Newest</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+ <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><!-- urpmi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- smart -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- yum -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- yum2 -->
+@@ -551,13 +552,13 @@
+ <tr>
+ <td><b>Arch</b></td>
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt -->
+-<td><img src="img/status-bad.png" alt="[no]"/></td><!-- apt2 -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- alpm -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- box -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- conary -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- opkg -->
+ <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><!-- urpmi -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- smart -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- yum -->
+ <td><img src="img/status-bad.png" alt="[no]"/></td><!-- yum2 -->
+@@ -566,6 +567,43 @@
+ </table>
+
+ <hr>
++<h3><a name="1-click-install">Does PackageKit support 1-Click Install?</a></h3>
++<p>
++No, as they are a potential security problem. The issues are as follows:
++</p>
++<ul>
++<li>
++That some developer creates a repository with a package with a higher package epoch, and then the
++distro releases a critical security package (with an updated version, but smaller epoch) and the
++package does not get upgraded, leaving the user vulnerable.
++</li>
++<li>
++The user installs some random repository, where the developer pushes a few svn packages.
++The developer gets bored, and stop produces updates, and then one of the old packages blocks
++on the distribution update, causing no further automatic system updates.
++</li>
++<li>
++There's no signing of 1-click-install files, so we can't actually be sure that they come from a
++reputable source.
++</li>
++<li>
++There's no localisation in the 1-click-files.
++For instance, if we only show a French language speaker a description of "remote exploit trojan"
++they are not going to understand the description.
++</li>
++</ul>
++<p>
++So what's the solution? Using a standard <code>$vendor-release.rpm</code> or <code>.deb</code>
++you can ship the standard repo or source with a signed GPG key.
++</p>
++<p>
++Quoting Sebastian Heinlein,
++<i>Allowing to easily add third party repositories and install third party software without a
++certification infrastructure is like opening the gates to hell.
++Most user just don't have got the technical understanding to handle this well.</i>
++</p>
++
++<hr>
+ <h3><a name="run-as-root">When run as root, <code>gpk-application</code> and <code>pkcon</code> do not work!</a></h3>
+ <p>
+ GTK+ tools should not be run as the root user, <b>PERIOD</b>.
+diff --git a/docs/spec/pk-concepts.xml b/docs/spec/pk-concepts.xml
+index 0b75b10..51a165a 100644
+--- a/docs/spec/pk-concepts.xml
++++ b/docs/spec/pk-concepts.xml
+@@ -402,6 +402,13 @@
+ signature is not valid in some way.
+ </entry>
+ </row>
++ <row>
++ <entry><literal>package-corrupt</literal></entry>
++ <entry>
++ The downloaded package is corrupt.
++ </entry>
++ </row>
++
+ </tbody>
+ </tgroup>
+ </informaltable>
+diff --git a/docs/spec/pk-signals.xml b/docs/spec/pk-signals.xml
+index a79e647..2970dda 100644
+--- a/docs/spec/pk-signals.xml
++++ b/docs/spec/pk-signals.xml
+@@ -360,11 +360,21 @@
+ </row>
+ <row>
+ <entry><literal>updates</literal></entry>
+- <entry>A list of package_id's that are to be updated</entry>
++ <entry>
++ A list of package_id's that are to be updated, seporated by <literal>^</literal>.
++ This odd delimited was chosen as <literal>\t</literal> is already being used in the
++ spawned backends, and <literal>^</literal> is a banned character in a package_id.
++ This will change in 0.3.x where <literal>updates</literal> will be a proper string
++ array field.
++ </entry>
+ </row>
+ <row>
+ <entry><literal>obsoletes</literal></entry>
+- <entry>A list of package_id's that are to be obsoletes</entry>
++ <entry>
++ A list of package_id's that are to be obsoleted, seporated by <literal>^</literal>
++ This will change in 0.3.x where <literal>obsoletes</literal> will be a proper string
++ array field.
++ </entry>
+ </row>
+ <row>
+ <entry><literal>vendor_url</literal></entry>
+diff --git a/etc/PackageKit.conf.in b/etc/PackageKit.conf.in
+index 8f9bd57..7a48320 100644
+--- a/etc/PackageKit.conf.in
++++ b/etc/PackageKit.conf.in
+@@ -39,5 +39,5 @@ DefaultBackend=@defaultbackend@
+ # They are in the format username:password@server:port
+ #
+ # ProxyHTTP=username:password@server.lan:8080
+-# ProxyFTP=username:password@server.lan:21
++# ProxyFTP=server.lan:21
+
+diff --git a/libpackagekit/pk-client.c b/libpackagekit/pk-client.c
+index dd2387b..8fb82f1 100644
+--- a/libpackagekit/pk-client.c
++++ b/libpackagekit/pk-client.c
+@@ -275,7 +275,7 @@ pk_client_get_tid (PkClient *client)
+ * If the package buffer is enabled then after the transaction has completed
+ * then the package list can be retrieved in one go, rather than processing
+ * each package request async.
+- * If this is not set true explicitly, then pk_client_package_buffer_get_size
++ * If this is not set true explicitly, then pk_client_get_package_list
+ * will always return zero items.
+ *
+ * This is not forced on as there may be significant overhead if the list
+@@ -364,26 +364,7 @@ pk_client_get_require_restart (PkClient *client)
+ }
+
+ /**
+- * pk_client_package_buffer_get_size:
+- * @client: a valid #PkClient instance
+- *
+- * We do not provide access to the internal package list (as it could be being
+- * updated) so provide a way to get access to the current size here.
+- *
+- * Return value: The size of the package buffer.
+- **/
+-guint
+-pk_client_package_buffer_get_size (PkClient *client)
+-{
+- g_return_val_if_fail (PK_IS_CLIENT (client), 0);
+- if (!client->priv->use_buffer) {
+- return 0;
+- }
+- return pk_package_list_get_size (client->priv->package_list);
+-}
+-
+-/**
+- * pk_client_package_buffer_get_item:
++ * pk_client_get_package_list:
+ * @client: a valid #PkClient instance
+ * @item: the item in the package buffer
+ *
+@@ -392,14 +373,17 @@ pk_client_package_buffer_get_size (PkClient *client)
+ *
+ * Return value: The #PkPackageItem or %NULL if not found or invalid
+ **/
+-PkPackageItem *
+-pk_client_package_buffer_get_item (PkClient *client, guint item)
++PkPackageList *
++pk_client_get_package_list (PkClient *client)
+ {
++ PkPackageList *list;
+ g_return_val_if_fail (PK_IS_CLIENT (client), NULL);
+ if (!client->priv->use_buffer) {
+ return NULL;
+ }
+- return pk_package_list_get_item (client->priv->package_list, item);
++ list = client->priv->package_list;
++ g_object_ref (list);
++ return list;
+ }
+
+ /**
+@@ -412,6 +396,10 @@ pk_client_finished_cb (DBusGProxy *proxy, const gchar *exit_text, guint runtime,
+
+ g_return_if_fail (PK_IS_CLIENT (client));
+
++ /* ref in case we unref the PkClient in ::finished --
++ * see https://bugzilla.novell.com/show_bug.cgi?id=390929 for rationale */
++ g_object_ref (client);
++
+ exit = pk_exit_enum_from_text (exit_text);
+ pk_debug ("emit finished %s, %i", exit_text, runtime);
+
+@@ -420,16 +408,13 @@ pk_client_finished_cb (DBusGProxy *proxy, const gchar *exit_text, guint runtime,
+
+ g_signal_emit (client, signals [PK_CLIENT_FINISHED], 0, exit, runtime);
+
+- /* check we are still valid */
+- if (!PK_IS_CLIENT (client)) {
+- pk_debug ("client was g_object_unref'd in finalise, object no longer valid");
+- return;
+- }
+-
+ /* exit our private loop */
+ if (client->priv->synchronous) {
+ g_main_loop_quit (client->priv->loop);
+ }
++
++ /* unref what we previously ref'd */
++ g_object_unref (client);
+ }
+
+ /**
+@@ -491,7 +476,6 @@ pk_client_package_cb (DBusGProxy *proxy,
+
+ /* cache */
+ if (client->priv->use_buffer || client->priv->synchronous) {
+- pk_debug ("adding to cache array package %i, %s, %s", info, package_id, summary);
+ pk_package_list_add (client->priv->package_list, info, package_id, summary);
+ }
+ }
+@@ -566,16 +550,12 @@ pk_client_details_cb (DBusGProxy *proxy,
+ * pk_client_files_cb:
+ */
+ static void
+-pk_client_files_cb (DBusGProxy *proxy,
+- const gchar *package_id,
+- const gchar *filelist,
+- PkClient *client)
++pk_client_files_cb (DBusGProxy *proxy, const gchar *package_id, const gchar *filelist, PkClient *client)
+ {
+ g_return_if_fail (PK_IS_CLIENT (client));
+
+- pk_debug ("emit files %s, %s", package_id, filelist);
+- g_signal_emit (client , signals [PK_CLIENT_FILES], 0, package_id,
+- filelist);
++ pk_debug ("emit files %s, <lots of files>", package_id);
++ g_signal_emit (client , signals [PK_CLIENT_FILES], 0, package_id, filelist);
+ }
+
+ /**
+@@ -934,10 +914,8 @@ pk_client_cancel (PkClient *client, GError **error)
+ return TRUE;
+ }
+
+- /* special case - if the tid is already finished, then cancel should
+- * return TRUE as it's what we wanted */
+- if (pk_strequal (error_local->message, "cancelling a non-running transaction") ||
+- g_str_has_suffix (error_local->message, " doesn't exist\n")) {
++ /* special case - if the tid is already finished, then cancel should return TRUE */
++ if (g_str_has_suffix (error_local->message, " doesn't exist\n")) {
+ pk_debug ("error ignored '%s' as we are trying to cancel", error_local->message);
+ g_error_free (error_local);
+ return TRUE;
+@@ -1022,7 +1000,7 @@ pk_client_get_updates (PkClient *client, PkFilterEnum filters, GError **error)
+ G_TYPE_STRING, filter_text,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ g_free (filter_text);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1112,7 +1090,7 @@ pk_client_update_system (PkClient *client, GError **error)
+ g_propagate_error (error, error_pk);
+ }
+
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1167,7 +1145,7 @@ pk_client_search_name (PkClient *client, PkFilterEnum filters, const gchar *sear
+ G_TYPE_STRING, search,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ g_free (filter_text);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1223,7 +1201,7 @@ pk_client_search_details (PkClient *client, PkFilterEnum filters, const gchar *s
+ G_TYPE_STRING, search,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ g_free (filter_text);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1277,7 +1255,7 @@ pk_client_search_group (PkClient *client, PkFilterEnum filters, const gchar *sea
+ G_TYPE_STRING, search,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ g_free (filter_text);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1331,7 +1309,7 @@ pk_client_search_file (PkClient *client, PkFilterEnum filters, const gchar *sear
+ G_TYPE_STRING, search,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ g_free (filter_text);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1397,7 +1375,7 @@ pk_client_get_depends (PkClient *client, PkFilterEnum filters, const gchar *pack
+ G_TYPE_BOOLEAN, recursive,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ g_free (filter_text);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1448,7 +1426,7 @@ pk_client_get_packages (PkClient *client, PkFilterEnum filters, GError **error)
+ G_TYPE_STRING, filter_text,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ g_free (filter_text);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1514,7 +1492,7 @@ pk_client_get_requires (PkClient *client, PkFilterEnum filters, const gchar *pac
+ G_TYPE_BOOLEAN, recursive,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ g_free (filter_text);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1579,7 +1557,7 @@ pk_client_what_provides (PkClient *client, PkFilterEnum filters, PkProvidesEnum
+ G_TYPE_STRING, search,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ g_free (filter_text);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1637,7 +1615,7 @@ pk_client_get_update_detail (PkClient *client, const gchar *package_id, GError *
+ ret = dbus_g_proxy_call (client->priv->proxy, "GetUpdateDetail", error,
+ G_TYPE_STRING, package_id,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1686,7 +1664,7 @@ pk_client_rollback (PkClient *client, const gchar *transaction_id, GError **erro
+ ret = dbus_g_proxy_call (client->priv->proxy, "Rollback", error,
+ G_TYPE_STRING, transaction_id,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1743,7 +1721,7 @@ pk_client_resolve (PkClient *client, PkFilterEnum filters, const gchar *package,
+ G_TYPE_STRING, package,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ g_free (filter_text);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1801,7 +1779,7 @@ pk_client_get_details (PkClient *client, const gchar *package_id, GError **error
+ ret = dbus_g_proxy_call (client->priv->proxy, "GetDetails", error,
+ G_TYPE_STRING, package_id,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1858,7 +1836,7 @@ pk_client_get_files (PkClient *client, const gchar *package_id, GError **error)
+ ret = dbus_g_proxy_call (client->priv->proxy, "GetFiles", error,
+ G_TYPE_STRING, package_id,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -1963,7 +1941,7 @@ pk_client_remove_packages (PkClient *client, gchar **package_ids, gboolean allow
+ g_propagate_error (error, error_pk);
+ }
+
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -2048,7 +2026,7 @@ pk_client_refresh_cache (PkClient *client, gboolean force, GError **error)
+ g_propagate_error (error, error_pk);
+ }
+
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -2142,7 +2120,7 @@ pk_client_install_packages (PkClient *client, gchar **package_ids, GError **erro
+ g_propagate_error (error, error_pk);
+ }
+
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -2242,7 +2220,7 @@ pk_client_install_signature (PkClient *client, PkSigTypeEnum type, const gchar *
+ g_propagate_error (error, error_pk);
+ }
+
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -2340,7 +2318,7 @@ pk_client_update_packages (PkClient *client, gchar **package_ids, GError **error
+ g_propagate_error (error, error_pk);
+ }
+
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -2570,7 +2548,7 @@ pk_client_install_files (PkClient *client, gboolean trusted, gchar **files_rel,
+ g_propagate_error (error, error_pk);
+ }
+
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -2622,7 +2600,7 @@ pk_client_get_repo_list (PkClient *client, PkFilterEnum filters, GError **error)
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ g_free (filter_text);
+ pk_client_error_fixup (error);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -2703,7 +2681,7 @@ pk_client_accept_eula (PkClient *client, const gchar *eula_id, GError **error)
+ g_propagate_error (error, error_pk);
+ }
+
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -2787,7 +2765,7 @@ pk_client_repo_enable (PkClient *client, const gchar *repo_id, gboolean enabled,
+ g_propagate_error (error, error_pk);
+ }
+
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -2880,7 +2858,7 @@ pk_client_repo_set_data (PkClient *client, const gchar *repo_id, const gchar *pa
+ g_propagate_error (error, error_pk);
+ }
+
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+
+@@ -2957,7 +2935,7 @@ pk_client_get_old_transactions (PkClient *client, guint number, GError **error)
+ G_TYPE_UINT, number,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ pk_client_error_fixup (error);
+- if (ret) {
++ if (ret && !client->priv->is_finished) {
+ /* allow clients to respond in the status changed callback */
+ pk_client_change_status (client, PK_STATUS_ENUM_WAIT);
+ }
+@@ -3085,6 +3063,7 @@ pk_client_set_tid (PkClient *client, const gchar *tid, GError **error)
+ return FALSE;
+ }
+ client->priv->tid = g_strdup (tid);
++ pk_debug ("set tid %s on %p", client->priv->tid, client);
+
+ dbus_g_proxy_add_signal (proxy, "Finished",
+ G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID);
+@@ -3523,9 +3502,8 @@ pk_client_reset (PkClient *client, GError **error)
+
+ g_return_val_if_fail (PK_IS_CLIENT (client), FALSE);
+
+- if (client->priv->tid != NULL &&
+- client->priv->is_finished != TRUE) {
+- pk_debug ("not exit status, will try to cancel");
++ if (client->priv->tid != NULL && !client->priv->is_finished) {
++ pk_debug ("not exit status, will try to cancel tid %s", client->priv->tid);
+ /* we try to cancel the running tranaction */
+ ret = pk_client_cancel (client, error);
+ if (!ret) {
+@@ -3790,6 +3768,7 @@ libst_client (LibSelfTest *test)
+ guint size_new;
+ guint i;
+ gchar *file;
++ PkPackageList *list;
+
+ if (libst_start (test, "PkClient", CLASS_AUTO) == FALSE) {
+ return;
+@@ -3833,6 +3812,15 @@ libst_client (LibSelfTest *test)
+ libst_failed (test, NULL);
+ }
+
++ /************************************************************/
++ libst_title (test, "reset client, unused");
++ ret = pk_client_reset (client, NULL);
++ if (ret) {
++ libst_success (test, NULL);
++ } else {
++ libst_failed (test, NULL);
++ }
++
+ /* check use after finalise */
+ g_signal_connect (client, "finished",
+ G_CALLBACK (libst_client_finished_cb), test);
+@@ -3871,7 +3859,9 @@ libst_client (LibSelfTest *test)
+ }
+
+ /* get size */
+- size = pk_client_package_buffer_get_size (client);
++ list = pk_client_get_package_list (client);
++ size = pk_package_list_get_size (list);
++ g_object_unref (list);
+ if (size == 0) {
+ libst_failed (test, "failed: to get any results");
+ }
+@@ -3891,7 +3881,9 @@ libst_client (LibSelfTest *test)
+ g_error_free (error);
+ }
+ /* check we got the same results */
+- size_new = pk_client_package_buffer_get_size (client);
++ list = pk_client_get_package_list (client);
++ size_new = pk_package_list_get_size (list);
++ g_object_unref (list);
+ if (size != size_new) {
+ libst_failed (test, "old size %i, new size %", size, size_new);
+ }
+diff --git a/libpackagekit/pk-client.h b/libpackagekit/pk-client.h
+index 2b1d1a2..6617159 100644
+--- a/libpackagekit/pk-client.h
++++ b/libpackagekit/pk-client.h
+@@ -346,9 +346,7 @@ gboolean pk_client_repo_set_data (PkClient *client,
+ G_GNUC_WARN_UNUSED_RESULT;
+
+ /* cached stuff */
+-guint pk_client_package_buffer_get_size (PkClient *client);
+-PkPackageItem *pk_client_package_buffer_get_item (PkClient *client,
+- guint item);
++PkPackageList *pk_client_get_package_list (PkClient *client);
+ PkRestartEnum pk_client_get_require_restart (PkClient *client);
+
+ /* not job specific */
+diff --git a/libpackagekit/pk-common.c b/libpackagekit/pk-common.c
+index 9d3cff7..0be0e6e 100644
+--- a/libpackagekit/pk-common.c
++++ b/libpackagekit/pk-common.c
+@@ -246,7 +246,7 @@ pk_strsafe (const gchar *text)
+ }
+
+ /* rip out any insane characters */
+- delimiters = "\\\f\n\r\t\"'";
++ delimiters = "\\\f\r\t\"'";
+ text_safe = g_strdup (text);
+ g_strdelimit (text_safe, delimiters, ' ');
+ return text_safe;
+@@ -613,6 +613,35 @@ pk_strpad_extra (const gchar *data, guint length, guint *extra)
+ }
+
+ /**
++ * pk_strreplace:
++ * @text: The input text to make safe
++ * @find: What to search for
++ * @replace: What to replace with
++ *
++ * Replaces chars in the text with a replacement.
++ * The %find and %replace variables to not have to be of the same length
++ *
++ * Return value: the new string (copied)
++ **/
++gchar *
++pk_strreplace (const gchar *text, const gchar *find, const gchar *replace)
++{
++ gchar **array;
++ gchar *retval;
++
++ /* common case, not found */
++ if (strstr (text, find) == NULL) {
++ return g_strdup (text);
++ }
++
++ /* split apart and rejoin with new delimiter */
++ array = g_strsplit (text, find, 0);
++ retval = g_strjoinv (replace, array);
++ g_strfreev (array);
++ return retval;
++}
++
++/**
+ * pk_delay_yield:
+ * @delay: the desired delay in seconds
+ *
+@@ -850,6 +879,23 @@ libst_common (LibSelfTest *test)
+ }
+ g_free (text_safe);
+
++ /************************************************************/
++ libst_title (test, "pk_strequal same argument");
++ temp = "dave";
++ if (pk_strequal (temp, temp)) {
++ libst_success (test, NULL);
++ } else {
++ libst_failed (test, "incorrect ret when both same");
++ }
++
++ /************************************************************/
++ libst_title (test, "pk_strequal both const");
++ if (pk_strequal ("dave", "dave")) {
++ libst_success (test, NULL);
++ } else {
++ libst_failed (test, "incorrect ret when both same");
++ }
++
+ /************************************************************
+ **************** build var args **************
+ ************************************************************/
+@@ -1283,6 +1329,48 @@ libst_common (LibSelfTest *test)
+ g_free (text_safe);
+
+ /************************************************************
++ **************** Replace ******************
++ ************************************************************/
++ libst_title (test, "replace start");
++ text_safe = pk_strreplace ("richard\nhughes", "r", "e");
++ if (pk_strequal (text_safe, "eichaed\nhughes")) {
++ libst_success (test, NULL);
++ } else {
++ libst_failed (test, "failed the replace '%s'", text_safe);
++ }
++ g_free (text_safe);
++
++ /************************************************************/
++ libst_title (test, "replace none");
++ text_safe = pk_strreplace ("richard\nhughes", "dave", "e");
++ if (pk_strequal (text_safe, "richard\nhughes")) {
++ libst_success (test, NULL);
++ } else {
++ libst_failed (test, "failed the replace '%s'", text_safe);
++ }
++ g_free (text_safe);
++
++ /************************************************************/
++ libst_title (test, "replace end");
++ text_safe = pk_strreplace ("richard\nhughes", "s", "e");
++ if (pk_strequal (text_safe, "richard\nhughee")) {
++ libst_success (test, NULL);
++ } else {
++ libst_failed (test, "failed the replace '%s'", text_safe);
++ }
++ g_free (text_safe);
++
++ /************************************************************/
++ libst_title (test, "replace unicode");
++ text_safe = pk_strreplace ("richard\n- hughes", "\n- ", "\n• ");
++ if (pk_strequal (text_safe, "richard\n• hughes")) {
++ libst_success (test, NULL);
++ } else {
++ libst_failed (test, "failed the replace '%s'", text_safe);
++ }
++ g_free (text_safe);
++
++ /************************************************************
+ **************** Padding ******************
+ ************************************************************/
+ libst_title (test, "pad smaller, no extra");
+diff --git a/libpackagekit/pk-common.h b/libpackagekit/pk-common.h
+index 9908ec2..9e5a05e 100644
+--- a/libpackagekit/pk-common.h
++++ b/libpackagekit/pk-common.h
+@@ -84,6 +84,9 @@ gchar **pk_strsplit (const gchar *id,
+ gchar *pk_strbuild_va (const gchar *first_element,
+ va_list *args)
+ G_GNUC_WARN_UNUSED_RESULT;
++gchar *pk_strreplace (const gchar *text,
++ const gchar *find,
++ const gchar *replace);
+ gchar **pk_ptr_array_to_argv (GPtrArray *array)
+ G_GNUC_WARN_UNUSED_RESULT;
+ gchar **pk_va_list_to_argv (const gchar *string_first,
+diff --git a/libpackagekit/pk-control.c b/libpackagekit/pk-control.c
+index f2de5ae..5a54ccc 100644
+--- a/libpackagekit/pk-control.c
++++ b/libpackagekit/pk-control.c
+@@ -198,6 +198,43 @@ out:
+ }
+
+ /**
++ * pk_control_set_proxy:
++ * @control: a valid #PkControl instance
++ * @proxy_http: a HTTP proxy string such as "username:password@server.lan:8080"
++ * @proxy_ftp: a FTP proxy string such as "server.lan:8080"
++ *
++ * Set a proxy on the PK daemon
++ *
++ * Return value: if we set the proxy successfully
++ **/
++gboolean
++pk_control_set_proxy (PkControl *control, const gchar *proxy_http, const gchar *proxy_ftp)
++{
++ gboolean ret = FALSE;
++ GError *error = NULL;
++
++ g_return_val_if_fail (PK_IS_CONTROL (control), PK_GROUP_ENUM_UNKNOWN);
++
++ /* check to see if we have a valid proxy */
++ if (control->priv->proxy == NULL) {
++ pk_warning ("No proxy for manager");
++ goto out;
++ }
++ ret = dbus_g_proxy_call (control->priv->proxy, "SetProxy", &error,
++ G_TYPE_STRING, proxy_http,
++ G_TYPE_STRING, proxy_ftp,
++ G_TYPE_INVALID,
++ G_TYPE_INVALID);
++ if (!ret) {
++ /* abort as the DBUS method failed */
++ pk_warning ("SetProxy failed :%s", error->message);
++ g_error_free (error);
++ }
++out:
++ return ret;
++}
++
++/**
+ * pk_control_get_groups:
+ * @control: a valid #PkControl instance
+ *
+diff --git a/libpackagekit/pk-control.h b/libpackagekit/pk-control.h
+index 63b30d3..c1b1be8 100644
+--- a/libpackagekit/pk-control.h
++++ b/libpackagekit/pk-control.h
+@@ -88,6 +88,9 @@ PkControl *pk_control_new (void);
+ gboolean pk_control_allocate_transaction_id (PkControl *control,
+ gchar **tid,
+ GError **error);
++gboolean pk_control_set_proxy (PkControl *control,
++ const gchar *proxy_http,
++ const gchar *proxy_ftp);
+ PkRoleEnum pk_control_get_actions (PkControl *control);
+ PkFilterEnum pk_control_get_filters (PkControl *control);
+ PkGroupEnum pk_control_get_groups (PkControl *control);
+diff --git a/libpackagekit/pk-enum.c b/libpackagekit/pk-enum.c
+index 5743dcb..9dccdd0 100644
+--- a/libpackagekit/pk-enum.c
++++ b/libpackagekit/pk-enum.c
+@@ -152,6 +152,7 @@ static PkEnumMatch enum_error[] = {
+ {PK_ERROR_ENUM_REPO_NOT_AVAILABLE, "repo-not-available"},
+ {PK_ERROR_ENUM_INVALID_PACKAGE_FILE, "invalid-package-file"},
+ {PK_ERROR_ENUM_PACKAGE_INSTALL_BLOCKED, "package-install-blocked"},
++ {PK_ERROR_ENUM_PACKAGE_CORRUPT, "package-corrupt"},
+ {0, NULL}
+ };
+
+@@ -417,6 +418,8 @@ static PkEnumMatch enum_free_licenses[] = {
+ {PK_LICENSE_ENUM_XANO, "XANO"},
+ {PK_LICENSE_ENUM_VOSTROM, "VOSTROM"},
+ {PK_LICENSE_ENUM_XEROX, "Xerox License"},
++ {PK_LICENSE_ENUM_RICEBSD, "RiceBSD"},
++ {PK_LICENSE_ENUM_QHULL, "Qhull"},
+ {0, NULL}
+ };
+
+diff --git a/libpackagekit/pk-enum.h b/libpackagekit/pk-enum.h
+index e616b64..4cc317e 100644
+--- a/libpackagekit/pk-enum.h
++++ b/libpackagekit/pk-enum.h
+@@ -256,6 +256,7 @@ typedef enum {
+ PK_ERROR_ENUM_REPO_NOT_AVAILABLE,
+ PK_ERROR_ENUM_INVALID_PACKAGE_FILE,
+ PK_ERROR_ENUM_PACKAGE_INSTALL_BLOCKED,
++ PK_ERROR_ENUM_PACKAGE_CORRUPT,
+ PK_ERROR_ENUM_UNKNOWN
+ } PkErrorCodeEnum;
+
+@@ -493,6 +494,8 @@ typedef enum {
+ PK_LICENSE_ENUM_XANO,
+ PK_LICENSE_ENUM_VOSTROM,
+ PK_LICENSE_ENUM_XEROX,
++ PK_LICENSE_ENUM_RICEBSD,
++ PK_LICENSE_ENUM_QHULL,
+ PK_LICENSE_ENUM_UNKNOWN
+ } PkLicenseEnum;
+
+diff --git a/libpackagekit/pk-extra.c b/libpackagekit/pk-extra.c
+index 7f01a4c..d0f0776 100644
+--- a/libpackagekit/pk-extra.c
++++ b/libpackagekit/pk-extra.c
+@@ -130,7 +130,6 @@ pk_extra_populate_package_cache_callback (void *data, gint argc, gchar **argv, g
+ obj->icon_name = icon_name;
+ obj->exec = exec;
+ g_hash_table_insert (extra->priv->hash_package, (gpointer) package, (gpointer) obj);
+- pk_debug ("adding %s, %s", package, icon_name);
+ out:
+ return 0;
+ }
+@@ -180,7 +179,6 @@ pk_extra_populate_locale_cache_callback (void *data, gint argc, gchar **argv, gc
+ obj = g_new (PkExtraLocaleObj, 1);
+ obj->summary = summary;
+ g_hash_table_insert (extra->priv->hash_locale, (gpointer) package, (gpointer) obj);
+- pk_debug ("adding %s, %s", package, summary);
+ out:
+ return 0;
+ }
+diff --git a/libpackagekit/pk-package-item.c b/libpackagekit/pk-package-item.c
+index 87905dc..ff4bd4e 100644
+--- a/libpackagekit/pk-package-item.c
++++ b/libpackagekit/pk-package-item.c
+@@ -56,7 +56,6 @@ pk_package_item_new (PkInfoEnum info, const gchar *package_id, const gchar *summ
+
+ g_return_val_if_fail (package_id != NULL, FALSE);
+
+- pk_debug ("adding to cache item package %s, %s, %s", pk_info_enum_to_text (info), package_id, summary);
+ item = g_new0 (PkPackageItem, 1);
+ item->info = info;
+ item->package_id = g_strdup (package_id);
+diff --git a/libpackagekit/pk-package-list.c b/libpackagekit/pk-package-list.c
+index 5d95e1b..6bdb0d4 100644
+--- a/libpackagekit/pk-package-list.c
++++ b/libpackagekit/pk-package-list.c
+@@ -77,7 +77,6 @@ pk_package_list_add (PkPackageList *plist, PkInfoEnum info, const gchar *package
+ g_return_val_if_fail (PK_IS_PACKAGE_LIST (plist), FALSE);
+ g_return_val_if_fail (package_id != NULL, FALSE);
+
+- pk_debug ("adding to cache array package %s, %s, %s", pk_info_enum_to_text (info), package_id, summary);
+ item = pk_package_item_new (info, package_id, summary);
+ g_ptr_array_add (plist->priv->array, item);
+
+@@ -104,9 +103,6 @@ pk_package_list_add_item (PkPackageList *plist, PkPackageItem *item)
+ return FALSE;
+ }
+
+- pk_debug ("adding to cache array package %s, %s, %s",
+- pk_info_enum_to_text (item->info), item->package_id, item->summary);
+-
+ item_new = pk_package_item_copy (item);
+ g_ptr_array_add (plist->priv->array, item_new);
+
+@@ -114,6 +110,30 @@ pk_package_list_add_item (PkPackageList *plist, PkPackageItem *item)
+ }
+
+ /**
++ * pk_package_list_add_list:
++ *
++ * Makes a deep copy of the list
++ **/
++gboolean
++pk_package_list_add_list (PkPackageList *plist, PkPackageList *list)
++{
++ guint i;
++ guint len;
++ PkPackageItem *item;
++
++ g_return_val_if_fail (PK_IS_PACKAGE_LIST (plist), FALSE);
++ g_return_val_if_fail (PK_IS_PACKAGE_LIST (list), FALSE);
++
++ /* add list to plist */
++ len = pk_package_list_get_size (list);
++ for (i=0; i<len; i++) {
++ item = pk_package_list_get_item (list, i);
++ pk_package_list_add_item (plist, item);
++ }
++ return TRUE;
++}
++
++/**
+ * pk_package_list_get_string:
+ **/
+ gchar *
+diff --git a/libpackagekit/pk-package-list.h b/libpackagekit/pk-package-list.h
+index 9734af4..83901ab 100644
+--- a/libpackagekit/pk-package-list.h
++++ b/libpackagekit/pk-package-list.h
+@@ -59,6 +59,8 @@ gboolean pk_package_list_add (PkPackageList *plist,
+ const gchar *summary);
+ gboolean pk_package_list_add_item (PkPackageList *plist,
+ PkPackageItem *item);
++gboolean pk_package_list_add_list (PkPackageList *plist,
++ PkPackageList *list);
+ gboolean pk_package_list_contains (PkPackageList *plist,
+ const gchar *package_id);
+ gboolean pk_package_list_contains_item (PkPackageList *plist,
+diff --git a/libpackagekit/pk-polkit-client.c b/libpackagekit/pk-polkit-client.c
+index dceb656..7308a29 100644
+--- a/libpackagekit/pk-polkit-client.c
++++ b/libpackagekit/pk-polkit-client.c
+@@ -54,9 +54,6 @@ static void pk_polkit_client_finalize (GObject *object);
+ #define POLKIT_DBUS_PATH "/org/gnome/PolicyKit/Manager"
+ #define POLKIT_DBUS_INTERFACE "org.gnome.PolicyKit.Manager"
+
+-/* we only support auth on the the transaction interface */
+-#define PK_ERROR_REFUSED_BY_POLICY "org.freedesktop.PackageKit.Transaction.RefusedByPolicy"
+-
+ /**
+ * PkPolkitClientPrivate:
+ *
+@@ -175,7 +172,10 @@ pk_polkit_client_error_denied_by_policy (GError *error)
+ /* check for specific error */
+ error_name = dbus_g_error_get_name (error);
+ pk_debug ("ERROR: %s: %s", error_name, error->message);
+- if (pk_strequal (error_name, PK_ERROR_REFUSED_BY_POLICY)) {
++ if (pk_strequal (error_name, "org.freedesktop.PackageKit.RefusedByPolicy")) {
++ return TRUE;
++ }
++ if (pk_strequal (error_name, "org.freedesktop.PackageKit.Transaction.RefusedByPolicy")) {
+ return TRUE;
+ }
+ return FALSE;
+diff --git a/libpackagekit/pk-task-list.c b/libpackagekit/pk-task-list.c
+index 76ab022..3dc1db0 100644
+--- a/libpackagekit/pk-task-list.c
++++ b/libpackagekit/pk-task-list.c
+@@ -161,7 +161,7 @@ pk_task_list_status_changed_cb (PkClient *client, PkStatusEnum status, PkTaskLis
+ g_return_if_fail (PK_IS_TASK_LIST (tlist));
+
+ tid = pk_client_get_tid (client);
+- pk_debug ("tid %s is now %i", tid, status);
++ pk_debug ("tid %s is now %s", tid, pk_status_enum_to_text (status));
+
+ /* get correct item */
+ item = pk_task_list_find_existing_tid (tlist, tid);
+diff --git a/po/LINGUAS b/po/LINGUAS
+index 6dbee0e..f87e6b3 100644
+--- a/po/LINGUAS
++++ b/po/LINGUAS
+@@ -5,6 +5,7 @@ es
+ fi
+ fr
+ he
++hu
+ it
+ nl
+ no_nb
+diff --git a/po/de.po b/po/de.po
+index 33d30c1..6e8013e 100644
+--- a/po/de.po
++++ b/po/de.po
+@@ -8,8 +8,8 @@ msgid ""
+ msgstr ""
+ "Project-Id-Version: PackageKit\n"
+ "Report-Msgid-Bugs-To: \n"
+-"POT-Creation-Date: 2008-04-23 01:36+0000\n"
+-"PO-Revision-Date: 2008-04-23 19:28+0100\n"
++"POT-Creation-Date: 2008-05-03 01:22+0000\n"
++"PO-Revision-Date: 2008-05-20 21:52+0100\n"
+ "Last-Translator: Fabian Affolter <fab@fedoraproject.org>\n"
+ "Language-Team: German <fedora-trans-de@redhat.com>\n"
+ "MIME-Version: 1.0\n"
+@@ -18,239 +18,239 @@ msgstr ""
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
+ "X-Poedit-Language: German\n"
+
+-#: ../client/pk-console.c:208
++#: ../client/pk-console.c:224
+ msgid "Update detail"
+ msgstr "Aktualisierungsdetails"
+
+-#: ../client/pk-console.c:400
++#: ../client/pk-console.c:425
+ msgid "A system restart is required"
+ msgstr "Ein Systemneustart ist erforderlich"
+
+-#: ../client/pk-console.c:402
++#: ../client/pk-console.c:427
+ msgid "A logout and login is required"
+ msgstr "Eine Neuanmeldung ist erforderlich"
+
+-#: ../client/pk-console.c:404
++#: ../client/pk-console.c:429
+ msgid "An application restart is required"
+ msgstr "Ein Neustart der Anwendung ist erforderlich"
+
+-#: ../client/pk-console.c:443
++#: ../client/pk-console.c:474
+ #, c-format
+ msgid "Please enter a number from 1 to %i: "
+ msgstr "Bitte eine Zahl zwischen 1 und %i eingeben: "
+
+-#: ../client/pk-console.c:493
++#: ../client/pk-console.c:524
+ msgid "Could not find a package match"
+ msgstr "Es konnte kein passendes Paket gefunden werden"
+
+-#: ../client/pk-console.c:507
++#: ../client/pk-console.c:538
+ msgid "There are multiple package matches"
+ msgstr "Es wurden mehrere passende Paket gefunden"
+
+ #. find out what package the user wants to use
+-#: ../client/pk-console.c:514
++#: ../client/pk-console.c:545
+ msgid "Please enter the package number: "
+ msgstr "Bitte die Paketnummer eingeben: "
+
+-#: ../client/pk-console.c:530
++#: ../client/pk-console.c:561
+ msgid "Could not find a package with that name to install, or package already installed"
+ msgstr "Es konnten weder installierte noch zu installierende Paket mit diesem Namen gefunden werden"
+
+-#: ../client/pk-console.c:612
++#: ../client/pk-console.c:643
+ msgid "Could not find a package with that name to remove"
+ msgstr "Es konnte kein Paket mit diesem Namen zum Deinstallieren gefunden werden"
+
+-#: ../client/pk-console.c:652
++#: ../client/pk-console.c:683
+ msgid "The following packages have to be removed"
+ msgstr "Die folgenden Paket werden entfernt"
+
+ #. get user input
+-#: ../client/pk-console.c:661
++#: ../client/pk-console.c:692
+ msgid "Okay to remove additional packages?"
+ msgstr "Die folgenden zusätzlichen Pakete entfernen?"
+
+-#: ../client/pk-console.c:665
++#: ../client/pk-console.c:696
+ msgid "Cancelled!"
+ msgstr "Abgebrochen!"
+
+-#: ../client/pk-console.c:687
++#: ../client/pk-console.c:718
+ msgid "Could not find a package with that name to update"
+ msgstr "Es konnte kein Paket mit diesem Namen zum Aktualisieren gefunden werden"
+
+-#: ../client/pk-console.c:705
++#: ../client/pk-console.c:736
+ msgid "Could not find what packages require this package"
+ msgstr "Es konnte nicht rausgefunden werden, welche Pakete dieses Paket benötigen"
+
+-#: ../client/pk-console.c:723
++#: ../client/pk-console.c:754
+ msgid "Could not get dependencies for this package"
+ msgstr "Die Abhängigkeiten für dieses Paket konnten nicht ermittelt werden"
+
+-#: ../client/pk-console.c:741
+-msgid "Could not find a description for this package"
+-msgstr "Die Beschreibung für dieses Paket konnten nicht ermittelt werden"
++#: ../client/pk-console.c:772
++msgid "Could not find details for this package"
++msgstr "Die Details für dieses Paket konnten nicht gefunden werden"
+
+-#: ../client/pk-console.c:759
++#: ../client/pk-console.c:790
+ msgid "Could not find the files for this package"
+ msgstr "Die Dateien für dieses Paket konnten nicht ermittelt werden"
+
+-#: ../client/pk-console.c:819
++#: ../client/pk-console.c:870
+ msgid "Package description"
+ msgstr "Paketbeschreibung"
+
+-#: ../client/pk-console.c:842
++#: ../client/pk-console.c:893
+ msgid "Package files"
+ msgstr "Paketinhalt"
+
+-#: ../client/pk-console.c:850
++#: ../client/pk-console.c:901
+ msgid "No files"
+ msgstr "Keine Dateien"
+
+ #. get user input
+-#: ../client/pk-console.c:882
++#: ../client/pk-console.c:933
+ msgid "Okay to import key?"
+ msgstr "Soll der Schlüssel importiert werden?"
+
+-#: ../client/pk-console.c:885
++#: ../client/pk-console.c:936
+ msgid "Did not import key"
+ msgstr "Den Schlüssel nicht importieren"
+
+ #. get user input
+-#: ../client/pk-console.c:925
++#: ../client/pk-console.c:976
+ msgid "Do you agree?"
+ msgstr "Sind Sie einverstanden?"
+
+-#: ../client/pk-console.c:928
++#: ../client/pk-console.c:979
+ msgid "Did not agree to licence, task will fail"
+ msgstr "Lizenz wurde abgelehnt, Aufgabe wird fehlschlagen"
+
+-#: ../client/pk-console.c:957
++#: ../client/pk-console.c:1008
+ msgid "The daemon crashed mid-transaction!"
+ msgstr "Der Dienst ist während der Verarbeitung abgestürzt!"
+
+ #. header
+-#: ../client/pk-console.c:1010
++#: ../client/pk-console.c:1061
+ msgid "PackageKit Console Interface"
+ msgstr "PackageKit-Konsolenschnittstelle"
+
+-#: ../client/pk-console.c:1010
++#: ../client/pk-console.c:1061
+ msgid "Subcommands:"
+ msgstr "Unterbefehle:"
+
+-#: ../client/pk-console.c:1114
+-#: ../client/pk-monitor.c:100
++#: ../client/pk-console.c:1165
++#: ../client/pk-monitor.c:104
+ #: ../src/pk-main.c:189
+ msgid "Show extra debugging information"
+ msgstr "Zusätzliche Debugging-Informationen anzeigen"
+
+-#: ../client/pk-console.c:1116
+-#: ../client/pk-monitor.c:102
++#: ../client/pk-console.c:1167
++#: ../client/pk-monitor.c:106
+ msgid "Show the program version and exit"
+ msgstr "Die Programmversion anzeigen und beenden"
+
+-#: ../client/pk-console.c:1118
++#: ../client/pk-console.c:1169
+ msgid "Set the filter, e.g. installed"
+ msgstr "Setzt den Filter, z. B. installiert"
+
+-#: ../client/pk-console.c:1120
++#: ../client/pk-console.c:1171
+ msgid "Exit without waiting for actions to complete"
+ msgstr "Beenden ohne auf das Ende der Aktionen zu warten"
+
+-#: ../client/pk-console.c:1143
++#: ../client/pk-console.c:1194
+ msgid "Could not connect to system DBUS."
+ msgstr "Mit System-DBUS konnte nicht verbunden werden."
+
+-#: ../client/pk-console.c:1231
++#: ../client/pk-console.c:1288
+ msgid "You need to specify a search type"
+ msgstr "Es muss eine Suchart angegeben werden"
+
+-#: ../client/pk-console.c:1236
+-#: ../client/pk-console.c:1243
+-#: ../client/pk-console.c:1250
+-#: ../client/pk-console.c:1257
+-#: ../client/pk-console.c:1361
+-#: ../client/pk-console.c:1368
+-#: ../client/pk-console.c:1375
+-#: ../client/pk-console.c:1382
++#: ../client/pk-console.c:1293
++#: ../client/pk-console.c:1300
++#: ../client/pk-console.c:1307
++#: ../client/pk-console.c:1314
++#: ../client/pk-console.c:1421
++#: ../client/pk-console.c:1428
++#: ../client/pk-console.c:1435
++#: ../client/pk-console.c:1442
+ msgid "You need to specify a search term"
+ msgstr "Es muss ein Suchausdruck angegeben werden"
+
+-#: ../client/pk-console.c:1262
++#: ../client/pk-console.c:1319
+ msgid "Invalid search type"
+ msgstr "Ungültige Suchart"
+
+-#: ../client/pk-console.c:1267
++#: ../client/pk-console.c:1324
+ msgid "You need to specify a package or file to install"
+ msgstr "Es muss ein Paket oder eine Datei zum Installieren angegeben werden"
+
+-#: ../client/pk-console.c:1280
++#: ../client/pk-console.c:1339
+ msgid "You need to specify a type, key_id and package_id"
+ msgstr "Es muss ein Typ angegeben werden, key_id oder package_id"
+
+-#: ../client/pk-console.c:1287
++#: ../client/pk-console.c:1346
+ msgid "You need to specify a package to remove"
+ msgstr "Es muss ein Paket zum Entfernen angegeben werden"
+
+-#: ../client/pk-console.c:1294
++#: ../client/pk-console.c:1353
+ msgid "You need to specify a eula-id"
+ msgstr "Es muss eine eula-id angegeben werden"
+
+-#: ../client/pk-console.c:1309
++#: ../client/pk-console.c:1369
+ msgid "You need to specify a package name to resolve"
+ msgstr "Es muss ein Paketname zum Auflösen angegeben werden"
+
+-#: ../client/pk-console.c:1316
+-#: ../client/pk-console.c:1323
++#: ../client/pk-console.c:1376
++#: ../client/pk-console.c:1383
+ msgid "You need to specify a repo name"
+ msgstr "Es muss ein Repository-Name angegeben werden"
+
+-#: ../client/pk-console.c:1330
++#: ../client/pk-console.c:1390
+ msgid "You need to specify a repo name/parameter and value"
+ msgstr "Es muss ein Repository-Name/Argument und Wert angegeben werden"
+
+-#: ../client/pk-console.c:1343
++#: ../client/pk-console.c:1403
+ msgid "You need to specify a time term"
+ msgstr "Es muss ein Zeitausdruck angegeben werden"
+
+-#: ../client/pk-console.c:1348
++#: ../client/pk-console.c:1408
+ msgid "You need to specify a correct role"
+ msgstr "Es muss eine korrekte Rolle angegeben werden"
+
+-#: ../client/pk-console.c:1353
++#: ../client/pk-console.c:1413
+ msgid "Failed to get last time"
+ msgstr "Die letzte Zeit konnte nicht abgefragt werden"
+
+-#: ../client/pk-console.c:1389
+-msgid "You need to specify a package to find the description for"
+-msgstr "Es muss ein Paket angegeben werden zu dem die Beschreibung gefunden werden soll"
++#: ../client/pk-console.c:1449
++msgid "You need to specify a package to find the details for"
++msgstr "Es muss ein Paket angegeben werden zu dem die Details gefunden werden sollen"
+
+-#: ../client/pk-console.c:1396
++#: ../client/pk-console.c:1456
+ msgid "You need to specify a package to find the files for"
+ msgstr "Es muss ein Paket angegeben werden zu dem die Dateien gefunden werden sollen"
+
+-#: ../client/pk-console.c:1441
++#: ../client/pk-console.c:1503
+ #, c-format
+ msgid "Option '%s' not supported"
+ msgstr "Option '%s' wird nicht unterstützt"
+
+-#: ../client/pk-console.c:1452
++#: ../client/pk-console.c:1514
+ msgid "Command failed"
+ msgstr "Befehl fehlgeschlagen"
+
+-#: ../client/pk-console.c:1456
++#: ../client/pk-console.c:1518
+ msgid "You don't have the necessary privileges for this operation"
+ msgstr "Es fehlen die benötigten Rechte für diese Operation"
+
+-#: ../client/pk-monitor.c:113
++#: ../client/pk-monitor.c:117
+ msgid "PackageKit Monitor"
+ msgstr "PackageKit Monitor"
+
+-#: ../client/pk-import-desktop.c:283
++#: ../client/pk-import-desktop.c:293
+ #: ../client/pk-import-specspo.c:169
+ #, c-format
+ msgid "Could not open database: %s"
+ msgstr "Datenbank konnte nicht geöffnet werden: %s"
+
+-#: ../client/pk-import-desktop.c:284
++#: ../client/pk-import-desktop.c:294
+ #: ../client/pk-import-specspo.c:170
+ msgid "You probably need to run this program as the root user"
+ msgstr "Das Programm muss möglicherweise als Benutzer root ausgeführt werden"
+@@ -308,6 +308,12 @@ msgstr "Es konnte nicht zum System-Bus verbunden werden"
+ msgid "Error trying to start: %s\n"
+ msgstr "Fehler beim Versuch zu starten: %s\n"
+
++#~ msgid "Could not find a description for this package"
++#~ msgstr "Die Beschreibung für dieses Paket konnten nicht ermittelt werden"
++#~ msgid "You need to specify a package to find the description for"
++#~ msgstr ""
++#~ "Es muss ein Paket angegeben werden zu dem die Beschreibung gefunden "
++#~ "werden soll"
+ #~ msgid "Accept EULA"
+ #~ msgstr "EULA akzeptieren"
+ #~ msgid "Authentication is required to accept a EULA"
+diff --git a/po/hu.po b/po/hu.po
+new file mode 100644
+index 0000000..ea732d0
+--- /dev/null
++++ b/po/hu.po
+@@ -0,0 +1,311 @@
++# SOME DESCRIPTIVE TITLE.
++# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
++# This file is distributed under the same license as the PACKAGE package.
++# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
++#
++msgid ""
++msgstr ""
++"Project-Id-Version: packagekit\n"
++"Report-Msgid-Bugs-To: \n"
++"POT-Creation-Date: 2008-05-18 17:43+0000\n"
++"PO-Revision-Date: 2008-05-19 00:08+0100\n"
++"Last-Translator: Sulyok Péter <peti@fedoraproject.org>\n"
++"Language-Team: Hungarian <fedora-trans-hu@redhat.com>\n"
++"MIME-Version: 1.0\n"
++"Content-Type: text/plain; charset=utf-8\n"
++"Content-Transfer-Encoding: 8bit\n"
++"Plural-Forms: nplurals=2; plural=n>1\n"
++"X-Poedit-Language: Hungarian\n"
++"X-Poedit-Country: HUNGARY\n"
++"X-Poedit-SourceCharset: utf-8\n"
++
++#: ../client/pk-console.c:224
++msgid "Update detail"
++msgstr "Frissítés részletező"
++
++#: ../client/pk-console.c:425
++msgid "A system restart is required"
++msgstr "Rendszer-újraindítás szükséges"
++
++#: ../client/pk-console.c:427
++msgid "A logout and login is required"
++msgstr "Kijelentkezés és bejelentkezés szükséges"
++
++#: ../client/pk-console.c:429
++msgid "An application restart is required"
++msgstr "Alkalmazás-újraindítás szükséges"
++
++#: ../client/pk-console.c:474
++#, c-format
++msgid "Please enter a number from 1 to %i: "
++msgstr "Kérem adjon meg egy számot 1-től %i-ig:"
++
++#: ../client/pk-console.c:524
++msgid "Could not find a package match"
++msgstr "Nincs megfelelő csomag"
++
++#: ../client/pk-console.c:538
++msgid "There are multiple package matches"
++msgstr "Több csomag illik"
++
++#. find out what package the user wants to use
++#: ../client/pk-console.c:545
++msgid "Please enter the package number: "
++msgstr "Kérem adja meg a csomagszámot:"
++
++#: ../client/pk-console.c:561
++msgid "Could not find a package with that name to install, or package already installed"
++msgstr "Nem lehetett csomagot találni azzal a névvel telepítésre, vagy márt telepített csomagot"
++
++#: ../client/pk-console.c:643
++msgid "Could not find a package with that name to remove"
++msgstr "Nem lehetett csomagot találni azzal a névvel törlésre"
++
++#: ../client/pk-console.c:683
++msgid "The following packages have to be removed"
++msgstr "A következő csomagokat kell eltávolítani"
++
++#. get user input
++#: ../client/pk-console.c:692
++msgid "Okay to remove additional packages?"
++msgstr "Eltávolíthatók további csomagok?"
++
++#: ../client/pk-console.c:696
++msgid "Cancelled!"
++msgstr "Megszakítva!"
++
++#: ../client/pk-console.c:718
++msgid "Could not find a package with that name to update"
++msgstr "Nem lehetett csomagot találni azzal a névvel frissítésre"
++
++#: ../client/pk-console.c:736
++msgid "Could not find what packages require this package"
++msgstr "Nem lehetett megtudni mely csomagok szükségesek"
++
++#: ../client/pk-console.c:754
++msgid "Could not get dependencies for this package"
++msgstr "Nem lehetett csomagfüggőséget megkapni e csomaghoz"
++
++#: ../client/pk-console.c:772
++msgid "Could not find details for this package"
++msgstr "Nem lehetett részletezőt találni e csomaghoz"
++
++#: ../client/pk-console.c:790
++msgid "Could not find the files for this package"
++msgstr "Nem lehetett fájlokat találni e csomaghoz"
++
++#: ../client/pk-console.c:870
++msgid "Package description"
++msgstr "Csomagleírás"
++
++#: ../client/pk-console.c:893
++msgid "Package files"
++msgstr "Csomagfájlok"
++
++#: ../client/pk-console.c:901
++msgid "No files"
++msgstr "Nincs fájl"
++
++#. get user input
++#: ../client/pk-console.c:933
++msgid "Okay to import key?"
++msgstr "Behozhatunk kulcsot?"
++
++#: ../client/pk-console.c:936
++msgid "Did not import key"
++msgstr "Nem hoztunk be kulcsot"
++
++#. get user input
++#: ../client/pk-console.c:976
++msgid "Do you agree?"
++msgstr "Egyetért?"
++
++#: ../client/pk-console.c:979
++msgid "Did not agree to licence, task will fail"
++msgstr "Nem egyezett meg az engedélyben, a munka elbukik"
++
++#: ../client/pk-console.c:1008
++msgid "The daemon crashed mid-transaction!"
++msgstr "A szolgáltatás összeomlott tranzakció közben!"
++
++#. header
++#: ../client/pk-console.c:1061
++msgid "PackageKit Console Interface"
++msgstr "PackageKit parancssori felület"
++
++#: ../client/pk-console.c:1061
++msgid "Subcommands:"
++msgstr "Részparancsok:"
++
++#: ../client/pk-console.c:1165
++#: ../client/pk-monitor.c:104
++#: ../src/pk-main.c:189
++msgid "Show extra debugging information"
++msgstr "Extra hibakereső adatok megjelenítése"
++
++#: ../client/pk-console.c:1167
++#: ../client/pk-monitor.c:106
++msgid "Show the program version and exit"
++msgstr "Programváltozat megmutatása és kilépés"
++
++#: ../client/pk-console.c:1169
++msgid "Set the filter, e.g. installed"
++msgstr "Szűrő beállítása, pl. telepítve"
++
++#: ../client/pk-console.c:1171
++msgid "Exit without waiting for actions to complete"
++msgstr "Kilépés cselekmény befejezésére várakozás nélkül"
++
++#: ../client/pk-console.c:1194
++msgid "Could not connect to system DBUS."
++msgstr "Nem lehetett kapcsolódni DBUS-hoz."
++
++#: ../client/pk-console.c:1288
++msgid "You need to specify a search type"
++msgstr "Meg kell adni a keresendő típust"
++
++#: ../client/pk-console.c:1293
++#: ../client/pk-console.c:1300
++#: ../client/pk-console.c:1307
++#: ../client/pk-console.c:1314
++#: ../client/pk-console.c:1421
++#: ../client/pk-console.c:1428
++#: ../client/pk-console.c:1435
++#: ../client/pk-console.c:1442
++msgid "You need to specify a search term"
++msgstr "Meg kell adni a keresendő kifejezést"
++
++#: ../client/pk-console.c:1319
++msgid "Invalid search type"
++msgstr "Érvénytelen típus"
++
++#: ../client/pk-console.c:1324
++msgid "You need to specify a package or file to install"
++msgstr "Meg kell adnia a telepítendő csomag vagy fájl nevét"
++
++#: ../client/pk-console.c:1339
++msgid "You need to specify a type, key_id and package_id"
++msgstr "Meg kell adnia egy típust, kulcs azonosítót és csomag azonosítót"
++
++#: ../client/pk-console.c:1346
++msgid "You need to specify a package to remove"
++msgstr "Meg kell adnia egy eltávolítandó csomagot"
++
++#: ../client/pk-console.c:1353
++msgid "You need to specify a eula-id"
++msgstr "Meg kell adnia egy végfelhasználó azonosítót"
++
++#: ../client/pk-console.c:1369
++msgid "You need to specify a package name to resolve"
++msgstr "Meg kell adnia egy feloldandó csomagnevet"
++
++#: ../client/pk-console.c:1376
++#: ../client/pk-console.c:1383
++msgid "You need to specify a repo name"
++msgstr "Meg kell adnia egy tár nevét"
++
++#: ../client/pk-console.c:1390
++msgid "You need to specify a repo name/parameter and value"
++msgstr "Meg kell adnia egy tárnevet/paramétert és értéket"
++
++#: ../client/pk-console.c:1403
++msgid "You need to specify a time term"
++msgstr "Meg kell adnia egy időszakot"
++
++#: ../client/pk-console.c:1408
++msgid "You need to specify a correct role"
++msgstr "Meg kell adnia egy helyes szerepet"
++
++#: ../client/pk-console.c:1413
++msgid "Failed to get last time"
++msgstr "Nem sikerült megkapni az utolsó időt"
++
++#: ../client/pk-console.c:1449
++msgid "You need to specify a package to find the details for"
++msgstr "Meg kell adnia egy egy csomagot, amihez részletező keresendő"
++
++#: ../client/pk-console.c:1456
++msgid "You need to specify a package to find the files for"
++msgstr "Meg kell adnia egy csomagot, amihez fájlokat kell találni"
++
++#: ../client/pk-console.c:1503
++#, c-format
++msgid "Option '%s' not supported"
++msgstr "„%s” opció nem támogatott"
++
++#: ../client/pk-console.c:1514
++msgid "Command failed"
++msgstr "Parancs elbukott"
++
++#: ../client/pk-console.c:1518
++msgid "You don't have the necessary privileges for this operation"
++msgstr "Önnek nincs meg szükséges jogosultsága e műveletre"
++
++#: ../client/pk-monitor.c:117
++msgid "PackageKit Monitor"
++msgstr "PackageKit figyelő"
++
++#: ../client/pk-import-desktop.c:293
++#: ../client/pk-import-specspo.c:169
++#, c-format
++msgid "Could not open database: %s"
++msgstr "Nem lehetett megnyitni %s adatbázist"
++
++#: ../client/pk-import-desktop.c:294
++#: ../client/pk-import-specspo.c:170
++msgid "You probably need to run this program as the root user"
++msgstr "E program valószínűleg rendszergazdaként futtatható"
++
++#: ../src/pk-main.c:83
++msgid "Startup failed due to security policies on this machine."
++msgstr "Indulás sikertelen a gép biztonsági szabályzata miatt."
++
++#: ../src/pk-main.c:84
++msgid "This can happen for two reasons:"
++msgstr "Két okból történet mehet:"
++
++#: ../src/pk-main.c:85
++msgid "The correct user is not launching the executable (usually root)"
++msgstr "A helyes használó nem indítja a futtathatót (rendszerint rendszergada)"
++
++#: ../src/pk-main.c:86
++msgid "The org.freedesktop.PackageKit.conf file is not installed in the system /etc/dbus-1/system.d directory"
++msgstr "Az org.freedesktop.PackageKit.conf a rendszert nem telepítették a system /etc/dbus-1/system.d mappába"
++
++#: ../src/pk-main.c:185
++msgid "Packaging backend to use, e.g. dummy"
++msgstr "Használandó csomagoló háttér, pl. dummy"
++
++#: ../src/pk-main.c:187
++msgid "Daemonize and detach from the terminal"
++msgstr "Szolgálatatás és leválasztás terminálról"
++
++#: ../src/pk-main.c:191
++msgid "Disable the idle timer"
++msgstr "Tétlen időzítő kikapcsolása"
++
++#: ../src/pk-main.c:193
++msgid "Show version and exit"
++msgstr "Változat mutatása és kilépés"
++
++#: ../src/pk-main.c:195
++msgid "Exit after a small delay"
++msgstr "Kilépés rövid késleltetés után"
++
++#: ../src/pk-main.c:197
++msgid "Exit after the engine has loaded"
++msgstr "Kilépés a motor betöltése után"
++
++#: ../src/pk-main.c:207
++msgid "PackageKit service"
++msgstr "PackageKit szolgáltatás"
++
++#: ../src/pk-main.c:233
++msgid "Cannot connect to the system bus"
++msgstr "Nem lehetett csatlakozni a rendszerbuszhoz"
++
++#: ../src/pk-main.c:273
++#, c-format
++msgid "Error trying to start: %s\n"
++msgstr "Hiba %s indításakor\n"
++
+diff --git a/policy/org.freedesktop.packagekit.policy.in b/policy/org.freedesktop.packagekit.policy.in
+index 32efce7..4c4607d 100644
+--- a/policy/org.freedesktop.packagekit.policy.in
++++ b/policy/org.freedesktop.packagekit.policy.in
+@@ -133,5 +133,17 @@
+ <allow_active>yes</allow_active>
+ </defaults>
+ </action>
++
++ <action id="org.freedesktop.packagekit.set-proxy">
++ <_description>Set network proxy</_description>
++ <_message>Authentication is required to set the network proxy used for downloading packages</_message>
++ <icon_name>applications-internet</icon_name>
++ <vendor_url>http://www.packagekit.org/pk-reference.html#methods-set-proxy</vendor_url>
++ <defaults>
++ <allow_inactive>no</allow_inactive>
++ <allow_active>yes</allow_active>
++ </defaults>
++ </action>
++
+ </policyconfig>
+
+diff --git a/python/packagekit/daemonBackend.py b/python/packagekit/daemonBackend.py
+index 5253b39..9fd627a 100644
+--- a/python/packagekit/daemonBackend.py
++++ b/python/packagekit/daemonBackend.py
+@@ -325,13 +325,13 @@ class PackageKitBaseBackend(dbus.service.Object):
+
+ @PKSignalHouseKeeper
+ @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
+- signature='sssssss')
+- def RepoSignatureRequired(self,repo_name,key_url,key_userid,key_id,key_fingerprint,key_timestamp,key_type):
++ signature='ssssssss')
++ def RepoSignatureRequired(self,id,repo_name,key_url,key_userid,key_id,key_fingerprint,key_timestamp,key_type):
+ '''
+ send 'repo-signature-required' signal:
+ '''
+ pklog.info("RepoSignatureRequired (%s, %s, %s, %s, %s, %s, %s, %s)" %
+- (repo_name,key_url,key_userid,key_id,key_fingerprint,key_timestamp,key_type))
++ (id,repo_name,key_url,key_userid,key_id,key_fingerprint,key_timestamp,key_type))
+
+
+ #
+@@ -658,8 +658,9 @@ class PackageKitBaseBackend(dbus.service.Object):
+ '''
+ Implement the {backend}-remove functionality
+ '''
+- pklog.info("RemovePackages(%s, %s, %s)" % (package[0], allowdep, autoremove))
+- self.doRemovePackages(package, allowdep, autoremove)
++ pklog.info("RemovePackages(%s, %s, %s)" % (packages, allowdep,
++ autoremove))
++ self.doRemovePackages(packages, allowdep, autoremove)
+
+ def doRemovePackages(self, packages, allowdep, autoremove):
+ '''
+diff --git a/src/pk-backend-spawn.c b/src/pk-backend-spawn.c
+index f9c9f12..2bd416d 100644
+--- a/src/pk-backend-spawn.c
++++ b/src/pk-backend-spawn.c
+@@ -316,8 +316,8 @@ pk_backend_spawn_parse_stdout (PkBackendSpawn *backend_spawn, const gchar *line)
+ pk_backend_set_percentage (backend_spawn->priv->backend, PK_BACKEND_PERCENTAGE_INVALID);
+ } else if (pk_strequal (command, "repo-signature-required")) {
+
+- if (size != 9+99) {
+- pk_error ("invalid command '%s'", command);
++ if (size != 9) {
++ pk_warning ("invalid command '%s'", command);
+ ret = FALSE;
+ goto out;
+ }
+diff --git a/src/pk-backend.c b/src/pk-backend.c
+index 37ed024..f0f245f 100644
+--- a/src/pk-backend.c
++++ b/src/pk-backend.c
+@@ -1484,8 +1484,7 @@ pk_backend_finished (PkBackend *backend)
+ backend->priv->role == PK_ROLE_ENUM_REMOVE_PACKAGES ||
+ backend->priv->role == PK_ROLE_ENUM_UPDATE_PACKAGES)) {
+ pk_backend_message (backend, PK_MESSAGE_ENUM_DAEMON,
+- "Backends need to send a Package() for this role!");
+- return FALSE;
++ "Backends should send a Package() for this role!");
+ }
+
+ /* if we set an error code notifier, clear */
+diff --git a/src/pk-backend.h b/src/pk-backend.h
+index fb17e3c..a7ba754 100644
+--- a/src/pk-backend.h
++++ b/src/pk-backend.h
+@@ -256,7 +256,7 @@ typedef struct {
+ void (*update_system) (PkBackend *backend);
+ void (*what_provides) (PkBackend *backend,
+ PkFilterEnum filters,
+- PkProvidesEnum provide,
++ PkProvidesEnum provides,
+ const gchar *search);
+ gpointer padding[10];
+ } PkBackendDesc;
+diff --git a/src/pk-engine.c b/src/pk-engine.c
+index 028a0d0..14ecf41 100644
+--- a/src/pk-engine.c
++++ b/src/pk-engine.c
+@@ -154,6 +154,8 @@ pk_engine_error_get_type (void)
+ static const GEnumValue values[] =
+ {
+ ENUM_ENTRY (PK_ENGINE_ERROR_INVALID_STATE, "InvalidState"),
++ ENUM_ENTRY (PK_ENGINE_ERROR_REFUSED_BY_POLICY, "RefusedByPolicy"),
++ ENUM_ENTRY (PK_ENGINE_ERROR_CANNOT_SET_PROXY, "CannotSetProxy"),
+ { 0, NULL, NULL }
+ };
+ etype = g_enum_register_static ("PkEngineError", values);
+@@ -502,6 +504,47 @@ pk_engine_suggest_daemon_quit (PkEngine *engine, GError **error)
+ }
+
+ /**
++ * pk_engine_set_proxy:
++ **/
++void
++pk_engine_set_proxy (PkEngine *engine, const gchar *proxy_http, const gchar *proxy_ftp, DBusGMethodInvocation *context)
++{
++ gboolean ret;
++ GError *error;
++ gchar *sender = NULL;
++ gchar *error_detail = NULL;
++
++ g_return_if_fail (PK_IS_ENGINE (engine));
++
++ pk_debug ("SetProxy method called: %s, %s", proxy_http, proxy_ftp);
++
++ /* check if the action is allowed from this client - if not, set an error */
++ sender = dbus_g_method_get_sender (context);
++
++ /* use security model to get auth */
++ ret = pk_security_action_is_allowed (engine->priv->security, sender, FALSE, PK__ROLE_ENUM_SET_PROXY, &error_detail);
++ if (!ret) {
++ error = g_error_new (PK_ENGINE_ERROR, PK_ENGINE_ERROR_REFUSED_BY_POLICY, "%s", error_detail);
++ dbus_g_method_return_error (context, error);
++ goto out;
++ }
++
++ /* try to set the new proxy */
++ ret = pk_backend_set_proxy (engine->priv->backend, proxy_http, proxy_ftp);
++ if (!ret) {
++ error = g_error_new (PK_ENGINE_ERROR, PK_ENGINE_ERROR_CANNOT_SET_PROXY, "%s", "setting the proxy failed");
++ dbus_g_method_return_error (context, error);
++ goto out;
++ }
++
++ /* all okay */
++ dbus_g_method_return (context);
++out:
++ g_free (sender);
++ g_free (error_detail);
++}
++
++/**
+ * pk_engine_class_init:
+ * @klass: The PkEngineClass
+ **/
+diff --git a/src/pk-engine.h b/src/pk-engine.h
+index c59b1f3..668451f 100644
+--- a/src/pk-engine.h
++++ b/src/pk-engine.h
+@@ -57,9 +57,12 @@ typedef enum
+ {
+ PK_ENGINE_ERROR_DENIED,
+ PK_ENGINE_ERROR_INVALID_STATE,
++ PK_ENGINE_ERROR_REFUSED_BY_POLICY,
++ PK_ENGINE_ERROR_CANNOT_SET_PROXY,
+ PK_ENGINE_ERROR_LAST
+ } PkEngineError;
+
++
+ GQuark pk_engine_error_quark (void);
+ GType pk_engine_error_get_type (void) G_GNUC_CONST;
+ GType pk_engine_get_type (void) G_GNUC_CONST;
+@@ -100,6 +103,10 @@ gboolean pk_engine_state_has_changed (PkEngine *engine,
+ GError **error);
+ gboolean pk_engine_suggest_daemon_quit (PkEngine *engine,
+ GError **error);
++void pk_engine_set_proxy (PkEngine *engine,
++ const gchar *proxy_http,
++ const gchar *proxy_ftp,
++ DBusGMethodInvocation *context);
+
+ G_END_DECLS
+
+diff --git a/src/pk-interface.xml b/src/pk-interface.xml
+index e9e74e1..7290bbe 100644
+--- a/src/pk-interface.xml
++++ b/src/pk-interface.xml
+@@ -33,6 +33,11 @@
+ <method name="GetNetworkState">
+ <arg type="s" name="state" direction="out"/>
+ </method>
++ <method name="SetProxy">
++ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
++ <arg type="s" name="proxy_http" direction="in"/>
++ <arg type="s" name="proxy_ftp" direction="in"/>
++ </method>
+
+ <signal name="TransactionListChanged">
+ <arg type="as" name="transactions" direction="out"/>
+diff --git a/src/pk-security-polkit.c b/src/pk-security-polkit.c
+index 9abf992..81332d0 100644
+--- a/src/pk-security-polkit.c
++++ b/src/pk-security-polkit.c
+@@ -128,6 +128,9 @@ pk_security_role_to_action (PkSecurity *security, gboolean trusted, PkRoleEnum r
+ policy = "org.freedesktop.packagekit.repo-change";
+ } else if (role == PK_ROLE_ENUM_REFRESH_CACHE) {
+ policy = "org.freedesktop.packagekit.refresh-cache";
++ /* PRIVATE: not actually roles */
++ } else if (role == PK__ROLE_ENUM_SET_PROXY) {
++ policy = "org.freedesktop.packagekit.refresh-cache";
+ }
+ return policy;
+ }
+diff --git a/src/pk-security.h b/src/pk-security.h
+index 3432095..eb55932 100644
+--- a/src/pk-security.h
++++ b/src/pk-security.h
+@@ -34,6 +34,9 @@ G_BEGIN_DECLS
+ #define PK_IS_SECURITY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PK_TYPE_SECURITY))
+ #define PK_SECURITY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PK_TYPE_SECURITY, PkSecurityClass))
+
++/* FIXME: not actually a role */
++#define PK__ROLE_ENUM_SET_PROXY 1 << 31
++
+ typedef struct PkSecurityPrivate PkSecurityPrivate;
+
+ typedef struct
+diff --git a/src/pk-transaction-db.c b/src/pk-transaction-db.c
+index 7aa183f..d42bc7a 100644
+--- a/src/pk-transaction-db.c
++++ b/src/pk-transaction-db.c
+@@ -46,7 +46,12 @@ static void pk_transaction_db_init (PkTransactionDb *tdb);
+ static void pk_transaction_db_finalize (GObject *object);
+
+ #define PK_TRANSACTION_DB_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PK_TYPE_TRANSACTION_DB, PkTransactionDbPrivate))
++
++#if PK_BUILD_LOCAL
++#define PK_TRANSACTION_DB_FILE "./transactions.db"
++#else
+ #define PK_TRANSACTION_DB_FILE PK_DB_DIR "/transactions.db"
++#endif
+
+ struct PkTransactionDbPrivate
+ {
+diff --git a/src/pk-transaction-list.c b/src/pk-transaction-list.c
+index 0921c7c..f325f94 100644
+--- a/src/pk-transaction-list.c
++++ b/src/pk-transaction-list.c
+@@ -89,7 +89,6 @@ pk_transaction_list_get_from_transaction (PkTransactionList *tlist, PkTransactio
+
+ /* find the runner with the transaction ID */
+ length = tlist->priv->array->len;
+- pk_debug ("length = %i", length);
+ for (i=0; i<length; i++) {
+ item = (PkTransactionItem *) g_ptr_array_index (tlist->priv->array, i);
+ if (item->transaction == transaction) {
+@@ -352,28 +351,29 @@ gchar **
+ pk_transaction_list_get_array (PkTransactionList *tlist)
+ {
+ guint i;
+- guint count = 0;
+ guint length;
++ GPtrArray *parray;
+ gchar **array;
+ PkTransactionItem *item;
+
+ g_return_val_if_fail (PK_IS_TRANSACTION_LIST (tlist), NULL);
+
++ /* use a temp array, as not all are in progress */
++ parray = g_ptr_array_new ();
++
+ /* find all the transactions in progress */
+ length = tlist->priv->array->len;
+-
+- /* create new strv list */
+- array = g_new0 (gchar *, length + 1);
+-
+- pk_debug ("%i active transactions", length);
+ for (i=0; i<length; i++) {
+ item = (PkTransactionItem *) g_ptr_array_index (tlist->priv->array, i);
+- /* only return in the list if it worked */
+- if (item->committed && item->finished == FALSE) {
+- array[count] = g_strdup (item->tid);
+- count++;
++ /* only return in the list if its committed and not finished */
++ if (item->committed && !item->finished) {
++ g_ptr_array_add (parray, g_strdup (item->tid));
+ }
+ }
++ pk_debug ("%i transactions in list, %i active", length, parray->len);
++ array = pk_ptr_array_to_argv (parray);
++ g_ptr_array_free (parray, TRUE);
++
+ return array;
+ }
+
+diff --git a/src/pk-transaction.c b/src/pk-transaction.c
+index 07ffdee..15faed3 100644
+--- a/src/pk-transaction.c
++++ b/src/pk-transaction.c
+@@ -71,6 +71,7 @@ struct PkTransactionPrivate
+ PkStatusEnum status;
+ gboolean finished;
+ gboolean running;
++ gboolean has_been_run;
+ gboolean allow_cancel;
+ gboolean emit_eula_required;
+ gboolean emit_signature_required;
+@@ -798,6 +799,7 @@ pk_transaction_set_running (PkTransaction *transaction)
+
+ /* mark running */
+ transaction->priv->running = TRUE;
++ transaction->priv->has_been_run = TRUE;
+
+ /* set all possible arguments for backend */
+ pk_backend_set_bool (priv->backend, "force", priv->cached_force);
+@@ -1152,11 +1154,17 @@ pk_transaction_cancel (PkTransaction *transaction, GError **error)
+ g_return_val_if_fail (transaction->priv->tid != NULL, FALSE);
+
+ pk_debug ("Cancel method called");
+- /* check to see if we are trying to cancel a non-running task */
+- if (!transaction->priv->running) {
+- g_set_error (error, PK_TRANSACTION_ERROR, PK_TRANSACTION_ERROR_NOT_RUNNING,
+- "cancelling a non-running transaction");
+- return FALSE;
++
++ /* if it's never been run, just remove this transaction from the list */
++ if (!transaction->priv->has_been_run) {
++ pk_transaction_list_remove (transaction->priv->transaction_list, transaction);
++ return TRUE;
++ }
++
++ /* if it's finished, cancelling will have no action */
++ if (transaction->priv->finished) {
++ pk_warning ("No point trying to cancel a finished transaction, ignoring");
++ return TRUE;
+ }
+
+ /* not implemented yet */
+@@ -2871,7 +2879,7 @@ pk_transaction_what_provides (PkTransaction *transaction, const gchar *filter, c
+ return;
+ }
+
+- provides = pk_role_enum_from_text (type);
++ provides = pk_provides_enum_from_text (type);
+ if (provides == PK_PROVIDES_ENUM_UNKNOWN) {
+ error = g_error_new (PK_TRANSACTION_ERROR, PK_TRANSACTION_ERROR_INVALID_PROVIDE,
+ "provide type '%s' not found", type);
+@@ -3011,6 +3019,7 @@ pk_transaction_init (PkTransaction *transaction)
+ transaction->priv = PK_TRANSACTION_GET_PRIVATE (transaction);
+ transaction->priv->finished = FALSE;
+ transaction->priv->running = FALSE;
++ transaction->priv->has_been_run = FALSE;
+ transaction->priv->allow_cancel = FALSE;
+ transaction->priv->emit_eula_required = FALSE;
+ transaction->priv->emit_signature_required = FALSE;
+diff --git a/tools/add-error-enum.sh b/tools/add-error-enum.sh
+index f78c891..6521e69 100755
+--- a/tools/add-error-enum.sh
++++ b/tools/add-error-enum.sh
+@@ -7,5 +7,5 @@
+ # the Free Software Foundation; either version 2 of the License, or
+ # (at your option) any later version.
+
+-$EDITOR docs/spec/pk-introduction.xml libpackagekit/pk-enum.h libpackagekit/pk-enum.c ../gnome-packagekit/src/gpk-common.c
++$EDITOR docs/spec/pk-concepts.xml libpackagekit/pk-enum.h libpackagekit/pk-enum.c ../gnome-packagekit/src/gpk-common.c
+
+diff --git a/tools/rpmbuild.sh b/tools/rpmbuild.sh
+deleted file mode 100755
+index ebbd8f7..0000000
+--- a/tools/rpmbuild.sh
++++ /dev/null
+@@ -1,19 +0,0 @@
+-#!/bin/sh
+-# Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+-#
+-# Licensed under the GNU General Public License Version 2
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-
+-sudo echo "Build!"
+-#autobuild.sh all PolicyKit
+-#sudo auto_refresh_from_repo.sh
+-#autobuild.sh all PolicyKit-gnome
+-#sudo auto_refresh_from_repo.sh
+-autobuild.sh all PackageKit force
+-sudo auto_refresh_from_repo.sh
+-autobuild.sh all gnome-packagekit force
+-sudo auto_refresh_from_repo.sh
+-