diff -pruN 1.1.1-4/applet.py 1.1.1+bzr982-0ubuntu14/applet.py
--- 1.1.1-4/applet.py	2013-03-11 06:00:59.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/applet.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,131 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""Demo applet which monitors the state of aptdaemon transactions"""
-# Copyright (C) 2008 Sebastian Heinlein <devel@glatzor.de>
-#
-# 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
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-__author__  = "Sebastian Heinlein <devel@glatzor.de>"
-
-import logging
-
-import gobject
-import gtk
-import pango
-
-import aptdaemon.client
-import aptdaemon.gtkwidgets
-
-logging.basicConfig(level=logging.DEBUG)
-log = logging.getLogger("AptStatusIcon")
-
-class AptStatusIcon(object):
-
-    """Shows an icon in the notification bar which provides a menu to access
-    the currently running and queued transactions.
-    """
-
-    def __init__(self):
-        """Initialize a new AptStatusIcon instance."""
-        self._client = aptdaemon.client.AptClient()
-        self.loop = gobject.MainLoop()
-        self.icon = gtk.status_icon_new_from_icon_name("update-notifier")
-        self.icon.set_visible(False)
-        self.icon.connect("popup-menu", self._on_popup_menu)
-        self.icon.connect("activate", self._on_icon_activated)
-        self._daemon = aptdaemon.client.get_aptdaemon()
-        self._daemon.connect_to_signal("ActiveTransactionsChanged",
-                                       self._on_transactions_changed)
-
-    def run(self):
-        """Run the status icon application."""
-        log.debug("Run")
-        self.loop.run()
-
-    def quit(self):
-        """Quit the status icon application."""
-        log.debug("Quit")
-        self.quit()
-
-    def _on_transactions_changed(self, current, queued):
-        """Callback if the active transactions of the daemon changed.
-
-        Hide the icon if there isn't any active or queued transaction.
-        """
-        if current or queued:
-            self.icon.set_visible(True)
-        else:
-            self.icon.set_visible(False)
-
-    def _on_popup_menu(self, status_icon, button, time):
-        """Callback if the status icon popup menu is requested (usually a right
-        click.
-
-        Shows a popup menu containg the currently running and all queued
-        transactions.
-        """
-        log.debug("Popup menu")
-        menu = gtk.Menu()
-        current, queued = self._daemon.GetActiveTransactions()
-        if current:
-            log.debug("current: %s", current)
-            menu.append(self._get_transaction_menu_item(current))
-            if queued:
-                menu.append(gtk.SeparatorMenuItem())
-        for tid in queued:
-            log.debug("queued: %s", tid)
-            menu.append(self._get_transaction_menu_item(tid))
-        menu.popup(None, None, gtk.status_icon_position_menu, button, time,
-                   status_icon)
-        menu.show_all()
-
-    def _get_transaction_menu_item(self, tid):
-        """Return a menu item for the given transaction id which monitors
-        the transaction progress."""
-        trans = aptdaemon.client.get_transaction(tid)
-        item = gtk.MenuItem()
-        box = gtk.HBox(spacing=6)
-        icon = aptdaemon.gtkwidgets.AptStatusIcon(trans, gtk.ICON_SIZE_MENU)
-        box.pack_start(icon, expand=False)
-        label = aptdaemon.gtkwidgets.AptRoleLabel(trans)
-        label.set_ellipsize(pango.ELLIPSIZE_NONE)
-        box.pack_start(label, expand=True, fill=True)
-        item.add(box)
-        item.connect("activate", self._on_menu_item_activated, trans)
-        return item
-
-    def _on_menu_item_activated(self, item, trans):
-        """Callback if a menu item gets activated.
-
-        Show a progress dialog for the transaction of the activated
-        menu item."""
-        dialog = aptdaemon.gtkwidgets.AptProgressDialog(trans, terminal=False,
-                                                        debconf=False)
-        dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
-        dialog.run(attach=True)
-        dialog.hide()
-
-    def _on_icon_activated(self, status_icon):
-        """Callback if the status icon gets activated.
-
-        This method will call the popup_menu callback to show the menu.
-        """
-        log.debug("Activated")
-        time = gtk.get_current_event_time()
-        self._on_popup_menu(status_icon, 3, time)
-
-if __name__ == "__main__":
-    asi = AptStatusIcon()
-    asi.run()
diff -pruN 1.1.1-4/apport/aptdaemon.py 1.1.1+bzr982-0ubuntu14/apport/aptdaemon.py
--- 1.1.1-4/apport/aptdaemon.py	2013-03-11 06:00:59.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/apport/aptdaemon.py	2015-10-12 18:06:10.000000000 +0000
@@ -28,6 +28,7 @@ import apt_pkg
 
 apt_pkg.init()
 
+
 def add_info(report):
     """Collect and append additional information about a crash.
 
diff -pruN 1.1.1-4/aptdaemon/client.py 1.1.1+bzr982-0ubuntu14/aptdaemon/client.py
--- 1.1.1-4/aptdaemon/client.py	2015-10-12 18:06:09.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/client.py	2015-10-12 18:06:10.000000000 +0000
@@ -33,17 +33,10 @@ import weakref
 import sys
 
 import dbus
-import dbus.glib
 import dbus.mainloop.glib
 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
-if 'gobject' in sys.modules and sys.modules['gobject'] is not None:
-    import gobject as GObject
-    GLib = GObject
-    _GObject = GObject.GObject
-else:
-    from gi.repository import GObject, GLib
-    _GObject = GObject.Object
+from gi.repository import GObject, GLib
 
 from . import enums
 from . import debconf
@@ -58,7 +51,7 @@ __all__ = ("AptTransaction", "AptClient"
 _APTDAEMON_DBUS_TIMEOUT = 86400
 
 
-class AptTransaction(_GObject):
+class AptTransaction(GObject.Object):
 
     """Represents an aptdaemon transaction.
 
@@ -507,7 +500,7 @@ class AptTransaction(_GObject):
         try:
             return AptTransaction._tid_cache[tid]
         except KeyError:
-            value = _GObject.__new__(cls, tid, *args, **kwargs)
+            value = GObject.Object.__new__(cls, tid, *args, **kwargs)
             AptTransaction._tid_cache[tid] = value
             return value
 
@@ -687,9 +680,9 @@ class AptTransaction(_GObject):
                                reply_handler=sync_properties,
                                error_handler=error_handler)
         else:
-            properties = self._proxy.GetAll("org.debian.apt.transaction",
-                                            dbus_interface=
-                                            dbus.PROPERTIES_IFACE)
+            properties = self._proxy.GetAll(
+                "org.debian.apt.transaction",
+                dbus_interface=dbus.PROPERTIES_IFACE)
             sync_properties(properties)
 
     @deferable
@@ -943,7 +936,7 @@ class AptTransaction(_GObject):
     def set_terminal(self, ttyname, reply_handler=None, error_handler=None):
         """Allow to set a controlling terminal for the underlying dpkg call.
 
-        See the source code of gtkwidgets.AptTerminal or console.ConsoleClient
+        See the source code of gtk3widgets.AptTerminal or console.ConsoleClient
         as example.
 
         >>> master, slave = pty.openpty()
@@ -1278,7 +1271,7 @@ class AptClient(object):
         """
         # Root is not allowed to access FUSE file systems. So copy files
         # to the local system.
-        #FIXME: the locally cached one should be removed afterwards
+        # FIXME: the locally cached one should be removed afterwards
         home = os.getenv("HOME", None)
         if home and path.startswith(os.path.join(home, ".gvfs")):
             shutil.copy(path, "/tmp")
@@ -1600,7 +1593,7 @@ class AptClient(object):
             context = GLib.main_context_default()
             while not hasattr(deferred, "result"):
                 context.iteration(True)
-           # If there has been an error in the helper raise it
+            # If there has been an error in the helper raise it
             if isinstance(deferred.result, defer.DeferredException):
                 deferred.result.raise_exception()
             trans = deferred.result
@@ -1679,6 +1672,18 @@ def get_transaction(tid, bus=None, reply
         return trans
 
 
+def get_size_string(bytes):
+    """Returns a human friendly string for a given byte size.
+
+    Note: The bytes are skipped from the returned unit: 1024 returns 1K
+    """
+    for unit in ["", "K", "M", "G"]:
+        if bytes < 1024.0:
+            return "%3.1f%s" % (bytes, unit)
+        bytes /= 1024.0
+    return "%3.1f%s" % (bytes, "T")
+
+
 def get_aptdaemon(bus=None):
     """Get the daemon D-Bus interface.
 
diff -pruN 1.1.1-4/aptdaemon/config.py 1.1.1+bzr982-0ubuntu14/aptdaemon/config.py
--- 1.1.1-4/aptdaemon/config.py	2015-10-12 18:06:09.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/config.py	2014-08-21 13:10:24.000000000 +0000
@@ -1,21 +1,21 @@
 """Handling configuration files."""
-#Copyright (C) 2010 Sebastian Heinlein <sevel@glatzor.de>
+# Copyright (C) 2010 Sebastian Heinlein <sevel@glatzor.de>
 #
-#Licensed under the GNU General Public License Version 2
+# 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 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.
+# 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.
+# 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.
 
 __author__ = "Sebastian Heinlein <devel@glatzor.de>"
 
@@ -174,7 +174,7 @@ class ConfigWriter(object):
             If the value is overriden by a later configuration file snippet
             it will be disabled in the corresponding configuration file.
         """
-        #FIXME: Support value lists
+        # FIXME: Support value lists
         # Convert the value to string
         if value is True:
             value = "true"
@@ -217,7 +217,7 @@ class ConfigWriter(object):
                 else:
                     # Comment out existing values instead in non default
                     # configuration files
-                    #FIXME Quite dangerous for brackets
+                    # FIXME Quite dangerous for brackets
                     lines[val.line] = "// %s" % lines[val.line]
             with open(os.path.join(etc_parts, filename), "w") as fd:
                 log.debug("Writting %s", filename)
diff -pruN 1.1.1-4/aptdaemon/console.py 1.1.1+bzr982-0ubuntu14/aptdaemon/console.py
--- 1.1.1-4/aptdaemon/console.py	2013-08-11 19:05:47.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/console.py	2015-04-02 21:37:46.000000000 +0000
@@ -39,9 +39,7 @@ import signal
 import sys
 
 from aptsources.sourceslist import SourceEntry
-import apt_pkg
 from gi.repository import GLib
-import dbus.glib
 import dbus.mainloop.glib
 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
@@ -204,11 +202,12 @@ class ConsoleClient:
         # Make sure to dettach the terminal
         self._detach()
         if self._show_progress:
-            output = "[+] 100%% %s %-*.*s%s\n" % (ANSI_BOLD,
-                     self._terminal_width - 9,
-                     self._terminal_width - 9,
-                     enums.get_exit_string_from_enum(enum),
-                     ANSI_RESET)
+            output = "[+] 100%% %s %-*.*s%s\n" % (
+                ANSI_BOLD,
+                self._terminal_width - 9,
+                self._terminal_width - 9,
+                enums.get_exit_string_from_enum(enum),
+                ANSI_RESET)
             sys.stderr.write(output)
 
         if enum == enums.EXIT_FAILED:
@@ -246,14 +245,16 @@ class ConsoleClient:
                              bytes_done, bytes_total, speed, eta):
         """Callback for the ProgressDetails signal of the transaction."""
         if bytes_total and speed:
-            self._progress_details = (_("Downloaded %sB of %sB at %sB/s") %
-                                      (apt_pkg.size_to_str(bytes_done),
-                                       apt_pkg.size_to_str(bytes_total),
-                                       apt_pkg.size_to_str(speed)))
+            self._progress_details = (
+                _("Downloaded %(cur)sB of %(total)sB at %(rate)sB/s") %
+                {'cur': client.get_size_string(bytes_done),
+                 'total': client.get_size_string(bytes_total),
+                 'rate': client.get_size_string(speed)})
         elif bytes_total:
-            self._progress_details = (_("Downloaded %sB of %sB") %
-                                      (apt_pkg.size_to_str(bytes_done),
-                                       apt_pkg.size_to_str(bytes_total)))
+            self._progress_details = (
+                _("Downloaded %(cur)sB of %(total)sB") %
+                {'cur': client.get_size_string(bytes_done),
+                 'total': client.get_size_string(bytes_total)})
         else:
             self._progress_details = ""
         self._update_progress()
@@ -402,7 +403,7 @@ class ConsoleClient:
                                       enums.ROLE_ADD_VENDOR_KEY_FROM_KEYSERVER,
                                       enums.ROLE_REMOVE_VENDOR_KEY,
                                       enums.ROLE_FIX_INCOMPLETE_INSTALL]:
-            #TRANSLATORS: status message
+            # TRANSLATORS: status message
             self._progress_id = GLib.timeout_add(250,
                                                  self._update_custom_progress,
                                                  _("Queuing"))
@@ -410,7 +411,7 @@ class ConsoleClient:
                 error_handler=self._on_exception,
                 reply_handler=lambda: self._stop_custom_progress())
         else:
-            #TRANSLATORS: status message
+            # TRANSLATORS: status message
             self._progress_id = GLib.timeout_add(250,
                                                  self._update_custom_progress,
                                                  _("Resolving dependencies"))
@@ -454,7 +455,7 @@ class ConsoleClient:
         downgrades.extend(dep_downgrades)
         kepts = dep_kepts
         if installs:
-            #TRANSLATORS: %s is the number of packages
+            # TRANSLATORS: %s is the number of packages
             print((ngettext("The following NEW package will be installed "
                             "(%(count)s):",
                             "The following NEW packages will be installed "
@@ -462,7 +463,7 @@ class ConsoleClient:
                             len(installs)) % {"count": len(installs)}))
             show_packages(installs)
         if upgrades:
-            #TRANSLATORS: %s is the number of packages
+            # TRANSLATORS: %s is the number of packages
             print((ngettext("The following package will be upgraded "
                             "(%(count)s):",
                             "The following packages will be upgraded "
@@ -470,16 +471,16 @@ class ConsoleClient:
                             len(upgrades)) % {"count": len(upgrades)}))
             show_packages(upgrades)
         if removals:
-            #TRANSLATORS: %s is the number of packages
+            # TRANSLATORS: %s is the number of packages
             print((ngettext("The following package will be REMOVED "
                             "(%(count)s):",
                             "The following packages will be REMOVED "
                             "(%(count)s):",
                             len(removals)) % {"count": len(removals)}))
-            #FIXME: mark purges
+            # FIXME: mark purges
             show_packages(removals)
         if downgrades:
-            #TRANSLATORS: %s is the number of packages
+            # TRANSLATORS: %s is the number of packages
             print((ngettext("The following package will be DOWNGRADED "
                             "(%(count)s):",
                             "The following packages will be DOWNGRADED "
@@ -487,7 +488,7 @@ class ConsoleClient:
                             len(downgrades)) % {"count": len(downgrades)}))
             show_packages(downgrades)
         if reinstalls:
-            #TRANSLATORS: %s is the number of packages
+            # TRANSLATORS: %s is the number of packages
             print((ngettext("The following package will be reinstalled "
                             "(%(count)s):",
                             "The following packages will be reinstalled "
@@ -504,19 +505,18 @@ class ConsoleClient:
 
         if self._transaction.download:
             print(_("Need to get %sB of archives.") %
-                  apt_pkg.size_to_str(self._transaction.download))
+                  client.get_size_string(self._transaction.download))
         if self._transaction.space > 0:
             print(_("After this operation, %sB of additional disk space "
                     "will be used.") %
-                  apt_pkg.size_to_str(self._transaction.space))
+                  client.get_size_string(self._transaction.space))
         elif self._transaction.space < 0:
             print(_("After this operation, %sB of additional disk space "
                     "will be freed.") %
-                  apt_pkg.size_to_str(self._transaction.space))
-        if (not apt_pkg.config.find_b("APT::Get::Assume-Yes") and
-            (self._transaction.space or self._transaction.download or
-             installs or upgrades or downgrades or removals or kepts or
-             reinstalls)):
+                  client.get_size_string(self._transaction.space))
+        if (self._transaction.space or self._transaction.download or
+                installs or upgrades or downgrades or removals or kepts or
+                reinstalls):
             try:
                 if PY3K:
                     cont = input(_("Do you want to continue [Y/n]?"))
@@ -524,14 +524,14 @@ class ConsoleClient:
                     cont = raw_input(_("Do you want to continue [Y/n]?"))
             except EOFError:
                 cont = "n"
-            #FIXME: Listen to changed dependencies!
+            # FIXME: Listen to changed dependencies!
             if (not re.match(locale.nl_langinfo(locale.YESEXPR), cont) and
                     cont != ""):
                 msg = enums.get_exit_string_from_enum(enums.EXIT_CANCELLED)
                 self._update_custom_progress(msg, None, False)
                 self._loop.quit()
                 sys.exit(1)
-        #TRANSLATORS: status message
+        # TRANSLATORS: status message
         self._progress_id = GLib.timeout_add(250,
                                              self._update_custom_progress,
                                              _("Queuing"))
@@ -642,7 +642,7 @@ def main():
     con = ConsoleClient(show_terminal=not options.hide_terminal,
                         allow_unauthenticated=options.allow_unauthenticated,
                         details=options.details)
-    #TRANSLATORS: status message
+    # TRANSLATORS: status message
     con._progress_id = GLib.timeout_add(250, con._update_custom_progress,
                                         _("Waiting for authentication"))
     if options.safe_upgrade:
@@ -672,7 +672,7 @@ def main():
     elif options.add_repository:
         con.add_repository(options.add_repository, options.sources_file)
     elif options.add_vendor_key:
-        #FIXME: Should detect if from stdin or file
+        # FIXME: Should detect if from stdin or file
         con.add_vendor_key_from_file(options.add_vendor_key)
     elif options.add_vendor_key_from_keyserver and options.keyserver:
         con.add_vendor_key_from_keyserver(
diff -pruN 1.1.1-4/aptdaemon/core.py 1.1.1+bzr982-0ubuntu14/aptdaemon/core.py
--- 1.1.1-4/aptdaemon/core.py	2015-10-12 18:06:09.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/core.py	2015-10-12 18:06:10.000000000 +0000
@@ -53,9 +53,6 @@ from gi.repository import GObject, GLib
 import dbus.exceptions
 import dbus.service
 import dbus.mainloop.glib
-import dbus.glib
-import apt_pkg
-import apt.auth
 
 from .config import ConfigWriter
 from . import errors
@@ -63,10 +60,10 @@ from . import enums
 from defer import inline_callbacks, return_value, Deferred
 from defer.utils import dbus_deferred_method
 from . import policykit1
-from .worker import (
-    AptWorker,
-    DummyWorker,
-    trans_only_installs_pkgs_from_high_trust_repos)
+from .utils import split_package_id
+from .worker import DummyWorker
+from .worker.aptworker import (AptWorker,
+                               trans_only_installs_pkgs_from_high_trust_repos)
 from .loop import mainloop
 from .logger import ColoredFormatter
 
@@ -130,7 +127,7 @@ _console_formatter = ColoredFormatter("%
                                       "%T")
 _console_handler.setFormatter(_console_formatter)
 log.addHandler(_console_handler)
-#FIXME: Use LoggerAdapter (requires Python 2.6)
+# FIXME: Use LoggerAdapter (requires Python 2.6)
 log_trans = logging.getLogger("AptDaemon.Trans")
 
 # Required for translations from APT
@@ -139,27 +136,12 @@ try:
 except locale.Error:
     log.warning("Failed to unset LC_ALL. Translations are not available.")
 
-_POPCON_PATH = "/etc/popularity-contest.conf"
-_POPCON_DEFAULT = """# Config file for Debian's popularity-contest package.
-#
-# To change this file, use:
-#        dpkg-reconfigure popularity-contest
-#
-# You can also edit it by hand, if you so choose.
-#
-# See /usr/share/popularity-contest/default.conf for more info
-# on the options.
-MY_HOSTID="%(host_id)s"
-PARTICIPATE="%(participate)s"
-USE_HTTP="yes"
-"""
-
 
 def _excepthook(exc_type, exc_obj, exc_tb, apport_excepthook):
     """Handle exceptions of aptdaemon and avoid tiggering apport crash
-    reports for valid DBusExceptions that are send to the client.
+    reports for valid DBusExceptions that are sent to the client.
     """
-    # apport registers is own excepthook as sys.excepthook. So we have to
+    # apport registers it's own excepthook as sys.excepthook. So we have to
     # send exceptions that we don't want to be tracked to Python's
     # internal excepthook directly
     if issubclass(exc_type, errors.AptDaemonError):
@@ -342,7 +324,7 @@ class Transaction(DBusObject):
                            "DebconfSocket", "MetaData", "Locale",
                            "RemoveObsoleteDepends")
 
-    def __init__(self, tid, role, queue, pid, uid, cmdline, sender,
+    def __init__(self, tid, role, queue, pid, uid, gid, cmdline, sender,
                  connect=True, bus=None, packages=None, kwargs=None):
         """Initialize a new Transaction instance.
 
@@ -378,6 +360,7 @@ class Transaction(DBusObject):
             kwargs = {}
         self.queue = queue
         self.uid = uid
+        self.gid = gid
         self.locale = dbus.String("")
         self.allow_unauthenticated = dbus.Boolean(False)
         self.remove_obsoleted_depends = dbus.Boolean(False)
@@ -857,7 +840,7 @@ class Transaction(DBusObject):
         Keyword arguments:
         url -- the URL of the proxy server, e.g. http://proxy:8080
         """
-        if url != "" and (not url.startswith("http://") or not ":" in url):
+        if url != "" and (not url.startswith("http://") or ":" not in url):
             raise errors.InvalidProxyError(url)
         action = policykit1.PK_ACTION_SET_PROXY
         yield policykit1.check_authorization_by_name(sender, action,
@@ -941,7 +924,7 @@ class Transaction(DBusObject):
     @inline_callbacks
     def _check_simulated(self):
         # Simulate the new transaction if this has not been done before:
-        #FIXME: Compare the simulated timestamp with the time stamp of
+        # FIXME: Compare the simulated timestamp with the time stamp of
         #       the status and re-simulate the transaction
         if self.simulated is None:
             # If there isn't any transaction on the queue we send an early
@@ -1361,7 +1344,7 @@ class TransactionQueue(GObject.GObject):
 
     def _on_transaction_done(self, worker, trans):
         """Mark the last item as done and request a new item."""
-        #FIXME: Check if the transaction failed because of a broken system or
+        # FIXME: Check if the transaction failed because of a broken system or
         #       if dpkg journal is dirty. If so allready queued transactions
         #       except the repair transactions should be removed from the queue
         if trans.exit in [enums.EXIT_FAILED, enums.EXIT_CANCELLED]:
@@ -1420,8 +1403,8 @@ class AptDaemon(DBusObject):
         """
         log.info("Initializing daemon")
         # glib does not support SIGQUIT
-        #GLib.unix_signal_add_full(
-        #    GLib.PRIORITY_HIGH, signal.SIGQUIT, self._sigquit, None)
+        # GLib.unix_signal_add_full(
+        #     GLib.PRIORITY_HIGH, signal.SIGQUIT, self._sigquit, None)
         GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM,
                              self._sigquit, None)
         # Decrease the priority of the daemon to avoid blocking UI
@@ -1443,7 +1426,7 @@ class AptDaemon(DBusObject):
                 if self.options.replace is False:
                     log.critical("Another daemon is already running")
                     sys.exit(1)
-                log.warn("Replacing already running daemon")
+                log.warning("Replacing already running daemon")
                 the_other_guy = bus.get_object(APTDAEMON_DBUS_SERVICE,
                                                APTDAEMON_DBUS_PATH)
                 the_other_guy.Quit(dbus_interface=APTDAEMON_DBUS_INTERFACE,
@@ -1461,12 +1444,13 @@ class AptDaemon(DBusObject):
         else:
             load_plugins = not options.disable_plugins
             try:
+                from .worker.pkworker import AptPackageKitWorker
                 from . import pkcompat
             except ImportError:
                 self.worker = AptWorker(options.chroot, load_plugins)
             else:
-                self.worker = pkcompat.PackageKitWorker(options.chroot,
-                                                        load_plugins)
+                self.worker = AptPackageKitWorker(options.chroot,
+                                                  load_plugins)
         self.queue = TransactionQueue(self.worker)
         self.queue.connect("queue-changed", self._on_queue_changed)
         # keep state of the last information about reboot required
@@ -1474,7 +1458,7 @@ class AptDaemon(DBusObject):
         try:
             self.packagekit = pkcompat.PackageKit(self.queue, connect, bus)
         except dbus.exceptions.NameExistsException:
-            log.warn("PackageKit is already running")
+            log.warning("PackageKit is already running")
         except NameError:
             pass
         log.debug("Daemon was initialized")
@@ -1538,11 +1522,12 @@ class AptDaemon(DBusObject):
     @inline_callbacks
     def _create_trans(self, role, sender, packages=None, kwargs=None):
         """Helper method which returns the tid of a new transaction."""
-        pid, uid, cmdline = (
+        pid, uid, gid, cmdline = (
             yield policykit1.get_proc_info_from_dbus_name(sender, self.bus))
         tid = uuid.uuid4().hex
-        trans = Transaction(tid, role, self.queue, pid, uid, cmdline, sender,
-                            packages=packages, kwargs=kwargs, bus=self.bus)
+        trans = Transaction(
+            tid, role, self.queue, pid, uid, gid, cmdline, sender,
+            packages=packages, kwargs=kwargs, bus=self.bus)
         self.queue.limbo[trans.tid] = trans
         return_value(trans.tid)
 
@@ -1704,7 +1689,7 @@ class AptDaemon(DBusObject):
         :returns: The D-Bus path of the new transaction object which
             performs this action.
         """
-        #FIXME: take sha1 or md5 cash into accout to allow selecting a version
+        # FIXME: take sha1 or md5 cash into accout to allow selecting a version
         #       or an origin different from the candidate
         log.info("CommitPackages() was called: %s, %s, %s, %s, %s, %s",
                  install, reinstall, remove, purge, upgrade, downgrade)
@@ -1865,8 +1850,8 @@ class AptDaemon(DBusObject):
             performs this action.
         """
         log.info("InstallFile() was called: %s" % path)
-        #FIXME: Perform some checks
-        #FIXME: Should we already extract the package name here?
+        # FIXME: Perform some checks
+        # FIXME: Should we already extract the package name here?
         return self._create_trans(enums.ROLE_INSTALL_FILE,
                                   sender, kwargs={"path": path,
                                                   "force": force})
@@ -1997,7 +1982,7 @@ class AptDaemon(DBusObject):
         action = policykit1.PK_ACTION_GET_TRUSTED_VENDOR_KEYS
         yield policykit1.check_authorization_by_name(sender, action,
                                                      bus=self.bus)
-        fingerprints = [key.keyid for key in apt.auth.list_keys()]
+        fingerprints = self.worker.get_trusted_vendor_keys()
         return_value(fingerprints)
 
     # pylint: disable-msg=C0103,C0322
@@ -2062,20 +2047,15 @@ class AptDaemon(DBusObject):
                                                      bus=self.bus)
         if iface == APTDAEMON_DBUS_INTERFACE:
             if name == "PopConParticipation":
-                self._set_popcon_participation(value)
+                self.worker.set_config(name, dbus.Boolean(value))
             elif name == "AutoUpdateInterval":
-                self._set_apt_config("APT::Periodic::Update-Package-Lists",
-                                     dbus.Int32(value), "10periodic")
+                self.worker.set_config(name, dbus.Int32(value), "10periodic")
             elif name == "AutoDownload":
-                self._set_apt_config("APT::Periodic::"
-                                     "Download-Upgradeable-Packages",
-                                     dbus.Boolean(value), "10periodic")
+                self.worker.set_config(name, dbus.Boolean(value), "10periodic")
             elif name == "AutoCleanInterval":
-                self._set_apt_config("APT::Periodic::AutocleanInterval",
-                                     dbus.Int32(value), "10periodic")
+                self.worker.set_config(name, dbus.Int32(value), "10periodic")
             elif name == "UnattendedUpgrade":
-                self._set_apt_config("APT::Periodic::Unattended-Upgrade",
-                                     dbus.Boolean(value), "10periodic")
+                self.worker.set_config(name, dbus.Boolean(value), "10periodic")
             else:
                 raise dbus.exceptions.DBusException("Unknown or read only "
                                                     "property: %s" % name)
@@ -2088,7 +2068,11 @@ class AptDaemon(DBusObject):
         exception.
         """
         for fullname in pkg_names:
-            name, version, release = AptWorker._split_package_id(fullname)
+            name, version, release = split_package_id(fullname)
+            name, sep, auto_flag = name.partition("#")
+            if not auto_flag in ("", "auto"):
+                raise errors.AptDaemonError("%s isn't a valid flag" %
+                                            auto_flag)
             if not re.match(REGEX_VALID_PACKAGENAME, name):
                 raise errors.AptDaemonError("%s isn't a valid package name" %
                                             name)
@@ -2101,72 +2085,22 @@ class AptDaemon(DBusObject):
                 raise errors.AptDaemonError("%s isn't a valid release" %
                                             release)
 
-    def _set_apt_config(self, option, key, filename):
-        cw = ConfigWriter()
-        cw.set_value(option, key, filename)
-        apt_pkg.init_config()
-
-    def _set_popcon_participation(self, participate):
-        if participate:
-            value = "yes"
-        else:
-            value = "no"
-        if os.path.exists(_POPCON_PATH):
-            # read the current config and replace the corresponding settings
-            # FIXME: Check if the config file is a valid bash script and
-            #        contains the host_id
-            with open(_POPCON_PATH) as conf_file:
-                old_config = conf_file.read()
-            config = re.sub(r'(PARTICIPATE=*)(".+?")',
-                            '\\1"%s"' % value,
-                            old_config)
-        else:
-            # create a new popcon config file
-            m = md5()
-            m.update(open("/dev/urandom", "r").read(1024))
-            config = _POPCON_DEFAULT % {"host_id": m.hexdigest(),
-                                        "participate": value}
-
-        with open(_POPCON_PATH, "w") as conf_file:
-            conf_file.write(config)
-
-    def _get_popcon_participation(self):
-        #FIXME: Use a script to evaluate the configuration:
-        #       #!/bin/sh
-        #       . /etc/popularitiy-contest.conf
-        #       . /usr/share/popularitiy-contest/default.conf
-        #       echo $PARTICIAPTE $HOST_ID
-        if os.path.exists(_POPCON_PATH):
-            with open(_POPCON_PATH) as conf_file:
-                config = conf_file.read()
-            match = re.match("\nPARTICIPATE=\"(yes|no)\"", config)
-            if match and match[0] == "yes":
-                return True
-        return False
-
     def _get_properties(self, iface):
         """Helper get the properties of a D-Bus interface."""
         if iface == APTDAEMON_DBUS_INTERFACE:
-            return {"AutoUpdateInterval": dbus.Int32(
-                apt_pkg.config.find_i("APT::Periodic::"
-                                      "Update-Package-Lists",
-                                      0)),
-                    "AutoDownload": dbus.Boolean(
-                        apt_pkg.config.find_b("APT::Periodic::"
-                                              "Download-Upgradeable-Packages",
-                                              False)),
-                    "AutoCleanInterval": dbus.Int32(
-                        apt_pkg.config.find_i("APT::Periodic::"
-                                              "AutocleanInterval",
-                                              0)),
-                    "UnattendedUpgrade": dbus.Int32(
-                        apt_pkg.config.find_b("APT::Periodic::"
-                                              "Unattended-Upgrade",
-                                              False)),
-                    "PopConParticipation": dbus.Boolean(
-                        self._get_popcon_participation()),
-                    "RebootRequired": dbus.Boolean(
-                        self.worker.is_reboot_required())}
+            return {
+                "AutoUpdateInterval": dbus.Int32(
+                    self.worker.get_config("AutoUpdateInterval")),
+                "AutoDownload": dbus.Boolean(
+                    self.worker.get_config("AutoDownload")),
+                "AutoCleanInterval": dbus.Int32(
+                    self.worker.get_config("AutoCleanInterval")),
+                "UnattendedUpgrade": dbus.Int32(
+                    self.worker.get_config("UnattendedUpgrade")),
+                "PopConParticipation": dbus.Boolean(
+                    self.worker.get_config("PopConParticipation")),
+                "RebootRequired": dbus.Boolean(
+                    self.worker.is_reboot_required())}
         else:
             return {}
 
diff -pruN 1.1.1-4/aptdaemon/crash.py 1.1.1+bzr982-0ubuntu14/aptdaemon/crash.py
--- 1.1.1-4/aptdaemon/crash.py	2015-10-12 18:06:09.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/crash.py	2014-06-26 07:07:15.000000000 +0000
@@ -1,21 +1,21 @@
 """Apport integration to provide better problem reports."""
-#Copyright (C) 2010 Sebastian Heinlein <devel@glatzor.de>
+# Copyright (C) 2010 Sebastian Heinlein <devel@glatzor.de>
 #
-#Licensed under the GNU General Public License Version 2
+# 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 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.
+# 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.
+# 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.
 
 __author__ = "Sebastian Heinlein <devel@glatzor.de>"
 
diff -pruN 1.1.1-4/aptdaemon/debconf.py 1.1.1+bzr982-0ubuntu14/aptdaemon/debconf.py
--- 1.1.1-4/aptdaemon/debconf.py	2013-08-11 19:05:47.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/debconf.py	2014-08-21 12:56:35.000000000 +0000
@@ -35,25 +35,7 @@ import subprocess
 import tempfile
 import sys
 
-
-if 'gi.repository' in sys.modules and sys.modules['gi.repository'] is not None:
-    from gi.repository import GLib
-else:
-    import gobject as GLib
-
-    # Convert to old API
-    def _glib_io_watch_add_override(fd, prio, cond, cb, data=None):
-        """Override of gobject.io_add_watch() to keep compatibility
-        for the non-introspectable Python 2 clients.
-        """
-        if data:
-            return _glib_io_add_watch_orig(fd, cond, cb, data, priority=prio)
-        else:
-            return _glib_io_add_watch_orig(fd, cond, cb, priority=prio)
-
-    _glib_io_add_watch_orig = GLib.io_add_watch
-    GLib.io_add_watch = _glib_io_watch_add_override
-
+from gi.repository import GLib
 
 log = logging.getLogger("AptClient.DebconfProxy")
 
@@ -195,4 +177,4 @@ def _test():
 if __name__ == "__main__":
     _test()
 
-#vim:ts=4:sw=4:et
+# vim:ts=4:sw=4:et
diff -pruN 1.1.1-4/aptdaemon/enums.py 1.1.1+bzr982-0ubuntu14/aptdaemon/enums.py
--- 1.1.1-4/aptdaemon/enums.py	2013-08-11 19:05:47.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/enums.py	2014-06-26 07:07:15.000000000 +0000
@@ -532,35 +532,35 @@ _STRINGS_STATUS = {
     STATUS_AUTHENTICATING: _("Waiting for authentication")}
 
 STRINGS_PKG_STATUS = {
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_INSTALLING: _("Installing %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_CONFIGURING: _("Configuring %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_REMOVING: _("Removing %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_PURGING: _("Completely removing %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_PURGING: _("Noting disappearance of %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_RUNNING_TRIGGER: _("Running post-installation trigger %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_UPGRADING: _("Upgrading %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_UNPACKING: _("Unpacking %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_PREPARING_INSTALL: _("Preparing installation of %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_PREPARING_CONFIGURE: _("Preparing configuration of %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_PREPARING_REMOVE: _("Preparing removal of %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_PREPARING_PURGE: _("Preparing complete removal of %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_INSTALLED: _("Installed %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_PURGED: _("Completely removed %s"),
-    #TRANSLATORS: %s is the name of a package
+    # TRANSLATORS: %s is the name of a package
     PKG_REMOVED: _("Removed %s")}
 
 STRINGS_DOWNLOAD = {
diff -pruN 1.1.1-4/aptdaemon/gtk3widgets.py 1.1.1+bzr982-0ubuntu14/aptdaemon/gtk3widgets.py
--- 1.1.1-4/aptdaemon/gtk3widgets.py	2015-10-12 18:06:09.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/gtk3widgets.py	2014-11-10 18:03:20.000000000 +0000
@@ -38,6 +38,9 @@ import os
 import pty
 import re
 
+import gi
+gi.require_version("Vte", "2.91")
+
 import apt_pkg
 from gi.repository import GObject
 from gi.repository import GLib
@@ -46,6 +49,7 @@ from gi.repository import Gtk
 from gi.repository import Pango
 from gi.repository import Vte
 
+from . import client
 from .enums import *
 from defer import inline_callbacks
 from defer.utils import deferable
@@ -303,13 +307,13 @@ class AptProgressBar(Gtk.ProgressBar):
             return
         if speed != 0:
             self.set_text(_("Downloaded %sB of %sB at %sB/s") %
-                          (apt_pkg.size_to_str(bytes_done),
-                           apt_pkg.size_to_str(bytes_total),
-                           apt_pkg.size_to_str(speed)))
+                          (client.get_size_string(bytes_done),
+                           client.get_size_string(bytes_total),
+                           client.get_size_string(speed)))
         else:
             self.set_text(_("Downloaded %sB of %sB") %
-                          (apt_pkg.size_to_str(bytes_done),
-                           apt_pkg.size_to_str(bytes_total)))
+                          (client.get_size_string(bytes_done),
+                           client.get_size_string(bytes_total)))
 
     def _on_finished(self, transaction, exit):
         """Set the progress to 100% when the transaction is complete"""
@@ -390,7 +394,7 @@ class AptTerminal(Vte.Terminal):
         self._master, self._slave = pty.openpty()
         self._ttyname = os.ttyname(self._slave)
         self.set_size(80, 24)
-        self.set_pty_object(Vte.Pty.new_foreign(self._master))
+        self.set_pty(Vte.Pty.new_foreign_sync(self._master))
         if transaction is not None:
             self.set_transaction(transaction)
 
@@ -474,7 +478,7 @@ class AptDownloadsView(Gtk.TreeView):
         column_download.pack_start(cell_uri, True)
         column_download.add_attribute(cell_uri, "markup", self.COL_TEXT)
         cell_progress = Gtk.CellRendererProgress()
-        #TRANSLATORS: header of the progress download column
+        # TRANSLATORS: header of the progress download column
         column_progress = Gtk.TreeViewColumn(_("%"))
         column_progress.pack_start(cell_progress, True)
         column_progress.set_cell_data_func(cell_progress, self._data_progress,
@@ -504,20 +508,23 @@ class AptDownloadsView(Gtk.TreeView):
             progress = 100
         text = desc[:]
         text += "\n<small>"
-        #TRANSLATORS: %s is the full size in Bytes, e.g. 198M
+        # TRANSLATORS: %s is the full size in Bytes, e.g. 198M
         if status == DOWNLOAD_FETCHING:
             text += (_("Downloaded %sB of %sB") %
-                     (apt_pkg.size_to_str(downloaded),
-                      apt_pkg.size_to_str(full_size)))
+                     (client.get_size_string(downloaded),
+                      client.get_size_string(full_size)))
         elif status == DOWNLOAD_DONE:
             if full_size != 0:
-                text += _("Downloaded %sB") % apt_pkg.size_to_str(full_size)
+                text += (_("Downloaded %sB") %
+                         client.get_size_string(full_size))
             else:
                 text += _("Downloaded")
         else:
             text += get_download_status_from_enum(status)
         text += "</small>"
         model = self.get_model()
+        # LP: #1266844 - we don't know how this can happy, model
+        #                is never unset. but it does happen
         if not model:
             return
         try:
@@ -845,9 +852,9 @@ class AptMediumRequiredDialog(Gtk.Messag
     def __init__(self, medium, drive, parent=None):
         Gtk.MessageDialog.__init__(self, parent=parent,
                                    type=Gtk.MessageType.INFO)
-        #TRANSLATORS: %s represents the name of a CD or DVD
+        # TRANSLATORS: %s represents the name of a CD or DVD
         text = _("CD/DVD '%s' is required") % medium
-        #TRANSLATORS: %s is the name of the CD/DVD drive
+        # TRANSLATORS: %s is the name of the CD/DVD drive
         desc = _("Please insert the above CD/DVD into the drive '%s' to "
                  "install software packages from it.") % drive
         self.set_markup("<big><b>%s</b></big>\n\n%s" % (text, desc))
@@ -938,8 +945,8 @@ class AptConfirmDialog(Gtk.Dialog):
                         self.treestore.append(piter, [str(object)])
         # If there is only one type of changes (e.g. only installs) expand the
         # tree
-        #FIXME: adapt the title and message accordingly
-        #FIXME: Should we have different modes? Only show dependencies, only
+        # FIXME: adapt the title and message accordingly
+        # FIXME: Should we have different modes? Only show dependencies, only
         #       initial packages or both?
         msg = _("Please take a look at the list of changes below.")
         if len(self.treestore) == 1:
@@ -975,15 +982,15 @@ class AptConfirmDialog(Gtk.Dialog):
         if self.trans.download:
             msg += "\n"
             msg += (_("%sB will be downloaded in total.") %
-                    apt_pkg.size_to_str(self.trans.download))
+                    client.get_size_string(self.trans.download))
         if self.trans.space < 0:
             msg += "\n"
             msg += (_("%sB of disk space will be freed.") %
-                    apt_pkg.size_to_str(self.trans.space))
+                    client.get_size_string(self.trans.space))
         elif self.trans.space > 0:
             msg += "\n"
             msg += (_("%sB more disk space will be used.") %
-                    apt_pkg.size_to_str(self.trans.space))
+                    client.get_size_string(self.trans.space))
         self.label.set_markup("<b><big>%s</big></b>\n\n%s" % (title, msg))
 
     def map_package(self, pkg):
@@ -1053,7 +1060,7 @@ class AptConfigFileConflictDialog(_Expan
     def __init__(self, from_path, to_path, parent=None):
         self.from_path = from_path
         self.to_path = to_path
-        #TRANSLATORS: %s is a file path
+        # TRANSLATORS: %s is a file path
         title = _("Replace your changes in '%s' with a later version of "
                   "the configuration file?") % from_path
         msg = _("If you don't know why the file is there already, it is "
@@ -1095,7 +1102,7 @@ class DiffView(Gtk.TextView):
         self.set_property("editable", False)
         self.set_cursor_visible(False)
         tags = self.textbuffer.get_tag_table()
-        #FIXME: How to get better colors?
+        # FIXME: How to get better colors?
         tag_default = Gtk.TextTag.new("default")
         tag_default.set_properties(font="Mono")
         tags.add(tag_default)
@@ -1114,7 +1121,7 @@ class DiffView(Gtk.TextView):
 
     def show_diff(self, from_path, to_path):
         """Show the difference between two files."""
-        #FIXME: Use gio
+        # FIXME: Use gio
         try:
             with open(from_path) as fp:
                 from_lines = fp.readlines()
@@ -1126,7 +1133,7 @@ class DiffView(Gtk.TextView):
         # helper function to work around current un-introspectability of
         # varargs methods like insert_with_tags_by_name()
         def insert_tagged_text(iter, text, tag):
-            #self.textbuffer.insert_with_tags_by_name(iter, text, tag)
+            # self.textbuffer.insert_with_tags_by_name(iter, text, tag)
             offset = iter.get_offset()
             self.textbuffer.insert(iter, text)
             self.textbuffer.apply_tag_by_name(
@@ -1170,7 +1177,7 @@ class _DetailsExpanderMessageDialog(_Exp
         textview.set_wrap_mode(Gtk.WrapMode.WORD)
         buffer = textview.get_buffer()
         scrolled.add(textview)
-        #TRANSLATORS: expander label in the error dialog
+        # TRANSLATORS: expander label in the error dialog
         _ExpandableDialog.__init__(self, parent=parent,
                                    expander_label=_("_Details"),
                                    expanded_child=scrolled,
diff -pruN 1.1.1-4/aptdaemon/gtkwidgets.py 1.1.1+bzr982-0ubuntu14/aptdaemon/gtkwidgets.py
--- 1.1.1-4/aptdaemon/gtkwidgets.py	2013-08-11 19:05:47.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/gtkwidgets.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,1104 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""
-This module provides widgets to use aptdaemon in a GTK application.
-"""
-# Copyright (C) 2008-2009 Sebastian Heinlein <devel@glatzor.de>
-#
-# 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.
-
-__author__ = "Sebastian Heinlein <devel@glatzor.de>"
-
-__all__ = ("AptConfigFileConflictDialog", "AptCancelButton",
-           "AptConfirmDialog",
-           "AptProgressDialog", "AptTerminalExpander", "AptStatusIcon",
-           "AptRoleIcon", "AptStatusAnimation", "AptRoleLabel",
-           "AptStatusLabel", "AptMediumRequiredDialog", "AptMessageDialog",
-           "AptErrorDialog", "AptProgressBar", "DiffView", "AptTerminal")
-
-import difflib
-import gettext
-import os
-import pty
-import re
-
-import apt_pkg
-import dbus
-import dbus.mainloop.glib
-import gobject
-import gtk
-import pango
-import vte
-
-from .enums import *
-from defer import inline_callbacks
-from defer.utils import deferable
-
-dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
-
-_ = lambda msg: gettext.dgettext("aptdaemon", msg)
-
-(COLUMN_ID,
- COLUMN_PACKAGE) = list(range(2))
-
-
-class AptStatusIcon(gtk.Image):
-    """
-    Provides a gtk.Image which shows an icon representing the status of a
-    aptdaemon transaction
-    """
-    def __init__(self, transaction=None, size=gtk.ICON_SIZE_DIALOG):
-        gtk.Image.__init__(self)
-        self.icon_size = size
-        self.icon_name = None
-        self._signals = []
-        self.set_alignment(0, 0)
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect to the given transaction"""
-        for sig in self._signals:
-            gobject.source_remove(sig)
-        self._signals = []
-        self._signals.append(transaction.connect("status-changed",
-                                                 self._on_status_changed))
-
-    def set_icon_size(self, size):
-        """Set the icon size to gtk stock icon size value"""
-        self.icon_size = size
-
-    def _on_status_changed(self, transaction, status):
-        """Set the status icon according to the changed status"""
-        icon_name = get_status_icon_name_from_enum(status)
-        if icon_name is None:
-            icon_name = gtk.STOCK_MISSING_IMAGE
-        if icon_name != self.icon_name:
-            self.set_from_icon_name(icon_name, self.icon_size)
-            self.icon_name = icon_name
-
-
-class AptRoleIcon(AptStatusIcon):
-    """
-    Provides a gtk.Image which shows an icon representing the role of an
-    aptdaemon transaction
-    """
-    def set_transaction(self, transaction):
-        for sig in self._signals:
-            gobject.source_remove(sig)
-        self._signals = []
-        self._signals.append(transaction.connect("role-changed",
-                                                 self._on_role_changed))
-        self._on_role_changed(transaction, transaction.role)
-
-    def _on_role_changed(self, transaction, role_enum):
-        """Show an icon representing the role"""
-        icon_name = get_role_icon_name_from_enum(role_enum)
-        if icon_name is None:
-            icon_name = gtk.STOCK_MISSING_IMAGE
-        if icon_name != self.icon_name:
-            self.set_from_icon_name(icon_name, self.icon_size)
-            self.icon_name = icon_name
-
-
-class AptStatusAnimation(AptStatusIcon):
-    """
-    Provides a gtk.Image which shows an animation representing the
-    transaction status
-    """
-    def __init__(self, transaction=None, size=gtk.ICON_SIZE_DIALOG):
-        AptStatusIcon.__init__(self, transaction, size)
-        self.animation = []
-        self.ticker = 0
-        self.frame_counter = 0
-        self.iter = 0
-        name = get_status_animation_name_from_enum(STATUS_WAITING)
-        fallback = get_status_icon_name_from_enum(STATUS_WAITING)
-        self.set_animation(name, fallback)
-
-    def set_animation(self, name, fallback=None, size=None):
-        """Show and start the animation of the given name and size"""
-        if name == self.icon_name:
-            return
-        if size is not None:
-            self.icon_size = size
-        self.stop_animation()
-        animation = []
-        (width, height) = gtk.icon_size_lookup(self.icon_size)
-        theme = gtk.icon_theme_get_default()
-        if name is not None and theme.has_icon(name):
-            pixbuf = theme.load_icon(name, width, 0)
-            rows = pixbuf.get_height() / height
-            cols = pixbuf.get_width() / width
-            for r in range(rows):
-                for c in range(cols):
-                    animation.append(pixbuf.subpixbuf(c * width, r * height,
-                                                      width, height))
-            if len(animation) > 0:
-                self.animation = animation
-                self.iter = 0
-                self.set_from_pixbuf(self.animation[0])
-                self.start_animation()
-            else:
-                self.set_from_pixbuf(pixbuf)
-            self.icon_name = name
-        elif fallback is not None and theme.has_icon(fallback):
-            self.set_from_icon_name(fallback, self.icon_size)
-            self.icon_name = fallback
-        else:
-            self.set_from_icon_name(gtk.STOCK_MISSING_IMAGE)
-
-    def start_animation(self):
-        """Start the animation"""
-        if self.ticker == 0:
-            self.ticker = gobject.timeout_add(200, self._advance)
-
-    def stop_animation(self):
-        """Stop the animation"""
-        if self.ticker != 0:
-            gobject.source_remove(self.ticker)
-            self.ticker = 0
-
-    def _advance(self):
-        """
-        Show the next frame of the animation and stop the animation if the
-        widget is no longer visible
-        """
-        if self.get_property("visible") is not False:
-            self.ticker = 0
-            return False
-        self.iter = self.iter + 1
-        if self.iter >= len(self.animation):
-            self.iter = 0
-        self.set_from_pixbuf(self.animation[self.iter])
-        return True
-
-    def _on_status_changed(self, transaction, status):
-        """
-        Set the animation according to the changed status
-        """
-        name = get_status_animation_name_from_enum(status)
-        fallback = get_status_icon_name_from_enum(status)
-        self.set_animation(name, fallback)
-
-
-class AptRoleLabel(gtk.Label):
-    """
-    Status label for the running aptdaemon transaction
-    """
-    def __init__(self, transaction=None):
-        gtk.Label.__init__(self)
-        self.set_alignment(0, 0)
-        self.set_ellipsize(pango.ELLIPSIZE_END)
-        self._signals = []
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect the status label to the given aptdaemon transaction"""
-        for sig in self._signals:
-            gobject.source_remove(sig)
-        self._signals = []
-        self._on_role_changed(transaction, transaction.role)
-        self._signals.append(transaction.connect("role-changed",
-                                                 self._on_role_changed))
-
-    def _on_role_changed(self, transaction, role):
-        """Set the role text."""
-        self.set_markup(get_role_localised_present_from_enum(role))
-
-
-class AptStatusLabel(gtk.Label):
-    """
-    Status label for the running aptdaemon transaction
-    """
-    def __init__(self, transaction=None):
-        gtk.Label.__init__(self)
-        self.set_alignment(0, 0)
-        self.set_ellipsize(pango.ELLIPSIZE_END)
-        self._signals = []
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect the status label to the given aptdaemon transaction"""
-        for sig in self._signals:
-            gobject.source_remove(sig)
-        self._signals = []
-        self._signals.append(transaction.connect("status-changed",
-                                                 self._on_status_changed))
-        self._signals.append(
-            transaction.connect("status-details-changed",
-                                self._on_status_details_changed))
-
-    def _on_status_changed(self, transaction, status):
-        """Set the status text according to the changed status"""
-        self.set_markup(get_status_string_from_enum(status))
-
-    def _on_status_details_changed(self, transaction, text):
-        """Set the status text to the one reported by apt"""
-        self.set_markup(text)
-
-
-class AptProgressBar(gtk.ProgressBar):
-    """
-    Provides a gtk.Progress which represents the progress of an aptdaemon
-    transactions
-    """
-    def __init__(self, transaction=None):
-        gtk.ProgressBar.__init__(self)
-        self.set_ellipsize(pango.ELLIPSIZE_END)
-        self.set_text(" ")
-        self.set_pulse_step(0.05)
-        self._signals = []
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect the progress bar to the given aptdaemon transaction"""
-        for sig in self._signals:
-            gobject.source_remove(sig)
-        self._signals = []
-        self._signals.append(
-            transaction.connect("finished", self._on_finished))
-        self._signals.append(transaction.connect("progress-changed",
-                                                 self._on_progress_changed))
-        self._signals.append(transaction.connect("progress-details-changed",
-                                                 self._on_progress_details))
-
-    def _on_progress_changed(self, transaction, progress):
-        """
-        Update the progress according to the latest progress information
-        """
-        if progress > 100:
-            self.pulse()
-        else:
-            self.set_fraction(progress / 100.0)
-
-    def _on_progress_details(self, transaction, items_done, items_total,
-                             bytes_done, bytes_total, speed, eta):
-        """
-        Update the progress bar text according to the latest progress details
-        """
-        if items_total == 0 and bytes_total == 0:
-            self.set_text(" ")
-            return
-        if speed != 0:
-            self.set_text(_("Downloaded %sB of %sB at %sB/s") %
-                          (apt_pkg.size_to_str(bytes_done),
-                           apt_pkg.size_to_str(bytes_total),
-                           apt_pkg.size_to_str(speed)))
-        else:
-            self.set_text(_("Downloaded %sB of %sB") %
-                          (apt_pkg.size_to_str(bytes_done),
-                           apt_pkg.size_to_str(bytes_total)))
-
-    def _on_finished(self, transaction, exit):
-        """Set the progress to 100% when the transaction is complete"""
-        self.set_fraction(1)
-
-
-class AptDetailsExpander(gtk.Expander):
-
-    def __init__(self, transaction=None, terminal=True):
-        gtk.Expander.__init__(self, _("Details"))
-        self.show_terminal = terminal
-        self._signals = []
-        self.set_sensitive(False)
-        self.set_expanded(False)
-        if self.show_terminal:
-            self.terminal = AptTerminal()
-        else:
-            self.terminal = None
-        self.download_view = AptDownloadsView()
-        self.download_scrolled = gtk.ScrolledWindow()
-        self.download_scrolled.set_shadow_type(gtk.SHADOW_ETCHED_IN)
-        self.download_scrolled.set_policy(gtk.POLICY_NEVER,
-                                          gtk.POLICY_AUTOMATIC)
-        self.download_scrolled.add(self.download_view)
-        hbox = gtk.HBox()
-        hbox.pack_start(self.download_scrolled, True, True)
-        hbox.pack_start(self.terminal, True, True)
-        self.add(hbox)
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect the status label to the given aptdaemon transaction"""
-        for sig in self._signals:
-            gobject.source_remove(sig)
-        self._signals.append(
-            transaction.connect("status-changed", self._on_status_changed))
-        self._signals.append(
-            transaction.connect("terminal-attached-changed",
-                                self._on_terminal_attached_changed))
-        self.terminal.set_transaction(transaction)
-        self.download_view.set_transaction(transaction)
-
-    def _on_status_changed(self, trans, status):
-        if status in (STATUS_DOWNLOADING, STATUS_DOWNLOADING_REPO):
-            self.set_sensitive(True)
-            self.download_scrolled.show()
-            if self.terminal:
-                self.terminal.hide()
-        elif status == STATUS_COMMITTING:
-            self.download_scrolled.hide()
-            if self.terminal:
-                self.terminal.show()
-                self.set_sensitive(True)
-            else:
-                self.set_expanded(False)
-                self.set_sensitive(False)
-        else:
-            self.download_scrolled.hide()
-            if self.terminal:
-                self.terminal.hide()
-            self.set_sensitive(False)
-            self.set_expanded(False)
-
-    def _on_terminal_attached_changed(self, transaction, attached):
-        """Connect the terminal to the pty device"""
-        if attached and self.terminal:
-            self.set_sensitive(True)
-
-
-class AptTerminal(vte.Terminal):
-
-    def __init__(self, transaction=None):
-        vte.Terminal.__init__(self)
-        self._signals = []
-        self._master, self._slave = pty.openpty()
-        self._ttyname = os.ttyname(self._slave)
-        self.set_size(80, 24)
-        self.set_pty(self._master)
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect the status label to the given aptdaemon transaction"""
-        for sig in self._signals:
-            gobject.source_remove(sig)
-        self._signals.append(
-            transaction.connect("terminal-attached-changed",
-                                self._on_terminal_attached_changed))
-        self._transaction = transaction
-        self._transaction.set_terminal(self._ttyname)
-
-    def _on_terminal_attached_changed(self, transaction, attached):
-        """Show the terminal"""
-        self.set_sensitive(attached)
-
-
-class AptCancelButton(gtk.Button):
-
-    """Provides a gtk.Button which allows to cancel a running aptdaemon
-    transaction
-    """
-
-    def __init__(self, transaction=None):
-        gtk.Button.__init__(self, stock=gtk.STOCK_CANCEL)
-        self.set_sensitive(True)
-        self._signals = []
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect the status label to the given aptdaemon transaction"""
-        for sig in self._signals:
-            gobject.source_remove(sig)
-        self._signals = []
-        self._signals.append(
-            transaction.connect("finished", self._on_finished))
-        self._signals.append(
-            transaction.connect("cancellable-changed",
-                                self._on_cancellable_changed))
-        self.connect("clicked", self._on_clicked, transaction)
-
-    def _on_cancellable_changed(self, transaction, cancellable):
-        """
-        Enable the button if cancel is allowed and disable it in the other case
-        """
-        self.set_sensitive(cancellable)
-
-    def _on_finished(self, transaction, status):
-        self.set_sensitive(False)
-
-    def _on_clicked(self, button, transaction):
-        transaction.cancel()
-        self.set_sensitive(False)
-
-
-class AptDownloadsView(gtk.TreeView):
-
-    """A gtk.TreeView which displays the progress and status of each dowload
-    of a transaction.
-    """
-
-    COL_TEXT, COL_PROGRESS, COL_URI = list(range(3))
-
-    def __init__(self, transaction=None):
-        gtk.TreeView.__init__(self)
-        model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT,
-                              gobject.TYPE_STRING)
-        self.set_model(model)
-        self.props.headers_visible = False
-        self.set_rules_hint(True)
-        self._download_map = {}
-        self._signals = []
-        if transaction is not None:
-            self.set_transaction(transaction)
-        cell_uri = gtk.CellRendererText()
-        cell_uri.props.ellipsize = pango.ELLIPSIZE_END
-        column_download = gtk.TreeViewColumn(_("File"))
-        column_download.pack_start(cell_uri, True)
-        column_download.add_attribute(cell_uri, "markup", self.COL_TEXT)
-        cell_progress = gtk.CellRendererProgress()
-        #TRANSLATORS: header of the progress download column
-        column_progress = gtk.TreeViewColumn(_("%"))
-        column_progress.pack_start(cell_progress, True)
-        column_progress.set_cell_data_func(cell_progress, self._data_progress)
-        self.append_column(column_progress)
-        self.append_column(column_download)
-        self.set_tooltip_column(self.COL_URI)
-
-    def set_transaction(self, transaction):
-        """Connect the download view to the given aptdaemon transaction"""
-        for sig in self._signals:
-            gobject.source_remove(sig)
-        self._signals = []
-        self._signals.append(transaction.connect("progress-download-changed",
-                                                 self._on_download_changed))
-
-    def _on_download_changed(self, transaction, uri, status, desc, full_size,
-                             downloaded, message):
-        """Callback for a changed download progress."""
-        try:
-            progress = downloaded * 100 / full_size
-        except ZeroDivisionError:
-            progress = -1
-        if status == DOWNLOAD_DONE:
-            progress = 100
-        if progress > 100:
-            progress = 100
-        text = desc[:]
-        text += "\n<small>"
-        #TRANSLATORS: %s is the full size in Bytes, e.g. 198M
-        if status == DOWNLOAD_FETCHING:
-            text += (_("Downloaded %sB of %sB") %
-                     (apt_pkg.size_to_str(downloaded),
-                      apt_pkg.size_to_str(full_size)))
-        elif status == DOWNLOAD_DONE:
-            if full_size != 0:
-                text += _("Downloaded %sB") % apt_pkg.size_to_str(full_size)
-            else:
-                text += _("Downloaded")
-        else:
-            text += get_download_status_from_enum(status)
-        text += "</small>"
-        model = self.get_model()
-        try:
-            iter = self._download_map[uri]
-        except KeyError:
-            adj = self.get_vadjustment()
-            is_scrolled_down = adj.value + adj.page_size == adj.upper
-            iter = model.append((text, progress, uri))
-            self._download_map[uri] = iter
-            if is_scrolled_down:
-                # If the treeview was scrolled to the end, do this again
-                # after appending a new item
-                self.scroll_to_cell(model.get_path(iter))
-        else:
-            model.set(iter, self.COL_TEXT, text)
-            model.set(iter, self.COL_PROGRESS, progress)
-
-    def _data_progress(self, column, cell, model, iter):
-        progress = model.get_value(iter, self.COL_PROGRESS)
-        if progress == -1:
-            cell.props.pulse = progress
-        else:
-            cell.props.value = progress
-
-
-class AptProgressDialog(gtk.Dialog):
-    """
-    Complete progress dialog for long taking aptdaemon transactions, which
-    features a progress bar, cancel button, status icon and label
-    """
-
-    __gsignals__ = {"finished": (gobject.SIGNAL_RUN_FIRST,
-                                 gobject.TYPE_NONE, ())}
-
-    def __init__(self, transaction=None, parent=None, terminal=True,
-                 debconf=True):
-        gtk.Dialog.__init__(self, buttons=None, parent=parent)
-        self._expanded_size = None
-        self.debconf = debconf
-        # Setup the dialog
-        self.set_border_width(6)
-        self.set_has_separator(False)
-        self.set_resizable(False)
-        self.vbox.set_spacing(6)
-        # Setup the cancel button
-        self.button_cancel = AptCancelButton(transaction)
-        self.action_area.pack_start(self.button_cancel, False, False, 0)
-        # Setup the status icon, label and progressbar
-        hbox = gtk.HBox()
-        hbox.set_spacing(12)
-        hbox.set_border_width(6)
-        self.icon = AptRoleIcon()
-        hbox.pack_start(self.icon, False, True, 0)
-        vbox = gtk.VBox()
-        vbox.set_spacing(12)
-        self.label_role = gtk.Label()
-        self.label_role.set_alignment(0, 0)
-        vbox.pack_start(self.label_role, False, True, 0)
-        vbox_progress = gtk.VBox()
-        vbox_progress.set_spacing(6)
-        self.progress = AptProgressBar()
-        vbox_progress.pack_start(self.progress, False, True, 0)
-        self.label = AptStatusLabel()
-        self.label._on_status_changed(None, STATUS_WAITING)
-        vbox_progress.pack_start(self.label, False, True, 0)
-        vbox.pack_start(vbox_progress, False, True, 0)
-        hbox.pack_start(vbox, True, True, 0)
-        self.expander = AptDetailsExpander(terminal=terminal)
-        self.expander.connect("notify::expanded", self._on_expanded)
-        vbox.pack_start(self.expander, True, True, 0)
-        self.vbox.pack_start(hbox, True, True, 0)
-        self._transaction = None
-        self._signals = []
-        self.set_title("")
-        self.realize()
-        self.progress.set_size_request(350, -1)
-        self.window.set_functions(gtk.gdk.FUNC_MOVE | gtk.gdk.FUNC_RESIZE)
-        if transaction is not None:
-            self.set_transaction(transaction)
-        # catch ESC and behave as if cancel was clicked
-        self.connect("delete-event", self._on_dialog_delete_event)
-
-    def _on_dialog_delete_event(self, dialog, event):
-        self.button_cancel.clicked()
-        return True
-
-    def _on_expanded(self, expander, param):
-        # Make the dialog resizable if the expander is expanded
-        # try to restore a previous size
-        if not expander.get_expanded():
-            self._expanded_size = self.get_size()
-            self.set_resizable(False)
-        elif self._expanded_size:
-            self.set_resizable(True)
-            self.resize(*self._expanded_size)
-        else:
-            self.set_resizable(True)
-
-    @deferable
-    def run(self, attach=False, close_on_finished=True, show_error=True,
-            reply_handler=None, error_handler=None):
-        """Run the transaction and show the progress in the dialog.
-
-        Keyword arguments:
-        attach -- do not start the transaction but instead only monitor
-                  an already running one
-        close_on_finished -- if the dialog should be closed when the
-                  transaction is complete
-        show_error -- show a dialog with the error message
-        """
-        return self._run(attach, close_on_finished, show_error,
-                         reply_handler, error_handler)
-
-    @inline_callbacks
-    def _run(self, attach, close_on_finished, show_error,
-             reply_handler, error_handler):
-        try:
-            sig = self._transaction.connect("finished", self._on_finished,
-                                            close_on_finished, show_error)
-            self._signals.append(sig)
-            if attach:
-                yield self._transaction.sync()
-            else:
-                if self.debconf:
-                    yield self._transaction.set_debconf_frontend("gnome")
-                yield self._transaction.run()
-            self.show_all()
-        except Exception as error:
-            if error_handler:
-                error_handler(error)
-            else:
-                raise
-        else:
-            if reply_handler:
-                reply_handler()
-
-    def _on_role_changed(self, transaction, role_enum):
-        """Show the role of the transaction in the dialog interface"""
-        role = get_role_localised_present_from_enum(role_enum)
-        self.set_title(role)
-        self.label_role.set_markup("<big><b>%s</b></big>" % role)
-
-    def set_transaction(self, transaction):
-        """Connect the dialog to the given aptdaemon transaction"""
-        for sig in self._signals:
-            gobject.source_remove(sig)
-        self._signals = []
-        self._signals.append(transaction.connect("role-changed",
-                                                 self._on_role_changed))
-        self._signals.append(transaction.connect("medium-required",
-                                                 self._on_medium_required))
-        self._signals.append(transaction.connect("config-file-conflict",
-                             self._on_config_file_conflict))
-        self._on_role_changed(transaction, transaction.role)
-        self.progress.set_transaction(transaction)
-        self.icon.set_transaction(transaction)
-        self.label.set_transaction(transaction)
-        self.expander.set_transaction(transaction)
-        self._transaction = transaction
-
-    def _on_medium_required(self, transaction, medium, drive):
-        dialog = AptMediumRequiredDialog(medium, drive, self)
-        res = dialog.run()
-        dialog.hide()
-        if res == gtk.RESPONSE_OK:
-            self._transaction.provide_medium(medium)
-        else:
-            self._transaction.cancel()
-
-    def _on_config_file_conflict(self, transaction, old, new):
-        dialog = AptConfigFileConflictDialog(old, new, self)
-        res = dialog.run()
-        dialog.hide()
-        if res == gtk.RESPONSE_YES:
-            self._transaction.resolve_config_file_conflict(old, "replace")
-        else:
-            self._transaction.resolve_config_file_conflict(old, "keep")
-
-    def _on_finished(self, transaction, status, close, show_error):
-        if close:
-            self.hide()
-        if status == EXIT_FAILED and show_error:
-            err_dia = AptErrorDialog(self._transaction.error, self)
-            err_dia.run()
-            err_dia.hide()
-        self.emit("finished")
-
-
-class _ExpandableDialog(gtk.Dialog):
-
-    """Dialog with an expander."""
-
-    def __init__(self, parent=None, stock_type=None, expanded_child=None,
-                 expander_label=None, title=None, message=None, buttons=None):
-        """Return an _AptDaemonDialog instance.
-
-        Keyword arguments:
-        parent -- set the dialog transient for the given gtk.Window
-        stock_type -- type of the Dialog, defaults to gtk.STOCK_DIALOG_QUESTION
-        expanded_child -- Widget which should be expanded
-        expander_label -- label for the expander
-        title -- a news header like title of the dialog
-        message -- the message which should be shown in the dialog
-        buttons -- tuple containing button text/reponse id pairs, defaults
-                   to a close button
-        """
-        if not buttons:
-            buttons = (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
-        gtk.Dialog.__init__(self, parent=parent, buttons=buttons)
-        self.set_resizable(True)
-        self.set_border_width(6)
-        self.vbox.set_spacing(12)
-        if not stock_type:
-            stock_type = gtk.STOCK_DIALOG_QUESTION
-        icon = gtk.image_new_from_stock(stock_type, gtk.ICON_SIZE_DIALOG)
-        icon.set_alignment(0, 0)
-        hbox_base = gtk.HBox()
-        hbox_base.set_spacing(12)
-        hbox_base.set_border_width(6)
-        vbox_left = gtk.VBox()
-        vbox_left.set_spacing(12)
-        hbox_base.pack_start(icon, False, True)
-        hbox_base.pack_start(vbox_left, True, True)
-        self.label = gtk.Label()
-        self.label.set_selectable(True)
-        self.label.set_alignment(0, 0)
-        self.label.set_line_wrap(True)
-        vbox_left.pack_start(self.label, False, True)
-        self.set_has_separator(False)
-        self.vbox.pack_start(hbox_base, True, True)
-        # The expander widget
-        self.expander = gtk.Expander(label=expander_label)
-        self.expander.set_spacing(6)
-        self.expander.set_use_underline(True)
-        self.expander.connect("notify::expanded", self._on_expanded)
-        vbox_left.pack_start(self.expander, True, True)
-        self._expanded_size = self.get_size()
-        # Set some initial data
-        text = ""
-        if title:
-            text = "<b><big>%s</big></b>" % title
-        if message:
-            if text:
-                text += "\n\n"
-            text += message
-        self.label.set_markup(text)
-        if expanded_child:
-            self.expander.add(expanded_child)
-            expanded_child.set_size_request(-1, 125)
-        else:
-            self.expander.set_sensitive(True)
-
-    def _on_expanded(self, expander, param):
-        if expander.get_expanded():
-            self.set_resizable(True)
-            self.resize(*self._expanded_size)
-        else:
-            self._expanded_size = self.get_size()
-            self.set_resizable(False)
-
-    def run(self):
-        self.show_all()
-        return gtk.Dialog.run(self)
-
-
-class AptMediumRequiredDialog(gtk.MessageDialog):
-
-    """Dialog to ask for medium change."""
-
-    def __init__(self, medium, drive, parent=None):
-        gtk.MessageDialog.__init__(self, parent=parent,
-                                   type=gtk.MESSAGE_INFO)
-        #TRANSLATORS: %s represents the name of a CD or DVD
-        text = _("CD/DVD '%s' is required") % medium
-        #TRANSLATORS: %s is the name of the CD/DVD drive
-        desc = _("Please insert the above CD/DVD into the drive '%s' to "
-                 "install software packages from it.") % drive
-        self.set_markup("<big><b>%s</b></big>\n\n%s" % (text, desc))
-        self.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
-                         _("C_ontinue"), gtk.RESPONSE_OK)
-        self.set_default_response(gtk.RESPONSE_OK)
-
-
-class AptConfirmDialog(gtk.Dialog):
-
-    """Dialog to confirm the changes that would be required by a
-    transaction."""
-
-    def __init__(self, trans, cache=None, parent=None):
-        """Return an AptConfirmDialog instance.
-
-        Keyword arguments:
-        trans -- the transaction of which the dependencies should be shown
-        cache -- an optional apt.cache.Cache() instance to provide more details
-                 about packages
-        parent -- set the dialog transient for the given gtk.Window
-        """
-        self.cache = cache
-        self.trans = trans
-        buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
-                   _("C_ontinue"), gtk.RESPONSE_OK)
-        gtk.Dialog.__init__(self, buttons=buttons)
-        if isinstance(parent, gtk.gdk.Window):
-            self.realize()
-            self.window.set_transient_for(parent)
-        else:
-            self.set_transient_for(parent)
-        self.set_resizable(True)
-        self.set_border_width(6)
-        self.vbox.set_spacing(12)
-        icon = gtk.image_new_from_stock(gtk.STOCK_DIALOG_QUESTION,
-                                        gtk.ICON_SIZE_DIALOG)
-        icon.set_alignment(0, 0)
-        hbox_base = gtk.HBox()
-        hbox_base.set_spacing(12)
-        hbox_base.set_border_width(6)
-        vbox_left = gtk.VBox()
-        vbox_left.set_spacing(12)
-        hbox_base.pack_start(icon, False, True)
-        hbox_base.pack_start(vbox_left, True, True)
-        self.label = gtk.Label()
-        self.label.set_selectable(True)
-        self.label.set_alignment(0, 0)
-        self.label.set_line_wrap(True)
-        vbox_left.pack_start(self.label, False, True)
-        self.set_has_separator(False)
-        self.vbox.pack_start(hbox_base, True, True)
-        self.treestore = gtk.TreeStore(str)
-        self.treeview = gtk.TreeView(self.treestore)
-        self.treeview.set_headers_visible(False)
-        self.treeview.set_rules_hint(True)
-        self.column = gtk.TreeViewColumn()
-        self.treeview.append_column(self.column)
-        cell_icon = gtk.CellRendererPixbuf()
-        self.column.pack_start(cell_icon, expand=False)
-        self.column.set_cell_data_func(cell_icon, self.render_package_icon)
-        cell_desc = gtk.CellRendererText()
-        self.column.pack_start(cell_desc, expand=True)
-        self.column.set_cell_data_func(cell_desc, self.render_package_desc)
-        self.scrolled = gtk.ScrolledWindow()
-        self.scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-        self.scrolled.set_shadow_type(gtk.SHADOW_ETCHED_IN)
-        self.scrolled.add(self.treeview)
-        vbox_left.pack_start(self.scrolled, True, True)
-        self.set_default_response(gtk.RESPONSE_CANCEL)
-
-    def _show_changes(self):
-        """Show a message and the dependencies in the dialog."""
-        self.treestore.clear()
-        for index, msg in enumerate([_("Install"),
-                                     _("Reinstall"),
-                                     _("Remove"),
-                                     _("Purge"),
-                                     _("Upgrade"),
-                                     _("Downgrade"),
-                                     _("Skip upgrade")]):
-            if self.trans.dependencies[index]:
-                piter = self.treestore.append(None, ["<b>%s</b>" % msg])
-                for pkg in self.trans.dependencies[index]:
-                    for object in self.map_package(pkg):
-                        self.treestore.append(piter, [object])
-        # If there is only one type of changes (e.g. only installs) expand the
-        # tree
-        #FIXME: adapt the title and message accordingly
-        #FIXME: Should we have different modes? Only show dependencies, only
-        #       initial packages or both?
-        msg = _("Please take a look at the list of changes below.")
-        if len(self.treestore) == 1:
-            filtered_store = self.treestore.filter_new(root=(0))
-            self.treeview.expand_all()
-            self.treeview.set_model(filtered_store)
-            self.treeview.set_show_expanders(False)
-            if self.trans.dependencies[PKGS_INSTALL]:
-                title = _("Additional software has to be installed")
-            elif self.trans.dependencies[PKGS_REINSTALL]:
-                title = _("Additional software has to be re-installed")
-            elif self.trans.dependencies[PKGS_REMOVE]:
-                title = _("Additional software has to be removed")
-            elif self.trans.dependencies[PKGS_PURGE]:
-                title = _("Additional software has to be purged")
-            elif self.trans.dependencies[PKGS_UPGRADE]:
-                title = _("Additional software has to be upgraded")
-            elif self.trans.dependencies[PKGS_DOWNGRADE]:
-                title = _("Additional software has to be downgraded")
-            elif self.trans.dependencies[PKGS_KEEP]:
-                title = _("Updates will be skipped")
-            if len(filtered_store) < 6:
-                self.set_resizable(False)
-                self.scrolled.set_policy(gtk.POLICY_AUTOMATIC,
-                                         gtk.POLICY_NEVER)
-            else:
-                self.treeview.set_size_request(350, 200)
-        else:
-            title = _("Additional changes are required")
-            self.treeview.set_size_request(350, 200)
-            self.treeview.collapse_all()
-        if self.trans.download:
-            msg += "\n"
-            msg += (_("%sB will be downloaded in total.") %
-                    apt_pkg.size_to_str(self.trans.download))
-        if self.trans.space < 0:
-            msg += "\n"
-            msg += (_("%sB of disk space will be freed.") %
-                    apt_pkg.size_to_str(self.trans.space))
-        elif self.trans.space > 0:
-            msg += "\n"
-            msg += (_("%sB more disk space will be used.") %
-                    apt_pkg.size_to_str(self.trans.space))
-        self.label.set_markup("<b><big>%s</big></b>\n\n%s" % (title, msg))
-
-    def map_package(self, pkg):
-        """Map a package to a different object type, e.g. applications
-        and return a list of those.
-
-        By default return the package itself inside a list.
-
-        Override this method if you don't want to store package names
-        in the treeview.
-        """
-        return [pkg]
-
-    def render_package_icon(self, column, cell, model, iter):
-        """Data func for the gtk.CellRendererPixbuf which shows the package.
-
-        Override this method if you want to show custom icons for
-        a package or map it to applications.
-        """
-        path = model.get_path(iter)
-        if len(path) == 1:
-            cell.props.visible = False
-        else:
-            cell.props.visible = True
-        cell.props.icon_name = "applications-other"
-
-    def render_package_desc(self, column, cell, model, iter):
-        """Data func for the gtk.CellRendererText which shows the package.
-
-        Override this method if you want to show more information about
-        a package or map it to applications.
-        """
-        value = model.get_value(iter, 0)
-        try:
-            pkg_name, pkg_version = value.split("=")[0:2]
-        except ValueError:
-            pkg_name = value
-            pkg_version = None
-        try:
-            if pkg_version:
-                text = "%s (%s)\n<small>%s</small>" % (
-                    pkg_name, pkg_version, self.cache[pkg_name].summary)
-            else:
-                text = "%s\n<small>%s</small>" % (
-                    pkg_name, self.cache[pkg_name].summary)
-        except (KeyError, TypeError):
-            if pkg_version:
-                text = "%s (%s)" % (pkg_name, pkg_version)
-            else:
-                text = "%s" % pkg_name
-        cell.set_property("markup", text)
-
-    def run(self):
-        self._show_changes()
-        self.show_all()
-        return gtk.Dialog.run(self)
-
-
-class AptConfigFileConflictDialog(_ExpandableDialog):
-
-    """Dialog to resolve conflicts between local and shipped
-    configuration files.
-    """
-
-    def __init__(self, from_path, to_path, parent=None):
-        self.from_path = from_path
-        self.to_path = to_path
-        #TRANSLATORS: %s is a file path
-        title = _("Replace your changes in '%s' with a later version of "
-                  "the configuration file?") % from_path
-        msg = _("If you don't know why the file is there already, it is "
-                "usually safe to replace it.")
-        scrolled = gtk.ScrolledWindow()
-        scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-        scrolled.set_shadow_type(gtk.SHADOW_ETCHED_IN)
-        self.diffview = DiffView()
-        self.diffview.set_size_request(-1, 200)
-        scrolled.add(self.diffview)
-        _ExpandableDialog.__init__(self, parent=parent,
-                                   expander_label=_("_Changes"),
-                                   expanded_child=scrolled,
-                                   title=title, message=msg,
-                                   buttons=(_("_Keep"), gtk.RESPONSE_NO,
-                                            _("_Replace"), gtk.RESPONSE_YES))
-        self.set_default_response(gtk.RESPONSE_NO)
-
-    def run(self):
-        self.show_all()
-        self.diffview.show_diff(self.from_path, self.to_path)
-        return _ExpandableDialog.run(self)
-
-
-class DiffView(gtk.TextView):
-
-    """Shows the difference between two files."""
-
-    REGEX_RANGE = "^@@ \-(?P<from_start>[0-9]+),(?P<from_context>[0-9]+) " \
-                  "\+(?P<to_start>[0-9]+),(?P<to_context>[0-9]+) @@"
-    ELLIPSIS = "[…]\n"
-
-    def __init__(self):
-        self.buffer = gtk.TextBuffer()
-        gtk.TextView.__init__(self, self.buffer)
-        self.set_property("editable", False)
-        self.set_cursor_visible(False)
-        tags = self.buffer.get_tag_table()
-        #FIXME: How to get better colors?
-        tag_default = gtk.TextTag("default")
-        tag_default.set_properties(font="Mono")
-        tags.add(tag_default)
-        tag_add = gtk.TextTag("add")
-        tag_add.set_properties(font="Mono",
-                               background='#8ae234')
-        tags.add(tag_add)
-        tag_remove = gtk.TextTag("remove")
-        tag_remove.set_properties(font="Mono",
-                                  background='#ef2929')
-        tags.add(tag_remove)
-        tag_num = gtk.TextTag("number")
-        tag_num.set_properties(font="Mono",
-                               background='#eee')
-        tags.add(tag_num)
-
-    def show_diff(self, from_path, to_path):
-        """Show the difference between two files."""
-        #FIXME: Use gio
-        try:
-            from_lines = open(from_path).readlines()
-            to_lines = open(to_path).readlines()
-        except IOError:
-            return
-        iter = self.buffer.get_start_iter()
-        for line in difflib.unified_diff(from_lines, to_lines, lineterm=""):
-            if line.startswith("@@"):
-                match = re.match(self.REGEX_RANGE, line)
-                if not match:
-                    continue
-                line_number = int(match.group("from_start"))
-                if line_number > 1:
-                    self.buffer.insert_with_tags_by_name(iter, self.ELLIPSIS,
-                                                         "default")
-            elif line.startswith("---") or line.startswith("+++"):
-                continue
-            elif line.startswith(" "):
-                line_number += 1
-                self.buffer.insert_with_tags_by_name(iter, str(line_number),
-                                                     "number")
-                self.buffer.insert_with_tags_by_name(iter, line, "default")
-            elif line.startswith("-"):
-                line_number += 1
-                self.buffer.insert_with_tags_by_name(iter, str(line_number),
-                                                     "number")
-                self.buffer.insert_with_tags_by_name(iter, line, "remove")
-            elif line.startswith("+"):
-                spaces = " " * len(str(line_number))
-                self.buffer.insert_with_tags_by_name(iter, spaces, "number")
-                self.buffer.insert_with_tags_by_name(iter, line, "add")
-
-
-class AptErrorDialog(_ExpandableDialog):
-
-    """
-    Dialog for aptdaemon errors with details in an expandable text view
-    """
-
-    def __init__(self, error=None, parent=None):
-        title = get_error_string_from_enum(error.code)
-        msg = get_error_description_from_enum(error.code)
-
-        if error.details:
-            scrolled = gtk.ScrolledWindow()
-            scrolled.set_policy(gtk.POLICY_AUTOMATIC,
-                                gtk.POLICY_AUTOMATIC)
-            scrolled.set_shadow_type(gtk.SHADOW_ETCHED_IN)
-            textview = gtk.TextView()
-            buffer = textview.get_buffer()
-            buffer.insert_at_cursor(error.details)
-            scrolled.add(textview)
-        else:
-            scrolled = None
-
-        _ExpandableDialog.__init__(self, parent=parent,
-                                   expander_label=_("_Details"),
-                                   expanded_child=scrolled,
-                                   stock_type=gtk.STOCK_DIALOG_ERROR,
-                                   title=title, message=msg)
diff -pruN 1.1.1-4/aptdaemon/__init__.py 1.1.1+bzr982-0ubuntu14/aptdaemon/__init__.py
--- 1.1.1-4/aptdaemon/__init__.py	2013-08-12 04:33:46.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/__init__.py	2014-08-21 12:56:35.000000000 +0000
@@ -22,7 +22,7 @@ __state__ = "development"
 __version__ = '1.1.1'
 
 __all__ = ("client", "console", "core", "debconf", "defer", "enums",
-           "errors", "gtkwidgets", "loop", "policykit1", "progress",
+           "errors", "gtk3widgets", "loop", "policykit1", "progress",
            "test", "utils", "worker")
 
 # vim:ts=4:sw=4:et
diff -pruN 1.1.1-4/aptdaemon/lock.py 1.1.1+bzr982-0ubuntu14/aptdaemon/lock.py
--- 1.1.1-4/aptdaemon/lock.py	2013-03-11 06:00:59.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/lock.py	2014-06-26 07:07:15.000000000 +0000
@@ -178,7 +178,7 @@ def wait_for_lock(trans, alt_lock=None):
         trans.paused = True
         trans.status = enums.STATUS_WAITING_LOCK
         if error.process:
-            #TRANSLATORS: %s is the name of a package manager
+            # TRANSLATORS: %s is the name of a package manager
             msg = trans.gettext("Waiting for %s to exit")
             trans.status_details = msg % error.process
         lock_watch = GLib.timeout_add_seconds(3, watch_lock)
diff -pruN 1.1.1-4/aptdaemon/loop.py 1.1.1+bzr982-0ubuntu14/aptdaemon/loop.py
--- 1.1.1-4/aptdaemon/loop.py	2013-03-11 06:00:59.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/loop.py	2014-08-21 12:56:35.000000000 +0000
@@ -27,7 +27,7 @@ mainloop = GLib.MainLoop()
 
 
 def get_main_loop():
-    """Return the gobject main loop as a singelton."""
+    """Return the glib main loop as a singleton."""
     return mainloop
 
 # vim:ts=4:sw=4:et
diff -pruN 1.1.1-4/aptdaemon/networking.py 1.1.1+bzr982-0ubuntu14/aptdaemon/networking.py
--- 1.1.1-4/aptdaemon/networking.py	2013-08-11 19:05:47.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/networking.py	2014-06-26 07:09:59.000000000 +0000
@@ -176,7 +176,7 @@ class NetworkManagerMonitor(NetworkMonit
     @inline_callbacks
     def _on_nm_active_conn_props_changed(self, props):
         """Callback if properties of the active connection changed."""
-        if not "Default" in props:
+        if "Default" not in props:
             raise StopIteration
         yield self.get_network_state()
 
diff -pruN 1.1.1-4/aptdaemon/pkcompat.py 1.1.1+bzr982-0ubuntu14/aptdaemon/pkcompat.py
--- 1.1.1-4/aptdaemon/pkcompat.py	2015-10-12 18:06:09.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/pkcompat.py	2015-10-12 18:06:10.000000000 +0000
@@ -30,7 +30,6 @@ import tempfile
 import time
 import uuid
 
-import apt_pkg
 from defer import inline_callbacks, return_value
 from defer.utils import dbus_deferred_method
 import dbus
@@ -52,6 +51,9 @@ from . import errors
 from .progress import DaemonAcquireProgress
 from . import worker
 from . import networking
+from .pkutils import (bitfield_summarize, bitfield_add, bitfield_remove,
+                      bitfield_contains)
+from .utils import split_package_id
 
 
 pklog = logging.getLogger("AptDaemon.PackageKit")
@@ -65,100 +67,6 @@ except ImportError:
 else:
     META_RELEASE_SUPPORT = True
 
-# Xapian database is optionally used to speed up package description search
-XAPIAN_DB_PATH = os.environ.get("AXI_DB_PATH", "/var/lib/apt-xapian-index")
-XAPIAN_DB = XAPIAN_DB_PATH + "/index"
-XAPIAN_DB_VALUES = XAPIAN_DB_PATH + "/values"
-XAPIAN_SUPPORT = False
-try:
-    import xapian
-except ImportError:
-    pass
-else:
-    if os.access(XAPIAN_DB, os.R_OK):
-        pklog.debug("Use XAPIAN for the search")
-        XAPIAN_SUPPORT = True
-
-# Regular expressions to detect bug numbers in changelogs according to the
-# Debian Policy Chapter 4.4. For details see the footnote 16:
-# http://www.debian.org/doc/debian-policy/footnotes.html#f16
-MATCH_BUG_CLOSES_DEBIAN = (
-    r"closes:\s*(?:bug)?\#?\s?\d+(?:,\s*(?:bug)?\#?\s?\d+)*")
-MATCH_BUG_NUMBERS = r"\#?\s?(\d+)"
-# URL pointing to a bug in the Debian bug tracker
-HREF_BUG_DEBIAN = "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s"
-
-MATCH_BUG_CLOSES_UBUNTU = r"lp:\s+\#\d+(?:,\s*\#\d+)*"
-HREF_BUG_UBUNTU = "https://bugs.launchpad.net/bugs/%s"
-
-# Regular expression to find cve references
-MATCH_CVE = "CVE-\d{4}-\d{4,}"
-HREF_CVE = "http://web.nvd.nist.gov/view/vuln/detail?vulnId=%s"
-
-# Map Debian sections to the PackageKit group name space
-SECTION_GROUP_MAP = {
-    "admin": pk.GroupEnum.ADMIN_TOOLS,
-    "base": pk.GroupEnum.SYSTEM,
-    "cli-mono": pk.GroupEnum.PROGRAMMING,
-    "comm": pk.GroupEnum.COMMUNICATION,
-    "database": pk.GroupEnum.SERVERS,
-    "debian-installer": pk.GroupEnum.SYSTEM,
-    "debug": pk.GroupEnum.PROGRAMMING,
-    "devel": pk.GroupEnum.PROGRAMMING,
-    "doc": pk.GroupEnum.DOCUMENTATION,
-    "editors": pk.GroupEnum.PUBLISHING,
-    "education": pk.GroupEnum.EDUCATION,
-    "electronics": pk.GroupEnum.ELECTRONICS,
-    "embedded": pk.GroupEnum.SYSTEM,
-    "fonts": pk.GroupEnum.FONTS,
-    "games": pk.GroupEnum.GAMES,
-    "gnome": pk.GroupEnum.DESKTOP_GNOME,
-    "gnu-r": pk.GroupEnum.PROGRAMMING,
-    "gnustep": pk.GroupEnum.DESKTOP_OTHER,
-    "graphics": pk.GroupEnum.GRAPHICS,
-    "hamradio": pk.GroupEnum.COMMUNICATION,
-    "haskell": pk.GroupEnum.PROGRAMMING,
-    "httpd": pk.GroupEnum.SERVERS,
-    "interpreters": pk.GroupEnum.PROGRAMMING,
-    "introspection": pk.GroupEnum.PROGRAMMING,
-    "java": pk.GroupEnum.PROGRAMMING,
-    "kde": pk.GroupEnum.DESKTOP_KDE,
-    "kernel": pk.GroupEnum.SYSTEM,
-    "libdevel": pk.GroupEnum.PROGRAMMING,
-    "libs": pk.GroupEnum.SYSTEM,
-    "lisp": pk.GroupEnum.PROGRAMMING,
-    "localization": pk.GroupEnum.LOCALIZATION,
-    "mail": pk.GroupEnum.INTERNET,
-    "math": pk.GroupEnum.SCIENCE,
-    "misc": pk.GroupEnum.OTHER,
-    "net": pk.GroupEnum.NETWORK,
-    "news": pk.GroupEnum.INTERNET,
-    "ocaml": pk.GroupEnum.PROGRAMMING,
-    "oldlibs": pk.GroupEnum.LEGACY,
-    "otherosfs": pk.GroupEnum.SYSTEM,
-    "perl": pk.GroupEnum.PROGRAMMING,
-    "php": pk.GroupEnum.PROGRAMMING,
-    "python": pk.GroupEnum.PROGRAMMING,
-    "ruby": pk.GroupEnum.PROGRAMMING,
-    "science": pk.GroupEnum.SCIENCE,
-    "shells": pk.GroupEnum.ADMIN_TOOLS,
-    "sound": pk.GroupEnum.MULTIMEDIA,
-    "tex": pk.GroupEnum.PUBLISHING,
-    "text": pk.GroupEnum.PUBLISHING,
-    "utils": pk.GroupEnum.ACCESSORIES,
-    "vcs": pk.GroupEnum.PROGRAMMING,
-    "video": pk.GroupEnum.MULTIMEDIA,
-    "virtual": pk.GroupEnum.COLLECTIONS,
-    "web": pk.GroupEnum.INTERNET,
-    "xfce": pk.GroupEnum.DESKTOP_OTHER,
-    "x11": pk.GroupEnum.DESKTOP_OTHER,
-    "zope": pk.GroupEnum.PROGRAMMING,
-    "unknown": pk.GroupEnum.UNKNOWN,
-    "alien": pk.GroupEnum.UNKNOWN,
-    "translations": pk.GroupEnum.LOCALIZATION,
-    "metapackages": pk.GroupEnum.COLLECTIONS,
-    "tasks": pk.GroupEnum.COLLECTIONS}
-
 PACKAGEKIT_DBUS_INTERFACE = "org.freedesktop.PackageKit"
 PACKAGEKIT_DBUS_SERVICE = "org.freedesktop.PackageKit"
 PACKAGEKIT_DBUS_PATH = "/org/freedesktop/PackageKit"
@@ -276,8 +184,6 @@ MAP_POLICY = {
     "org.freedesktop.packagekit.clear-offline-update": (
         policykit1.PK_ACTION_UPGRADE_PACKAGES)}
 
-NATIVE_ARCH = apt_pkg.get_architectures()[0]
-
 
 class PackageKit(core.DBusObject):
 
@@ -310,47 +216,6 @@ class PackageKit(core.DBusObject):
         self.netmon = networking.get_network_monitor()
         self.netmon.connect("network-state-changed",
                             self._on_network_state_changed)
-        self.roles = bitfield_summarize(pk.RoleEnum.REFRESH_CACHE,
-                                        pk.RoleEnum.UPDATE_PACKAGES,
-                                        pk.RoleEnum.INSTALL_PACKAGES,
-                                        pk.RoleEnum.INSTALL_FILES,
-                                        pk.RoleEnum.REMOVE_PACKAGES,
-                                        pk.RoleEnum.GET_UPDATES,
-                                        pk.RoleEnum.GET_UPDATE_DETAIL,
-                                        pk.RoleEnum.GET_PACKAGES,
-                                        pk.RoleEnum.GET_DETAILS,
-                                        pk.RoleEnum.GET_DEPENDS,
-                                        pk.RoleEnum.GET_REQUIRES,
-                                        pk.RoleEnum.SEARCH_NAME,
-                                        pk.RoleEnum.SEARCH_DETAILS,
-                                        pk.RoleEnum.SEARCH_GROUP,
-                                        pk.RoleEnum.SEARCH_FILE,
-                                        pk.RoleEnum.WHAT_PROVIDES,
-                                        pk.RoleEnum.REPO_ENABLE,
-                                        pk.RoleEnum.INSTALL_SIGNATURE,
-                                        pk.RoleEnum.REPAIR_SYSTEM,
-                                        pk.RoleEnum.CANCEL,
-                                        pk.RoleEnum.DOWNLOAD_PACKAGES)
-        if META_RELEASE_SUPPORT:
-            self.roles = bitfield_add(self.roles,
-                                      pk.RoleEnum.GET_DISTRO_UPGRADES)
-        self.filters = bitfield_summarize(pk.FilterEnum.INSTALLED,
-                                          pk.FilterEnum.NOT_INSTALLED,
-                                          pk.FilterEnum.FREE,
-                                          pk.FilterEnum.NOT_FREE,
-                                          pk.FilterEnum.GUI,
-                                          pk.FilterEnum.NOT_GUI,
-                                          pk.FilterEnum.COLLECTIONS,
-                                          pk.FilterEnum.NOT_COLLECTIONS,
-                                          pk.FilterEnum.SUPPORTED,
-                                          pk.FilterEnum.NOT_SUPPORTED,
-                                          pk.FilterEnum.ARCH,
-                                          pk.FilterEnum.NOT_ARCH,
-                                          pk.FilterEnum.NEWEST)
-        self.groups = bitfield_summarize(*SECTION_GROUP_MAP.values())
-        #FIXME: Add support for Plugins
-        self.provides = (pk.ProvidesEnum.ANY)
-
         self._get_network_state()
 
     @inline_callbacks
@@ -469,9 +334,10 @@ class PackageKit(core.DBusObject):
 
     @inline_callbacks
     def _create_transaction(self, sender):
-        pid, uid, cmdline = yield policykit1.get_proc_info_from_dbus_name(
+        pid, uid, gid, cmdline = yield policykit1.get_proc_info_from_dbus_name(
             sender, self.bus)
-        pktrans = PackageKitTransaction(pid, uid, cmdline, self.queue, sender)
+        pktrans = PackageKitTransaction(
+            pid, uid, gid, cmdline, self.queue, sender)
         return_value(pktrans.tid)
 
     # pylint: disable-msg=C0103,C0322
@@ -480,7 +346,7 @@ class PackageKit(core.DBusObject):
     def GetDaemonState(self):
         """Return the state of the currently running transactions."""
         pklog.info("GetDaemonState() was called")
-        #FIXME: Add some useful data here
+        # FIXME: Add some useful data here
         return "All is fine!"
 
     # pylint: disable-msg=C0103,C0322
@@ -508,11 +374,12 @@ class PackageKit(core.DBusObject):
                 "BackendName": dbus.String("aptdaemon"),
                 "BackendDescription": dbus.String("Compatibility layer"),
                 "BackendAuthor": dbus.String(__author__),
-                "Groups": dbus.UInt64(self.groups),
-                "Provides": dbus.UInt64(self.provides),
-                "Filters": dbus.UInt64(self.filters),
-                "Roles": dbus.UInt64(self.roles),
-                "MimeTypes": dbus.Array(["application/x-deb"], signature="s"),
+                "Groups": dbus.UInt64(self.queue.worker.groups),
+                "Provides": dbus.UInt64(self.queue.worker.provides),
+                "Filters": dbus.UInt64(self.queue.worker.filters),
+                "Roles": dbus.UInt64(self.queue.worker.roles),
+                "MimeTypes": dbus.Array(self.queue.worker.mime_types,
+                                        signature="s"),
                 "Locked": dbus.Boolean(False),
                 "NetworkState": dbus.UInt32(self.netmon.state),
                 "DistroId": dbus.String(self._get_distro_id())}
@@ -525,7 +392,7 @@ class PackageKit(core.DBusObject):
             distro, version, _codename = platform.dist()
             self._distro_id = "%s;%s;%s" % (distro or "unknown",
                                             version or "unknown",
-                                            NATIVE_ARCH)
+                                            self.queue.worker.NATIVE_ARCH)
         return self._distro_id
 
     def _on_network_state_changed(self, mon, state):
@@ -541,7 +408,7 @@ class PackageKit(core.DBusObject):
         pk_transactions = []
         for trans in self.queue.items:
             # We currently only emit PackageKit transaction
-            #FIXME: Should we use MergedTransaction for all transactions and
+            # FIXME: Should we use MergedTransaction for all transactions and
             #       ROLE_UNKOWN for aptdaemon only transactions?
             try:
                 pk_transactions.append(trans.pktrans.tid)
@@ -602,7 +469,7 @@ class MergedTransaction(core.Transaction
     def __init__(self, pktrans, role, queue, connect=True,
                  bus=None, packages=None, kwargs=None):
         core.Transaction.__init__(self, pktrans.tid[1:], role, queue,
-                                  pktrans.pid, pktrans.uid,
+                                  pktrans.pid, pktrans.uid, pktrans.gid,
                                   pktrans.cmdline, pktrans.sender,
                                   connect, bus, packages, kwargs)
         self.pktrans = pktrans
@@ -720,6 +587,8 @@ class MergedTransaction(core.Transaction
 
     def _remove_from_connection_no_raise(self):
         core.Transaction._remove_from_connection_no_raise(self)
+        if self.pktrans is None:
+            return False
         self.pktrans.Destroy()
         try:
             self.pktrans.remove_from_connection()
@@ -758,7 +627,7 @@ class PackageKitTransaction(core.DBusObj
 
     """Provides a PackageKit transaction object."""
 
-    def __init__(self, pid, uid, cmdline, queue, sender,
+    def __init__(self, pid, uid, gid, cmdline, queue, sender,
                  connect=True, bus=None):
         pklog.info("Initializing PackageKit transaction")
         bus_name = None
@@ -784,6 +653,7 @@ class PackageKitTransaction(core.DBusObj
         self._status = pk.StatusEnum.SETUP
         self._last_package = ""
         self.uid = dbus.UInt32(uid)
+        self.gid = dbus.UInt32(gid)
         self.pid = pid
         self.cmdline = cmdline
         self.role = pk.RoleEnum.UNKNOWN
@@ -1240,7 +1110,7 @@ class PackageKitTransaction(core.DBusObj
         yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
                                        "RemoveObsoletedDepends", autoremove,
                                        sender)
-        #FIXME: Implement allow_deps
+        # FIXME: Implement allow_deps
         yield self.trans._run(sender)
 
     # pylint: disable-msg=C0103,C0322
@@ -1472,7 +1342,7 @@ class PackageKitTransaction(core.DBusObj
         GLib.idle_add(defer_idle, self._get_distro_upgrades)
 
     def _get_distro_upgrades(self):
-        #FIXME: Should go into the worker after the threading branch is merged
+        # FIXME: Should go into the worker after the threading branch is merged
         #       It allows to run a nested loop until the download is finished
         self.allow_cancel = False
         self.percentage = 101
@@ -1485,13 +1355,13 @@ class PackageKitTransaction(core.DBusObj
             self.exit = pk.ExitEnum.FAILED
             return
 
-        #FIXME Evil to start the download during init
+        # FIXME Evil to start the download during init
         meta_release = GMetaRelease()
         meta_release.connect("download-done",
                              self._on_distro_upgrade_download_done)
 
     def _on_distro_upgrade_download_done(self, meta_release):
-        #FIXME: Add support for description
+        # FIXME: Add support for description
         if meta_release.new_dist is not None:
             self.DistroUpgrade("stable",
                                "%s %s" % (meta_release.new_dist.name,
@@ -2024,11 +1894,24 @@ class PackageKitTransaction(core.DBusObj
                                             kwargs=kwargs)
         yield self.trans._run(sender)
 
+    def _get_aptd_package_id(self, pk_id):
+        """Convert a PackageKit Package ID to the apt syntax.
+        e.g. xterm;235;i386;installed to xterm:i386=235
+        """
+        name, version, arch, data = pk_id.split(";")
+        id = name
+        if arch != self.queue.worker.NATIVE_ARCH and arch != "all":
+            id += ":%s" % arch
+        if version:
+            id += "=%s" % version
+        return id
+
     def _get_merged_trans(self, role, pkg_ids=None, pkg_type=None,
                           kwargs=None):
         if pkg_ids:
             packages = [[], [], [], [], [], []]
-            packages[pkg_type] = [get_aptd_package_id(pkg) for pkg in pkg_ids]
+            packages[pkg_type] = [self._get_aptd_package_id(pkg)
+                                  for pkg in pkg_ids]
         else:
             packages = None
         if self.trans:
@@ -2050,1117 +1933,6 @@ class PackageKitTransaction(core.DBusObj
         return trans
 
 
-class PackageKitWorker(worker.AptWorker):
-
-    _plugins = None
-
-    """Process PackageKit Query transactions."""
-
-    def _process_transaction(self, trans):
-        if (hasattr(trans, "pktrans") and
-            bitfield_contains(trans.pktrans.flags,
-                              pk.TransactionFlagEnum.SIMULATE)):
-            self._simulate_and_emit_packages(trans)
-            return False
-        else:
-            return worker.AptWorker._process_transaction(self, trans)
-
-    def _simulate_and_emit_packages(self, trans):
-        trans.status = aptd_enums.STATUS_RUNNING
-
-        self._simulate(trans)
-
-        # The simulate method lets the transaction fail in the case of an
-        # error
-        if trans.exit == aptd_enums.EXIT_UNFINISHED:
-            # It is a little bit complicated to get the packages but avoids
-            # a larger refactoring of apt.AptWorker._simulate()
-            for pkg in trans.depends[aptd_enums.PKGS_INSTALL]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.INSTALLING)
-            for pkg in trans.depends[aptd_enums.PKGS_REINSTALL]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.REINSTALLING)
-            for pkg in trans.depends[aptd_enums.PKGS_REMOVE]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.REMOVING)
-            for pkg in trans.depends[aptd_enums.PKGS_PURGE]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.REMOVING)
-            for pkg in trans.depends[aptd_enums.PKGS_UPGRADE]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.UPDATING, force_candidate=True)
-            for pkg in trans.depends[aptd_enums.PKGS_DOWNGRADE]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.DOWNGRADING,
-                                   force_candidate=True)
-            for pkg in trans.depends[aptd_enums.PKGS_KEEP]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.BLOCKED, force_candidate=True)
-            for pkg in trans.unauthenticated:
-                self._emit_package(trans, self._cache[pkg],
-                                   pk.InfoEnum.UNTRUSTED, force_candidate=True)
-            trans.status = aptd_enums.STATUS_FINISHED
-            trans.progress = 100
-            trans.exit = aptd_enums.EXIT_SUCCESS
-        tid = trans.tid[:]
-        self.trans = None
-        self.marked_tid = None
-        self._emit_transaction_done(trans)
-        pklog.info("Finished transaction %s", tid)
-
-    def query(self, trans):
-        """Run the worker"""
-        if trans.role != aptd_enums.ROLE_PK_QUERY:
-            raise TransactionFailed(aptd_enums.ERROR_UNKNOWN,
-                                    "The transaction doesn't seem to be "
-                                    "a query")
-        if trans.pktrans.role == pk.RoleEnum.RESOLVE:
-            self.resolve(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_UPDATES:
-            self.get_updates(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_UPDATE_DETAIL:
-            self.get_update_detail(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_PACKAGES:
-            self.get_packages(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_FILES:
-            self.get_files(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.SEARCH_NAME:
-            self.search_names(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.SEARCH_GROUP:
-            self.search_groups(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.SEARCH_DETAILS:
-            self.search_details(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.SEARCH_FILE:
-            self.search_files(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_DEPENDS:
-            self.get_depends(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_REQUIRES:
-            self.get_requires(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_DETAILS:
-            self.get_details(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.DOWNLOAD_PACKAGES:
-            self.download_packages(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.WHAT_PROVIDES:
-            self.what_provides(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.REPO_ENABLE:
-            self.repo_enable(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.INSTALL_SIGNATURE:
-            self.install_signature(trans, **trans.kwargs)
-        else:
-            raise TransactionFailed(aptd_enums.ERROR_UNKNOWN,
-                                    "Role %s isn't supported",
-                                    trans.pktrans.role)
-
-    def search_files(self, trans, filters, values):
-        """Implement org.freedesktop.PackageKit.Transaction.SearchFiles()
-
-        Works only for installed file if apt-file isn't installed.
-        """
-        trans.progress = 101
-
-        result_names = set()
-        # Optionally make use of apt-file's Contents cache to search for not
-        # installed files. But still search for installed files additionally
-        # to make sure that we provide up-to-date results
-        if (os.path.exists("/usr/bin/apt-file") and
-                not bitfield_contains(filters, pk.FilterEnum.INSTALLED)):
-            #FIXME: Make use of rapt-file on Debian if the network is available
-            #FIXME: Show a warning to the user if the apt-file cache is several
-            #       weeks old
-            pklog.debug("Using apt-file")
-            filenames_regex = []
-            for filename in values:
-                if filename.startswith("/"):
-                    pattern = "^%s$" % filename[1:].replace("/", "\/")
-                else:
-                    pattern = "\/%s$" % filename
-                filenames_regex.append(pattern)
-            cmd = ["/usr/bin/apt-file", "--regexp", "--non-interactive",
-                   "--package-only", "find", "|".join(filenames_regex)]
-            pklog.debug("Calling: %s" % cmd)
-            apt_file = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-                                        stderr=subprocess.PIPE)
-            stdout, stderr = apt_file.communicate()
-            if apt_file.returncode == 0:
-                #FIXME: Actually we should check if the file is part of the
-                #       candidate, e.g. if unstable and experimental are
-                #       enabled and a file would only be part of the
-                #       experimental version
-                result_names.update(stdout.split())
-                self._emit_visible_packages_by_name(trans, filters,
-                                                    result_names)
-            else:
-                raise TransactionFailed(aptd_enums.ERROR_INTERNAL_ERROR,
-                                        "%s %s" % (stdout, stderr))
-        # Search for installed files
-        filenames_regex = []
-        for filename in values:
-            if filename.startswith("/"):
-                pattern = "^%s$" % filename.replace("/", "\/")
-            else:
-                pattern = ".*\/%s$" % filename
-            filenames_regex.append(pattern)
-        files_pattern = re.compile("|".join(filenames_regex))
-        for pkg in self._iterate_packages():
-            if pkg.name in result_names:
-                continue
-            for installed_file in self._get_installed_files(pkg):
-                if files_pattern.match(installed_file):
-                    self._emit_visible_package(trans, filters, pkg)
-                    break
-
-    def search_groups(self, trans, filters, values):
-        """Implement org.freedesktop.PackageKit.Transaction.SearchGroups()"""
-        #FIXME: Handle repo and category search
-        trans.progress = 101
-
-        for pkg in self._iterate_packages():
-            group_str = pk.group_enum_to_string(self._get_package_group(pkg))
-            if group_str in values:
-                self._emit_visible_package(trans, filters, pkg)
-
-    def search_names(self, trans, filters, values):
-        """Implement org.freedesktop.PackageKit.Transaction.SearchNames()"""
-        def matches(searches, text):
-            for search in searches:
-                if not search in text:
-                    return False
-            return True
-        trans.progress = 101
-
-        for pkg_name in list(self._cache.keys()):
-            if matches(values, pkg_name):
-                self._emit_all_visible_pkg_versions(trans, filters,
-                                                    self._cache[pkg_name])
-
-    def search_details(self, trans, filters, values):
-        """Implement org.freedesktop.PackageKit.Transaction.SearchDetails()"""
-        trans.progress = 101
-
-        if XAPIAN_SUPPORT is 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(XAPIAN_DB)
-            parser = xapian.QueryParser()
-            parser.set_default_op(xapian.Query.OP_AND)
-            query = parser.parse_query(" ".join(values), search_flags)
-            enquire = xapian.Enquire(db)
-            enquire.set_query(query)
-            matches = enquire.get_mset(0, 1000)
-            for pkg_name in (match.document.get_data()
-                             for match in enquire.get_mset(0, 1000)):
-                if pkg_name in self._cache:
-                    self._emit_visible_package(trans, filters,
-                                               self._cache[pkg_name])
-        else:
-            def matches(searches, text):
-                for search in searches:
-                    if not search in text:
-                        return False
-                return True
-            pklog.debug("Performing apt cache based search")
-            values = [val.lower() for val in values]
-            for pkg in self._iterate_packages():
-                txt = pkg.name
-                try:
-                    txt += pkg.candidate.raw_description.lower()
-                    txt += pkg.candidate._translated_records.long_desc.lower()
-                except AttributeError:
-                    pass
-                if matches(values, txt):
-                    self._emit_visible_package(trans, filters, pkg)
-
-    def get_updates(self, trans, filters):
-        """Only report updates which can be installed safely: Which can depend
-        on the installation of additional packages but which don't require
-        the removal of already installed packages or block any other update.
-        """
-        def succeeds_security_update(pkg):
-            """
-            Return True if an update succeeds a previous security update
-
-            An example would be a package with version 1.1 in the security
-            archive and 1.1.1 in the archive of proposed updates or the
-            same version in both archives.
-            """
-            for version in pkg.versions:
-                # Only check versions between the installed and the candidate
-                if (pkg.installed and
-                    apt_pkg.version_compare(version.version,
-                                            pkg.installed.version) <= 0 and
-                    apt_pkg.version_compare(version.version,
-                                            pkg.candidate.version) > 0):
-                    continue
-                for origin in version.origins:
-                    if (origin.origin in ["Debian", "Ubuntu"] and
-                            (origin.archive.endswith("-security") or
-                             origin.label == "Debian-Security") and
-                            origin.trusted):
-                        return True
-            return False
-        #FIXME: Implment the basename filter
-        self.cancellable = False
-        self.progress = 101
-        # Start with a safe upgrade
-        try:
-            self._cache.upgrade(dist_upgrade=True)
-        except SystemError:
-            pass
-        for pkg in self._iterate_packages():
-            if not pkg.is_upgradable:
-                continue
-            # This may occur on pinned packages which have been updated to
-            # later version than the pinned one
-            if not pkg.candidate.origins:
-                continue
-            if not pkg.marked_upgrade:
-                #FIXME: Would be nice to all show why
-                self._emit_package(trans, pkg, pk.InfoEnum.BLOCKED,
-                                   force_candidate=True)
-                continue
-            # The update can be safely installed
-            info = pk.InfoEnum.NORMAL
-            # Detect the nature of the upgrade (e.g. security, enhancement)
-            candidate_origin = pkg.candidate.origins[0]
-            archive = candidate_origin.archive
-            origin = candidate_origin.origin
-            trusted = candidate_origin.trusted
-            label = candidate_origin.label
-            if origin in ["Debian", "Ubuntu"] and trusted is True:
-                if archive.endswith("-security") or label == "Debian-Security":
-                    info = pk.InfoEnum.SECURITY
-                elif succeeds_security_update(pkg):
-                    pklog.debug("Update of %s succeeds a security update. "
-                                "Raising its priority." % pkg.name)
-                    info = pk.InfoEnum.SECURITY
-                elif archive.endswith("-backports"):
-                    info = pk.InfoEnum.ENHANCEMENT
-                elif archive.endswith("-updates"):
-                    info = pk.InfoEnum.BUGFIX
-            if origin in ["Backports.org archive"] and trusted is True:
-                info = pk.InfoEnum.ENHANCEMENT
-            self._emit_package(trans, pkg, info, force_candidate=True)
-        self._emit_require_restart(trans)
-
-    def _emit_require_restart(self, trans):
-        """Emit RequireRestart if required."""
-        # Check for a system restart
-        if self.is_reboot_required():
-            trans.pktrans.RequireRestart(pk.RestartEnum.SYSTEM, "")
-
-    def get_update_detail(self, trans, package_ids):
-        """
-        Implement the {backend}-get-update-details functionality
-        """
-        def get_bug_urls(changelog):
-            """
-            Create a list of urls pointing to closed bugs in the changelog
-            """
-            urls = []
-            for r in re.findall(MATCH_BUG_CLOSES_DEBIAN, changelog,
-                                re.IGNORECASE | re.MULTILINE):
-                urls.extend([HREF_BUG_DEBIAN % bug for bug in
-                             re.findall(MATCH_BUG_NUMBERS, r)])
-            for r in re.findall(MATCH_BUG_CLOSES_UBUNTU, changelog,
-                                re.IGNORECASE | re.MULTILINE):
-                urls.extend([HREF_BUG_UBUNTU % bug for bug in
-                             re.findall(MATCH_BUG_NUMBERS, r)])
-            return urls
-
-        def get_cve_urls(changelog):
-            """
-            Create a list of urls pointing to cves referred in the changelog
-            """
-            return [HREF_CVE % c for c in re.findall(MATCH_CVE, changelog,
-                                                     re.MULTILINE)]
-
-        trans.progress = 0
-        trans.cancellable = False
-        trans.pktrans.status = pk.StatusEnum.DOWNLOAD_CHANGELOG
-        total = len(package_ids)
-        count = 1
-        old_locale = locale.getlocale(locale.LC_TIME)
-        locale.setlocale(locale.LC_TIME, "C")
-        for pkg_id in package_ids:
-            self._iterate_mainloop()
-            trans.progress = count * 100 / total
-            count += 1
-            pkg = self._get_package_by_id(pkg_id)
-            # FIXME add some real data
-            if pkg.installed.origins:
-                installed_origin = pkg.installed.origins[0].label
-                # APT returns a str with Python 2
-                if isinstance(installed_origin, bytes):
-                    installed_origin = installed_origin.decode("UTF-8")
-            else:
-                installed_origin = ""
-            updates = ["%s;%s;%s;%s" % (pkg.name, pkg.installed.version,
-                                        pkg.installed.architecture,
-                                        installed_origin)]
-            # Get the packages which will be replaced by the update
-            obsoletes = set()
-            if pkg.candidate:
-                for dep_group in pkg.candidate.get_dependencies("Replaces"):
-                    for dep in dep_group:
-                        try:
-                            obs = self._cache[dep.name]
-                        except KeyError:
-                            continue
-                        if not obs.installed:
-                            continue
-                        if dep.relation:
-                            cmp = apt_pkg.version_compare(
-                                obs.candidate.version,
-                                dep.version)
-                            # Same version
-                            if cmp == 0 and dep.relation in [">", "<"]:
-                                continue
-                            # Installed version higer
-                            elif cmp < 0 and dep.relation in ["<"]:
-                                continue
-                            # Installed version lower
-                            elif cmp > 0 and dep.relation in [">"]:
-                                continue
-                        obs_id = self._get_id_from_version(obs.installed)
-                        obsoletes.add(obs_id)
-            vendor_urls = []
-            restart = pk.RestartEnum.NONE
-            update_text = ""
-            state = pk.UpdateStateEnum.UNKNOWN
-            # FIXME: Add support for Ubuntu and a better one for Debian
-            if (pkg.candidate and pkg.candidate.origins[0].trusted and
-                    pkg.candidate.origins[0].label == "Debian"):
-                archive = pkg.candidate.origins[0].archive
-                if archive == "stable":
-                    state = pk.UpdateStateEnum.STABLE
-                elif archive == "testing":
-                    state = pk.UpdateStateEnum.TESTING
-                elif archive == "unstable":
-                    state = pk.UpdateStateEnum.UNSTABLE
-            issued = ""
-            updated = ""
-            #FIXME: make this more configurable. E.g. a dbus update requires
-            #       a reboot on Ubuntu but not on Debian
-            if (pkg.name.startswith("linux-image-") or
-                    pkg.name in ["libc6", "dbus"]):
-                restart == pk.RestartEnum.SYSTEM
-            changelog_dir = apt_pkg.config.find_dir("Dir::Cache::Changelogs")
-            if changelog_dir == "/":
-                changelog_dir = os.path.join(apt_pkg.config.find_dir("Dir::"
-                                                                     "Cache"),
-                                             "Changelogs")
-            filename = os.path.join(changelog_dir,
-                                    "%s_%s.gz" % (pkg.name,
-                                                  pkg.candidate.version))
-            changelog_raw = ""
-            if os.path.exists(filename):
-                pklog.debug("Reading changelog from cache")
-                changelog_file = gzip.open(filename, "rb")
-                try:
-                    changelog_raw = changelog_file.read().decode("UTF-8")
-                except:
-                    pass
-                finally:
-                    changelog_file.close()
-            if not changelog_raw:
-                pklog.debug("Downloading changelog")
-                changelog_raw = pkg.get_changelog()
-                # The internal download error string of python-apt ist not
-                # provided as unicode object
-                if not isinstance(changelog_raw, str):
-                    changelog_raw = changelog_raw.decode("UTF-8")
-                # Cache the fetched changelog
-                if not os.path.exists(changelog_dir):
-                    os.makedirs(changelog_dir)
-                # Remove old cached changelogs
-                pattern = os.path.join(changelog_dir, "%s_*" % pkg.name)
-                for old_changelog in glob.glob(pattern):
-                    os.remove(os.path.join(changelog_dir, old_changelog))
-                changelog_file = gzip.open(filename, mode="wb")
-                try:
-                    changelog_file.write(changelog_raw.encode("UTF-8"))
-                finally:
-                    changelog_file.close()
-            # Convert the changelog to markdown syntax
-            changelog = ""
-            for line in changelog_raw.split("\n"):
-                if line == "":
-                    changelog += " \n"
-                else:
-                    changelog += "    %s  \n" % line
-                if line.startswith(pkg.candidate.source_name):
-                    match = re.match(r"(?P<source>.+) \((?P<version>.*)\) "
-                                     "(?P<dist>.+); urgency=(?P<urgency>.+)",
-                                     line)
-                    update_text += "%s\n%s\n\n" % (match.group("version"),
-                                                   "=" *
-                                                   len(match.group("version")))
-                elif line.startswith("  "):
-                    #FIXME: The GNOME PackageKit markup parser doesn't support
-                    #       monospaced yet
-                    #update_text += "  %s  \n" % line
-                    update_text += "%s\n\n" % line
-                elif line.startswith(" --"):
-                    #FIXME: Add %z for the time zone - requires Python 2.6
-                    update_text += "  \n"
-                    match = re.match("^ -- (?P<maintainer>.+) (?P<mail><.+>)  "
-                                     "(?P<date>.+) (?P<offset>[-\+][0-9]+)$",
-                                     line)
-                    if not match:
-                        continue
-                    try:
-                        date = datetime.datetime.strptime(match.group("date"),
-                                                          "%a, %d %b %Y "
-                                                          "%H:%M:%S")
-                    except ValueError:
-                        continue
-                    issued = date.isoformat()
-                    if not updated:
-                        updated = date.isoformat()
-            if issued == updated:
-                updated = ""
-            bugzilla_urls = get_bug_urls(changelog)
-            cve_urls = get_cve_urls(changelog)
-            trans.emit_update_detail(pkg_id, updates, obsoletes, vendor_urls,
-                                     bugzilla_urls, cve_urls, restart,
-                                     update_text, changelog,
-                                     state, issued, updated)
-        locale.setlocale(locale.LC_TIME, old_locale)
-
-    def get_details(self, trans, package_ids):
-        """Implement org.freedesktop.PackageKit.Transaction.GetDetails()"""
-        trans.progress = 101
-
-        for pkg_id in package_ids:
-            version = self._get_version_by_id(pkg_id)
-            #FIXME: We need more fine grained license information!
-            origins = version.origins
-            if (origins and
-                    origins[0].component in ["main", "universe"] and
-                    origins[0].origin in ["Debian", "Ubuntu"]):
-                license = "free"
-            else:
-                license = "unknown"
-            group = self._get_package_group(version.package)
-            trans.emit_details(pkg_id, license, group, version.description,
-                               version.homepage, version.size)
-
-    def get_packages(self, trans, filters):
-        """Implement org.freedesktop.PackageKit.Transaction.GetPackages()"""
-        self.progress = 101
-
-        for pkg in self._iterate_packages():
-            if self._is_package_visible(pkg, filters):
-                self._emit_package(trans, pkg)
-
-    def resolve(self, trans, filters, packages):
-        """Implement org.freedesktop.PackageKit.Transaction.Resolve()"""
-        trans.status = aptd_enums.STATUS_QUERY
-        trans.progress = 101
-        self.cancellable = False
-
-        for name in packages:
-            try:
-                # Check if the name is a valid package id
-                version = self._get_version_by_id(name)
-            except ValueError:
-                pass
-            else:
-                if self._is_version_visible(version, filters):
-                    self._emit_pkg_version(trans, version)
-                continue
-            # The name seems to be a normal name
-            try:
-                pkg = self._cache[name]
-            except KeyError:
-                raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
-                                        "Package name %s could not be "
-                                        "resolved.", name)
-            else:
-                self._emit_all_visible_pkg_versions(trans, filters, pkg)
-
-    def get_depends(self, trans, filters, package_ids, recursive):
-        """Emit all dependencies of the given package ids.
-
-        Doesn't support recursive dependency resolution.
-        """
-        def emit_blocked_dependency(base_dependency, pkg=None,
-                                    filters=pk.FilterEnum.NONE):
-            """Send a blocked package signal for the given
-            apt.package.BaseDependency.
-            """
-            if pk.FilterEnum.INSTALLED in filters:
-                return
-            if pkg:
-                summary = pkg.candidate.summary
-                filters = bitfield_remove(filters, pk.FilterEnum.NOT_INSTALLED)
-                if not self._is_package_visible(pkg, filters):
-                    return
-            else:
-                summary = ""
-            if base_dependency.relation:
-                version = "%s%s" % (base_dependency.relation,
-                                    base_dependency.version)
-            else:
-                version = base_dependency.version
-            trans.emit_package("%s;%s;;" % (base_dependency.name, version),
-                               pk.InfoEnum.BLOCKED, summary)
-
-        def check_dependency(pkg, base_dep):
-            """Check if the given apt.package.Package can satisfy the
-            BaseDepenendcy and emit the corresponding package signals.
-            """
-            if not self._is_package_visible(pkg, filters):
-                return
-            if base_dep.version:
-                satisfied = False
-                # Sort the version list to check the installed
-                # and candidate before the other ones
-                ver_list = list(pkg.versions)
-                if pkg.installed:
-                    ver_list.remove(pkg.installed)
-                    ver_list.insert(0, pkg.installed)
-                if pkg.candidate:
-                    ver_list.remove(pkg.candidate)
-                    ver_list.insert(0, pkg.candidate)
-                for dep_ver in ver_list:
-                    if apt_pkg.check_dep(dep_ver.version,
-                                         base_dep.relation,
-                                         base_dep.version):
-                        self._emit_pkg_version(trans, dep_ver)
-                        satisfied = True
-                        break
-                if not satisfied:
-                    emit_blocked_dependency(base_dep, pkg, filters)
-            else:
-                self._emit_package(trans, pkg)
-
-        # Setup the transaction
-        self.status = aptd_enums.STATUS_RESOLVING_DEP
-        trans.progress = 101
-        self.cancellable = True
-
-        dependency_types = ["PreDepends", "Depends"]
-        if apt_pkg.config["APT::Install-Recommends"]:
-            dependency_types.append("Recommends")
-        for id in package_ids:
-            version = self._get_version_by_id(id)
-            for dependency in version.get_dependencies(*dependency_types):
-                # Walk through all or_dependencies
-                for base_dep in dependency.or_dependencies:
-                    if self._cache.is_virtual_package(base_dep.name):
-                        # Check each proivider of a virtual package
-                        for provider in self._cache.get_providing_packages(
-                                base_dep.name):
-                            check_dependency(provider, base_dep)
-                    elif base_dep.name in self._cache:
-                        check_dependency(self._cache[base_dep.name], base_dep)
-                    else:
-                        # The dependency does not exist
-                        emit_blocked_dependency(trans, base_dep,
-                                                filters=filters)
-
-    def get_requires(self, trans, filters, package_ids, recursive):
-        """Emit all packages which depend on the given ids.
-
-        Recursive searching is not supported.
-        """
-        self.status = aptd_enums.STATUS_RESOLVING_DEP
-        self.progress = 101
-        self.cancellable = True
-        for id in package_ids:
-            version = self._get_version_by_id(id)
-            for pkg in self._iterate_packages():
-                if not self._is_package_visible(pkg, filters):
-                    continue
-                if pkg.is_installed:
-                    pkg_ver = pkg.installed
-                elif pkg.candidate:
-                    pkg_ver = pkg.candidate
-                for dependency in pkg_ver.dependencies:
-                    satisfied = False
-                    for base_dep in dependency.or_dependencies:
-                        if (version.package.name == base_dep.name or
-                                base_dep.name in version.provides):
-                            satisfied = True
-                            break
-                    if satisfied:
-                        self._emit_package(trans, pkg)
-                        break
-
-    def download_packages(self, trans, store_in_cache, package_ids):
-        """Implement the DownloadPackages functionality.
-
-        The store_in_cache parameter gets ignored.
-        """
-        def get_download_details(ids):
-            """Calculate the start and end point of a package download
-            progress.
-            """
-            total = 0
-            downloaded = 0
-            versions = []
-            # Check if all ids are vaild and calculate the total download size
-            for id in ids:
-                pkg_ver = self._get_version_by_id(id)
-                if not pkg_ver.downloadable:
-                    raise TransactionFailed(
-                        aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED,
-                        "package %s isn't downloadable" % id)
-                total += pkg_ver.size
-                versions.append((id, pkg_ver))
-            for id, ver in versions:
-                start = downloaded * 100 / total
-                end = start + ver.size * 100 / total
-                yield id, ver, start, end
-                downloaded += ver.size
-        trans.status = aptd_enums.STATUS_DOWNLOADING
-        trans.cancellable = True
-        trans.progress = 10
-        # Check the destination directory
-        if store_in_cache:
-            dest = apt_pkg.config.find_dir("Dir::Cache::archives")
-        else:
-            dest = tempfile.mkdtemp(prefix="aptdaemon-download")
-        if not os.path.isdir(dest) or not os.access(dest, os.W_OK):
-            raise TransactionFailed(aptd_enums.ERROR_INTERNAL_ERROR,
-                                    "The directory '%s' is not writable" %
-                                    dest)
-        # Start the download
-        for id, ver, start, end in get_download_details(package_ids):
-            progress = DaemonAcquireProgress(trans, start, end)
-            self._emit_pkg_version(trans, ver, pk.InfoEnum.DOWNLOADING)
-            try:
-                ver.fetch_binary(dest, progress)
-            except Exception as error:
-                raise TransactionFailed(
-                    aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED, str(error))
-            else:
-                path = os.path.join(dest, os.path.basename(ver.filename))
-                trans.emit_files(id, [path])
-                self._emit_pkg_version(trans, ver, pk.InfoEnum.FINISHED)
-
-    def get_files(self, trans, package_ids):
-        """Emit the Files signal which includes the files included in a package
-        Apt only supports this for installed packages
-        """
-        for id in package_ids:
-            pkg = self._get_package_by_id(id)
-            trans.emit_files(id, self._get_installed_files(pkg))
-
-    def what_provides(self, trans, filters, provides_type, values):
-        """Emit all packages which provide the given type and search value."""
-        self._init_plugins()
-
-        supported_type = False
-        provides_type_str = pk.provides_enum_to_string(provides_type)
-
-        # run plugins
-        for plugin in self._plugins.get("what_provides", []):
-            pklog.debug("calling what_provides plugin %s %s",
-                        str(plugin), str(filters))
-            for search_item in values:
-                try:
-                    for package in plugin(self._cache, provides_type_str,
-                                          search_item):
-                        self._emit_visible_package(trans, filters, package)
-                    supported_type = True
-                except NotImplementedError:
-                    # keep supported_type as False
-                    pass
-
-        if not supported_type and provides_type != pk.ProvidesEnum.ANY:
-            # none of the plugins felt responsible for this type
-            raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
-                                    "Query type '%s' is not supported" %
-                                    pk.provides_enum_to_string(provides_type))
-
-    def repo_enable(self, trans, repo_id, enabled):
-        """Enable or disable a repository."""
-        if not enabled:
-            raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
-                                    "Disabling repositories is not "
-                                    "implemented")
-
-        fields = repo_id.split()
-        if len(fields) < 3 or fields[0] not in ('deb', 'deb-src'):
-            raise TransactionFailed(
-                aptd_enums.ERROR_NOT_SUPPORTED,
-                "Unknown repository ID format: %s" % repo_id)
-
-        self.add_repository(trans, fields[0], fields[1], fields[2],
-                            fields[3:], '', None)
-
-    def install_signature(self, trans, sig_type, key_id, package_id):
-        """Install an archive key."""
-        if sig_type != pk.SigTypeEnum.GPG:
-            raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
-                                    "Type %s is not supported" % sig_type)
-        try:
-            keyserver = os.environ["APTDAEMON_KEYSERVER"]
-        except KeyError:
-            if platform.dist()[0] == "Ubuntu":
-                keyserver = "hkp://keyserver.ubuntu.com:80"
-            else:
-                keyserver = "hkp://keys.gnupg.net"
-        self.add_vendor_key_from_keyserver(trans, key_id, keyserver)
-
-    # Helpers
-
-    def _get_id_from_version(self, version):
-        """Return the package id of an apt.package.Version instance."""
-        if version.origins:
-            origin = version.origins[0].label
-            # APT returns a str with Python 2
-            if isinstance(origin, bytes):
-                origin = origin.decode("UTF-8")
-        else:
-            origin = ""
-        if version.architecture in [NATIVE_ARCH, "all"]:
-            name = version.package.name
-        else:
-            name = version.package.name.split(":")[0]
-        id = "%s;%s;%s;%s" % (name, version.version,
-                              version.architecture, origin)
-        return id
-
-    def _emit_package(self, trans, pkg, info=None, force_candidate=False):
-        """
-        Send the Package signal for a given apt package
-        """
-        if (not pkg.is_installed or force_candidate) and pkg.candidate:
-            self._emit_pkg_version(trans, pkg.candidate, info)
-        elif pkg.is_installed:
-            self._emit_pkg_version(trans, pkg.installed, info)
-        else:
-            pklog.debug("Package %s hasn't got any version." % pkg.name)
-
-    def _emit_pkg_version(self, trans, version, info=None):
-        """Emit the Package signal of the given apt.package.Version."""
-        id = self._get_id_from_version(version)
-        section = version.section.split("/")[-1]
-        if not info:
-            if version == version.package.installed:
-                if section == "metapackages":
-                    info = pk.InfoEnum.COLLECTION_INSTALLED
-                else:
-                    info = pk.InfoEnum.INSTALLED
-            else:
-                if section == "metapackages":
-                    info = pk.InfoEnum.COLLECTION_AVAILABLE
-                else:
-                    info = pk.InfoEnum.AVAILABLE
-        trans.emit_package(info, id, version.summary)
-
-    def _emit_all_visible_pkg_versions(self, trans, filters, pkg):
-        """Emit all available versions of a package."""
-        for version in pkg.versions:
-            if self._is_version_visible(version, filters):
-                self._emit_pkg_version(trans, version)
-
-    def _emit_visible_package(self, trans, filters, pkg, info=None):
-        """
-        Filter and emit a package
-        """
-        if self._is_package_visible(pkg, filters):
-            self._emit_package(trans, pkg, info)
-
-    def _emit_visible_packages(self, trans, filters, pkgs, info=None):
-        """
-        Filter and emit packages
-        """
-        for pkg in pkgs:
-            if self._is_package_visible(pkg, filters):
-                self._emit_package(trans, pkg, info)
-
-    def _emit_visible_packages_by_name(self, trans, filters, pkgs, info=None):
-        """
-        Find the packages with the given namens. Afterwards filter and emit
-        them
-        """
-        for name in pkgs:
-            if (name in self._cache and
-                    self._is_package_visible(self._cache[name], filters)):
-                self._emit_package(trans, self._cache[name], info)
-
-    def _is_version_visible(self, version, filters):
-        """Return True if the package version is matched by the given
-        filters.
-        """
-        if filters == pk.FilterEnum.NONE:
-            return True
-        if (bitfield_contains(filters, pk.FilterEnum.NEWEST) and
-                version.package.candidate != version):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.INSTALLED) and
-                version.package.installed != version):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_INSTALLED) and
-                version.package.installed == version):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.SUPPORTED) and
-                not self._is_package_supported(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_SUPPORTED) and
-                self._is_package_supported(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.FREE) and
-                not self._is_version_free(version)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_FREE) and
-                self._is_version_free(version)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.GUI) and
-                not self._has_package_gui(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_GUI) and
-                self._has_package_gui(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.COLLECTIONS) and
-                not self._is_package_collection(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_COLLECTIONS) and
-                self._is_package_collection(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.DEVELOPMENT) and
-                not self._is_package_devel(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_DEVELOPMENT) and
-                self._is_package_devel(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.ARCH) and
-                not version.architecture in [NATIVE_ARCH, "all"]):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_ARCH) and
-                version.architecture in [NATIVE_ARCH, "all"]):
-            return False
-        return True
-
-    def _is_package_visible(self, pkg, filters):
-        """Return True if the package is matched by the given filters."""
-        if filters == pk.FilterEnum.NONE:
-            return True
-        if (bitfield_contains(filters, pk.FilterEnum.INSTALLED) and
-                not pkg.is_installed):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_INSTALLED) and
-                pkg.is_installed):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.SUPPORTED) and
-                not self._is_package_supported(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_SUPPORTED) and
-                self._is_package_supported(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.FREE) and
-                not self._is_package_free(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_FREE) and
-                self._is_package_free(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.GUI) and
-                not self._has_package_gui(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_GUI) and
-                self._has_package_gui(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.COLLECTIONS) and
-                not self._is_package_collection(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_COLLECTIONS) and
-                self._is_package_collection(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.DEVELOPMENT) and
-                not self._is_package_devel(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_DEVELOPMENT) and
-                self._is_package_devel(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.ARCH) and
-                ":" in pkg.name):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_ARCH) and
-                not ":" in pkg.name):
-            return False
-        return True
-
-    def _is_package_free(self, pkg):
-        """Return True if we can be sure that the package's license is a
-        free one
-        """
-        if not pkg.candidate:
-            return False
-        return self._is_version_free(pkg.candidate)
-
-    def _is_version_free(self, version):
-        """Return True if we can be sure that the package version has got
-        a free license.
-        """
-        origins = version.origins
-        return (origins and
-                ((origins[0].origin == "Ubuntu" and
-                  origins[0].component in ["main", "universe"]) or
-                 (origins[0].origin == "Debian" and
-                  origins[0].component == "main")) and
-                origins[0].trusted)
-
-    def _is_package_collection(self, pkg):
-        """Return True if the package is a metapackge
-        """
-        section = pkg.section.split("/")[-1]
-        return section == "metapackages"
-
-    def _has_package_gui(self, pkg):
-        #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 _is_package_devel(self, pkg):
-        return (pkg.name.endswith("-dev") or pkg.name.endswith("-dbg") or
-                pkg.section.split('/')[-1].lower() in ['devel', 'libdevel'])
-
-    def _is_package_supported(self, pkg):
-        if not pkg.candidate:
-            return False
-        origins = pkg.candidate.origins
-        return (origins and
-                ((origins[0].origin == "Ubuntu" and
-                  origins[0].component in ["main", "restricted"]) or
-                 (origins[0].origin == "Debian" and
-                  origins[0].component == "main")) and
-                origins[0].trusted)
-
-    def _get_package_by_id(self, id):
-        """Return the apt.package.Package corresponding to the given
-        package id.
-
-        If the package isn't available error out.
-        """
-        version = self._get_version_by_id(id)
-        return version.package
-
-    def _get_version_by_id(self, id):
-        """Return the apt.package.Version corresponding to the given
-        package id.
-
-        If the version isn't available error out.
-        """
-        name, version_string, arch, data = id.split(";", 4)
-        if arch and not arch in [NATIVE_ARCH, "all"]:
-            name += ":%s" % arch
-        try:
-            pkg = self._cache[name]
-        except KeyError:
-            raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
-                                    "There isn't any package named %s",
-                                    name)
-        try:
-            version = pkg.versions[version_string]
-        except:
-            raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
-                                    "Verion %s doesn't exist",
-                                    version_string)
-        if version.architecture != arch:
-            raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
-                                    "Version %s of %s isn't available "
-                                    "for architecture %s",
-                                    pkg.name, version.version, arch)
-        return version
-
-    def _get_installed_files(self, pkg):
-        """
-        Return the list of unicode names of the files which have
-        been installed by the package
-
-        This method should be obsolete by the
-        apt.package.Package.installedFiles attribute as soon as the
-        consolidate branch of python-apt gets merged
-        """
-        path = os.path.join(apt_pkg.config["Dir"],
-                            "var/lib/dpkg/info/%s.list" % pkg.name)
-        try:
-            with open(path, 'rb') as f:
-                files = f.read().decode('UTF-8').split("\n")
-        except IOError:
-            return []
-        return files
-
-    def _get_package_group(self, pkg):
-        """
-        Return the packagekit group corresponding to the package's section
-        """
-        section = pkg.section.split("/")[-1]
-        if section in SECTION_GROUP_MAP:
-            return SECTION_GROUP_MAP[section]
-        else:
-            pklog.warn("Unkown package section %s of %s" % (pkg.section,
-                                                            pkg.name))
-            return pk.GroupEnum.UNKNOWN
-
-    def _init_plugins(self):
-        """Initialize PackageKit apt backend plugins.
-        Do nothing if plugins are already initialized.
-        """
-        if self._plugins is not None:
-            return
-
-        if not pkg_resources:
-            return
-
-        self._plugins = {}  # plugin_name -> [plugin_fn1, ...]
-
-        # just look in standard Python paths for now
-        dists, errors = pkg_resources.working_set.find_plugins(
-            pkg_resources.Environment())
-        for dist in dists:
-            pkg_resources.working_set.add(dist)
-        for plugin_name in ["what_provides"]:
-            for entry_point in pkg_resources.iter_entry_points(
-                    "packagekit.apt.plugins", plugin_name):
-                try:
-                    plugin = entry_point.load()
-                except Exception as e:
-                    pklog.warning("Failed to load %s from plugin %s: %s" % (
-                        plugin_name, str(entry_point.dist), str(e)))
-                    continue
-                pklog.debug("Loaded %s from plugin %s" % (
-                    plugin_name, str(entry_point.dist)))
-                self._plugins.setdefault(plugin_name, []).append(plugin)
-
-    def _apply_changes(self, trans, fetch_range=(15, 50),
-                       install_range=(50, 90)):
-        """Apply changes and emit RequireRestart accordingly."""
-        if hasattr(trans, "pktrans"):
-            # Cache the ids of the to be changed packages, since we will
-            # only get the package name during download/install time
-            for pkg in self._cache.get_changes():
-                if pkg.marked_delete or pkg.marked_reinstall:
-                    pkg_id = self._get_id_from_version(pkg.installed)
-                else:
-                    pkg_id = self._get_id_from_version(pkg.candidate)
-                trans.pktrans.pkg_id_cache[pkg.name] = pkg_id
-
-        worker.AptWorker._apply_changes(self, trans, fetch_range,
-                                        install_range)
-
-        if (hasattr(trans, "pktrans") and
-            (trans.role == aptd_enums.ROLE_UPGRADE_SYSTEM or
-             trans.packages[aptd_enums.PKGS_UPGRADE] or
-             trans.depends[aptd_enums.PKGS_UPGRADE])):
-            self._emit_require_restart(trans)
-
-
 if META_RELEASE_SUPPORT:
 
     class GMetaRelease(GObject.GObject, MetaReleaseCore):
@@ -3206,25 +1978,12 @@ def get_pk_error_enum(enum):
         return pk.ErrorEnum.UNKNOWN
 
 
-def get_aptd_package_id(pk_id):
-    """Convert a PackageKit Package ID to the apt syntax.
-    e.g. xterm;235;i386;installed to xterm:i386=235
-    """
-    name, version, arch, data = pk_id.split(";")
-    id = name
-    if arch != NATIVE_ARCH and arch != "all":
-        id += ":%s" % arch
-    if version:
-        id += "=%s" % version
-    return id
-
-
 def get_pk_package_id(pk_id, data=""):
     """Convert an AptDaemon package ID to the PackageKit syntax.
     e.g. xterm:i368=235; to xterm;235;i386;installed
     """
-    #FIXME add arch support
-    name, version, release = worker.AptWorker._split_package_id(pk_id)
+    # FIXME add arch support
+    name, version, release = split_package_id(pk_id)
     try:
         name, arch = name.split(":", 1)
     except ValueError:
@@ -3241,31 +2000,6 @@ def defer_idle(func, *args):
     return False
 
 
-def bitfield_summarize(*enums):
-    """Return the bitfield with the given PackageKit enums."""
-    field = 0
-    for enum in enums:
-        field |= 2 ** int(enum)
-    return field
-
-
-def bitfield_add(field, enum):
-    """Add a PackageKit enum to a given field"""
-    field |= 2 ** int(enum)
-    return field
-
-
-def bitfield_remove(field, enum):
-    """Remove a PackageKit enum to a given field"""
-    field = field ^ 2 ** int(enum)
-    return field
-
-
-def bitfield_contains(field, enum):
-    """Return True if a bitfield contains the given PackageKit enum"""
-    return field & 2 ** int(enum)
-
-
 def get_string_from_flags(flags):
     """Return a human readable string of the applied transaction flags."""
     ret = ""
diff -pruN 1.1.1-4/aptdaemon/pkutils.py 1.1.1+bzr982-0ubuntu14/aptdaemon/pkutils.py
--- 1.1.1-4/aptdaemon/pkutils.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/pkutils.py	2013-07-22 10:25:25.000000000 +0000
@@ -0,0 +1,46 @@
+# !/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Provides helper functions for the PackageKit layer
+
+Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
+Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
+Copyright (C) 2008-2013 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>"
+
+
+def bitfield_summarize(*enums):
+    """Return the bitfield with the given PackageKit enums."""
+    field = 0
+    for enum in enums:
+        field |= 2 ** int(enum)
+    return field
+
+
+def bitfield_add(field, enum):
+    """Add a PackageKit enum to a given field"""
+    field |= 2 ** int(enum)
+    return field
+
+
+def bitfield_remove(field, enum):
+    """Remove a PackageKit enum to a given field"""
+    field = field ^ 2 ** int(enum)
+    return field
+
+
+def bitfield_contains(field, enum):
+    """Return True if a bitfield contains the given PackageKit enum"""
+    return field & 2 ** int(enum)
+
+
+# vim: ts=4 et sts=4
diff -pruN 1.1.1-4/aptdaemon/policykit1.py 1.1.1+bzr982-0ubuntu14/aptdaemon/policykit1.py
--- 1.1.1-4/aptdaemon/policykit1.py	2013-03-11 06:00:59.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/policykit1.py	2015-10-12 18:06:10.000000000 +0000
@@ -161,12 +161,15 @@ def get_proc_info_from_dbus_name(dbus_na
         bus = dbus.SystemBus()
     pid = yield get_pid_from_dbus_name(dbus_name, bus)
     with open("/proc/%s/status" % pid) as proc:
-        values = [v for v in proc.readlines() if v.startswith("Uid:")]
+        lines = proc.readlines()
+        uid_values = [v for v in lines if v.startswith("Uid:")]
+        gid_values = [v for v in lines if v.startswith("Gid:")]
     # instead of ", encoding='utf8'" we use the "rb"/decode() here for
     # py2 compatibility
     with open("/proc/%s/cmdline" % pid, "rb") as cmdline_file:
         cmdline = cmdline_file.read().decode("utf-8")
-    uid = int(values[0].split()[1])
-    return_value((pid, uid, cmdline))
+    uid = int(uid_values[0].split()[1])
+    gid = int(gid_values[0].split()[1])
+    return_value((pid, uid, gid, cmdline))
 
 # vim:ts=4:sw=4:et
diff -pruN 1.1.1-4/aptdaemon/progress.py 1.1.1+bzr982-0ubuntu14/aptdaemon/progress.py
--- 1.1.1-4/aptdaemon/progress.py	2015-10-12 18:06:09.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/progress.py	2015-10-12 18:06:10.000000000 +0000
@@ -165,7 +165,7 @@ class DaemonAcquireProgress(apt.progress
             else:
                 names.add(item.shortdesc)
         if names:
-            #TRANSLATORS: %s is a list of package names
+            # TRANSLATORS: %s is a list of package names
             msg = self.transaction.ngettext("Downloading %(files)s",
                                             "Downloading %(files)s",
                                             len(items)) % {"files":
@@ -276,11 +276,11 @@ class DaemonAcquireRepoProgress(DaemonAc
             try:
                 repos.add(item.description.split()[0].split("://")[-1])
             except IndexError:
-                #TRANSLATORS: the string is used as a fallback if we cannot
+                # TRANSLATORS: the string is used as a fallback if we cannot
                 #             get the URI of a local repository
                 repos.add(self.transaction.gettext("local repository"))
         if repos:
-            #TRANSLATORS: %s is a list of repository names
+            # TRANSLATORS: %s is a list of repository names
             msg = self.transaction.ngettext("Downloading from %s",
                                             "Downloading from %s",
                                             len(repos)) % " ".join(repos)
@@ -315,30 +315,30 @@ class DaemonAcquireRepoProgress(DaemonAc
         try:
             host = host.split("://")[1]
         except IndexError:
-            #TRANSLATORS: the string is used as a fallback if we cannot
+            # TRANSLATORS: the string is used as a fallback if we cannot
             #             get the URI of a local repository
             desc = self.transaction.gettext("local repository")
         repo = "%s %s" % (host, dist)
         if item.shortdesc == "InRelease":
-            #TRANSLATORS: repo is the name of a repository
+            # TRANSLATORS: repo is the name of a repository
             desc = self.transaction.gettext("Structure of %s") % repo
         elif item.shortdesc == "Release":
-            #TRANSLATORS: repo is the name of a repository
+            # TRANSLATORS: repo is the name of a repository
             desc = self.transaction.gettext("Description of %s") % repo
         elif item.shortdesc == "Release.gpg":
-            #TRANSLATORS: repo is the name of a repository
+            # TRANSLATORS: repo is the name of a repository
             desc = self.transaction.gettext("Description signature "
                                             "of %s") % repo
         elif item.shortdesc.startswith("Packages"):
-            #TRANSLATORS: repo is the name of a repository
+            # TRANSLATORS: repo is the name of a repository
             desc = self.transaction.gettext(
                 "Available packages from %s") % repo
         elif item.shortdesc.startswith("Sources"):
-            #TRANSLATORS: repo is the name of a repository
+            # TRANSLATORS: repo is the name of a repository
             desc = self.transaction.gettext(
                 "Available sources from %s") % repo
         elif item.shortdesc == "TranslationIndex":
-            #TRANSLATORS: repo is the name of a repository
+            # TRANSLATORS: repo is the name of a repository
             desc = self.transaction.gettext("Available translations from "
                                             "%s") % repo
         elif item.shortdesc.startswith("Translation-"):
@@ -352,18 +352,18 @@ class DaemonAcquireRepoProgress(DaemonAc
             region = self.regions.get_localised_name(region_code,
                                                      self.transaction.locale)
             if lang and region:
-                #TRANSLATORS: The first %s is the name of a language. The
+                # TRANSLATORS: The first %s is the name of a language. The
                 #             second one the name of the region/country. Th
                 #             third %s is the name of the repository
                 desc = self.transaction.gettext(
                     "Translations for %s (%s) from %s") % (lang, region, repo)
             elif lang:
-                #TRANSLATORS: %s is the name of a language. The second one is
+                # TRANSLATORS: %s is the name of a language. The second one is
                 #             the name of the repository
                 desc = self.transaction.gettext("Translations for %s from "
                                                 "%s") % (lang, repo)
             else:
-                #TRANSLATORS: %s is the code of a language, e.g. ru_RU.
+                # TRANSLATORS: %s is the code of a language, e.g. ru_RU.
                 #             The second one is the name of the repository
                 desc = self.transaction.gettext("Translations (%s) from "
                                                 "%s") % (lang_code, repo)
@@ -527,14 +527,14 @@ class DaemonForkProgress(object):
         return pid
 
     def _setup_child(self):
-        """Setup the environemnt of the child process."""
+        """Setup the environment of the child process."""
         def interrupt_handler(signum, frame):
             # Exit the child immediately if we receive the interrupt
             # signal or a Ctrl+C - otherwise the atexit methods would
             # be called, e.g. the frozen status decorator
             os._exit(apt_pkg.PackageManager.RESULT_FAILED)
         signal.signal(signal.SIGINT, interrupt_handler)
-        # Make sure that exceptions of the child are not catched by apport
+        # Make sure that exceptions of the child are not caught by apport
         sys.excepthook = sys.__excepthook__
 
         mainloop.quit()
@@ -628,6 +628,11 @@ class DaemonLintianProgress(DaemonForkPr
 
     def _child(self, path):
         # Avoid running lintian as root
+        try:
+            os.setgroups([self.transaction.gid])
+        except OSError:
+            pass
+        os.setgid(self.transaction.gid)
         os.setuid(self.transaction.uid)
 
         if platform.dist()[1] == "debian":
@@ -681,7 +686,7 @@ class DaemonInstallProgress(DaemonForkPr
             # silently ignore lines that can't be parsed
             return True
         message = message_raw.strip()
-        #print "percent: %s %s" % (pkg, float(percent)/100.0)
+        # print "percent: %s %s" % (pkg, float(percent)/100.0)
         if status == "pmerror":
             self._error(pkg, message)
         elif status == "pmconffile":
@@ -807,7 +812,7 @@ class DaemonDpkgInstallProgress(DaemonIn
         #  - "processing: STAGE: PACKAGE" with STAGE is one of upgrade,
         #    install, configure, trigproc, remove, purge
         if status[0] == "status":
-            #FIXME: Handle STATUS
+            # FIXME: Handle STATUS
             if status[2] == "error":
                 self._error(status[1], status[3])
             elif status[2] == "conffile":
diff -pruN 1.1.1-4/aptdaemon/utils.py 1.1.1+bzr982-0ubuntu14/aptdaemon/utils.py
--- 1.1.1-4/aptdaemon/utils.py	2013-03-11 06:00:59.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/utils.py	2014-06-26 07:07:15.000000000 +0000
@@ -2,23 +2,23 @@
 
 deprecated - decorator to emit a warning if a depreacted function is used
 """
-#Copyright (C) 2008-2009 Sebastian Heinlein <sevel@glatzor.de>
+# Copyright (C) 2008-2009 Sebastian Heinlein <sevel@glatzor.de>
 #
-#Licensed under the GNU General Public License Version 2
+# 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 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.
+# 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.
+# 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.
 
 __author__ = "Sebastian Heinlein <devel@glatzor.de>"
 
@@ -92,4 +92,19 @@ class IsoCodes(object):
             return None
 
 
+def split_package_id(package):
+    """Return the name, the version number and the release of the
+    specified package."""
+    if "=" in package:
+        name, version = package.split("=", 1)
+        release = None
+    elif "/" in package:
+        name, release = package.split("/", 1)
+        version = None
+    else:
+        name = package
+        version = release = None
+    return name, version, release
+
+
 # vim:ts=4:sw=4:et
diff -pruN 1.1.1-4/aptdaemon/worker/aptworker.py 1.1.1+bzr982-0ubuntu14/aptdaemon/worker/aptworker.py
--- 1.1.1-4/aptdaemon/worker/aptworker.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/worker/aptworker.py	2015-10-12 18:06:10.000000000 +0000
@@ -0,0 +1,1540 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""Provides AptWorker which processes transactions."""
+# Copyright (C) 2008-2009 Sebastian Heinlein <devel@glatzor.de>
+#
+# 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
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+__author__ = "Sebastian Heinlein <devel@glatzor.de>"
+
+__all__ = ("AptWorker")
+
+import contextlib
+import errno
+import glob
+import logging
+import netrc
+import os
+import re
+import shutil
+import stat
+import sys
+import tempfile
+import time
+import traceback
+try:
+    from urllib.parse import urlsplit, urlunsplit
+except ImportError:
+    from urlparse import urlsplit, urlunsplit
+
+try:
+    from configparser import ConfigParser
+except ImportError:
+    from ConfigParser import ConfigParser
+
+import apt
+import apt.auth
+import apt.cache
+import apt.debfile
+import apt_pkg
+import aptsources
+import aptsources.distro
+from aptsources.sourceslist import SourcesList
+from gi.repository import GObject, GLib
+
+from . import BaseWorker
+from ..enums import *
+from ..errors import *
+from .. import lock
+from ..progress import (
+    DaemonOpenProgress,
+    DaemonInstallProgress,
+    DaemonAcquireProgress,
+    DaemonAcquireRepoProgress,
+    DaemonDpkgInstallProgress,
+    DaemonDpkgReconfigureProgress,
+    DaemonDpkgRecoverProgress,
+    DaemonLintianProgress,
+    DaemonForkProgress)
+
+log = logging.getLogger("AptDaemon.Worker")
+
+# Just required to detect translatable strings. The translation is done by
+# core.Transaction.gettext
+_ = lambda s: s
+
+_POPCON_PATH = "/etc/popularity-contest.conf"
+_POPCON_DEFAULT = """# Config file for Debian's popularity-contest package.
+#
+# To change this file, use:
+#        dpkg-reconfigure popularity-contest
+#
+# You can also edit it by hand, if you so choose.
+#
+# See /usr/share/popularity-contest/default.conf for more info
+# on the options.
+MY_HOSTID="%(host_id)s"
+PARTICIPATE="%(participate)s"
+USE_HTTP="yes"
+"""
+
+
+@contextlib.contextmanager
+def set_euid_egid(uid, gid):
+    # no need to drop privs
+    if os.getuid() != 0 and os.getgid() != 0:
+        yield
+        return
+    # temporary drop privs
+    os.setegid(gid)
+    old_groups = os.getgroups()
+    os.setgroups([gid])
+    os.seteuid(uid)
+    try:
+        yield
+    finally:
+        os.seteuid(os.getuid())
+        os.setegid(os.getgid())
+        os.setgroups(old_groups)
+
+
+def trans_only_installs_pkgs_from_high_trust_repos(trans,
+                                                   whitelist=set()):
+    """Return True if this transaction only touches packages in the
+    aptdaemon repoisotry high trust repository whitelist
+    """
+    # the transaction *must* be simulated before
+    if not trans.simulated:
+        return False
+    # we never allow unauthenticated ones
+    if trans.unauthenticated:
+        return False
+    # paranoia: wrong role
+    if trans.role not in (ROLE_INSTALL_PACKAGES, ROLE_COMMIT_PACKAGES):
+        return False
+    # if there is anything touched that is not a install bail out
+    for enum in (PKGS_REINSTALL, PKGS_REMOVE, PKGS_PURGE, PKGS_DOWNGRADE,
+                 PKGS_UPGRADE):
+        if trans.packages[enum]:
+            return False
+    # paranoia(2): we must want to install something
+    if not trans.packages[PKGS_INSTALL]:
+        return False
+    # we only care about the name, not the version
+    pkgs = [pkg.split("=")[0] for pkg in trans.packages[PKGS_INSTALL]]
+    # if the install packages matches the whitelisted set we are good
+    return set(pkgs) == set(trans.high_trust_packages)
+
+
+def read_high_trust_repository_dir(whitelist_cfg_d):
+    """Return a set of (origin, component, pkgname-regexp) from a
+    high-trust-repository-whitelist.d directory
+    """
+    whitelist = set()
+    for path in glob.glob(os.path.join(whitelist_cfg_d, "*.cfg")):
+        whitelist |= _read_high_trust_repository_whitelist_file(path)
+    return whitelist
+
+
+def _read_high_trust_repository_whitelist_file(path):
+    """Read a individual high-trust-repository whitelist file and return
+       a set of tuples (origin, component, pkgname-regexp)
+    """
+    parser = ConfigParser()
+    whitelist = set()
+    try:
+        parser.read(path)
+    except Exception as e:
+        log.error("Failed to read repository whitelist '%s' (%s)" % (path, e))
+        return whitelist
+    for section in parser.sections():
+        origin = parser.get(section, "origin")
+        component = parser.get(section, "component")
+        pkgnames = parser.get(section, "pkgnames")
+        whitelist.add((origin, component, pkgnames))
+    return whitelist
+
+
+class AptWorker(BaseWorker):
+
+    """Worker which processes transactions from the queue."""
+
+    NATIVE_ARCH = apt_pkg.get_architectures()[0]
+
+    # the basedir under which license keys can be stored
+    LICENSE_KEY_ROOTDIR = "/opt/"
+
+    def __init__(self, chroot=None, load_plugins=True):
+        """Initialize a new AptWorker instance."""
+        BaseWorker.__init__(self, chroot, load_plugins)
+        self._cache = None
+
+        # Change to a given chroot
+        if self.chroot:
+            apt_conf_file = os.path.join(chroot, "etc/apt/apt.conf")
+            if os.path.exists(apt_conf_file):
+                apt_pkg.read_config_file(apt_pkg.config, apt_conf_file)
+            apt_conf_dir = os.path.join(chroot, "etc/apt/apt.conf.d")
+            if os.path.isdir(apt_conf_dir):
+                apt_pkg.read_config_dir(apt_pkg.config, apt_conf_dir)
+            apt_pkg.config["Dir"] = chroot
+            apt_pkg.config["Dir::State::Status"] = os.path.join(
+                chroot, "var/lib/dpkg/status")
+            apt_pkg.config.clear("DPkg::Post-Invoke")
+            apt_pkg.config.clear("DPkg::Options")
+            apt_pkg.config["DPkg::Options::"] = "--root=%s" % chroot
+            apt_pkg.config["DPkg::Options::"] = ("--log=%s/var/log/dpkg.log" %
+                                                 chroot)
+            status_file = apt_pkg.config.find_file("Dir::State::status")
+            lock.status_lock.path = os.path.join(os.path.dirname(status_file),
+                                                 "lock")
+            archives_dir = apt_pkg.config.find_dir("Dir::Cache::Archives")
+            lock.archive_lock.path = os.path.join(archives_dir, "lock")
+            lists_dir = apt_pkg.config.find_dir("Dir::State::lists")
+            lock.lists_lock.path = os.path.join(lists_dir, "lock")
+            apt_pkg.init_system()
+
+        # a set of tuples of the type (origin, component, pkgname-regexp)
+        # that on install will trigger a different kind of polkit
+        # authentication request (see LP: #1035207), useful for e.g.
+        # webapps/company repos
+        self._high_trust_repositories = read_high_trust_repository_dir(
+            os.path.join(apt_pkg.config.find_dir("Dir"),
+                         "etc/aptdaemon/high-trust-repository-whitelist.d"))
+        log.debug(
+            "using high-trust whitelist: '%s'" % self._high_trust_repositories)
+
+        self._status_orig = apt_pkg.config.find_file("Dir::State::status")
+        self._status_frozen = None
+        if load_plugins:
+            self._load_plugins(["modify_cache_after", "modify_cache_before",
+                                "get_license_key"])
+
+    def _call_plugins(self, name, resolver=None):
+        """Call all plugins of a given type."""
+        if not resolver:
+            # If the resolver of the original task isn't available we create
+            # a new one and protect the already marked changes
+            resolver = apt.cache.ProblemResolver(self._cache)
+            for pkg in self._cache.get_changes():
+                resolver.clear(pkg)
+                resolver.protect(pkg)
+                if pkg.marked_delete:
+                    resolver.remove(pkg)
+        if name not in self.plugins:
+            log.debug("There isn't any registered %s plugin" % name)
+            return False
+        for plugin in self.plugins[name]:
+            log.debug("Calling %s plugin: %s", name, plugin)
+            try:
+                plugin(resolver, self._cache)
+            except Exception as error:
+                log.critical("Failed to call %s plugin:\n%s" % (plugin, error))
+        return True
+
+    def _run_transaction(self, trans):
+        """Run the worker"""
+        try:
+            lock.wait_for_lock(trans)
+            # Prepare the package cache
+            if (trans.role == ROLE_FIX_INCOMPLETE_INSTALL or
+                    not self.is_dpkg_journal_clean()):
+                self.fix_incomplete_install(trans)
+            # Process transaction which don't require a cache
+            if trans.role == ROLE_ADD_VENDOR_KEY_FILE:
+                self.add_vendor_key_from_file(trans, **trans.kwargs)
+            elif trans.role == ROLE_ADD_VENDOR_KEY_FROM_KEYSERVER:
+                self.add_vendor_key_from_keyserver(trans, **trans.kwargs)
+            elif trans.role == ROLE_REMOVE_VENDOR_KEY:
+                self.remove_vendor_key(trans, **trans.kwargs)
+            elif trans.role == ROLE_ADD_REPOSITORY:
+                self.add_repository(trans, **trans.kwargs)
+            elif trans.role == ROLE_ENABLE_DISTRO_COMP:
+                self.enable_distro_comp(trans, **trans.kwargs)
+            elif trans.role == ROLE_RECONFIGURE:
+                self.reconfigure(trans, trans.packages[PKGS_REINSTALL],
+                                 **trans.kwargs)
+            elif trans.role == ROLE_CLEAN:
+                self.clean(trans)
+            # Check if the transaction has been just simulated. So we could
+            # skip marking the changes a second time.
+            elif (trans.role in (ROLE_REMOVE_PACKAGES, ROLE_INSTALL_PACKAGES,
+                                 ROLE_UPGRADE_PACKAGES, ROLE_COMMIT_PACKAGES,
+                                 ROLE_UPGRADE_SYSTEM,
+                                 ROLE_FIX_BROKEN_DEPENDS) and
+                  self.marked_tid == trans.tid):
+                self._apply_changes(trans)
+                trans.exit = EXIT_SUCCESS
+                return False
+            else:
+                self._open_cache(trans)
+            # Process transaction which can handle a broken dep cache
+            if trans.role == ROLE_FIX_BROKEN_DEPENDS:
+                self.fix_broken_depends(trans)
+            elif trans.role == ROLE_UPDATE_CACHE:
+                self.update_cache(trans, **trans.kwargs)
+            # Process the transactions which require a consistent cache
+            elif trans.role == ROLE_ADD_LICENSE_KEY:
+                self.add_license_key(trans, **trans.kwargs)
+            elif self._cache and self._cache.broken_count:
+                raise TransactionFailed(ERROR_CACHE_BROKEN,
+                                        self._get_broken_details(trans))
+            if trans.role == ROLE_PK_QUERY:
+                self.query(trans)
+            elif trans.role == ROLE_INSTALL_FILE:
+                self.install_file(trans, **trans.kwargs)
+            elif trans.role in [ROLE_REMOVE_PACKAGES, ROLE_INSTALL_PACKAGES,
+                                ROLE_UPGRADE_PACKAGES, ROLE_COMMIT_PACKAGES]:
+                self.commit_packages(trans, *trans.packages)
+            elif trans.role == ROLE_UPGRADE_SYSTEM:
+                self.upgrade_system(trans, **trans.kwargs)
+        finally:
+            lock.release()
+
+    def commit_packages(self, trans, install, reinstall, remove, purge,
+                        upgrade, downgrade, simulate=False):
+        """Perform a complex package operation.
+
+        Keyword arguments:
+        trans - the transaction
+        install - list of package names to install
+        reinstall - list of package names to reinstall
+        remove - list of package names to remove
+        purge - list of package names to purge including configuration files
+        upgrade - list of package names to upgrade
+        downgrade - list of package names to upgrade
+        simulate -- if True the changes won't be applied
+        """
+        log.info("Committing packages: %s, %s, %s, %s, %s, %s",
+                 install, reinstall, remove, purge, upgrade, downgrade)
+        with self._cache.actiongroup():
+            resolver = apt.cache.ProblemResolver(self._cache)
+            self._mark_packages_for_installation(install, resolver)
+            self._mark_packages_for_installation(reinstall, resolver,
+                                                 reinstall=True)
+            self._mark_packages_for_removal(remove, resolver)
+            self._mark_packages_for_removal(purge, resolver, purge=True)
+            self._mark_packages_for_upgrade(upgrade, resolver)
+            self._mark_packages_for_downgrade(downgrade, resolver)
+            self._resolve_depends(trans, resolver)
+        self._check_obsoleted_dependencies(trans, resolver)
+        if not simulate:
+            self._apply_changes(trans)
+
+    def _resolve_depends(self, trans, resolver):
+        """Resolve the dependencies using the given ProblemResolver."""
+        self._call_plugins("modify_cache_before", resolver)
+        resolver.install_protect()
+        try:
+            resolver.resolve()
+        except SystemError:
+            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED,
+                                    self._get_broken_details(trans, now=False))
+        if self._call_plugins("modify_cache_after", resolver):
+            try:
+                resolver.resolve()
+            except SystemError:
+                details = self._get_broken_details(trans, now=False)
+                raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED, details)
+
+    def _get_high_trust_packages(self):
+        """ Return a list of packages that come from a high-trust repo """
+        def _in_high_trust_repository(pkgname, pkgorigin):
+            for origin, component, regexp in self._high_trust_repositories:
+                if (origin == pkgorigin.origin and
+                        component == pkgorigin.component and
+                        re.match(regexp, pkgname)):
+                    return True
+            return False
+        # loop
+        from_high_trust_repo = []
+        for pkg in self._cache.get_changes():
+            if pkg.marked_install:
+                for origin in pkg.candidate.origins:
+                    if _in_high_trust_repository(pkg.name, origin):
+                        from_high_trust_repo.append(pkg.name)
+                        break
+        return from_high_trust_repo
+
+    def _get_unauthenticated(self):
+        """Return a list of unauthenticated package names """
+        unauthenticated = []
+        for pkg in self._cache.get_changes():
+            if (pkg.marked_install or
+                    pkg.marked_downgrade or
+                    pkg.marked_upgrade or
+                    pkg.marked_reinstall):
+                trusted = False
+                for origin in pkg.candidate.origins:
+                    trusted |= origin.trusted
+                if not trusted:
+                    unauthenticated.append(pkg.name)
+        return unauthenticated
+
+    def _mark_packages_for_installation(self, packages, resolver,
+                                        reinstall=False):
+        """Mark packages for installation."""
+        for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
+                                           for pkg in packages]:
+            pkg_name, sep, auto_marker = pkg_name.partition("#")
+            from_user = (auto_marker != "auto")
+            try:
+                pkg = self._cache[pkg_name]
+            except KeyError:
+                raise TransactionFailed(ERROR_NO_PACKAGE,
+                                        _("Package %s isn't available"),
+                                        pkg_name)
+            if reinstall:
+                if not pkg.is_installed:
+                    raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
+                                            _("Package %s isn't installed"),
+                                            pkg.name)
+                if pkg_ver and pkg.installed.version != pkg_ver:
+                    raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
+                                            _("The version %s of %s isn't "
+                                              "installed"),
+                                            pkg_ver, pkg_name)
+            else:
+                # Fail if the user requests to install the same version
+                # of an already installed package.
+                if (pkg.is_installed and
+                    # Compare version numbers
+                    pkg_ver and pkg_ver == pkg.installed.version and
+                    # Optionally compare the origin if specified
+                    (not pkg_rel or
+                     pkg_rel in [origin.archive for
+                                 origin in pkg.installed.origins])):
+                        raise TransactionFailed(
+                            ERROR_PACKAGE_ALREADY_INSTALLED,
+                            _("Package %s is already installed"), pkg_name)
+            pkg.mark_install(False, True, from_user)
+            resolver.clear(pkg)
+            resolver.protect(pkg)
+            if pkg_ver:
+                try:
+                    pkg.candidate = pkg.versions[pkg_ver]
+                except KeyError:
+                    raise TransactionFailed(ERROR_NO_PACKAGE,
+                                            _("The version %s of %s isn't "
+                                              "available."), pkg_ver, pkg_name)
+            elif pkg_rel:
+                self._set_candidate_release(pkg, pkg_rel)
+
+    def enable_distro_comp(self, trans, component):
+        """Enable given component in the sources list.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        component -- a component, e.g. main or universe
+        """
+        trans.progress = 101
+        trans.status = STATUS_COMMITTING
+        old_umask = os.umask(0o022)
+        try:
+            sourceslist = SourcesList()
+            distro = aptsources.distro.get_distro()
+            distro.get_sources(sourceslist)
+            distro.enable_component(component)
+            sourceslist.save()
+        finally:
+            os.umask(old_umask)
+
+    def add_repository(self, trans, src_type, uri, dist, comps, comment,
+                       sourcesfile):
+        """Add given repository to the sources list.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        src_type -- the type of the entry (deb, deb-src)
+        uri -- the main repository uri (e.g. http://archive.ubuntu.com/ubuntu)
+        dist -- the distribution to use (e.g. karmic, "/")
+        comps -- a (possible empty) list of components (main, restricted)
+        comment -- an (optional) comment
+        sourcesfile -- an (optinal) filename in sources.list.d
+        """
+        trans.progress = 101
+        trans.status = STATUS_COMMITTING
+
+        if sourcesfile:
+            if not sourcesfile.endswith(".list"):
+                sourcesfile += ".list"
+            dir = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
+            sourcesfile = os.path.join(dir, os.path.basename(sourcesfile))
+        else:
+            sourcesfile = None
+        # Store any private login information in a separate auth.conf file
+        if re.match("(http|https|ftp)://\S+?:\S+?@\S+", uri):
+            uri = self._store_and_strip_password_from_uri(uri)
+            auth_conf_path = apt_pkg.config.find_file("Dir::etc::netrc")
+            if not comment:
+                comment = "credentials stored in %s" % auth_conf_path
+            else:
+                comment += "; credentials stored in %s" % auth_conf_path
+        try:
+            sources = SourcesList()
+            entry = sources.add(src_type, uri, dist, comps, comment,
+                                file=sourcesfile)
+            if entry.invalid:
+                # FIXME: Introduce new error codes
+                raise RepositoryInvalidError()
+        except:
+            log.exception("adding repository")
+            raise
+        else:
+            sources.save()
+
+    def _store_and_strip_password_from_uri(self, uri, auth_conf_path=None):
+        """Extract the credentials from an URI. Store the password in
+        auth.conf and return the URI without any password information.
+        """
+        try:
+            res = urlsplit(uri)
+        except ValueError as error:
+            log.warning("Failed to urlsplit '%s'", error)
+            return uri
+        netloc_public = res.netloc.replace("%s:%s@" % (res.username,
+                                                       res.password),
+                                           "")
+        machine = netloc_public + res.path
+        # find auth.conf
+        if auth_conf_path is None:
+            auth_conf_path = apt_pkg.config.find_file("Dir::etc::netrc")
+
+        # read all "machine"s from the auth.conf "netrc" file
+        netrc_hosts = {}
+        netrc_hosts_as_text = ""
+        if os.path.exists(auth_conf_path):
+                netrc_hosts = netrc.netrc(auth_conf_path).hosts
+                with open(auth_conf_path, "rb") as f:
+                    netrc_hosts_as_text = f.read().decode("UTF-8")
+
+        # the new entry
+        new_netrc_entry = "\nmachine %s login %s password %s\n" % (
+            machine, res.username, res.password)
+        # if there is the same machine already defined, update it
+        # using a regexp this will ensure order/comments remain
+        if machine in netrc_hosts:
+            sub_regexp = r'machine\s+%s\s+login\s+%s\s+password\s+%s' % (
+                re.escape(machine),
+                re.escape(netrc_hosts[machine][0]),
+                re.escape(netrc_hosts[machine][2]))
+            replacement = 'machine %s login %s password %s' % (
+                machine, res.username, res.password)
+            # this may happen if e.g. the order is unexpected
+            if not re.search(sub_regexp, netrc_hosts_as_text):
+                log.warning("can not replace existing netrc entry for '%s' "
+                            "prepending it instead" % machine)
+                netrc_hosts_as_text = new_netrc_entry + netrc_hosts_as_text
+            else:
+                netrc_hosts_as_text = re.sub(
+                    sub_regexp, replacement, netrc_hosts_as_text)
+        else:
+            netrc_hosts_as_text += new_netrc_entry
+
+        # keep permssion bits of the file
+        mode = 0o640
+        try:
+            mode = os.stat(auth_conf_path)[stat.ST_MODE]
+        except OSError as e:
+            if e.errno != errno.ENOENT:
+                raise
+        # write out, tmp file first plus rename to be atomic
+        try:
+            auth_conf_tmp = tempfile.NamedTemporaryFile(
+                dir=os.path.dirname(auth_conf_path),
+                prefix=os.path.basename(auth_conf_path),
+                delete=False)
+            auth_conf_tmp.write(netrc_hosts_as_text.encode('UTF-8'))
+            auth_conf_tmp.close()
+            os.rename(auth_conf_tmp.name, auth_conf_path)
+            # and restore permissions (or set default ones)
+            os.chmod(auth_conf_path, mode)
+        except OSError as error:
+            log.warning("Failed to write auth.conf: '%s'" % error)
+
+        # Return URI without user/pass
+        return urlunsplit((res.scheme, netloc_public, res.path, res.query,
+                           res.fragment))
+
+    def add_vendor_key_from_keyserver(self, trans, keyid, keyserver):
+        """Add the signing key from the given (keyid, keyserver) to the
+        trusted vendors.
+
+        Keyword argument:
+        trans -- the corresponding transaction
+        keyid - the keyid of the key (e.g. 0x0EB12F05)
+        keyserver - the keyserver (e.g. keyserver.ubuntu.com)
+        """
+        log.info("Adding vendor key from keyserver: %s %s", keyid, keyserver)
+        # Perform some sanity checks
+        try:
+            res = urlsplit(keyserver)
+        except ValueError:
+            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
+                                    # TRANSLATORS: %s is the URL of GnuPG
+                                    #             keyserver
+                                    _("The keyserver URL is invalid: %s"),
+                                    keyserver)
+        if res.scheme not in ["hkp", "ldap", "ldaps", "http", "https"]:
+            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
+                                    # TRANSLATORS: %s is the URL of GnuPG
+                                    #             keyserver
+                                    _("Invalid protocol of the server: %s"),
+                                    keyserver)
+        try:
+            int(keyid, 16)
+        except ValueError:
+            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
+                                    # TRANSLATORS: %s is the id of a GnuPG key
+                                    #             e.g. E08ADE95
+                                    _("Invalid key id: %s"), keyid)
+        trans.status = STATUS_DOWNLOADING
+        trans.progress = 101
+        with DaemonForkProgress(trans) as progress:
+            progress.run(apt.auth.add_key_from_keyserver, keyid, keyserver)
+        if progress._child_exit != 0:
+            # TRANSLATORS: The first %s is the key id and the second the server
+            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
+                                    _("Failed to download and install the key "
+                                      "%s from %s:\n%s"),
+                                    keyid, keyserver, progress.output)
+
+    def add_vendor_key_from_file(self, trans, path):
+        """Add the signing key from the given file to the trusted vendors.
+
+        Keyword argument:
+        path -- absolute path to the key file
+        """
+        log.info("Adding vendor key from file: %s", path)
+        trans.progress = 101
+        trans.status = STATUS_COMMITTING
+        with DaemonForkProgress(trans) as progress:
+            progress.run(apt.auth.add_key_from_file, path)
+        if progress._child_exit != 0:
+            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
+                                    _("Key file %s couldn't be installed: %s"),
+                                    path, progress.output)
+
+    def remove_vendor_key(self, trans, fingerprint):
+        """Remove repository key.
+
+        Keyword argument:
+        trans -- the corresponding transaction
+        fingerprint -- fingerprint of the key to remove
+        """
+        log.info("Removing vendor key: %s", fingerprint)
+        trans.progress = 101
+        trans.status = STATUS_COMMITTING
+        try:
+            int(fingerprint, 16)
+        except ValueError:
+            raise TransactionFailed(ERROR_KEY_NOT_REMOVED,
+                                    # TRANSLATORS: %s is the id of a GnuPG key
+                                    #             e.g. E08ADE95
+                                    _("Invalid key id: %s"), fingerprint)
+        with DaemonForkProgress(trans) as progress:
+            progress.run(apt.auth.remove_key, fingerprint)
+        if progress._child_exit != 0:
+            raise TransactionFailed(ERROR_KEY_NOT_REMOVED,
+                                    _("Key with fingerprint %s couldn't be "
+                                      "removed: %s"),
+                                    fingerprint, progress.output)
+
+    def install_file(self, trans, path, force, simulate=False):
+        """Install local package file.
+
+        Keyword argument:
+        trans -- the corresponding transaction
+        path -- absolute path to the package file
+        force -- if installing an invalid package is allowed
+        simulate -- if True the changes won't be committed but the debfile
+                    instance will be returned
+        """
+        log.info("Installing local package file: %s", path)
+        # Check if the dpkg can be installed at all
+        trans.status = STATUS_RESOLVING_DEP
+        deb = self._check_deb_file(trans, path, force)
+        # Check for required changes and apply them before
+        (install, remove, unauth) = deb.required_changes
+        self._call_plugins("modify_cache_after")
+        if simulate:
+            return deb
+        with self._frozen_status():
+            if len(install) > 0 or len(remove) > 0:
+                self._apply_changes(trans, fetch_range=(15, 33),
+                                    install_range=(34, 63))
+            # Install the dpkg file
+            deb_progress = DaemonDpkgInstallProgress(trans, begin=64, end=95)
+            res = deb.install(deb_progress)
+            trans.output += deb_progress.output
+            if res:
+                raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
+                                        trans.output)
+
+    def _mark_packages_for_removal(self, packages, resolver, purge=False):
+        """Mark packages for installation."""
+        for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
+                                           for pkg in packages]:
+            try:
+                pkg = self._cache[pkg_name]
+            except KeyError:
+                raise TransactionFailed(ERROR_NO_PACKAGE,
+                                        _("Package %s isn't available"),
+                                        pkg_name)
+            if not pkg.is_installed and not pkg.installed_files:
+                raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
+                                        _("Package %s isn't installed"),
+                                        pkg_name)
+            if pkg.essential is True:
+                raise TransactionFailed(ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE,
+                                        _("Package %s cannot be removed."),
+                                        pkg_name)
+            if pkg_ver and pkg.installed != pkg_ver:
+                raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
+                                        _("The version %s of %s is not "
+                                          "installed"), pkg_ver, pkg_name)
+            pkg.mark_delete(False, purge)
+            resolver.clear(pkg)
+            resolver.protect(pkg)
+            resolver.remove(pkg)
+
+    def _check_obsoleted_dependencies(self, trans, resolver=None):
+        """Mark obsoleted dependencies of to be removed packages
+        for removal.
+        """
+        if not trans.remove_obsoleted_depends:
+            return
+        if not resolver:
+            resolver = apt.cache.ProblemResolver(self._cache)
+        installed_deps = set()
+        with self._cache.actiongroup():
+            for pkg in self._cache.get_changes():
+                if pkg.marked_delete:
+                    installed_deps = self._installed_dependencies(
+                        pkg.name, installed_deps)
+            for dep_name in installed_deps:
+                if dep_name in self._cache:
+                    pkg = self._cache[dep_name]
+                    if pkg.is_installed and pkg.is_auto_removable:
+                        pkg.mark_delete(False)
+            # do an additional resolver run to ensure that the autoremove
+            # never leaves the cache in an inconsistent state, see bug
+            # LP: #659111 for the rational, essentially this may happen
+            # if a package is marked install during problem resolving but
+            # is later no longer required. the resolver deals with that
+            self._resolve_depends(trans, resolver)
+
+    def _installed_dependencies(self, pkg_name, all_deps=None):
+        """Recursively return all installed dependencies of a given package."""
+        # FIXME: Should be part of python-apt, since it makes use of non-public
+        #       API. Perhaps by adding a recursive argument to
+        #       apt.package.Version.get_dependencies()
+        if not all_deps:
+            all_deps = set()
+        if pkg_name not in self._cache:
+            return all_deps
+        cur = self._cache[pkg_name]._pkg.current_ver
+        if not cur:
+            return all_deps
+        for sec in ("PreDepends", "Depends", "Recommends"):
+            try:
+                for dep in cur.depends_list[sec]:
+                    dep_name = dep[0].target_pkg.name
+                    if dep_name not in all_deps:
+                        all_deps.add(dep_name)
+                        all_deps |= self._installed_dependencies(dep_name,
+                                                                 all_deps)
+            except KeyError:
+                pass
+        return all_deps
+
+    def _mark_packages_for_downgrade(self, packages, resolver):
+        """Mark packages for downgrade."""
+        for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
+                                           for pkg in packages]:
+            try:
+                pkg = self._cache[pkg_name]
+            except KeyError:
+                raise TransactionFailed(ERROR_NO_PACKAGE,
+                                        _("Package %s isn't available"),
+                                        pkg_name)
+            if not pkg.is_installed:
+                raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
+                                        _("Package %s isn't installed"),
+                                        pkg_name)
+            auto = pkg.is_auto_installed
+            pkg.mark_install(False, True, True)
+            pkg.mark_auto(auto)
+            resolver.clear(pkg)
+            resolver.protect(pkg)
+            if pkg_ver:
+                if pkg.installed and pkg.installed.version < pkg_ver:
+                    # FIXME: We need a new error enum
+                    raise TransactionFailed(ERROR_NO_PACKAGE,
+                                            _("The former version %s of %s "
+                                              "is already installed"),
+                                            pkg.installed.version, pkg.name)
+                elif pkg.installed and pkg.installed.version == pkg_ver:
+                    raise TransactionFailed(ERROR_PACKAGE_ALREADY_INSTALLED,
+                                            _("The version %s of %s "
+                                              "is already installed"),
+                                            pkg.installed.version, pkg.name)
+                try:
+                    pkg.candidate = pkg.versions[pkg_ver]
+                except KeyError:
+                    raise TransactionFailed(ERROR_NO_PACKAGE,
+                                            _("The version %s of %s isn't "
+                                              "available"), pkg_ver, pkg_name)
+            else:
+                raise TransactionFailed(ERROR_NO_PACKAGE,
+                                        _("You need to specify a version to "
+                                          "downgrade %s to"),
+                                        pkg_name)
+
+    def _mark_packages_for_upgrade(self, packages, resolver):
+        """Mark packages for upgrade."""
+        for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
+                                           for pkg in packages]:
+            try:
+                pkg = self._cache[pkg_name]
+            except KeyError:
+                raise TransactionFailed(ERROR_NO_PACKAGE,
+                                        _("Package %s isn't available"),
+                                        pkg_name)
+            if not pkg.is_installed:
+                raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
+                                        _("Package %s isn't installed"),
+                                        pkg_name)
+            auto = pkg.is_auto_installed
+            pkg.mark_install(False, True, True)
+            pkg.mark_auto(auto)
+            resolver.clear(pkg)
+            resolver.protect(pkg)
+            if pkg_ver:
+                if (pkg.installed and
+                    apt_pkg.version_compare(pkg.installed.version,
+                                            pkg_ver) == 1):
+                    raise TransactionFailed(ERROR_PACKAGE_UPTODATE,
+                                            _("The later version %s of %s "
+                                              "is already installed"),
+                                            pkg.installed.version, pkg.name)
+                elif (pkg.installed and
+                      apt_pkg.version_compare(pkg.installed.version,
+                                              pkg_ver) == 0):
+                    raise TransactionFailed(ERROR_PACKAGE_UPTODATE,
+                                            _("The version %s of %s "
+                                              "is already installed"),
+                                            pkg.installed.version, pkg.name)
+                try:
+                    pkg.candidate = pkg.versions[pkg_ver]
+                except KeyError:
+                    raise TransactionFailed(ERROR_NO_PACKAGE,
+                                            _("The version %s of %s isn't "
+                                              "available."), pkg_ver, pkg_name)
+
+            elif pkg_rel:
+                self._set_candidate_release(pkg, pkg_rel)
+
+    @staticmethod
+    def _set_candidate_release(pkg, release):
+        """Set the candidate of a package to the one from the given release."""
+        # FIXME: Should be moved to python-apt
+        # Check if the package is provided in the release
+        for version in pkg.versions:
+            if [origin for origin in version.origins
+                    if origin.archive == release]:
+                break
+        else:
+            raise TransactionFailed(ERROR_NO_PACKAGE,
+                                    _("The package %s isn't available in "
+                                      "the %s release."), pkg.name, release)
+        pkg._pcache.cache_pre_change()
+        pkg._pcache._depcache.set_candidate_release(pkg._pkg, version._cand,
+                                                    release)
+        pkg._pcache.cache_post_change()
+
+    def update_cache(self, trans, sources_list):
+        """Update the cache.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        sources_list -- only update the repositories found in the sources.list
+                        snippet by the given file name.
+        """
+
+        def compare_pathes(first, second):
+            """Small helper to compare two pathes."""
+            return os.path.normpath(first) == os.path.normpath(second)
+
+        log.info("Updating cache")
+
+        progress = DaemonAcquireRepoProgress(trans, begin=10, end=90)
+        if sources_list and not sources_list.startswith("/"):
+            dir = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
+            sources_list = os.path.join(dir, sources_list)
+        if sources_list:
+            # For security reasons (LP #722228) we only allow files inside
+            # sources.list.d as basedir
+            basedir = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
+            system_sources = apt_pkg.config.find_file("Dir::Etc::sourcelist")
+            if "/" in sources_list:
+                sources_list = os.path.abspath(sources_list)
+                # Check if the sources_list snippet is in the sourceparts
+                # directory
+                common_prefix = os.path.commonprefix([sources_list, basedir])
+                if not (compare_pathes(common_prefix, basedir) or
+                        compare_pathes(sources_list, system_sources)):
+                    raise AptDaemonError("Only alternative sources.list files "
+                                         "inside '%s' are allowed (not '%s')" %
+                                         (basedir, sources_list))
+            else:
+                sources_list = os.path.join(basedir, sources_list)
+        try:
+            self._cache.update(progress, sources_list=sources_list)
+        except apt.cache.FetchFailedException as error:
+            # ListUpdate() method of apt handles a cancelled operation
+            # as a failed one, see LP #162441
+            if trans.cancelled:
+                raise TransactionCancelled()
+            else:
+                raise TransactionFailed(ERROR_REPO_DOWNLOAD_FAILED,
+                                        str(error))
+        except apt.cache.FetchCancelledException:
+            raise TransactionCancelled()
+        except apt.cache.LockFailedException:
+            raise TransactionFailed(ERROR_NO_LOCK)
+        self._open_cache(trans, begin=91, end=95)
+
+    def upgrade_system(self, trans, safe_mode=True, simulate=False):
+        """Upgrade the system.
+
+        Keyword argument:
+        trans -- the corresponding transaction
+        safe_mode -- if additional software should be installed or removed to
+                     satisfy the dependencies the an updates
+        simulate -- if the changes should not be applied
+        """
+        log.info("Upgrade system with safe mode: %s" % safe_mode)
+        trans.status = STATUS_RESOLVING_DEP
+        # FIXME: What to do if already uptotdate? Add error code?
+        self._call_plugins("modify_cache_before")
+        try:
+            self._cache.upgrade(dist_upgrade=not safe_mode)
+        except SystemError as excep:
+            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED, str(excep))
+        self._call_plugins("modify_cache_after")
+        self._check_obsoleted_dependencies(trans)
+        if not simulate:
+            self._apply_changes(trans)
+
+    def fix_incomplete_install(self, trans):
+        """Run dpkg --configure -a to recover from a failed installation.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        """
+        log.info("Fixing incomplete installs")
+        trans.status = STATUS_CLEANING_UP
+        with self._frozen_status():
+            with DaemonDpkgRecoverProgress(trans) as progress:
+                progress.run()
+        trans.output += progress.output
+        if progress._child_exit != 0:
+            raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
+                                    trans.output)
+
+    def reconfigure(self, trans, packages, priority):
+        """Run dpkg-reconfigure to reconfigure installed packages.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        packages -- list of packages to reconfigure
+        priority -- the lowest priority of question which should be asked
+        """
+        log.info("Reconfiguring packages")
+        with self._frozen_status():
+            with DaemonDpkgReconfigureProgress(trans) as progress:
+                progress.run(packages, priority)
+        trans.output += progress.output
+        if progress._child_exit != 0:
+            raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
+                                    trans.output)
+
+    def fix_broken_depends(self, trans, simulate=False):
+        """Try to fix broken dependencies.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        simualte -- if the changes should not be applied
+        """
+        log.info("Fixing broken depends")
+        trans.status = STATUS_RESOLVING_DEP
+        try:
+            self._cache._depcache.fix_broken()
+        except SystemError:
+            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED,
+                                    self._get_broken_details(trans))
+        if not simulate:
+            self._apply_changes(trans)
+
+    def _open_cache(self, trans, begin=1, end=5, quiet=False, status=None):
+        """Open the APT cache.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        start -- the begin of the progress range
+        end -- the end of the the progress range
+        quiet -- if True do no report any progress
+        status -- an alternative dpkg status file
+        """
+        self.marked_tid = None
+        trans.status = STATUS_LOADING_CACHE
+        if not status:
+            status = self._status_orig
+        apt_pkg.config.set("Dir::State::status", status)
+        apt_pkg.init_system()
+        progress = DaemonOpenProgress(trans, begin=begin, end=end,
+                                      quiet=quiet)
+        try:
+            if not isinstance(self._cache, apt.cache.Cache):
+                self._cache = apt.cache.Cache(progress)
+            else:
+                self._cache.open(progress)
+        except SystemError as excep:
+            raise TransactionFailed(ERROR_NO_CACHE, str(excep))
+
+    def is_dpkg_journal_clean(self):
+        """Return False if there are traces of incomplete dpkg status
+        updates."""
+        status_updates = os.path.join(os.path.dirname(self._status_orig),
+                                      "updates/")
+        for dentry in os.listdir(status_updates):
+            if dentry.isdigit():
+                return False
+        return True
+
+    def _apply_changes(self, trans, fetch_range=(15, 50),
+                       install_range=(50, 90)):
+        """Apply previously marked changes to the system.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        fetch_range -- tuple containing the start and end point of the
+                       download progress
+        install_range -- tuple containing the start and end point of the
+                         install progress
+        """
+        changes = self._cache.get_changes()
+        if not changes:
+            return
+        # Do not allow to remove essential packages
+        for pkg in changes:
+            if pkg.marked_delete and (pkg.essential is True or
+                                      (pkg.installed and
+                                       pkg.installed.priority == "required") or
+                                      pkg.name == "aptdaemon"):
+                raise TransactionFailed(ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE,
+                                        _("Package %s cannot be removed"),
+                                        pkg.name)
+        # Check if any of the cache changes get installed from an
+        # unauthenticated repository""
+        if not trans.allow_unauthenticated and trans.unauthenticated:
+            raise TransactionFailed(ERROR_PACKAGE_UNAUTHENTICATED,
+                                    " ".join(sorted(trans.unauthenticated)))
+        if trans.cancelled:
+            raise TransactionCancelled()
+        trans.cancellable = False
+        fetch_progress = DaemonAcquireProgress(trans, begin=fetch_range[0],
+                                               end=fetch_range[1])
+        inst_progress = DaemonInstallProgress(trans, begin=install_range[0],
+                                              end=install_range[1])
+        with self._frozen_status():
+            try:
+                self._cache.commit(fetch_progress, inst_progress)
+            except apt.cache.FetchFailedException as error:
+                raise TransactionFailed(ERROR_PACKAGE_DOWNLOAD_FAILED,
+                                        str(error))
+            except apt.cache.FetchCancelledException:
+                raise TransactionCancelled()
+            except SystemError as excep:
+                # Run dpkg --configure -a to recover from a failed transaction
+                trans.status = STATUS_CLEANING_UP
+                with DaemonDpkgRecoverProgress(trans, begin=90, end=95) as pro:
+                    pro.run()
+                output = inst_progress.output + pro.output
+                trans.output += output
+                raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
+                                        "%s: %s" % (excep, trans.output))
+            else:
+                trans.output += inst_progress.output
+
+    @contextlib.contextmanager
+    def _frozen_status(self):
+        """Freeze the status file to allow simulate operations during
+        a dpkg call."""
+        frozen_dir = tempfile.mkdtemp(prefix="aptdaemon-frozen-status")
+        shutil.copy(self._status_orig, frozen_dir)
+        self._status_frozen = os.path.join(frozen_dir, "status")
+        try:
+            yield
+        finally:
+            shutil.rmtree(frozen_dir)
+            self._status_frozen = None
+
+    def query(self, trans):
+        """Process a PackageKit query transaction."""
+        raise NotImplementedError
+
+    def _simulate_transaction(self, trans):
+        depends = [[], [], [], [], [], [], []]
+        unauthenticated = []
+        high_trust_packages = []
+        skip_pkgs = []
+        size = 0
+        installs = reinstalls = removals = purges = upgrades = upgradables = \
+            downgrades = []
+
+        # Only handle transaction which change packages
+        # FIXME: Add support for ROLE_FIX_INCOMPLETE_INSTALL
+        if trans.role not in [ROLE_INSTALL_PACKAGES, ROLE_UPGRADE_PACKAGES,
+                              ROLE_UPGRADE_SYSTEM, ROLE_REMOVE_PACKAGES,
+                              ROLE_COMMIT_PACKAGES, ROLE_INSTALL_FILE,
+                              ROLE_FIX_BROKEN_DEPENDS]:
+            return depends, 0, 0, [], []
+
+        # If a transaction is currently running use the former status file
+        if self._status_frozen:
+            status_path = self._status_frozen
+        else:
+            status_path = self._status_orig
+        self._open_cache(trans, quiet=True, status=status_path)
+        if trans.role == ROLE_FIX_BROKEN_DEPENDS:
+            self.fix_broken_depends(trans, simulate=True)
+        elif self._cache.broken_count:
+            raise TransactionFailed(ERROR_CACHE_BROKEN,
+                                    self._get_broken_details(trans))
+        elif trans.role == ROLE_UPGRADE_SYSTEM:
+            for pkg in self._iterate_packages():
+                if pkg.is_upgradable:
+                    upgradables.append(pkg)
+            self.upgrade_system(trans, simulate=True, **trans.kwargs)
+        elif trans.role == ROLE_INSTALL_FILE:
+            deb = self.install_file(trans, simulate=True, **trans.kwargs)
+            skip_pkgs.append(deb.pkgname)
+            try:
+                # Sometimes a thousands comma is used in packages
+                # See LP #656633
+                size = int(deb["Installed-Size"].replace(",", "")) * 1024
+                # Some packages ship really large install sizes e.g.
+                # openvpn access server, see LP #758837
+                if size > sys.maxsize:
+                    raise OverflowError("Size is too large: %s Bytes" % size)
+            except (KeyError, AttributeError, ValueError, OverflowError):
+                if not trans.kwargs["force"]:
+                    msg = trans.gettext("The package doesn't provide a "
+                                        "valid Installed-Size control "
+                                        "field. See Debian Policy 5.6.20.")
+                    raise TransactionFailed(ERROR_INVALID_PACKAGE_FILE, msg)
+            try:
+                pkg = self._cache[deb.pkgname]
+            except KeyError:
+                trans.packages = [[deb.pkgname], [], [], [], [], []]
+            else:
+                if pkg.is_installed:
+                    # if we failed to get the size from the deb file do nor
+                    # try to get the delta
+                    if size != 0:
+                        size -= pkg.installed.installed_size
+                    trans.packages = [[], [deb.pkgname], [], [], [], []]
+                else:
+                    trans.packages = [[deb.pkgname], [], [], [], [], []]
+        else:
+            # FIXME: ugly code to get the names of the packages
+            (installs, reinstalls, removals, purges,
+             upgrades, downgrades) = [[re.split("(=|/)", entry, 1)[0]
+                                       for entry in lst]
+                                      for lst in trans.packages]
+            self.commit_packages(trans, *trans.packages, simulate=True)
+
+        changes = self._cache.get_changes()
+        changes_names = []
+        # get the additional dependencies
+        for pkg in changes:
+            if (pkg.marked_upgrade and pkg.is_installed and
+                    pkg.name not in upgrades):
+                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
+                depends[PKGS_UPGRADE].append(pkg_str)
+            elif pkg.marked_reinstall and pkg.name not in reinstalls:
+                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
+                depends[PKGS_REINSTALL].append(pkg_str)
+            elif pkg.marked_downgrade and pkg.name not in downgrades:
+                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
+                depends[PKGS_DOWNGRADE].append(pkg_str)
+            elif pkg.marked_install and pkg.name not in installs:
+                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
+                depends[PKGS_INSTALL].append(pkg_str)
+            elif pkg.marked_delete and pkg.name not in removals:
+                pkg_str = "%s=%s" % (pkg.name, pkg.installed.version)
+                depends[PKGS_REMOVE].append(pkg_str)
+            # FIXME: add support for purges
+            changes_names.append(pkg.name)
+        # get the unauthenticated packages
+        unauthenticated = self._get_unauthenticated()
+        high_trust_packages = self._get_high_trust_packages()
+        # Check for skipped upgrades
+        for pkg in upgradables:
+            if pkg.marked_keep:
+                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
+                depends[PKGS_KEEP].append(pkg_str)
+
+        # apt.cache.Cache.required_download requires a clean cache. Under some
+        # strange circumstances it can fail (most likely an interrupted
+        # debconf question), see LP#659438
+        # Running dpkg --configure -a fixes the situation
+        try:
+            required_download = self._cache.required_download
+        except SystemError as error:
+            raise TransactionFailed(ERROR_INCOMPLETE_INSTALL, str(error))
+
+        required_space = size + self._cache.required_space
+
+        return (depends, required_download, required_space, unauthenticated,
+                high_trust_packages)
+
+    def _check_deb_file(self, trans, path, force):
+        """Perform some basic checks for the Debian package.
+
+        :param trans: The transaction instance.
+
+        :returns: An apt.debfile.Debfile instance.
+        """
+        # This code runs as root for simulate and simulate requires no
+        # authentication - so we need to ensure we do not leak information
+        # about files here (LP: #1449587, CVE-2015-1323)
+        #
+        # Note that the actual lintian run is also droping privs (real,
+        # not just seteuid)
+        with set_euid_egid(trans.uid, trans.gid):
+            if not os.path.isfile(path):
+                raise TransactionFailed(ERROR_UNREADABLE_PACKAGE_FILE, path)
+
+        if not force and os.path.isfile("/usr/bin/lintian"):
+            with DaemonLintianProgress(trans) as progress:
+                progress.run(path)
+            # FIXME: Add an error to catch return state 2 (failure)
+            if progress._child_exit != 0:
+                raise TransactionFailed(ERROR_INVALID_PACKAGE_FILE,
+                                        "Lintian check results for %s:"
+                                        "\n%s" % (path, progress.output))
+        try:
+            deb = apt.debfile.DebPackage(path, self._cache)
+        except IOError:
+            raise TransactionFailed(ERROR_UNREADABLE_PACKAGE_FILE, path)
+        except Exception as error:
+            raise TransactionFailed(ERROR_INVALID_PACKAGE_FILE, str(error))
+        try:
+            ret = deb.check()
+        except Exception as error:
+            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED, str(error))
+        if not ret:
+            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED,
+                                    deb._failure_string)
+        return deb
+
+    def clean(self, trans):
+        """Clean the download directories.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        """
+        # FIXME: Use pkgAcquire.Clean(). Currently not part of python-apt.
+        trans.status = STATUS_CLEANING_UP
+        archive_path = apt_pkg.config.find_dir("Dir::Cache::archives")
+        for dir in [archive_path, os.path.join(archive_path, "partial")]:
+            for filename in os.listdir(dir):
+                if filename == "lock":
+                    continue
+                path = os.path.join(dir, filename)
+                if os.path.isfile(path):
+                    log.debug("Removing file %s", path)
+                    os.remove(path)
+
+    def add_license_key(self, trans, pkg_name, json_token, server_name):
+        """Add a license key data to the given package.
+
+        Keyword arguemnts:
+        trans -- the coresponding transaction
+        pkg_name -- the name of the corresponding package
+        json_token -- the oauth token as json
+        server_name -- the server to use (ubuntu-production, ubuntu-staging)
+        """
+        # set transaction state to downloading
+        trans.status = STATUS_DOWNLOADING
+        try:
+            license_key, license_key_path = (
+                self.plugins["get_license_key"][0](trans.uid, pkg_name,
+                                                   json_token, server_name))
+        except Exception as error:
+            logging.exception("get_license_key plugin failed")
+            raise TransactionFailed(ERROR_LICENSE_KEY_DOWNLOAD_FAILED,
+                                    str(error))
+        # ensure stuff is good
+        if not license_key_path or not license_key:
+            raise TransactionFailed(ERROR_LICENSE_KEY_DOWNLOAD_FAILED,
+                                    _("The license key is empty"))
+
+        # add license key if we have one
+        self._add_license_key_to_system(pkg_name, license_key,
+                                        license_key_path)
+
+    def _add_license_key_to_system(self, pkg_name, license_key,
+                                   license_key_path):
+        # fixup path
+        license_key_path = os.path.join(apt_pkg.config.find_dir("Dir"),
+                                        license_key_path.lstrip("/"))
+
+        # Check content of the key
+        if (license_key.strip().startswith("#!") or
+                license_key.startswith("\x7fELF")):
+            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
+                                    _("The license key is not allowed to "
+                                      "contain executable code."))
+        # Check the path of the license
+        license_key_path = os.path.normpath(license_key_path)
+        license_key_path_rootdir = os.path.join(
+            apt_pkg.config["Dir"], self.LICENSE_KEY_ROOTDIR.lstrip("/"),
+            pkg_name)
+        if not license_key_path.startswith(license_key_path_rootdir):
+            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
+                                    _("The license key path %s is invalid"),
+                                    license_key_path)
+        if os.path.lexists(license_key_path):
+            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
+                                    _("The license key already exists: %s"),
+                                    license_key_path)
+        # Symlink attacks!
+        if os.path.realpath(license_key_path) != license_key_path:
+            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
+                                    _("The location of the license key is "
+                                      "unsecure since it contains symbolic "
+                                      "links. The path %s maps to %s"),
+                                    license_key_path,
+                                    os.path.realpath(license_key_path))
+        # Check if the directory already exists
+        if not os.path.isdir(os.path.dirname(license_key_path)):
+            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
+                                    _("The directory where to install the key "
+                                      "to doesn't exist yet: %s"),
+                                    license_key_path)
+        # write it
+        log.info("Writing license key to '%s'" % license_key_path)
+        old_umask = os.umask(18)
+        try:
+            with open(license_key_path, "w") as license_file:
+                license_file.write(license_key)
+        except IOError:
+            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
+                                    _("Failed to write key file to: %s"),
+                                    license_key_path)
+        finally:
+            os.umask(old_umask)
+
+    def _iterate_mainloop(self):
+        """Process pending actions on the main loop."""
+        while GLib.main_context_default().pending():
+            GLib.main_context_default().iteration()
+
+    def _iterate_packages(self, interval=1000):
+        """Itarte von the packages of the cache and iterate on the
+        GObject main loop time for more responsiveness.
+
+        Keyword arguments:
+        interval - the number of packages after which we iterate on the
+            mainloop
+        """
+        for enum, pkg in enumerate(self._cache):
+            if not enum % interval:
+                self._iterate_mainloop()
+            yield pkg
+
+    def _get_broken_details(self, trans, now=True):
+        """Return a message which provides debugging information about
+        broken packages.
+
+        This method is basically a Python implementation of apt-get.cc's
+        ShowBroken.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        now -- if we check currently broken dependecies or the installation
+               candidate
+        """
+        msg = trans.gettext("The following packages have unmet dependencies:")
+        msg += "\n\n"
+        for pkg in self._cache:
+            if not ((now and pkg.is_now_broken) or
+                    (not now and pkg.is_inst_broken)):
+                continue
+            msg += "%s: " % pkg.name
+            if now:
+                version = pkg.installed
+            else:
+                version = pkg.candidate
+            indent = " " * (len(pkg.name) + 2)
+            dep_msg = ""
+            for dep in version.dependencies:
+                or_msg = ""
+                for base_dep in dep.or_dependencies:
+                    if or_msg:
+                        or_msg += "or\n"
+                        or_msg += indent
+                    # Check if it's an important dependency
+                    # See apt-pkg/depcache.cc IsImportantDep
+                    # See apt-pkg/pkgcache.cc IsCritical()
+                    if not (base_dep.rawtype in ["Depends", "PreDepends",
+                                                 "Obsoletes", "DpkgBreaks",
+                                                 "Conflicts"] or
+                            (apt_pkg.config.find_b("APT::Install-Recommends",
+                                                   False) and
+                            base_dep.rawtype == "Recommends") or
+                            (apt_pkg.config.find_b("APT::Install-Suggests",
+                                                   False) and
+                             base_dep.rawtype == "Suggests")):
+                        continue
+                    # Get the version of the target package
+                    try:
+                        pkg_dep = self._cache[base_dep.name]
+                    except KeyError:
+                        dep_version = None
+                    else:
+                        if now:
+                            dep_version = pkg_dep.installed
+                        else:
+                            dep_version = pkg_dep.candidate
+                    # We only want to display dependencies which cannot
+                    # be satisfied
+                    if dep_version and not apt_pkg.check_dep(base_dep.version,
+                                                             base_dep.relation,
+                                                             version.version):
+                        break
+                    or_msg = "%s: %s " % (base_dep.rawtype, base_dep.name)
+                    if base_dep.version:
+                        or_msg += "(%s %s) " % (base_dep.relation,
+                                                base_dep.version)
+                    if self._cache.is_virtual_package(base_dep.name):
+                        or_msg += trans.gettext("but it is a virtual package")
+                    elif not dep_version:
+                        if now:
+                            or_msg += trans.gettext("but it is not installed")
+                        else:
+                            or_msg += trans.gettext("but it is not going to "
+                                                    "be installed")
+                    elif now:
+                        # TRANSLATORS: %s is a version number
+                        or_msg += (trans.gettext("but %s is installed") %
+                                   dep_version.version)
+                    else:
+                        # TRANSLATORS: %s is a version number
+                        or_msg += (trans.gettext("but %s is to be installed") %
+                                   dep_version.version)
+                else:
+                    # Only append an or-group if at least one of the
+                    # dependencies cannot be satisfied
+                    if dep_msg:
+                        dep_msg += indent
+                    dep_msg += or_msg
+                    dep_msg += "\n"
+            msg += dep_msg
+        return msg
+
+    def is_reboot_required(self):
+        """If a reboot is required to get all changes into effect."""
+        return os.path.exists(os.path.join(apt_pkg.config.find_dir("Dir"),
+                                           "var/run/reboot-required"))
+
+    def set_config(self, option, value, filename=None):
+        """Write a configuration value to file."""
+        if option in ["AutoUpdateInterval", "AutoDownload",
+                      "AutoCleanInterval", "UnattendedUpgrade"]:
+            self._set_apt_config(option, value, filename)
+        elif option == "PopConParticipation":
+            self._set_popcon_pariticipation(value)
+
+    def _set_apt_config(self, option, value, filename):
+        config_writer = ConfigWriter()
+        cw.set_value(option, value, filename)
+        apt_pkg.init_config()
+
+    def _set_popcon_participation(self, participate):
+        if participate in [True, 1, "yes"]:
+            value = "yes"
+        else:
+            value = "no"
+        if os.path.exists(_POPCON_PATH):
+            # read the current config and replace the corresponding settings
+            # FIXME: Check if the config file is a valid bash script and
+            #        contains the host_id
+            with open(_POPCON_PATH) as conf_file:
+                old_config = conf_file.read()
+            config = re.sub(r'(PARTICIPATE=*)(".+?")',
+                            '\\1"%s"' % value,
+                            old_config)
+        else:
+            # create a new popcon config file
+            m = md5()
+            m.update(open("/dev/urandom", "r").read(1024))
+            config = _POPCON_DEFAULT % {"host_id": m.hexdigest(),
+                                        "participate": value}
+
+        with open(_POPCON_PATH, "w") as conf_file:
+            conf_file.write(config)
+
+    def get_config(self, option):
+        """Return a configuration value."""
+        if option == "AutoUpdateInterval":
+            key = "APT::Periodic::Update-Package-Lists"
+            return apt_pkg.config.find_i(key, 0)
+        elif option == "AutoDownload":
+            key = "APT::Periodic::Download-Upgradeable-Packages"
+            return apt_pkg.config.find_b(key, False)
+        elif option == "AutoCleanInterval":
+            key = "APT::Periodic::AutocleanInterval"
+            return apt_pkg.config.find_i(key, 0)
+        elif option == "UnattendedUpgrade":
+            key = "APT::Periodic::Unattended-Upgrade"
+            return apt_pkg.config.find_b(key, False)
+        elif option == "GetPopconParticipation":
+            return self._get_popcon_pariticipation()
+
+    def _get_popcon_participation(self):
+        # FIXME: Use a script to evaluate the configuration:
+        #       #!/bin/sh
+        #       . /etc/popularitiy-contest.conf
+        #       . /usr/share/popularitiy-contest/default.conf
+        #       echo $PARTICIAPTE $HOST_ID
+        if os.path.exists(_POPCON_PATH):
+            with open(_POPCON_PATH) as conf_file:
+                config = conf_file.read()
+            match = re.match("\nPARTICIPATE=\"(yes|no)\"", config)
+            if match and match[0] == "yes":
+                return True
+        return False
+
+    def get_trusted_vendor_keys(self):
+        """Return a list of trusted GPG keys."""
+        return [key.keyid for key in apt.auth.list_keys()]
+
+
+# vim:ts=4:sw=4:et
diff -pruN 1.1.1-4/aptdaemon/worker/__init__.py 1.1.1+bzr982-0ubuntu14/aptdaemon/worker/__init__.py
--- 1.1.1-4/aptdaemon/worker/__init__.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/worker/__init__.py	2013-07-27 07:37:51.000000000 +0000
@@ -0,0 +1,334 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""Provides AptWorker which processes transactions."""
+# Copyright (C) 2008-2009 Sebastian Heinlein <devel@glatzor.de>
+#
+# 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
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+__author__ = "Sebastian Heinlein <devel@glatzor.de>"
+
+__all__ = ("BaseWorker", "DummyWorker")
+
+import logging
+import os
+import pkg_resources
+import time
+import traceback
+
+from gi.repository import GObject, GLib
+
+from .. import enums
+from .. import errors
+
+log = logging.getLogger("AptDaemon.Worker")
+
+# Just required to detect translatable strings. The translation is done by
+# core.Transaction.gettext
+_ = lambda s: s
+
+
+class BaseWorker(GObject.GObject):
+
+    """Worker which processes transactions from the queue."""
+
+    __gsignals__ = {"transaction-done": (GObject.SignalFlags.RUN_FIRST,
+                                         None,
+                                         (GObject.TYPE_PYOBJECT,)),
+                    "transaction-simulated": (GObject.SignalFlags.RUN_FIRST,
+                                              None,
+                                              (GObject.TYPE_PYOBJECT,))}
+    NATIVE_ARCH = None
+
+    def __init__(self, chroot=None, load_plugins=True):
+        """Initialize a new AptWorker instance."""
+        GObject.GObject.__init__(self)
+        self.trans = None
+        self.last_action_timestamp = time.time()
+        self.chroot = chroot
+        # Store the the tid of the transaction whose changes are currently
+        # marked in the cache
+        self.marked_tid = None
+        self.plugins = {}
+
+    @staticmethod
+    def _split_package_id(package):
+        """Return the name, the version number and the release of the
+        specified package."""
+        if "=" in package:
+            name, version = package.split("=", 1)
+            release = None
+        elif "/" in package:
+            name, release = package.split("/", 1)
+            version = None
+        else:
+            name = package
+            version = release = None
+        return name, version, release
+
+    def run(self, transaction):
+        """Process the given transaction in the background.
+
+        Keyword argument:
+        transaction -- core.Transcation instance to run
+        """
+        log.info("Processing transaction %s", transaction.tid)
+        if self.trans:
+            raise Exception("There is already a running transaction")
+        self.trans = transaction
+        GLib.idle_add(self._run_transaction_idle, transaction)
+
+    def simulate(self, trans):
+        """Return the dependencies which will be installed by the transaction,
+        the content of the dpkg status file after the transaction would have
+        been applied, the download size and the required disk space.
+
+        Keyword arguments:
+        trans -- the transaction which should be simulated
+        """
+        log.info("Simulating trans: %s" % trans.tid)
+        trans.status = enums.STATUS_RESOLVING_DEP
+        GLib.idle_add(self._simulate_transaction_idle, trans)
+
+    def _emit_transaction_simulated(self, trans):
+        """Emit the transaction-simulated signal.
+
+        Keyword argument:
+        trans -- the simulated transaction
+        """
+        log.debug("Emitting transaction-simulated: %s", trans.tid)
+        self.emit("transaction-simulated", trans)
+
+    def _emit_transaction_done(self, trans):
+        """Emit the transaction-done signal.
+
+        Keyword argument:
+        trans -- the finished transaction
+        """
+        log.debug("Emitting transaction-done: %s", trans.tid)
+        self.emit("transaction-done", trans)
+
+    def _run_transaction_idle(self, trans):
+        """Run the transaction"""
+        self.last_action_timestamp = time.time()
+        trans.status = enums.STATUS_RUNNING
+        trans.progress = 11
+        try:
+            self._run_transaction(trans)
+        except errors.TransactionCancelled:
+            trans.exit = enums.EXIT_CANCELLED
+        except errors.TransactionFailed as excep:
+            trans.error = excep
+            trans.exit = enums.EXIT_FAILED
+        except (KeyboardInterrupt, SystemExit):
+            trans.exit = enums.EXIT_CANCELLED
+        except Exception as excep:
+            tbk = traceback.format_exc()
+            trans.error = errors.TransactionFailed(enums.ERROR_UNKNOWN, tbk)
+            trans.exit = enums.EXIT_FAILED
+            try:
+                from . import crash
+            except ImportError:
+                pass
+            else:
+                crash.create_report("%s: %s" % (type(excep), str(excep)),
+                                    tbk, trans)
+        else:
+            trans.exit = enums.EXIT_SUCCESS
+        finally:
+            trans.progress = 100
+            self.last_action_timestamp = time.time()
+            tid = trans.tid[:]
+            self.trans = None
+            self.marked_tid = None
+            self._emit_transaction_done(trans)
+            log.info("Finished transaction %s", tid)
+        return False
+
+    def _simulate_transaction_idle(self, trans):
+        try:
+            (trans.depends, trans.download, trans.space,
+                trans.unauthenticated,
+                trans.high_trust_packages) = self._simulate_transaction(trans)
+        except errors.TransactionFailed as excep:
+            trans.error = excep
+            trans.exit = enums.EXIT_FAILED
+        except Exception as excep:
+            tbk = traceback.format_exc()
+            trans.error = errors.TransactionFailed(enums.ERROR_UNKNOWN, tbk)
+            try:
+                from . import crash
+            except ImportError:
+                pass
+            else:
+                crash.create_report("%s: %s" % (type(excep), str(excep)),
+                                    tbk, trans)
+            trans.exit = enums.EXIT_FAILED
+        else:
+            trans.status = enums.STATUS_SETTING_UP
+            trans.simulated = time.time()
+            self.marked_tid = trans.tid
+        finally:
+            self._emit_transaction_simulated(trans)
+            self.last_action_timestamp = time.time()
+        return False
+
+    def _load_plugins(self, plugins, entry_point="aptdaemon.plugins"):
+        """Load the plugins from setuptools' entry points."""
+        plugin_dirs = [os.path.join(os.path.dirname(__file__), "plugins")]
+        env = pkg_resources.Environment(plugin_dirs)
+        dists, errors = pkg_resources.working_set.find_plugins(env)
+        for dist in dists:
+            pkg_resources.working_set.add(dist)
+        for name in plugins:
+            for ept in pkg_resources.iter_entry_points(entry_point,
+                                                       name):
+                try:
+                    self.plugins.setdefault(name, []).append(ept.load())
+                except:
+                    log.critical("Failed to load %s plugin: "
+                                 "%s" % (name, ept.dist))
+                else:
+                    log.debug("Loaded %s plugin: %s", name, ept.dist)
+
+    def _simulate_transaction(self, trans):
+        """This method needs to be implemented by the backends."""
+        depends = [[], [], [], [], [], [], []]
+        unauthenticated = []
+        high_trust_packages = []
+        skip_pkgs = []
+        size = 0
+        installs = reinstalls = removals = purges = upgrades = upgradables = \
+            downgrades = []
+
+        return depends, 0, 0, [], []
+
+    def _run_transaction(self, trans):
+        """This method needs to be implemented by the backends."""
+        raise errors.TransactionFailed(enums.ERROR_NOT_SUPPORTED)
+
+    def set_config(self, option, value, filename):
+        """Set a configuration option.
+
+        This method needs to be implemented by the backends."""
+        raise NotImplementedError
+
+    def get_config(self, option):
+        """Get a configuration option.
+
+        This method needs to be implemented by the backends."""
+        raise NotImplementedError
+
+    def get_trusted_vendor_keys(self):
+        """This method needs to be implemented by the backends."""
+        return []
+
+    def is_reboot_required(self):
+        """This method needs to be implemented by the backends."""
+        return False
+
+
+class DummyWorker(BaseWorker):
+
+    """Allows to test the daemon without making any changes to the system."""
+
+    def run(self, transaction):
+        """Process the given transaction in the background.
+
+        Keyword argument:
+        transaction -- core.Transcation instance to run
+        """
+        log.info("Processing transaction %s", transaction.tid)
+        if self.trans:
+            raise Exception("There is already a running transaction")
+        self.trans = transaction
+        self.last_action_timestamp = time.time()
+        self.trans.status = enums.STATUS_RUNNING
+        self.trans.progress = 0
+        self.trans.cancellable = True
+        GLib.timeout_add(200, self._run_transaction_idle, transaction)
+
+    def _run_transaction_idle(self, trans):
+        """Run the worker"""
+        if trans.cancelled:
+            trans.exit = enums.EXIT_CANCELLED
+        elif trans.progress == 100:
+            trans.exit = enums.EXIT_SUCCESS
+        elif trans.role == enums.ROLE_UPDATE_CACHE:
+            trans.exit = enums.EXIT_FAILED
+        elif trans.role == enums.ROLE_UPGRADE_PACKAGES:
+            trans.exit = enums.EXIT_SUCCESS
+        elif trans.role == enums.ROLE_UPGRADE_SYSTEM:
+            trans.exit = enums.EXIT_CANCELLED
+        else:
+            if trans.role == enums.ROLE_INSTALL_PACKAGES:
+                if trans.progress == 1:
+                    trans.status = enums.STATUS_RESOLVING_DEP
+                elif trans.progress == 5:
+                    trans.status = enums.STATUS_DOWNLOADING
+                elif trans.progress == 50:
+                    trans.status = enums.STATUS_COMMITTING
+                    trans.status_details = "Heyas!"
+                elif trans.progress == 55:
+                    trans.paused = True
+                    trans.status = enums.STATUS_WAITING_CONFIG_FILE_PROMPT
+                    trans.config_file_conflict = "/etc/fstab", "/etc/mtab"
+                    while trans.paused:
+                        GLib.main_context_default().iteration()
+                    trans.config_file_conflict_resolution = None
+                    trans.config_file_conflict = None
+                    trans.status = enums.STATUS_COMMITTING
+                elif trans.progress == 60:
+                    trans.required_medium = ("Debian Lenny 5.0 CD 1",
+                                             "USB CD-ROM")
+                    trans.paused = True
+                    trans.status = enums.STATUS_WAITING_MEDIUM
+                    while trans.paused:
+                        GLib.main_context_default().iteration()
+                    trans.status = enums.STATUS_DOWNLOADING
+                elif trans.progress == 70:
+                    trans.status_details = "Servus!"
+                elif trans.progress == 90:
+                    trans.status_deatils = ""
+                    trans.status = enums.STATUS_CLEANING_UP
+            elif trans.role == enums.ROLE_REMOVE_PACKAGES:
+                if trans.progress == 1:
+                    trans.status = enums.STATUS_RESOLVING_DEP
+                elif trans.progress == 5:
+                    trans.status = enums.STATUS_COMMITTING
+                    trans.status_details = "Heyas!"
+                elif trans.progress == 50:
+                    trans.status_details = "Hola!"
+                elif trans.progress == 70:
+                    trans.status_details = "Servus!"
+                elif trans.progress == 90:
+                    trans.status_deatils = ""
+                    trans.status = enums.STATUS_CLEANING_UP
+            trans.progress += 1
+            return True
+        trans.status = enums.STATUS_FINISHED
+        self.last_action_timestamp = time.time()
+        tid = self.trans.tid[:]
+        trans = self.trans
+        self.trans = None
+        self._emit_transaction_done(trans)
+        log.info("Finished transaction %s", tid)
+        return False
+
+    def simulate(self, trans):
+        depends = [[], [], [], [], [], [], []]
+        return depends, 0, 0, [], []
+
+
+# vim:ts=4:sw=4:et
diff -pruN 1.1.1-4/aptdaemon/worker/pkworker.py 1.1.1+bzr982-0ubuntu14/aptdaemon/worker/pkworker.py
--- 1.1.1-4/aptdaemon/worker/pkworker.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/worker/pkworker.py	2014-06-26 07:13:49.000000000 +0000
@@ -0,0 +1,1355 @@
+# !/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Provides a compatibility layer to PackageKit
+
+Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
+Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
+Copyright (C) 2008-2011 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>"
+
+import datetime
+import glob
+import gzip
+import locale
+import logging
+import os
+import platform
+import re
+import subprocess
+import tempfile
+import time
+
+import apt_pkg
+
+from gi.repository import GObject
+from gi.repository import PackageKitGlib as pk
+
+# for optional plugin support
+try:
+    import pkg_resources
+except ImportError:
+    pkg_resources = None
+
+from ..pkutils import (bitfield_add, bitfield_remove, bitfield_summarize,
+                       bitfield_contains)
+from . import enums as aptd_enums
+from ..errors import TransactionFailed
+from ..progress import DaemonAcquireProgress
+from . import aptworker
+
+
+pklog = logging.getLogger("AptDaemon.PackageKitWorker")
+
+# Check if update-manager-core is installed to get aware of the
+# latest distro releases
+try:
+    from UpdateManager.Core.MetaRelease import MetaReleaseCore
+except ImportError:
+    META_RELEASE_SUPPORT = False
+else:
+    META_RELEASE_SUPPORT = True
+
+# Xapian database is optionally used to speed up package description search
+XAPIAN_DB_PATH = os.environ.get("AXI_DB_PATH", "/var/lib/apt-xapian-index")
+XAPIAN_DB = XAPIAN_DB_PATH + "/index"
+XAPIAN_DB_VALUES = XAPIAN_DB_PATH + "/values"
+XAPIAN_SUPPORT = False
+try:
+    import xapian
+except ImportError:
+    pass
+else:
+    if os.access(XAPIAN_DB, os.R_OK):
+        pklog.debug("Use XAPIAN for the search")
+        XAPIAN_SUPPORT = True
+
+# Regular expressions to detect bug numbers in changelogs according to the
+# Debian Policy Chapter 4.4. For details see the footnote 16:
+# http://www.debian.org/doc/debian-policy/footnotes.html#f16
+MATCH_BUG_CLOSES_DEBIAN = (
+    r"closes:\s*(?:bug)?\#?\s?\d+(?:,\s*(?:bug)?\#?\s?\d+)*")
+MATCH_BUG_NUMBERS = r"\#?\s?(\d+)"
+# URL pointing to a bug in the Debian bug tracker
+HREF_BUG_DEBIAN = "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s"
+
+MATCH_BUG_CLOSES_UBUNTU = r"lp:\s+\#\d+(?:,\s*\#\d+)*"
+HREF_BUG_UBUNTU = "https://bugs.launchpad.net/bugs/%s"
+
+# Regular expression to find cve references
+MATCH_CVE = "CVE-\d{4}-\d{4}"
+HREF_CVE = "http://web.nvd.nist.gov/view/vuln/detail?vulnId=%s"
+
+# Map Debian sections to the PackageKit group name space
+SECTION_GROUP_MAP = {
+    "admin": pk.GroupEnum.ADMIN_TOOLS,
+    "base": pk.GroupEnum.SYSTEM,
+    "cli-mono": pk.GroupEnum.PROGRAMMING,
+    "comm": pk.GroupEnum.COMMUNICATION,
+    "database": pk.GroupEnum.SERVERS,
+    "debian-installer": pk.GroupEnum.SYSTEM,
+    "debug": pk.GroupEnum.PROGRAMMING,
+    "devel": pk.GroupEnum.PROGRAMMING,
+    "doc": pk.GroupEnum.DOCUMENTATION,
+    "editors": pk.GroupEnum.PUBLISHING,
+    "education": pk.GroupEnum.EDUCATION,
+    "electronics": pk.GroupEnum.ELECTRONICS,
+    "embedded": pk.GroupEnum.SYSTEM,
+    "fonts": pk.GroupEnum.FONTS,
+    "games": pk.GroupEnum.GAMES,
+    "gnome": pk.GroupEnum.DESKTOP_GNOME,
+    "gnu-r": pk.GroupEnum.PROGRAMMING,
+    "gnustep": pk.GroupEnum.DESKTOP_OTHER,
+    "graphics": pk.GroupEnum.GRAPHICS,
+    "hamradio": pk.GroupEnum.COMMUNICATION,
+    "haskell": pk.GroupEnum.PROGRAMMING,
+    "httpd": pk.GroupEnum.SERVERS,
+    "interpreters": pk.GroupEnum.PROGRAMMING,
+    "introspection": pk.GroupEnum.PROGRAMMING,
+    "java": pk.GroupEnum.PROGRAMMING,
+    "kde": pk.GroupEnum.DESKTOP_KDE,
+    "kernel": pk.GroupEnum.SYSTEM,
+    "libdevel": pk.GroupEnum.PROGRAMMING,
+    "libs": pk.GroupEnum.SYSTEM,
+    "lisp": pk.GroupEnum.PROGRAMMING,
+    "localization": pk.GroupEnum.LOCALIZATION,
+    "mail": pk.GroupEnum.INTERNET,
+    "math": pk.GroupEnum.SCIENCE,
+    "misc": pk.GroupEnum.OTHER,
+    "net": pk.GroupEnum.NETWORK,
+    "news": pk.GroupEnum.INTERNET,
+    "ocaml": pk.GroupEnum.PROGRAMMING,
+    "oldlibs": pk.GroupEnum.LEGACY,
+    "otherosfs": pk.GroupEnum.SYSTEM,
+    "perl": pk.GroupEnum.PROGRAMMING,
+    "php": pk.GroupEnum.PROGRAMMING,
+    "python": pk.GroupEnum.PROGRAMMING,
+    "ruby": pk.GroupEnum.PROGRAMMING,
+    "science": pk.GroupEnum.SCIENCE,
+    "shells": pk.GroupEnum.ADMIN_TOOLS,
+    "sound": pk.GroupEnum.MULTIMEDIA,
+    "tex": pk.GroupEnum.PUBLISHING,
+    "text": pk.GroupEnum.PUBLISHING,
+    "utils": pk.GroupEnum.ACCESSORIES,
+    "vcs": pk.GroupEnum.PROGRAMMING,
+    "video": pk.GroupEnum.MULTIMEDIA,
+    "virtual": pk.GroupEnum.COLLECTIONS,
+    "web": pk.GroupEnum.INTERNET,
+    "xfce": pk.GroupEnum.DESKTOP_OTHER,
+    "x11": pk.GroupEnum.DESKTOP_OTHER,
+    "zope": pk.GroupEnum.PROGRAMMING,
+    "unknown": pk.GroupEnum.UNKNOWN,
+    "alien": pk.GroupEnum.UNKNOWN,
+    "translations": pk.GroupEnum.LOCALIZATION,
+    "metapackages": pk.GroupEnum.COLLECTIONS,
+    "tasks": pk.GroupEnum.COLLECTIONS}
+
+
+class AptPackageKitWorker(aptworker.AptWorker):
+
+    _plugins = None
+
+    """Process PackageKit Query transactions."""
+
+    def __init__(self, chroot=None, load_plugins=True):
+        aptworker.AptWorker.__init__(self, chroot, load_plugins)
+
+        self.roles = bitfield_summarize(pk.RoleEnum.REFRESH_CACHE,
+                                        pk.RoleEnum.UPDATE_PACKAGES,
+                                        pk.RoleEnum.INSTALL_PACKAGES,
+                                        pk.RoleEnum.INSTALL_FILES,
+                                        pk.RoleEnum.REMOVE_PACKAGES,
+                                        pk.RoleEnum.GET_UPDATES,
+                                        pk.RoleEnum.GET_UPDATE_DETAIL,
+                                        pk.RoleEnum.GET_PACKAGES,
+                                        pk.RoleEnum.GET_DETAILS,
+                                        pk.RoleEnum.GET_DEPENDS,
+                                        pk.RoleEnum.GET_REQUIRES,
+                                        pk.RoleEnum.SEARCH_NAME,
+                                        pk.RoleEnum.SEARCH_DETAILS,
+                                        pk.RoleEnum.SEARCH_GROUP,
+                                        pk.RoleEnum.SEARCH_FILE,
+                                        pk.RoleEnum.WHAT_PROVIDES,
+                                        pk.RoleEnum.REPO_ENABLE,
+                                        pk.RoleEnum.INSTALL_SIGNATURE,
+                                        pk.RoleEnum.REPAIR_SYSTEM,
+                                        pk.RoleEnum.CANCEL,
+                                        pk.RoleEnum.DOWNLOAD_PACKAGES)
+        if META_RELEASE_SUPPORT:
+            self.roles = bitfield_add(self.roles,
+                                      pk.RoleEnum.GET_DISTRO_UPGRADES)
+        self.filters = bitfield_summarize(pk.FilterEnum.INSTALLED,
+                                          pk.FilterEnum.NOT_INSTALLED,
+                                          pk.FilterEnum.FREE,
+                                          pk.FilterEnum.NOT_FREE,
+                                          pk.FilterEnum.GUI,
+                                          pk.FilterEnum.NOT_GUI,
+                                          pk.FilterEnum.COLLECTIONS,
+                                          pk.FilterEnum.NOT_COLLECTIONS,
+                                          pk.FilterEnum.SUPPORTED,
+                                          pk.FilterEnum.NOT_SUPPORTED,
+                                          pk.FilterEnum.ARCH,
+                                          pk.FilterEnum.NOT_ARCH,
+                                          pk.FilterEnum.NEWEST)
+        self.groups = bitfield_summarize(*SECTION_GROUP_MAP.values())
+        # FIXME: Add support for Plugins
+        self.provides = (pk.ProvidesEnum.ANY)
+        self.mime_types = ["application/x-deb"]
+
+    def _run_transaction(self, trans):
+        if (hasattr(trans, "pktrans") and
+            bitfield_contains(trans.pktrans.flags,
+                              pk.TransactionFlagEnum.SIMULATE)):
+            self._simulate_and_emit_packages(trans)
+            return False
+        else:
+            return aptworker.AptWorker._run_transaction(self, trans)
+
+    def _simulate_and_emit_packages(self, trans):
+        trans.status = aptd_enums.STATUS_RUNNING
+
+        self._simulate_transaction_idle(trans)
+
+        # The simulate method lets the transaction fail in the case of an
+        # error
+        if trans.exit == aptd_enums.EXIT_UNFINISHED:
+            # It is a little bit complicated to get the packages but avoids
+            # a larger refactoring of apt.AptWorker._simulate()
+            for pkg in trans.depends[aptd_enums.PKGS_INSTALL]:
+                self._emit_package(trans,
+                                   self._cache[self._split_package_id(pkg)[0]],
+                                   pk.InfoEnum.INSTALLING)
+            for pkg in trans.depends[aptd_enums.PKGS_REINSTALL]:
+                self._emit_package(trans,
+                                   self._cache[self._split_package_id(pkg)[0]],
+                                   pk.InfoEnum.REINSTALLING)
+            for pkg in trans.depends[aptd_enums.PKGS_REMOVE]:
+                self._emit_package(trans,
+                                   self._cache[self._split_package_id(pkg)[0]],
+                                   pk.InfoEnum.REMOVING)
+            for pkg in trans.depends[aptd_enums.PKGS_PURGE]:
+                self._emit_package(trans,
+                                   self._cache[self._split_package_id(pkg)[0]],
+                                   pk.InfoEnum.REMOVING)
+            for pkg in trans.depends[aptd_enums.PKGS_UPGRADE]:
+                self._emit_package(trans,
+                                   self._cache[self._split_package_id(pkg)[0]],
+                                   pk.InfoEnum.UPDATING, force_candidate=True)
+            for pkg in trans.depends[aptd_enums.PKGS_DOWNGRADE]:
+                self._emit_package(trans,
+                                   self._cache[self._split_package_id(pkg)[0]],
+                                   pk.InfoEnum.DOWNGRADING,
+                                   force_candidate=True)
+            for pkg in trans.depends[aptd_enums.PKGS_KEEP]:
+                self._emit_package(trans,
+                                   self._cache[self._split_package_id(pkg)[0]],
+                                   pk.InfoEnum.BLOCKED, force_candidate=True)
+            for pkg in trans.unauthenticated:
+                self._emit_package(trans, self._cache[pkg],
+                                   pk.InfoEnum.UNTRUSTED, force_candidate=True)
+            trans.status = aptd_enums.STATUS_FINISHED
+            trans.progress = 100
+            trans.exit = aptd_enums.EXIT_SUCCESS
+        tid = trans.tid[:]
+        self.trans = None
+        self.marked_tid = None
+        self._emit_transaction_done(trans)
+        pklog.info("Finished transaction %s", tid)
+
+    def query(self, trans):
+        """Run the worker"""
+        if trans.role != aptd_enums.ROLE_PK_QUERY:
+            raise TransactionFailed(aptd_enums.ERROR_UNKNOWN,
+                                    "The transaction doesn't seem to be "
+                                    "a query")
+        if trans.pktrans.role == pk.RoleEnum.RESOLVE:
+            self.resolve(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.GET_UPDATES:
+            self.get_updates(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.GET_UPDATE_DETAIL:
+            self.get_update_detail(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.GET_PACKAGES:
+            self.get_packages(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.GET_FILES:
+            self.get_files(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.SEARCH_NAME:
+            self.search_names(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.SEARCH_GROUP:
+            self.search_groups(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.SEARCH_DETAILS:
+            self.search_details(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.SEARCH_FILE:
+            self.search_files(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.GET_DEPENDS:
+            self.get_depends(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.GET_REQUIRES:
+            self.get_requires(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.GET_DETAILS:
+            self.get_details(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.DOWNLOAD_PACKAGES:
+            self.download_packages(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.WHAT_PROVIDES:
+            self.what_provides(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.REPO_ENABLE:
+            self.repo_enable(trans, **trans.kwargs)
+        elif trans.pktrans.role == pk.RoleEnum.INSTALL_SIGNATURE:
+            self.install_signature(trans, **trans.kwargs)
+        else:
+            raise TransactionFailed(aptd_enums.ERROR_UNKNOWN,
+                                    "Role %s isn't supported",
+                                    trans.pktrans.role)
+
+    def search_files(self, trans, filters, values):
+        """Implement org.freedesktop.PackageKit.Transaction.SearchFiles()
+
+        Works only for installed file if apt-file isn't installed.
+        """
+        trans.progress = 101
+
+        result_names = set()
+        # Optionally make use of apt-file's Contents cache to search for not
+        # installed files. But still search for installed files additionally
+        # to make sure that we provide up-to-date results
+        if (os.path.exists("/usr/bin/apt-file") and
+                not bitfield_contains(filters, pk.FilterEnum.INSTALLED)):
+            # FIXME: use rapt-file on Debian if the network is available
+            # FIXME: Show a warning to the user if the apt-file cache is
+            #        several weeks old
+            pklog.debug("Using apt-file")
+            filenames_regex = []
+            for filename in values:
+                if filename.startswith("/"):
+                    pattern = "^%s$" % filename[1:].replace("/", "\/")
+                else:
+                    pattern = "\/%s$" % filename
+                filenames_regex.append(pattern)
+            cmd = ["/usr/bin/apt-file", "--regexp", "--non-interactive",
+                   "--package-only", "find", "|".join(filenames_regex)]
+            pklog.debug("Calling: %s" % cmd)
+            apt_file = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                                        stderr=subprocess.PIPE)
+            stdout, stderr = apt_file.communicate()
+            if apt_file.returncode == 0:
+                # FIXME: Actually we should check if the file is part of the
+                #       candidate, e.g. if unstable and experimental are
+                #       enabled and a file would only be part of the
+                #       experimental version
+                result_names.update(stdout.split())
+                self._emit_visible_packages_by_name(trans, filters,
+                                                    result_names)
+            else:
+                raise TransactionFailed(aptd_enums.ERROR_INTERNAL_ERROR,
+                                        "%s %s" % (stdout, stderr))
+        # Search for installed files
+        filenames_regex = []
+        for filename in values:
+            if filename.startswith("/"):
+                pattern = "^%s$" % filename.replace("/", "\/")
+            else:
+                pattern = ".*\/%s$" % filename
+            filenames_regex.append(pattern)
+        files_pattern = re.compile("|".join(filenames_regex))
+        for pkg in self._iterate_packages():
+            if pkg.name in result_names:
+                continue
+            for installed_file in self._get_installed_files(pkg):
+                if files_pattern.match(installed_file):
+                    self._emit_visible_package(trans, filters, pkg)
+                    break
+
+    def search_groups(self, trans, filters, values):
+        """Implement org.freedesktop.PackageKit.Transaction.SearchGroups()"""
+        # FIXME: Handle repo and category search
+        trans.progress = 101
+
+        for pkg in self._iterate_packages():
+            group_str = pk.group_enum_to_string(self._get_package_group(pkg))
+            if group_str in values:
+                self._emit_visible_package(trans, filters, pkg)
+
+    def search_names(self, trans, filters, values):
+        """Implement org.freedesktop.PackageKit.Transaction.SearchNames()"""
+        def matches(searches, text):
+            for search in searches:
+                if search not in text:
+                    return False
+            return True
+        trans.progress = 101
+
+        for pkg_name in list(self._cache.keys()):
+            if matches(values, pkg_name):
+                self._emit_all_visible_pkg_versions(trans, filters,
+                                                    self._cache[pkg_name])
+
+    def search_details(self, trans, filters, values):
+        """Implement org.freedesktop.PackageKit.Transaction.SearchDetails()"""
+        trans.progress = 101
+
+        if XAPIAN_SUPPORT is 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(XAPIAN_DB)
+            parser = xapian.QueryParser()
+            parser.set_default_op(xapian.Query.OP_AND)
+            query = parser.parse_query(" ".join(values), search_flags)
+            enquire = xapian.Enquire(db)
+            enquire.set_query(query)
+            matches = enquire.get_mset(0, 1000)
+            for pkg_name in (match.document.get_data()
+                             for match in enquire.get_mset(0, 1000)):
+                if pkg_name in self._cache:
+                    self._emit_visible_package(trans, filters,
+                                               self._cache[pkg_name])
+        else:
+            def matches(searches, text):
+                for search in searches:
+                    if search not in text:
+                        return False
+                return True
+            pklog.debug("Performing apt cache based search")
+            values = [val.lower() for val in values]
+            for pkg in self._iterate_packages():
+                txt = pkg.name
+                try:
+                    txt += pkg.candidate.raw_description.lower()
+                    txt += pkg.candidate._translated_records.long_desc.lower()
+                except AttributeError:
+                    pass
+                if matches(values, txt):
+                    self._emit_visible_package(trans, filters, pkg)
+
+    def get_updates(self, trans, filters):
+        """Only report updates which can be installed safely: Which can depend
+        on the installation of additional packages but which don't require
+        the removal of already installed packages or block any other update.
+        """
+        def succeeds_security_update(pkg):
+            """
+            Return True if an update succeeds a previous security update
+
+            An example would be a package with version 1.1 in the security
+            archive and 1.1.1 in the archive of proposed updates or the
+            same version in both archives.
+            """
+            for version in pkg.versions:
+                # Only check versions between the installed and the candidate
+                if (pkg.installed and
+                    apt_pkg.version_compare(version.version,
+                                            pkg.installed.version) <= 0 and
+                    apt_pkg.version_compare(version.version,
+                                            pkg.candidate.version) > 0):
+                    continue
+                for origin in version.origins:
+                    if (origin.origin in ["Debian", "Ubuntu"] and
+                            (origin.archive.endswith("-security") or
+                             origin.label == "Debian-Security") and
+                            origin.trusted):
+                        return True
+            return False
+        # FIXME: Implment the basename filter
+        self.cancellable = False
+        self.progress = 101
+        # Start with a safe upgrade
+        try:
+            self._cache.upgrade(dist_upgrade=True)
+        except SystemError:
+            pass
+        for pkg in self._iterate_packages():
+            if not pkg.is_upgradable:
+                continue
+            # This may occur on pinned packages which have been updated to
+            # later version than the pinned one
+            if not pkg.candidate.origins:
+                continue
+            if not pkg.marked_upgrade:
+                # FIXME: Would be nice to all show why
+                self._emit_package(trans, pkg, pk.InfoEnum.BLOCKED,
+                                   force_candidate=True)
+                continue
+            # The update can be safely installed
+            info = pk.InfoEnum.NORMAL
+            # Detect the nature of the upgrade (e.g. security, enhancement)
+            candidate_origin = pkg.candidate.origins[0]
+            archive = candidate_origin.archive
+            origin = candidate_origin.origin
+            trusted = candidate_origin.trusted
+            label = candidate_origin.label
+            if origin in ["Debian", "Ubuntu"] and trusted is True:
+                if archive.endswith("-security") or label == "Debian-Security":
+                    info = pk.InfoEnum.SECURITY
+                elif succeeds_security_update(pkg):
+                    pklog.debug("Update of %s succeeds a security update. "
+                                "Raising its priority." % pkg.name)
+                    info = pk.InfoEnum.SECURITY
+                elif archive.endswith("-backports"):
+                    info = pk.InfoEnum.ENHANCEMENT
+                elif archive.endswith("-updates"):
+                    info = pk.InfoEnum.BUGFIX
+            if origin in ["Backports.org archive"] and trusted is True:
+                info = pk.InfoEnum.ENHANCEMENT
+            self._emit_package(trans, pkg, info, force_candidate=True)
+        self._emit_require_restart(trans)
+
+    def _emit_require_restart(self, trans):
+        """Emit RequireRestart if required."""
+        # Check for a system restart
+        if self.is_reboot_required():
+            trans.pktrans.RequireRestart(pk.RestartEnum.SYSTEM, "")
+
+    def get_update_detail(self, trans, package_ids):
+        """
+        Implement the {backend}-get-update-details functionality
+        """
+        def get_bug_urls(changelog):
+            """
+            Create a list of urls pointing to closed bugs in the changelog
+            """
+            urls = []
+            for r in re.findall(MATCH_BUG_CLOSES_DEBIAN, changelog,
+                                re.IGNORECASE | re.MULTILINE):
+                urls.extend([HREF_BUG_DEBIAN % bug for bug in
+                             re.findall(MATCH_BUG_NUMBERS, r)])
+            for r in re.findall(MATCH_BUG_CLOSES_UBUNTU, changelog,
+                                re.IGNORECASE | re.MULTILINE):
+                urls.extend([HREF_BUG_UBUNTU % bug for bug in
+                             re.findall(MATCH_BUG_NUMBERS, r)])
+            return urls
+
+        def get_cve_urls(changelog):
+            """
+            Create a list of urls pointing to cves referred in the changelog
+            """
+            return [HREF_CVE % c for c in re.findall(MATCH_CVE, changelog,
+                                                     re.MULTILINE)]
+
+        trans.progress = 0
+        trans.cancellable = False
+        trans.pktrans.status = pk.StatusEnum.DOWNLOAD_CHANGELOG
+        total = len(package_ids)
+        count = 1
+        old_locale = locale.getlocale(locale.LC_TIME)
+        locale.setlocale(locale.LC_TIME, "C")
+        for pkg_id in package_ids:
+            self._iterate_mainloop()
+            trans.progress = count * 100 / total
+            count += 1
+            pkg = self._get_package_by_id(pkg_id)
+            # FIXME add some real data
+            if pkg.installed.origins:
+                installed_origin = pkg.installed.origins[0].label
+                # APT returns a str with Python 2
+                if isinstance(installed_origin, bytes):
+                    installed_origin = installed_origin.decode("UTF-8")
+            else:
+                installed_origin = ""
+            updates = ["%s;%s;%s;%s" % (pkg.name, pkg.installed.version,
+                                        pkg.installed.architecture,
+                                        installed_origin)]
+            # Get the packages which will be replaced by the update
+            obsoletes = set()
+            if pkg.candidate:
+                for dep_group in pkg.candidate.get_dependencies("Replaces"):
+                    for dep in dep_group:
+                        try:
+                            obs = self._cache[dep.name]
+                        except KeyError:
+                            continue
+                        if not obs.installed:
+                            continue
+                        if dep.relation:
+                            cmp = apt_pkg.version_compare(
+                                obs.candidate.version,
+                                dep.version)
+                            # Same version
+                            if cmp == 0 and dep.relation in [">", "<"]:
+                                continue
+                            # Installed version higer
+                            elif cmp < 0 and dep.relation in ["<"]:
+                                continue
+                            # Installed version lower
+                            elif cmp > 0 and dep.relation in [">"]:
+                                continue
+                        obs_id = self._get_id_from_version(obs.installed)
+                        obsoletes.add(obs_id)
+            vendor_urls = []
+            restart = pk.RestartEnum.NONE
+            update_text = ""
+            state = pk.UpdateStateEnum.UNKNOWN
+            # FIXME: Add support for Ubuntu and a better one for Debian
+            if (pkg.candidate and pkg.candidate.origins[0].trusted and
+                    pkg.candidate.origins[0].label == "Debian"):
+                archive = pkg.candidate.origins[0].archive
+                if archive == "stable":
+                    state = pk.UpdateStateEnum.STABLE
+                elif archive == "testing":
+                    state = pk.UpdateStateEnum.TESTING
+                elif archive == "unstable":
+                    state = pk.UpdateStateEnum.UNSTABLE
+            issued = ""
+            updated = ""
+            # FIXME: make this more configurable. E.g. a dbus update requires
+            #       a reboot on Ubuntu but not on Debian
+            if (pkg.name.startswith("linux-image-") or
+                    pkg.name in ["libc6", "dbus"]):
+                restart == pk.RestartEnum.SYSTEM
+            changelog_dir = apt_pkg.config.find_dir("Dir::Cache::Changelogs")
+            if changelog_dir == "/":
+                changelog_dir = os.path.join(apt_pkg.config.find_dir("Dir::"
+                                                                     "Cache"),
+                                             "Changelogs")
+            filename = os.path.join(changelog_dir,
+                                    "%s_%s.gz" % (pkg.name,
+                                                  pkg.candidate.version))
+            changelog_raw = ""
+            if os.path.exists(filename):
+                pklog.debug("Reading changelog from cache")
+                changelog_file = gzip.open(filename, "rb")
+                try:
+                    changelog_raw = changelog_file.read().decode("UTF-8")
+                except:
+                    pass
+                finally:
+                    changelog_file.close()
+            if not changelog_raw:
+                pklog.debug("Downloading changelog")
+                changelog_raw = pkg.get_changelog()
+                # The internal download error string of python-apt ist not
+                # provided as unicode object
+                if not isinstance(changelog_raw, str):
+                    changelog_raw = changelog_raw.decode("UTF-8")
+                # Cache the fetched changelog
+                if not os.path.exists(changelog_dir):
+                    os.makedirs(changelog_dir)
+                # Remove old cached changelogs
+                pattern = os.path.join(changelog_dir, "%s_*" % pkg.name)
+                for old_changelog in glob.glob(pattern):
+                    os.remove(os.path.join(changelog_dir, old_changelog))
+                changelog_file = gzip.open(filename, mode="wb")
+                try:
+                    changelog_file.write(changelog_raw.encode("UTF-8"))
+                finally:
+                    changelog_file.close()
+            # Convert the changelog to markdown syntax
+            changelog = ""
+            for line in changelog_raw.split("\n"):
+                if line == "":
+                    changelog += " \n"
+                else:
+                    changelog += "    %s  \n" % line
+                if line.startswith(pkg.candidate.source_name):
+                    match = re.match(r"(?P<source>.+) \((?P<version>.*)\) "
+                                     "(?P<dist>.+); urgency=(?P<urgency>.+)",
+                                     line)
+                    update_text += "%s\n%s\n\n" % (match.group("version"),
+                                                   "=" *
+                                                   len(match.group("version")))
+                elif line.startswith("  "):
+                    # FIXME: The GNOME PackageKit markup parser doesn't support
+                    #        monospaced yet
+                    # update_text += "  %s  \n" % line
+                    update_text += "%s\n\n" % line
+                elif line.startswith(" --"):
+                    # FIXME: Add %z for the time zone - requires Python 2.6
+                    update_text += "  \n"
+                    match = re.match("^ -- (?P<maintainer>.+) (?P<mail><.+>)  "
+                                     "(?P<date>.+) (?P<offset>[-\+][0-9]+)$",
+                                     line)
+                    if not match:
+                        continue
+                    try:
+                        date = datetime.datetime.strptime(match.group("date"),
+                                                          "%a, %d %b %Y "
+                                                          "%H:%M:%S")
+                    except ValueError:
+                        continue
+                    issued = date.isoformat()
+                    if not updated:
+                        updated = date.isoformat()
+            if issued == updated:
+                updated = ""
+            bugzilla_urls = get_bug_urls(changelog)
+            cve_urls = get_cve_urls(changelog)
+            trans.emit_update_detail(pkg_id, updates, obsoletes, vendor_urls,
+                                     bugzilla_urls, cve_urls, restart,
+                                     update_text, changelog,
+                                     state, issued, updated)
+        locale.setlocale(locale.LC_TIME, old_locale)
+
+    def get_details(self, trans, package_ids):
+        """Implement org.freedesktop.PackageKit.Transaction.GetDetails()"""
+        trans.progress = 101
+
+        for pkg_id in package_ids:
+            version = self._get_version_by_id(pkg_id)
+            # FIXME: We need more fine grained license information!
+            origins = version.origins
+            if (origins and
+                    origins[0].component in ["main", "universe"] and
+                    origins[0].origin in ["Debian", "Ubuntu"]):
+                license = "free"
+            else:
+                license = "unknown"
+            group = self._get_package_group(version.package)
+            trans.emit_details(pkg_id, license, group, version.description,
+                               version.homepage, version.size)
+
+    def get_packages(self, trans, filters):
+        """Implement org.freedesktop.PackageKit.Transaction.GetPackages()"""
+        self.progress = 101
+
+        for pkg in self._iterate_packages():
+            if self._is_package_visible(pkg, filters):
+                self._emit_package(trans, pkg)
+
+    def resolve(self, trans, filters, packages):
+        """Implement org.freedesktop.PackageKit.Transaction.Resolve()"""
+        trans.status = aptd_enums.STATUS_QUERY
+        trans.progress = 101
+        self.cancellable = False
+
+        for name in packages:
+            try:
+                # Check if the name is a valid package id
+                version = self._get_version_by_id(name)
+            except ValueError:
+                pass
+            else:
+                if self._is_version_visible(version, filters):
+                    self._emit_pkg_version(trans, version)
+                continue
+            # The name seems to be a normal name
+            try:
+                pkg = self._cache[name]
+            except KeyError:
+                raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
+                                        "Package name %s could not be "
+                                        "resolved.", name)
+            else:
+                self._emit_all_visible_pkg_versions(trans, filters, pkg)
+
+    def get_depends(self, trans, filters, package_ids, recursive):
+        """Emit all dependencies of the given package ids.
+
+        Doesn't support recursive dependency resolution.
+        """
+        def emit_blocked_dependency(base_dependency, pkg=None,
+                                    filters=pk.FilterEnum.NONE):
+            """Send a blocked package signal for the given
+            apt.package.BaseDependency.
+            """
+            if pk.FilterEnum.INSTALLED in filters:
+                return
+            if pkg:
+                summary = pkg.candidate.summary
+                filters = bitfield_remove(filters, pk.FilterEnum.NOT_INSTALLED)
+                if not self._is_package_visible(pkg, filters):
+                    return
+            else:
+                summary = ""
+            if base_dependency.relation:
+                version = "%s%s" % (base_dependency.relation,
+                                    base_dependency.version)
+            else:
+                version = base_dependency.version
+            trans.emit_package("%s;%s;;" % (base_dependency.name, version),
+                               pk.InfoEnum.BLOCKED, summary)
+
+        def check_dependency(pkg, base_dep):
+            """Check if the given apt.package.Package can satisfy the
+            BaseDepenendcy and emit the corresponding package signals.
+            """
+            if not self._is_package_visible(pkg, filters):
+                return
+            if base_dep.version:
+                satisfied = False
+                # Sort the version list to check the installed
+                # and candidate before the other ones
+                ver_list = list(pkg.versions)
+                if pkg.installed:
+                    ver_list.remove(pkg.installed)
+                    ver_list.insert(0, pkg.installed)
+                if pkg.candidate:
+                    ver_list.remove(pkg.candidate)
+                    ver_list.insert(0, pkg.candidate)
+                for dep_ver in ver_list:
+                    if apt_pkg.check_dep(dep_ver.version,
+                                         base_dep.relation,
+                                         base_dep.version):
+                        self._emit_pkg_version(trans, dep_ver)
+                        satisfied = True
+                        break
+                if not satisfied:
+                    emit_blocked_dependency(base_dep, pkg, filters)
+            else:
+                self._emit_package(trans, pkg)
+
+        # Setup the transaction
+        self.status = aptd_enums.STATUS_RESOLVING_DEP
+        trans.progress = 101
+        self.cancellable = True
+
+        dependency_types = ["PreDepends", "Depends"]
+        if apt_pkg.config["APT::Install-Recommends"]:
+            dependency_types.append("Recommends")
+        for id in package_ids:
+            version = self._get_version_by_id(id)
+            for dependency in version.get_dependencies(*dependency_types):
+                # Walk through all or_dependencies
+                for base_dep in dependency.or_dependencies:
+                    if self._cache.is_virtual_package(base_dep.name):
+                        # Check each proivider of a virtual package
+                        for provider in self._cache.get_providing_packages(
+                                base_dep.name):
+                            check_dependency(provider, base_dep)
+                    elif base_dep.name in self._cache:
+                        check_dependency(self._cache[base_dep.name], base_dep)
+                    else:
+                        # The dependency does not exist
+                        emit_blocked_dependency(trans, base_dep,
+                                                filters=filters)
+
+    def get_requires(self, trans, filters, package_ids, recursive):
+        """Emit all packages which depend on the given ids.
+
+        Recursive searching is not supported.
+        """
+        self.status = aptd_enums.STATUS_RESOLVING_DEP
+        self.progress = 101
+        self.cancellable = True
+        for id in package_ids:
+            version = self._get_version_by_id(id)
+            for pkg in self._iterate_packages():
+                if not self._is_package_visible(pkg, filters):
+                    continue
+                if pkg.is_installed:
+                    pkg_ver = pkg.installed
+                elif pkg.candidate:
+                    pkg_ver = pkg.candidate
+                for dependency in pkg_ver.dependencies:
+                    satisfied = False
+                    for base_dep in dependency.or_dependencies:
+                        if (version.package.name == base_dep.name or
+                                base_dep.name in version.provides):
+                            satisfied = True
+                            break
+                    if satisfied:
+                        self._emit_package(trans, pkg)
+                        break
+
+    def download_packages(self, trans, store_in_cache, package_ids):
+        """Implement the DownloadPackages functionality.
+
+        The store_in_cache parameter gets ignored.
+        """
+        def get_download_details(ids):
+            """Calculate the start and end point of a package download
+            progress.
+            """
+            total = 0
+            downloaded = 0
+            versions = []
+            # Check if all ids are vaild and calculate the total download size
+            for id in ids:
+                pkg_ver = self._get_version_by_id(id)
+                if not pkg_ver.downloadable:
+                    raise TransactionFailed(
+                        aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED,
+                        "package %s isn't downloadable" % id)
+                total += pkg_ver.size
+                versions.append((id, pkg_ver))
+            for id, ver in versions:
+                start = downloaded * 100 / total
+                end = start + ver.size * 100 / total
+                yield id, ver, start, end
+                downloaded += ver.size
+        trans.status = aptd_enums.STATUS_DOWNLOADING
+        trans.cancellable = True
+        trans.progress = 10
+        # Check the destination directory
+        if store_in_cache:
+            dest = apt_pkg.config.find_dir("Dir::Cache::archives")
+        else:
+            dest = tempfile.mkdtemp(prefix="aptdaemon-download")
+        if not os.path.isdir(dest) or not os.access(dest, os.W_OK):
+            raise TransactionFailed(aptd_enums.ERROR_INTERNAL_ERROR,
+                                    "The directory '%s' is not writable" %
+                                    dest)
+        # Start the download
+        for id, ver, start, end in get_download_details(package_ids):
+            progress = DaemonAcquireProgress(trans, start, end)
+            self._emit_pkg_version(trans, ver, pk.InfoEnum.DOWNLOADING)
+            try:
+                ver.fetch_binary(dest, progress)
+            except Exception as error:
+                raise TransactionFailed(
+                    aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED, str(error))
+            else:
+                path = os.path.join(dest, os.path.basename(ver.filename))
+                trans.emit_files(id, [path])
+                self._emit_pkg_version(trans, ver, pk.InfoEnum.FINISHED)
+
+    def get_files(self, trans, package_ids):
+        """Emit the Files signal which includes the files included in a package
+        Apt only supports this for installed packages
+        """
+        for id in package_ids:
+            pkg = self._get_package_by_id(id)
+            trans.emit_files(id, self._get_installed_files(pkg))
+
+    def what_provides(self, trans, filters, provides_type, values):
+        """Emit all packages which provide the given type and search value."""
+        self._init_plugins()
+
+        supported_type = False
+        provides_type_str = pk.provides_enum_to_string(provides_type)
+
+        # run plugins
+        for plugin in self._plugins.get("what_provides", []):
+            pklog.debug("calling what_provides plugin %s %s",
+                        str(plugin), str(filters))
+            for search_item in values:
+                try:
+                    for package in plugin(self._cache, provides_type_str,
+                                          search_item):
+                        self._emit_visible_package(trans, filters, package)
+                    supported_type = True
+                except NotImplementedError:
+                    # keep supported_type as False
+                    pass
+
+        if not supported_type and provides_type != pk.ProvidesEnum.ANY:
+            # none of the plugins felt responsible for this type
+            raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
+                                    "Query type '%s' is not supported" %
+                                    pk.provides_enum_to_string(provides_type))
+
+    def repo_enable(self, trans, repo_id, enabled):
+        """Enable or disable a repository."""
+        if not enabled:
+            raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
+                                    "Disabling repositories is not "
+                                    "implemented")
+
+        fields = repo_id.split()
+        if len(fields) < 3 or fields[0] not in ('deb', 'deb-src'):
+            raise TransactionFailed(
+                aptd_enums.ERROR_NOT_SUPPORTED,
+                "Unknown repository ID format: %s" % repo_id)
+
+        self.add_repository(trans, fields[0], fields[1], fields[2],
+                            fields[3:], '', None)
+
+    def install_signature(self, trans, sig_type, key_id, package_id):
+        """Install an archive key."""
+        if sig_type != pk.SigTypeEnum.GPG:
+            raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
+                                    "Type %s is not supported" % sig_type)
+        try:
+            keyserver = os.environ["APTDAEMON_KEYSERVER"]
+        except KeyError:
+            if platform.dist()[0] == "Ubuntu":
+                keyserver = "hkp://keyserver.ubuntu.com:80"
+            else:
+                keyserver = "hkp://keys.gnupg.net"
+        self.add_vendor_key_from_keyserver(trans, key_id, keyserver)
+
+    # Helpers
+
+    def _get_id_from_version(self, version):
+        """Return the package id of an apt.package.Version instance."""
+        if version.origins:
+            origin = version.origins[0].label
+            # APT returns a str with Python 2
+            if isinstance(origin, bytes):
+                origin = origin.decode("UTF-8")
+        else:
+            origin = ""
+        if version.architecture in [self.NATIVE_ARCH, "all"]:
+            name = version.package.name
+        else:
+            name = version.package.name.split(":")[0]
+        id = "%s;%s;%s;%s" % (name, version.version,
+                              version.architecture, origin)
+        return id
+
+    def _emit_package(self, trans, pkg, info=None, force_candidate=False):
+        """
+        Send the Package signal for a given apt package
+        """
+        if (not pkg.is_installed or force_candidate) and pkg.candidate:
+            self._emit_pkg_version(trans, pkg.candidate, info)
+        elif pkg.is_installed:
+            self._emit_pkg_version(trans, pkg.installed, info)
+        else:
+            pklog.debug("Package %s hasn't got any version." % pkg.name)
+
+    def _emit_pkg_version(self, trans, version, info=None):
+        """Emit the Package signal of the given apt.package.Version."""
+        id = self._get_id_from_version(version)
+        section = version.section.split("/")[-1]
+        if not info:
+            if version == version.package.installed:
+                if section == "metapackages":
+                    info = pk.InfoEnum.COLLECTION_INSTALLED
+                else:
+                    info = pk.InfoEnum.INSTALLED
+            else:
+                if section == "metapackages":
+                    info = pk.InfoEnum.COLLECTION_AVAILABLE
+                else:
+                    info = pk.InfoEnum.AVAILABLE
+        trans.emit_package(info, id, version.summary)
+
+    def _emit_all_visible_pkg_versions(self, trans, filters, pkg):
+        """Emit all available versions of a package."""
+        for version in pkg.versions:
+            if self._is_version_visible(version, filters):
+                self._emit_pkg_version(trans, version)
+
+    def _emit_visible_package(self, trans, filters, pkg, info=None):
+        """
+        Filter and emit a package
+        """
+        if self._is_package_visible(pkg, filters):
+            self._emit_package(trans, pkg, info)
+
+    def _emit_visible_packages(self, trans, filters, pkgs, info=None):
+        """
+        Filter and emit packages
+        """
+        for pkg in pkgs:
+            if self._is_package_visible(pkg, filters):
+                self._emit_package(trans, pkg, info)
+
+    def _emit_visible_packages_by_name(self, trans, filters, pkgs, info=None):
+        """
+        Find the packages with the given namens. Afterwards filter and emit
+        them
+        """
+        for name in pkgs:
+            if (name in self._cache and
+                    self._is_package_visible(self._cache[name], filters)):
+                self._emit_package(trans, self._cache[name], info)
+
+    def _is_version_visible(self, version, filters):
+        """Return True if the package version is matched by the given
+        filters.
+        """
+        if filters == pk.FilterEnum.NONE:
+            return True
+        if (bitfield_contains(filters, pk.FilterEnum.NEWEST) and
+                version.package.candidate != version):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.INSTALLED) and
+                version.package.installed != version):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_INSTALLED) and
+                version.package.installed == version):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.SUPPORTED) and
+                not self._is_package_supported(version.package)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_SUPPORTED) and
+                self._is_package_supported(version.package)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.FREE) and
+                not self._is_version_free(version)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_FREE) and
+                self._is_version_free(version)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.GUI) and
+                not self._has_package_gui(version.package)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_GUI) and
+                self._has_package_gui(version.package)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.COLLECTIONS) and
+                not self._is_package_collection(version.package)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_COLLECTIONS) and
+                self._is_package_collection(version.package)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.DEVELOPMENT) and
+                not self._is_package_devel(version.package)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_DEVELOPMENT) and
+                self._is_package_devel(version.package)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.ARCH) and
+                version.architecture not in [self.NATIVE_ARCH, "all"]):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_ARCH) and
+                version.architecture in [self.NATIVE_ARCH, "all"]):
+            return False
+        return True
+
+    def _is_package_visible(self, pkg, filters):
+        """Return True if the package is matched by the given filters."""
+        if filters == pk.FilterEnum.NONE:
+            return True
+        if (bitfield_contains(filters, pk.FilterEnum.INSTALLED) and
+                not pkg.is_installed):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_INSTALLED) and
+                pkg.is_installed):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.SUPPORTED) and
+                not self._is_package_supported(pkg)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_SUPPORTED) and
+                self._is_package_supported(pkg)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.FREE) and
+                not self._is_package_free(pkg)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_FREE) and
+                self._is_package_free(pkg)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.GUI) and
+                not self._has_package_gui(pkg)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_GUI) and
+                self._has_package_gui(pkg)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.COLLECTIONS) and
+                not self._is_package_collection(pkg)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_COLLECTIONS) and
+                self._is_package_collection(pkg)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.DEVELOPMENT) and
+                not self._is_package_devel(pkg)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_DEVELOPMENT) and
+                self._is_package_devel(pkg)):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.ARCH) and
+                ":" in pkg.name):
+            return False
+        if (bitfield_contains(filters, pk.FilterEnum.NOT_ARCH) and
+                ":" not in pkg.name):
+            return False
+        return True
+
+    def _is_package_free(self, pkg):
+        """Return True if we can be sure that the package's license is a
+        free one
+        """
+        if not pkg.candidate:
+            return False
+        return self._is_version_free(pkg.candidate)
+
+    def _is_version_free(self, version):
+        """Return True if we can be sure that the package version has got
+        a free license.
+        """
+        origins = version.origins
+        return (origins and
+                ((origins[0].origin == "Ubuntu" and
+                  origins[0].component in ["main", "universe"]) or
+                 (origins[0].origin == "Debian" and
+                  origins[0].component == "main")) and
+                origins[0].trusted)
+
+    def _is_package_collection(self, pkg):
+        """Return True if the package is a metapackge
+        """
+        section = pkg.section.split("/")[-1]
+        return section == "metapackages"
+
+    def _has_package_gui(self, pkg):
+        # 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 _is_package_devel(self, pkg):
+        return (pkg.name.endswith("-dev") or pkg.name.endswith("-dbg") or
+                pkg.section.split('/')[-1].lower() in ['devel', 'libdevel'])
+
+    def _is_package_supported(self, pkg):
+        if not pkg.candidate:
+            return False
+        origins = pkg.candidate.origins
+        return (origins and
+                ((origins[0].origin == "Ubuntu" and
+                  origins[0].component in ["main", "restricted"]) or
+                 (origins[0].origin == "Debian" and
+                  origins[0].component == "main")) and
+                origins[0].trusted)
+
+    def _get_package_by_id(self, id):
+        """Return the apt.package.Package corresponding to the given
+        package id.
+
+        If the package isn't available error out.
+        """
+        version = self._get_version_by_id(id)
+        return version.package
+
+    def _get_version_by_id(self, id):
+        """Return the apt.package.Version corresponding to the given
+        package id.
+
+        If the version isn't available error out.
+        """
+        name, version_string, arch, data = id.split(";", 4)
+        if arch and arch not in [self.NATIVE_ARCH, "all"]:
+            name += ":%s" % arch
+        try:
+            pkg = self._cache[name]
+        except KeyError:
+            raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
+                                    "There isn't any package named %s",
+                                    name)
+        try:
+            version = pkg.versions[version_string]
+        except:
+            raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
+                                    "Verion %s doesn't exist",
+                                    version_string)
+        if version.architecture != arch:
+            raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
+                                    "Version %s of %s isn't available "
+                                    "for architecture %s",
+                                    pkg.name, version.version, arch)
+        return version
+
+    def _get_installed_files(self, pkg):
+        """
+        Return the list of unicode names of the files which have
+        been installed by the package
+
+        This method should be obsolete by the
+        apt.package.Package.installedFiles attribute as soon as the
+        consolidate branch of python-apt gets merged
+        """
+        path = os.path.join(apt_pkg.config["Dir"],
+                            "var/lib/dpkg/info/%s.list" % pkg.name)
+        try:
+            with open(path, 'rb') as f:
+                files = f.read().decode('UTF-8').split("\n")
+        except IOError:
+            return []
+        return files
+
+    def _get_package_group(self, pkg):
+        """
+        Return the packagekit group corresponding to the package's section
+        """
+        section = pkg.section.split("/")[-1]
+        if section in SECTION_GROUP_MAP:
+            return SECTION_GROUP_MAP[section]
+        else:
+            pklog.warning("Unkown package section %s of %s" % (pkg.section,
+                                                               pkg.name))
+            return pk.GroupEnum.UNKNOWN
+
+    def _init_plugins(self):
+        """Initialize PackageKit apt backend plugins.
+        Do nothing if plugins are already initialized.
+        """
+        if self._plugins is not None:
+            return
+
+        if not pkg_resources:
+            return
+
+        self._plugins = {}  # plugin_name -> [plugin_fn1, ...]
+
+        # just look in standard Python paths for now
+        dists, errors = pkg_resources.working_set.find_plugins(
+            pkg_resources.Environment())
+        for dist in dists:
+            pkg_resources.working_set.add(dist)
+        for plugin_name in ["what_provides"]:
+            for entry_point in pkg_resources.iter_entry_points(
+                    "packagekit.apt.plugins", plugin_name):
+                try:
+                    plugin = entry_point.load()
+                except Exception as e:
+                    pklog.warning("Failed to load %s from plugin %s: %s" % (
+                        plugin_name, str(entry_point.dist), str(e)))
+                    continue
+                pklog.debug("Loaded %s from plugin %s" % (
+                    plugin_name, str(entry_point.dist)))
+                self._plugins.setdefault(plugin_name, []).append(plugin)
+
+    def _apply_changes(self, trans, fetch_range=(15, 50),
+                       install_range=(50, 90)):
+        """Apply changes and emit RequireRestart accordingly."""
+        if hasattr(trans, "pktrans"):
+            # Cache the ids of the to be changed packages, since we will
+            # only get the package name during download/install time
+            for pkg in self._cache.get_changes():
+                if pkg.marked_delete or pkg.marked_reinstall:
+                    pkg_id = self._get_id_from_version(pkg.installed)
+                else:
+                    pkg_id = self._get_id_from_version(pkg.candidate)
+                trans.pktrans.pkg_id_cache[pkg.name] = pkg_id
+
+        aptworker.AptWorker._apply_changes(self, trans, fetch_range,
+                                           install_range)
+
+        if (hasattr(trans, "pktrans") and
+            (trans.role == aptd_enums.ROLE_UPGRADE_SYSTEM or
+             trans.packages[aptd_enums.PKGS_UPGRADE] or
+             trans.depends[aptd_enums.PKGS_UPGRADE])):
+            self._emit_require_restart(trans)
+
+
+if META_RELEASE_SUPPORT:
+
+    class GMetaRelease(GObject.GObject, MetaReleaseCore):
+
+        __gsignals__ = {"download-done": (GObject.SignalFlags.RUN_FIRST,
+                                          None,
+                                          ())}
+
+        def __init__(self):
+            GObject.GObject.__init__(self)
+            MetaReleaseCore.__init__(self, False, False)
+
+        def download(self):
+            MetaReleaseCore.download(self)
+            self.emit("download-done")
+
+
+def bitfield_summarize(*enums):
+    """Return the bitfield with the given PackageKit enums."""
+    field = 0
+    for enum in enums:
+        field |= 2 ** int(enum)
+    return field
+
+
+def bitfield_add(field, enum):
+    """Add a PackageKit enum to a given field"""
+    field |= 2 ** int(enum)
+    return field
+
+
+def bitfield_remove(field, enum):
+    """Remove a PackageKit enum to a given field"""
+    field = field ^ 2 ** int(enum)
+    return field
+
+
+def bitfield_contains(field, enum):
+    """Return True if a bitfield contains the given PackageKit enum"""
+    return field & 2 ** int(enum)
+
+
+# vim: ts=4 et sts=4
diff -pruN 1.1.1-4/aptdaemon/worker.py 1.1.1+bzr982-0ubuntu14/aptdaemon/worker.py
--- 1.1.1-4/aptdaemon/worker.py	2015-10-12 18:06:09.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon/worker.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,1661 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""Provides AptWorker which processes transactions."""
-# Copyright (C) 2008-2009 Sebastian Heinlein <devel@glatzor.de>
-#
-# 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
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-__author__ = "Sebastian Heinlein <devel@glatzor.de>"
-
-__all__ = ("AptWorker", "DummyWorker")
-
-import contextlib
-import errno
-import glob
-import logging
-import netrc
-import os
-import re
-import shutil
-import stat
-import sys
-import tempfile
-import time
-import traceback
-try:
-    from urllib.parse import urlsplit, urlunsplit
-except ImportError:
-    from urlparse import urlsplit, urlunsplit
-
-try:
-    from configparser import ConfigParser
-except ImportError:
-    from ConfigParser import ConfigParser
-
-import apt
-import apt.auth
-import apt.cache
-import apt.debfile
-import apt_pkg
-import aptsources
-import aptsources.distro
-from aptsources.sourceslist import SourcesList
-from gi.repository import GObject, GLib
-import pkg_resources
-
-from .enums import *
-from .errors import *
-from . import lock
-from .progress import (
-    DaemonOpenProgress,
-    DaemonInstallProgress,
-    DaemonAcquireProgress,
-    DaemonAcquireRepoProgress,
-    DaemonDpkgInstallProgress,
-    DaemonDpkgReconfigureProgress,
-    DaemonDpkgRecoverProgress,
-    DaemonLintianProgress,
-    DaemonForkProgress)
-
-log = logging.getLogger("AptDaemon.Worker")
-
-# Just required to detect translatable strings. The translation is done by
-# core.Transaction.gettext
-_ = lambda s: s
-
-
-def trans_only_installs_pkgs_from_high_trust_repos(trans,
-                                                   whitelist=set()):
-    """Return True if this transaction only touches packages in the
-    aptdaemon repoisotry high trust repository whitelist
-    """
-    # the transaction *must* be simulated before
-    if not trans.simulated:
-        return False
-    # we never allow unauthenticated ones
-    if trans.unauthenticated:
-        return False
-    # paranoia: wrong role
-    if not trans.role in (ROLE_INSTALL_PACKAGES, ROLE_COMMIT_PACKAGES):
-        return False
-    # if there is anything touched that is not a install bail out
-    for enum in (PKGS_REINSTALL, PKGS_REMOVE, PKGS_PURGE, PKGS_DOWNGRADE,
-                 PKGS_UPGRADE):
-        if trans.packages[enum]:
-            return False
-    # paranoia(2): we must want to install something
-    if not trans.packages[PKGS_INSTALL]:
-        return False
-    # we only care about the name, not the version
-    pkgs = [pkg.split("=")[0] for pkg in trans.packages[PKGS_INSTALL]]
-    # if the install packages matches the whitelisted set we are good
-    return set(pkgs) == set(trans.high_trust_packages)
-
-
-def read_high_trust_repository_dir(whitelist_cfg_d):
-    """Return a set of (origin, component, pkgname-regexp) from a
-    high-trust-repository-whitelist.d directory
-    """
-    whitelist = set()
-    for path in glob.glob(os.path.join(whitelist_cfg_d, "*.cfg")):
-        whitelist |= _read_high_trust_repository_whitelist_file(path)
-    return whitelist
-
-
-def _read_high_trust_repository_whitelist_file(path):
-    """Read a individual high-trust-repository whitelist file and return
-       a set of tuples (origin, component, pkgname-regexp)
-    """
-    parser = ConfigParser()
-    whitelist = set()
-    try:
-        parser.read(path)
-    except Exception as e:
-        log.error("Failed to read repository whitelist '%s' (%s)" % (path, e))
-        return whitelist
-    for section in parser.sections():
-        origin = parser.get(section, "origin")
-        component = parser.get(section, "component")
-        pkgnames = parser.get(section, "pkgnames")
-        whitelist.add((origin, component, pkgnames))
-    return whitelist
-
-
-class AptWorker(GObject.GObject):
-
-    """Worker which processes transactions from the queue."""
-
-    __gsignals__ = {"transaction-done": (GObject.SignalFlags.RUN_FIRST,
-                                         None,
-                                         (GObject.TYPE_PYOBJECT,)),
-                    "transaction-simulated": (GObject.SignalFlags.RUN_FIRST,
-                                              None,
-                                              (GObject.TYPE_PYOBJECT,))}
-
-    # the basedir under which license keys can be stored
-    LICENSE_KEY_ROOTDIR = "/opt/"
-
-    def __init__(self, chroot=None, load_plugins=True):
-        """Initialize a new AptWorker instance."""
-        GObject.GObject.__init__(self)
-        self.trans = None
-        self.last_action_timestamp = time.time()
-        self._cache = None
-        # Store the the tid of the transaction whose changes are currently
-        # marked in the cache
-        self.marked_tid = None
-
-        # Change to a given chroot
-        if chroot:
-            apt_conf_file = os.path.join(chroot, "etc/apt/apt.conf")
-            if os.path.exists(apt_conf_file):
-                apt_pkg.read_config_file(apt_pkg.config, apt_conf_file)
-            apt_conf_dir = os.path.join(chroot, "etc/apt/apt.conf.d")
-            if os.path.isdir(apt_conf_dir):
-                apt_pkg.read_config_dir(apt_pkg.config, apt_conf_dir)
-            apt_pkg.config["Dir"] = chroot
-            apt_pkg.config["Dir::State::Status"] = os.path.join(
-                chroot, "var/lib/dpkg/status")
-            apt_pkg.config.clear("DPkg::Post-Invoke")
-            apt_pkg.config.clear("DPkg::Options")
-            apt_pkg.config["DPkg::Options::"] = "--root=%s" % chroot
-            apt_pkg.config["DPkg::Options::"] = ("--log=%s/var/log/dpkg.log" %
-                                                 chroot)
-            status_file = apt_pkg.config.find_file("Dir::State::status")
-            lock.status_lock.path = os.path.join(os.path.dirname(status_file),
-                                                 "lock")
-            archives_dir = apt_pkg.config.find_dir("Dir::Cache::Archives")
-            lock.archive_lock.path = os.path.join(archives_dir, "lock")
-            lists_dir = apt_pkg.config.find_dir("Dir::State::lists")
-            lock.lists_lock.path = os.path.join(lists_dir, "lock")
-            apt_pkg.init_system()
-
-        # a set of tuples of the type (origin, component, pkgname-regexp)
-        # that on install will trigger a different kind of polkit
-        # authentication request (see LP: #1035207), useful for e.g.
-        # webapps/company repos
-        self._high_trust_repositories = read_high_trust_repository_dir(
-            os.path.join(apt_pkg.config.find_dir("Dir"),
-                         "etc/aptdaemon/high-trust-repository-whitelist.d"))
-        log.debug(
-            "using high-trust whitelist: '%s'" % self._high_trust_repositories)
-
-        self._status_orig = apt_pkg.config.find_file("Dir::State::status")
-        self._status_frozen = None
-        self.plugins = {}
-        if load_plugins:
-            self._load_plugins()
-
-    def _load_plugins(self):
-        """Load the plugins from setuptools' entry points."""
-        plugin_dirs = [os.path.join(os.path.dirname(__file__), "plugins")]
-        env = pkg_resources.Environment(plugin_dirs)
-        dists, errors = pkg_resources.working_set.find_plugins(env)
-        for dist in dists:
-            pkg_resources.working_set.add(dist)
-        for name in ["modify_cache_after", "modify_cache_before",
-                     "get_license_key"]:
-            for ept in pkg_resources.iter_entry_points("aptdaemon.plugins",
-                                                       name):
-                try:
-                    self.plugins.setdefault(name, []).append(ept.load())
-                except:
-                    log.critical("Failed to load %s plugin: "
-                                 "%s" % (name, ept.dist))
-                else:
-                    log.debug("Loaded %s plugin: %s", name, ept.dist)
-
-    def _call_plugins(self, name, resolver=None):
-        """Call all plugins of a given type."""
-        if not resolver:
-            # If the resolver of the original task isn't available we create
-            # a new one and protect the already marked changes
-            resolver = apt.cache.ProblemResolver(self._cache)
-            for pkg in self._cache.get_changes():
-                resolver.clear(pkg)
-                resolver.protect(pkg)
-                if pkg.marked_delete:
-                    resolver.remove(pkg)
-        if not name in self.plugins:
-            log.debug("There isn't any registered %s plugin" % name)
-            return False
-        for plugin in self.plugins[name]:
-            log.debug("Calling %s plugin: %s", name, plugin)
-            try:
-                plugin(resolver, self._cache)
-            except Exception as error:
-                log.critical("Failed to call %s plugin:\n%s" % (plugin, error))
-        return True
-
-    def run(self, transaction):
-        """Process the given transaction in the background.
-
-        Keyword argument:
-        transaction -- core.Transcation instance to run
-        """
-        log.info("Processing transaction %s", transaction.tid)
-        if self.trans:
-            raise Exception("There is already a running transaction")
-        self.trans = transaction
-        GLib.idle_add(self._process_transaction, transaction)
-
-    def _emit_transaction_simulated(self, trans):
-        """Emit the transaction-simulated signal.
-
-        Keyword argument:
-        trans -- the simulated transaction
-        """
-        log.debug("Emitting transaction-simulated: %s", trans.tid)
-        self.emit("transaction-simulated", trans)
-
-    def _emit_transaction_done(self, trans):
-        """Emit the transaction-done signal.
-
-        Keyword argument:
-        trans -- the finished transaction
-        """
-        log.debug("Emitting transaction-done: %s", trans.tid)
-        self.emit("transaction-done", trans)
-
-    def _process_transaction(self, trans):
-        """Run the worker"""
-        self.last_action_timestamp = time.time()
-        trans.status = STATUS_RUNNING
-        trans.progress = 11
-        try:
-            lock.wait_for_lock(trans)
-            # Prepare the package cache
-            if (trans.role == ROLE_FIX_INCOMPLETE_INSTALL or
-                    not self.is_dpkg_journal_clean()):
-                self.fix_incomplete_install(trans)
-            # Process transaction which don't require a cache
-            if trans.role == ROLE_ADD_VENDOR_KEY_FILE:
-                self.add_vendor_key_from_file(trans, **trans.kwargs)
-            elif trans.role == ROLE_ADD_VENDOR_KEY_FROM_KEYSERVER:
-                self.add_vendor_key_from_keyserver(trans, **trans.kwargs)
-            elif trans.role == ROLE_REMOVE_VENDOR_KEY:
-                self.remove_vendor_key(trans, **trans.kwargs)
-            elif trans.role == ROLE_ADD_REPOSITORY:
-                self.add_repository(trans, **trans.kwargs)
-            elif trans.role == ROLE_ENABLE_DISTRO_COMP:
-                self.enable_distro_comp(trans, **trans.kwargs)
-            elif trans.role == ROLE_RECONFIGURE:
-                self.reconfigure(trans, trans.packages[PKGS_REINSTALL],
-                                 **trans.kwargs)
-            elif trans.role == ROLE_CLEAN:
-                self.clean(trans)
-            # Check if the transaction has been just simulated. So we could
-            # skip marking the changes a second time.
-            elif (trans.role in (ROLE_REMOVE_PACKAGES, ROLE_INSTALL_PACKAGES,
-                                 ROLE_UPGRADE_PACKAGES, ROLE_COMMIT_PACKAGES,
-                                 ROLE_UPGRADE_SYSTEM,
-                                 ROLE_FIX_BROKEN_DEPENDS) and
-                  self.marked_tid == trans.tid):
-                self._apply_changes(trans)
-                trans.exit = EXIT_SUCCESS
-                return False
-            else:
-                self._open_cache(trans)
-            # Process transaction which can handle a broken dep cache
-            if trans.role == ROLE_FIX_BROKEN_DEPENDS:
-                self.fix_broken_depends(trans)
-            elif trans.role == ROLE_UPDATE_CACHE:
-                self.update_cache(trans, **trans.kwargs)
-            # Process the transactions which require a consistent cache
-            elif trans.role == ROLE_ADD_LICENSE_KEY:
-                self.add_license_key(trans, **trans.kwargs)
-            elif self._cache and self._cache.broken_count:
-                raise TransactionFailed(ERROR_CACHE_BROKEN,
-                                        self._get_broken_details(trans))
-            if trans.role == ROLE_PK_QUERY:
-                self.query(trans)
-            elif trans.role == ROLE_INSTALL_FILE:
-                self.install_file(trans, **trans.kwargs)
-            elif trans.role in [ROLE_REMOVE_PACKAGES, ROLE_INSTALL_PACKAGES,
-                                ROLE_UPGRADE_PACKAGES, ROLE_COMMIT_PACKAGES]:
-                self.commit_packages(trans, *trans.packages)
-            elif trans.role == ROLE_UPGRADE_SYSTEM:
-                self.upgrade_system(trans, **trans.kwargs)
-        except TransactionCancelled:
-            trans.exit = EXIT_CANCELLED
-        except TransactionFailed as excep:
-            trans.error = excep
-            trans.exit = EXIT_FAILED
-        except (KeyboardInterrupt, SystemExit):
-            trans.exit = EXIT_CANCELLED
-        except Exception as excep:
-            tbk = traceback.format_exc()
-            trans.error = TransactionFailed(ERROR_UNKNOWN, tbk)
-            trans.exit = EXIT_FAILED
-            try:
-                from . import crash
-            except ImportError:
-                pass
-            else:
-                crash.create_report("%s: %s" % (type(excep), str(excep)),
-                                    tbk, trans)
-        else:
-            trans.exit = EXIT_SUCCESS
-        finally:
-            trans.progress = 100
-            self.last_action_timestamp = time.time()
-            tid = trans.tid[:]
-            self.trans = None
-            self.marked_tid = None
-            self._emit_transaction_done(trans)
-            lock.release()
-            log.info("Finished transaction %s", tid)
-        return False
-
-    def commit_packages(self, trans, install, reinstall, remove, purge,
-                        upgrade, downgrade, simulate=False):
-        """Perform a complex package operation.
-
-        Keyword arguments:
-        trans - the transaction
-        install - list of package names to install
-        reinstall - list of package names to reinstall
-        remove - list of package names to remove
-        purge - list of package names to purge including configuration files
-        upgrade - list of package names to upgrade
-        downgrade - list of package names to upgrade
-        simulate -- if True the changes won't be applied
-        """
-        log.info("Committing packages: %s, %s, %s, %s, %s, %s",
-                 install, reinstall, remove, purge, upgrade, downgrade)
-        with self._cache.actiongroup():
-            resolver = apt.cache.ProblemResolver(self._cache)
-            self._mark_packages_for_installation(install, resolver)
-            self._mark_packages_for_installation(reinstall, resolver,
-                                                 reinstall=True)
-            self._mark_packages_for_removal(remove, resolver)
-            self._mark_packages_for_removal(purge, resolver, purge=True)
-            self._mark_packages_for_upgrade(upgrade, resolver)
-            self._mark_packages_for_downgrade(downgrade, resolver)
-            self._resolve_depends(trans, resolver)
-        self._check_obsoleted_dependencies(trans, resolver)
-        if not simulate:
-            self._apply_changes(trans)
-
-    def _resolve_depends(self, trans, resolver):
-        """Resolve the dependencies using the given ProblemResolver."""
-        self._call_plugins("modify_cache_before", resolver)
-        resolver.install_protect()
-        try:
-            resolver.resolve()
-        except SystemError:
-            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED,
-                                    self._get_broken_details(trans, now=False))
-        if self._call_plugins("modify_cache_after", resolver):
-            try:
-                resolver.resolve()
-            except SystemError:
-                details = self._get_broken_details(trans, now=False)
-                raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED, details)
-
-    @staticmethod
-    def _split_package_id(package):
-        """Return the name, the version number and the release of the
-        specified package."""
-        if "=" in package:
-            name, version = package.split("=", 1)
-            release = None
-        elif "/" in package:
-            name, release = package.split("/", 1)
-            version = None
-        else:
-            name = package
-            version = release = None
-        return name, version, release
-
-    def _get_high_trust_packages(self):
-        """ Return a list of packages that come from a high-trust repo """
-        def _in_high_trust_repository(pkgname, pkgorigin):
-            for origin, component, regexp in self._high_trust_repositories:
-                if (origin == pkgorigin.origin and
-                        component == pkgorigin.component and
-                        re.match(regexp, pkgname)):
-                    return True
-            return False
-        # loop
-        from_high_trust_repo = []
-        for pkg in self._cache.get_changes():
-            if pkg.marked_install:
-                for origin in pkg.candidate.origins:
-                    if _in_high_trust_repository(pkg.name, origin):
-                        from_high_trust_repo.append(pkg.name)
-                        break
-        return from_high_trust_repo
-
-    def _get_unauthenticated(self):
-        """Return a list of unauthenticated package names """
-        unauthenticated = []
-        for pkg in self._cache.get_changes():
-            if (pkg.marked_install or
-                    pkg.marked_downgrade or
-                    pkg.marked_upgrade or
-                    pkg.marked_reinstall):
-                trusted = False
-                for origin in pkg.candidate.origins:
-                    trusted |= origin.trusted
-                if not trusted:
-                    unauthenticated.append(pkg.name)
-        return unauthenticated
-
-    def _mark_packages_for_installation(self, packages, resolver,
-                                        reinstall=False):
-        """Mark packages for installation."""
-        for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
-                                           for pkg in packages]:
-            try:
-                pkg = self._cache[pkg_name]
-            except KeyError:
-                raise TransactionFailed(ERROR_NO_PACKAGE,
-                                        _("Package %s isn't available"),
-                                        pkg_name)
-            if reinstall:
-                if not pkg.is_installed:
-                    raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
-                                            _("Package %s isn't installed"),
-                                            pkg.name)
-                if pkg_ver and pkg.installed.version != pkg_ver:
-                    raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
-                                            _("The version %s of %s isn't "
-                                              "installed"),
-                                            pkg_ver, pkg_name)
-            else:
-                # Fail if the user requests to install the same version
-                # of an already installed package.
-                if (pkg.is_installed and
-                    # Compare version numbers
-                    pkg_ver and pkg_ver == pkg.installed.version and
-                    # Optionally compare the origin if specified
-                    (not pkg_rel or
-                     pkg_rel in [origin.archive for
-                                 origin in pkg.installed.origins])):
-                        raise TransactionFailed(
-                            ERROR_PACKAGE_ALREADY_INSTALLED,
-                            _("Package %s is already installed"), pkg_name)
-            pkg.mark_install(False, True, True)
-            resolver.clear(pkg)
-            resolver.protect(pkg)
-            if pkg_ver:
-                try:
-                    pkg.candidate = pkg.versions[pkg_ver]
-                except KeyError:
-                    raise TransactionFailed(ERROR_NO_PACKAGE,
-                                            _("The version %s of %s isn't "
-                                              "available."), pkg_ver, pkg_name)
-            elif pkg_rel:
-                self._set_candidate_release(pkg, pkg_rel)
-
-    def enable_distro_comp(self, trans, component):
-        """Enable given component in the sources list.
-
-        Keyword arguments:
-        trans -- the corresponding transaction
-        component -- a component, e.g. main or universe
-        """
-        trans.progress = 101
-        trans.status = STATUS_COMMITTING
-        old_umask = os.umask(0o022)
-        try:
-            sourceslist = SourcesList()
-            distro = aptsources.distro.get_distro()
-            distro.get_sources(sourceslist)
-            distro.enable_component(component)
-            sourceslist.save()
-        finally:
-            os.umask(old_umask)
-
-    def add_repository(self, trans, src_type, uri, dist, comps, comment,
-                       sourcesfile):
-        """Add given repository to the sources list.
-
-        Keyword arguments:
-        trans -- the corresponding transaction
-        src_type -- the type of the entry (deb, deb-src)
-        uri -- the main repository uri (e.g. http://archive.ubuntu.com/ubuntu)
-        dist -- the distribution to use (e.g. karmic, "/")
-        comps -- a (possible empty) list of components (main, restricted)
-        comment -- an (optional) comment
-        sourcesfile -- an (optinal) filename in sources.list.d
-        """
-        trans.progress = 101
-        trans.status = STATUS_COMMITTING
-
-        if sourcesfile:
-            if not sourcesfile.endswith(".list"):
-                sourcesfile += ".list"
-            dir = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
-            sourcesfile = os.path.join(dir, os.path.basename(sourcesfile))
-        else:
-            sourcesfile = None
-        # Store any private login information in a separate auth.conf file
-        if re.match("(http|https|ftp)://\S+?:\S+?@\S+", uri):
-            uri = self._store_and_strip_password_from_uri(uri)
-            auth_conf_path = apt_pkg.config.find_file("Dir::etc::netrc")
-            if not comment:
-                comment = "credentials stored in %s" % auth_conf_path
-            else:
-                comment += "; credentials stored in %s" % auth_conf_path
-        try:
-            sources = SourcesList()
-            entry = sources.add(src_type, uri, dist, comps, comment,
-                                file=sourcesfile)
-            if entry.invalid:
-                #FIXME: Introduce new error codes
-                raise RepositoryInvalidError()
-        except:
-            log.exception("adding repository")
-            raise
-        else:
-            sources.save()
-
-    def _store_and_strip_password_from_uri(self, uri, auth_conf_path=None):
-        """Extract the credentials from an URI. Store the password in
-        auth.conf and return the URI without any password information.
-        """
-        try:
-            res = urlsplit(uri)
-        except ValueError as error:
-            log.warn("Failed to urlsplit '%s'", error)
-            return uri
-        netloc_public = res.netloc.replace("%s:%s@" % (res.username,
-                                                       res.password),
-                                           "")
-        machine = netloc_public + res.path
-        # find auth.conf
-        if auth_conf_path is None:
-            auth_conf_path = apt_pkg.config.find_file("Dir::etc::netrc")
-
-        # read all "machine"s from the auth.conf "netrc" file
-        netrc_hosts = {}
-        netrc_hosts_as_text = ""
-        if os.path.exists(auth_conf_path):
-                netrc_hosts = netrc.netrc(auth_conf_path).hosts
-                with open(auth_conf_path, "rb") as f:
-                    netrc_hosts_as_text = f.read().decode("UTF-8")
-
-        # the new entry
-        new_netrc_entry = "\nmachine %s login %s password %s\n" % (
-            machine, res.username, res.password)
-        # if there is the same machine already defined, update it
-        # using a regexp this will ensure order/comments remain
-        if machine in netrc_hosts:
-            sub_regexp = r'machine\s+%s\s+login\s+%s\s+password\s+%s' % (
-                re.escape(machine),
-                re.escape(netrc_hosts[machine][0]),
-                re.escape(netrc_hosts[machine][2]))
-            replacement = 'machine %s login %s password %s' % (
-                machine, res.username, res.password)
-            # this may happen if e.g. the order is unexpected
-            if not re.search(sub_regexp, netrc_hosts_as_text):
-                log.warn("can not replace existing netrc entry for '%s' "
-                         "prepending it instead" % machine)
-                netrc_hosts_as_text = new_netrc_entry + netrc_hosts_as_text
-            else:
-                netrc_hosts_as_text = re.sub(
-                    sub_regexp, replacement, netrc_hosts_as_text)
-        else:
-            netrc_hosts_as_text += new_netrc_entry
-
-        # keep permssion bits of the file
-        mode = 0o640
-        try:
-            mode = os.stat(auth_conf_path)[stat.ST_MODE]
-        except OSError as e:
-            if e.errno != errno.ENOENT:
-                raise
-        # write out, tmp file first plus rename to be atomic
-        try:
-            auth_conf_tmp = tempfile.NamedTemporaryFile(
-                dir=os.path.dirname(auth_conf_path),
-                prefix=os.path.basename(auth_conf_path),
-                delete=False)
-            auth_conf_tmp.write(netrc_hosts_as_text.encode('UTF-8'))
-            auth_conf_tmp.close()
-            os.rename(auth_conf_tmp.name, auth_conf_path)
-            # and restore permissions (or set default ones)
-            os.chmod(auth_conf_path, mode)
-        except OSError as error:
-            log.warn("Failed to write auth.conf: '%s'" % error)
-
-        # Return URI without user/pass
-        return urlunsplit((res.scheme, netloc_public, res.path, res.query,
-                           res.fragment))
-
-    def add_vendor_key_from_keyserver(self, trans, keyid, keyserver):
-        """Add the signing key from the given (keyid, keyserver) to the
-        trusted vendors.
-
-        Keyword argument:
-        trans -- the corresponding transaction
-        keyid - the keyid of the key (e.g. 0x0EB12F05)
-        keyserver - the keyserver (e.g. keyserver.ubuntu.com)
-        """
-        log.info("Adding vendor key from keyserver: %s %s", keyid, keyserver)
-        # Perform some sanity checks
-        try:
-            res = urlsplit(keyserver)
-        except ValueError:
-            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
-                                    #TRANSLATORS: %s is the URL of GnuPG
-                                    #             keyserver
-                                    _("The keyserver URL is invalid: %s"),
-                                    keyserver)
-        if res.scheme not in ["hkp", "ldap", "ldaps", "http", "https"]:
-            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
-                                    #TRANSLATORS: %s is the URL of GnuPG
-                                    #             keyserver
-                                    _("Invalid protocol of the server: %s"),
-                                    keyserver)
-        try:
-            int(keyid, 16)
-        except ValueError:
-            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
-                                    #TRANSLATORS: %s is the id of a GnuPG key
-                                    #             e.g. E08ADE95
-                                    _("Invalid key id: %s"), keyid)
-        trans.status = STATUS_DOWNLOADING
-        trans.progress = 101
-        with DaemonForkProgress(trans) as progress:
-            progress.run(apt.auth.add_key_from_keyserver, keyid, keyserver)
-        if progress._child_exit != 0:
-            #TRANSLATORS: The first %s is the key id and the second the server
-            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
-                                    _("Failed to download and install the key "
-                                      "%s from %s:\n%s"),
-                                    keyid, keyserver, progress.output)
-
-    def add_vendor_key_from_file(self, trans, path):
-        """Add the signing key from the given file to the trusted vendors.
-
-        Keyword argument:
-        path -- absolute path to the key file
-        """
-        log.info("Adding vendor key from file: %s", path)
-        trans.progress = 101
-        trans.status = STATUS_COMMITTING
-        with DaemonForkProgress(trans) as progress:
-            progress.run(apt.auth.add_key_from_file, path)
-        if progress._child_exit != 0:
-            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
-                                    _("Key file %s couldn't be installed: %s"),
-                                    path, progress.output)
-
-    def remove_vendor_key(self, trans, fingerprint):
-        """Remove repository key.
-
-        Keyword argument:
-        trans -- the corresponding transaction
-        fingerprint -- fingerprint of the key to remove
-        """
-        log.info("Removing vendor key: %s", fingerprint)
-        trans.progress = 101
-        trans.status = STATUS_COMMITTING
-        try:
-            int(fingerprint, 16)
-        except ValueError:
-            raise TransactionFailed(ERROR_KEY_NOT_REMOVED,
-                                    #TRANSLATORS: %s is the id of a GnuPG key
-                                    #             e.g. E08ADE95
-                                    _("Invalid key id: %s"), fingerprint)
-        with DaemonForkProgress(trans) as progress:
-            progress.run(apt.auth.remove_key, fingerprint)
-        if progress._child_exit != 0:
-            raise TransactionFailed(ERROR_KEY_NOT_REMOVED,
-                                    _("Key with fingerprint %s couldn't be "
-                                      "removed: %s"),
-                                    fingerprint, progress.output)
-
-    def install_file(self, trans, path, force, simulate=False):
-        """Install local package file.
-
-        Keyword argument:
-        trans -- the corresponding transaction
-        path -- absolute path to the package file
-        force -- if installing an invalid package is allowed
-        simulate -- if True the changes won't be committed but the debfile
-                    instance will be returned
-        """
-        log.info("Installing local package file: %s", path)
-        # Check if the dpkg can be installed at all
-        trans.status = STATUS_RESOLVING_DEP
-        deb = self._check_deb_file(trans, path, force)
-        # Check for required changes and apply them before
-        (install, remove, unauth) = deb.required_changes
-        self._call_plugins("modify_cache_after")
-        if simulate:
-            return deb
-        with self._frozen_status():
-            if len(install) > 0 or len(remove) > 0:
-                self._apply_changes(trans, fetch_range=(15, 33),
-                                    install_range=(34, 63))
-            # Install the dpkg file
-            deb_progress = DaemonDpkgInstallProgress(trans, begin=64, end=95)
-            res = deb.install(deb_progress)
-            trans.output += deb_progress.output
-            if res:
-                raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
-                                        trans.output)
-
-    def _mark_packages_for_removal(self, packages, resolver, purge=False):
-        """Mark packages for installation."""
-        for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
-                                           for pkg in packages]:
-            try:
-                pkg = self._cache[pkg_name]
-            except KeyError:
-                raise TransactionFailed(ERROR_NO_PACKAGE,
-                                        _("Package %s isn't available"),
-                                        pkg_name)
-            if not pkg.is_installed and not pkg.installed_files:
-                raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
-                                        _("Package %s isn't installed"),
-                                        pkg_name)
-            if pkg.essential is True:
-                raise TransactionFailed(ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE,
-                                        _("Package %s cannot be removed."),
-                                        pkg_name)
-            if pkg_ver and pkg.installed != pkg_ver:
-                raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
-                                        _("The version %s of %s is not "
-                                          "installed"), pkg_ver, pkg_name)
-            pkg.mark_delete(False, purge)
-            resolver.clear(pkg)
-            resolver.protect(pkg)
-            resolver.remove(pkg)
-
-    def _check_obsoleted_dependencies(self, trans, resolver=None):
-        """Mark obsoleted dependencies of to be removed packages
-        for removal.
-        """
-        if not trans.remove_obsoleted_depends:
-            return
-        if not resolver:
-            resolver = apt.cache.ProblemResolver(self._cache)
-        installed_deps = set()
-        with self._cache.actiongroup():
-            for pkg in self._cache.get_changes():
-                if pkg.marked_delete:
-                    installed_deps = self._installed_dependencies(
-                        pkg.name, installed_deps)
-            for dep_name in installed_deps:
-                if dep_name in self._cache:
-                    pkg = self._cache[dep_name]
-                    if pkg.is_installed and pkg.is_auto_removable:
-                        pkg.mark_delete(False)
-            # do an additional resolver run to ensure that the autoremove
-            # never leaves the cache in an inconsistent state, see bug
-            # LP: #659111 for the rational, essentially this may happen
-            # if a package is marked install during problem resolving but
-            # is later no longer required. the resolver deals with that
-            self._resolve_depends(trans, resolver)
-
-    def _installed_dependencies(self, pkg_name, all_deps=None):
-        """Recursively return all installed dependencies of a given package."""
-        #FIXME: Should be part of python-apt, since it makes use of non-public
-        #       API. Perhaps by adding a recursive argument to
-        #       apt.package.Version.get_dependencies()
-        if not all_deps:
-            all_deps = set()
-        if not pkg_name in self._cache:
-            return all_deps
-        cur = self._cache[pkg_name]._pkg.current_ver
-        if not cur:
-            return all_deps
-        for sec in ("PreDepends", "Depends", "Recommends"):
-            try:
-                for dep in cur.depends_list[sec]:
-                    dep_name = dep[0].target_pkg.name
-                    if not dep_name in all_deps:
-                        all_deps.add(dep_name)
-                        all_deps |= self._installed_dependencies(dep_name,
-                                                                 all_deps)
-            except KeyError:
-                pass
-        return all_deps
-
-    def _mark_packages_for_downgrade(self, packages, resolver):
-        """Mark packages for downgrade."""
-        for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
-                                           for pkg in packages]:
-            try:
-                pkg = self._cache[pkg_name]
-            except KeyError:
-                raise TransactionFailed(ERROR_NO_PACKAGE,
-                                        _("Package %s isn't available"),
-                                        pkg_name)
-            if not pkg.is_installed:
-                raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
-                                        _("Package %s isn't installed"),
-                                        pkg_name)
-            auto = pkg.is_auto_installed
-            pkg.mark_install(False, True, True)
-            pkg.mark_auto(auto)
-            resolver.clear(pkg)
-            resolver.protect(pkg)
-            if pkg_ver:
-                if pkg.installed and pkg.installed.version < pkg_ver:
-                    #FIXME: We need a new error enum
-                    raise TransactionFailed(ERROR_NO_PACKAGE,
-                                            _("The former version %s of %s "
-                                              "is already installed"),
-                                            pkg.installed.version, pkg.name)
-                elif pkg.installed and pkg.installed.version == pkg_ver:
-                    raise TransactionFailed(ERROR_PACKAGE_ALREADY_INSTALLED,
-                                            _("The version %s of %s "
-                                              "is already installed"),
-                                            pkg.installed.version, pkg.name)
-                try:
-                    pkg.candidate = pkg.versions[pkg_ver]
-                except KeyError:
-                    raise TransactionFailed(ERROR_NO_PACKAGE,
-                                            _("The version %s of %s isn't "
-                                              "available"), pkg_ver, pkg_name)
-            else:
-                raise TransactionFailed(ERROR_NO_PACKAGE,
-                                        _("You need to specify a version to "
-                                          "downgrade %s to"),
-                                        pkg_name)
-
-    def _mark_packages_for_upgrade(self, packages, resolver):
-        """Mark packages for upgrade."""
-        for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
-                                           for pkg in packages]:
-            try:
-                pkg = self._cache[pkg_name]
-            except KeyError:
-                raise TransactionFailed(ERROR_NO_PACKAGE,
-                                        _("Package %s isn't available"),
-                                        pkg_name)
-            if not pkg.is_installed:
-                raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
-                                        _("Package %s isn't installed"),
-                                        pkg_name)
-            auto = pkg.is_auto_installed
-            pkg.mark_install(False, True, True)
-            pkg.mark_auto(auto)
-            resolver.clear(pkg)
-            resolver.protect(pkg)
-            if pkg_ver:
-                if (pkg.installed and
-                    apt_pkg.version_compare(pkg.installed.version,
-                                            pkg_ver) == 1):
-                    raise TransactionFailed(ERROR_PACKAGE_UPTODATE,
-                                            _("The later version %s of %s "
-                                              "is already installed"),
-                                            pkg.installed.version, pkg.name)
-                elif (pkg.installed and
-                      apt_pkg.version_compare(pkg.installed.version,
-                                              pkg_ver) == 0):
-                    raise TransactionFailed(ERROR_PACKAGE_UPTODATE,
-                                            _("The version %s of %s "
-                                              "is already installed"),
-                                            pkg.installed.version, pkg.name)
-                try:
-                    pkg.candidate = pkg.versions[pkg_ver]
-                except KeyError:
-                    raise TransactionFailed(ERROR_NO_PACKAGE,
-                                            _("The version %s of %s isn't "
-                                              "available."), pkg_ver, pkg_name)
-
-            elif pkg_rel:
-                self._set_candidate_release(pkg, pkg_rel)
-
-    @staticmethod
-    def _set_candidate_release(pkg, release):
-        """Set the candidate of a package to the one from the given release."""
-        #FIXME: Should be moved to python-apt
-        # Check if the package is provided in the release
-        for version in pkg.versions:
-            if [origin for origin in version.origins
-                    if origin.archive == release]:
-                break
-        else:
-            raise TransactionFailed(ERROR_NO_PACKAGE,
-                                    _("The package %s isn't available in "
-                                      "the %s release."), pkg.name, release)
-        pkg._pcache.cache_pre_change()
-        pkg._pcache._depcache.set_candidate_release(pkg._pkg, version._cand,
-                                                    release)
-        pkg._pcache.cache_post_change()
-
-    def update_cache(self, trans, sources_list):
-        """Update the cache.
-
-        Keyword arguments:
-        trans -- the corresponding transaction
-        sources_list -- only update the repositories found in the sources.list
-                        snippet by the given file name.
-        """
-
-        def compare_pathes(first, second):
-            """Small helper to compare two pathes."""
-            return os.path.normpath(first) == os.path.normpath(second)
-
-        log.info("Updating cache")
-
-        progress = DaemonAcquireRepoProgress(trans, begin=10, end=90)
-        if sources_list and not sources_list.startswith("/"):
-            dir = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
-            sources_list = os.path.join(dir, sources_list)
-        if sources_list:
-            # For security reasons (LP #722228) we only allow files inside
-            # sources.list.d as basedir
-            basedir = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
-            system_sources = apt_pkg.config.find_file("Dir::Etc::sourcelist")
-            if "/" in sources_list:
-                sources_list = os.path.abspath(sources_list)
-                # Check if the sources_list snippet is in the sourceparts
-                # directory
-                common_prefix = os.path.commonprefix([sources_list, basedir])
-                if not (compare_pathes(common_prefix, basedir) or
-                        compare_pathes(sources_list, system_sources)):
-                    raise AptDaemonError("Only alternative sources.list files "
-                                         "inside '%s' are allowed (not '%s')" %
-                                         (basedir, sources_list))
-            else:
-                sources_list = os.path.join(basedir, sources_list)
-        try:
-            self._cache.update(progress, sources_list=sources_list)
-        except apt.cache.FetchFailedException as error:
-            # ListUpdate() method of apt handles a cancelled operation
-            # as a failed one, see LP #162441
-            if trans.cancelled:
-                raise TransactionCancelled()
-            else:
-                raise TransactionFailed(ERROR_REPO_DOWNLOAD_FAILED,
-                                        str(error))
-        except apt.cache.FetchCancelledException:
-            raise TransactionCancelled()
-        except apt.cache.LockFailedException:
-            raise TransactionFailed(ERROR_NO_LOCK)
-        self._open_cache(trans, begin=91, end=95)
-
-    def upgrade_system(self, trans, safe_mode=True, simulate=False):
-        """Upgrade the system.
-
-        Keyword argument:
-        trans -- the corresponding transaction
-        safe_mode -- if additional software should be installed or removed to
-                     satisfy the dependencies the an updates
-        simulate -- if the changes should not be applied
-        """
-        log.info("Upgrade system with safe mode: %s" % safe_mode)
-        trans.status = STATUS_RESOLVING_DEP
-        #FIXME: What to do if already uptotdate? Add error code?
-        self._call_plugins("modify_cache_before")
-        try:
-            self._cache.upgrade(dist_upgrade=not safe_mode)
-        except SystemError as excep:
-            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED, str(excep))
-        self._call_plugins("modify_cache_after")
-        self._check_obsoleted_dependencies(trans)
-        if not simulate:
-            self._apply_changes(trans)
-
-    def fix_incomplete_install(self, trans):
-        """Run dpkg --configure -a to recover from a failed installation.
-
-        Keyword arguments:
-        trans -- the corresponding transaction
-        """
-        log.info("Fixing incomplete installs")
-        trans.status = STATUS_CLEANING_UP
-        with self._frozen_status():
-            with DaemonDpkgRecoverProgress(trans) as progress:
-                progress.run()
-        trans.output += progress.output
-        if progress._child_exit != 0:
-            raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
-                                    trans.output)
-
-    def reconfigure(self, trans, packages, priority):
-        """Run dpkg-reconfigure to reconfigure installed packages.
-
-        Keyword arguments:
-        trans -- the corresponding transaction
-        packages -- list of packages to reconfigure
-        priority -- the lowest priority of question which should be asked
-        """
-        log.info("Reconfiguring packages")
-        with self._frozen_status():
-            with DaemonDpkgReconfigureProgress(trans) as progress:
-                progress.run(packages, priority)
-        trans.output += progress.output
-        if progress._child_exit != 0:
-            raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
-                                    trans.output)
-
-    def fix_broken_depends(self, trans, simulate=False):
-        """Try to fix broken dependencies.
-
-        Keyword arguments:
-        trans -- the corresponding transaction
-        simualte -- if the changes should not be applied
-        """
-        log.info("Fixing broken depends")
-        trans.status = STATUS_RESOLVING_DEP
-        try:
-            self._cache._depcache.fix_broken()
-        except SystemError:
-            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED,
-                                    self._get_broken_details(trans))
-        if not simulate:
-            self._apply_changes(trans)
-
-    def _open_cache(self, trans, begin=1, end=5, quiet=False, status=None):
-        """Open the APT cache.
-
-        Keyword arguments:
-        trans -- the corresponding transaction
-        start -- the begin of the progress range
-        end -- the end of the the progress range
-        quiet -- if True do no report any progress
-        status -- an alternative dpkg status file
-        """
-        self.marked_tid = None
-        trans.status = STATUS_LOADING_CACHE
-        if not status:
-            status = self._status_orig
-        apt_pkg.config.set("Dir::State::status", status)
-        apt_pkg.init_system()
-        progress = DaemonOpenProgress(trans, begin=begin, end=end,
-                                      quiet=quiet)
-        try:
-            if not isinstance(self._cache, apt.cache.Cache):
-                self._cache = apt.cache.Cache(progress)
-            else:
-                self._cache.open(progress)
-        except SystemError as excep:
-            raise TransactionFailed(ERROR_NO_CACHE, str(excep))
-
-    def is_dpkg_journal_clean(self):
-        """Return False if there are traces of incomplete dpkg status
-        updates."""
-        status_updates = os.path.join(os.path.dirname(self._status_orig),
-                                      "updates/")
-        for dentry in os.listdir(status_updates):
-            if dentry.isdigit():
-                return False
-        return True
-
-    def _apply_changes(self, trans, fetch_range=(15, 50),
-                       install_range=(50, 90)):
-        """Apply previously marked changes to the system.
-
-        Keyword arguments:
-        trans -- the corresponding transaction
-        fetch_range -- tuple containing the start and end point of the
-                       download progress
-        install_range -- tuple containing the start and end point of the
-                         install progress
-        """
-        changes = self._cache.get_changes()
-        if not changes:
-            return
-        # Do not allow to remove essential packages
-        for pkg in changes:
-            if pkg.marked_delete and (pkg.essential is True or
-                                      (pkg.installed and
-                                       pkg.installed.priority == "required") or
-                                      pkg.name == "aptdaemon"):
-                raise TransactionFailed(ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE,
-                                        _("Package %s cannot be removed"),
-                                        pkg.name)
-        # Check if any of the cache changes get installed from an
-        # unauthenticated repository""
-        if not trans.allow_unauthenticated and trans.unauthenticated:
-            raise TransactionFailed(ERROR_PACKAGE_UNAUTHENTICATED,
-                                    " ".join(sorted(trans.unauthenticated)))
-        if trans.cancelled:
-            raise TransactionCancelled()
-        trans.cancellable = False
-        fetch_progress = DaemonAcquireProgress(trans, begin=fetch_range[0],
-                                               end=fetch_range[1])
-        inst_progress = DaemonInstallProgress(trans, begin=install_range[0],
-                                              end=install_range[1])
-        with self._frozen_status():
-            try:
-                self._cache.commit(fetch_progress, inst_progress)
-            except apt.cache.FetchFailedException as error:
-                raise TransactionFailed(ERROR_PACKAGE_DOWNLOAD_FAILED,
-                                        str(error))
-            except apt.cache.FetchCancelledException:
-                raise TransactionCancelled()
-            except SystemError as excep:
-                # Run dpkg --configure -a to recover from a failed transaction
-                trans.status = STATUS_CLEANING_UP
-                with DaemonDpkgRecoverProgress(trans, begin=90, end=95) as pro:
-                    pro.run()
-                output = inst_progress.output + pro.output
-                trans.output += output
-                raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
-                                        "%s: %s" % (excep, trans.output))
-            else:
-                trans.output += inst_progress.output
-
-    @contextlib.contextmanager
-    def _frozen_status(self):
-        """Freeze the status file to allow simulate operations during
-        a dpkg call."""
-        frozen_dir = tempfile.mkdtemp(prefix="aptdaemon-frozen-status")
-        shutil.copy(self._status_orig, frozen_dir)
-        self._status_frozen = os.path.join(frozen_dir, "status")
-        try:
-            yield
-        finally:
-            shutil.rmtree(frozen_dir)
-            self._status_frozen = None
-
-    def query(self, trans):
-        """Process a PackageKit query transaction."""
-        raise NotImplementedError
-
-    def simulate(self, trans):
-        """Return the dependencies which will be installed by the transaction,
-        the content of the dpkg status file after the transaction would have
-        been applied, the download size and the required disk space.
-
-        Keyword arguments:
-        trans -- the transaction which should be simulated
-        """
-        log.info("Simulating trans: %s" % trans.tid)
-        trans.status = STATUS_RESOLVING_DEP
-        GLib.idle_add(self._simulate, trans)
-
-    def _simulate(self, trans):
-        try:
-            (trans.depends, trans.download, trans.space,
-                trans.unauthenticated,
-                trans.high_trust_packages) = self.__simulate(trans)
-        except TransactionFailed as excep:
-            trans.error = excep
-            trans.exit = EXIT_FAILED
-        except Exception as excep:
-            tbk = traceback.format_exc()
-            trans.error = TransactionFailed(ERROR_UNKNOWN, tbk)
-            try:
-                from . import crash
-            except ImportError:
-                pass
-            else:
-                crash.create_report("%s: %s" % (type(excep), str(excep)),
-                                    tbk, trans)
-            trans.exit = EXIT_FAILED
-        else:
-            trans.status = STATUS_SETTING_UP
-            trans.simulated = time.time()
-            self.marked_tid = trans.tid
-        finally:
-            self._emit_transaction_simulated(trans)
-            self.last_action_timestamp = time.time()
-        return False
-
-    def __simulate(self, trans):
-        depends = [[], [], [], [], [], [], []]
-        unauthenticated = []
-        high_trust_packages = []
-        skip_pkgs = []
-        size = 0
-        installs = reinstalls = removals = purges = upgrades = upgradables = \
-            downgrades = []
-
-        # Only handle transaction which change packages
-        #FIXME: Add support for ROLE_FIX_INCOMPLETE_INSTALL
-        if trans.role not in [ROLE_INSTALL_PACKAGES, ROLE_UPGRADE_PACKAGES,
-                              ROLE_UPGRADE_SYSTEM, ROLE_REMOVE_PACKAGES,
-                              ROLE_COMMIT_PACKAGES, ROLE_INSTALL_FILE,
-                              ROLE_FIX_BROKEN_DEPENDS]:
-            return depends, 0, 0, [], []
-
-        # If a transaction is currently running use the former status file
-        if self._status_frozen:
-            status_path = self._status_frozen
-        else:
-            status_path = self._status_orig
-        self._open_cache(trans, quiet=True, status=status_path)
-        if trans.role == ROLE_FIX_BROKEN_DEPENDS:
-            self.fix_broken_depends(trans, simulate=True)
-        elif self._cache.broken_count:
-            raise TransactionFailed(ERROR_CACHE_BROKEN,
-                                    self._get_broken_details(trans))
-        elif trans.role == ROLE_UPGRADE_SYSTEM:
-            for pkg in self._iterate_packages():
-                if pkg.is_upgradable:
-                    upgradables.append(pkg)
-            self.upgrade_system(trans, simulate=True, **trans.kwargs)
-        elif trans.role == ROLE_INSTALL_FILE:
-            deb = self.install_file(trans, simulate=True, **trans.kwargs)
-            skip_pkgs.append(deb.pkgname)
-            try:
-                # Sometimes a thousands comma is used in packages
-                # See LP #656633
-                size = int(deb["Installed-Size"].replace(",", "")) * 1024
-                # Some packages ship really large install sizes e.g.
-                # openvpn access server, see LP #758837
-                if size > sys.maxsize:
-                    raise OverflowError("Size is too large: %s Bytes" % size)
-            except (KeyError, AttributeError, ValueError, OverflowError):
-                if not trans.kwargs["force"]:
-                    msg = trans.gettext("The package doesn't provide a "
-                                        "valid Installed-Size control "
-                                        "field. See Debian Policy 5.6.20.")
-                    raise TransactionFailed(ERROR_INVALID_PACKAGE_FILE, msg)
-            try:
-                pkg = self._cache[deb.pkgname]
-            except KeyError:
-                trans.packages = [[deb.pkgname], [], [], [], [], []]
-            else:
-                if pkg.is_installed:
-                    # if we failed to get the size from the deb file do nor
-                    # try to get the delta
-                    if size != 0:
-                        size -= pkg.installed.installed_size
-                    trans.packages = [[], [deb.pkgname], [], [], [], []]
-                else:
-                    trans.packages = [[deb.pkgname], [], [], [], [], []]
-        else:
-            #FIXME: ugly code to get the names of the packages
-            (installs, reinstalls, removals, purges,
-             upgrades, downgrades) = [[re.split("(=|/)", entry, 1)[0]
-                                       for entry in lst]
-                                      for lst in trans.packages]
-            self.commit_packages(trans, *trans.packages, simulate=True)
-
-        changes = self._cache.get_changes()
-        changes_names = []
-        # get the additional dependencies
-        for pkg in changes:
-            if (pkg.marked_upgrade and pkg.is_installed and
-                    not pkg.name in upgrades):
-                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
-                depends[PKGS_UPGRADE].append(pkg_str)
-            elif pkg.marked_reinstall and not pkg.name in reinstalls:
-                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
-                depends[PKGS_REINSTALL].append(pkg_str)
-            elif pkg.marked_downgrade and not pkg.name in downgrades:
-                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
-                depends[PKGS_DOWNGRADE].append(pkg_str)
-            elif pkg.marked_install and not pkg.name in installs:
-                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
-                depends[PKGS_INSTALL].append(pkg_str)
-            elif pkg.marked_delete and not pkg.name in removals:
-                pkg_str = "%s=%s" % (pkg.name, pkg.installed.version)
-                depends[PKGS_REMOVE].append(pkg_str)
-            #FIXME: add support for purges
-            changes_names.append(pkg.name)
-        # get the unauthenticated packages
-        unauthenticated = self._get_unauthenticated()
-        high_trust_packages = self._get_high_trust_packages()
-        # Check for skipped upgrades
-        for pkg in upgradables:
-            if pkg.marked_keep:
-                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
-                depends[PKGS_KEEP].append(pkg_str)
-
-        # apt.cache.Cache.required_download requires a clean cache. Under some
-        # strange circumstances it can fail (most likely an interrupted
-        # debconf question), see LP#659438
-        # Running dpkg --configure -a fixes the situation
-        try:
-            required_download = self._cache.required_download
-        except SystemError as error:
-            raise TransactionFailed(ERROR_INCOMPLETE_INSTALL, str(error))
-
-        required_space = size + self._cache.required_space
-
-        return (depends, required_download, required_space, unauthenticated,
-                high_trust_packages)
-
-    def _check_deb_file(self, trans, path, force):
-        """Perform some basic checks for the Debian package.
-
-        :param trans: The transaction instance.
-
-        :returns: An apt.debfile.Debfile instance.
-        """
-        if not os.path.isfile(path):
-            raise TransactionFailed(ERROR_UNREADABLE_PACKAGE_FILE, path)
-        if not force and os.path.isfile("/usr/bin/lintian"):
-            with DaemonLintianProgress(trans) as progress:
-                progress.run(path)
-            #FIXME: Add an error to catch return state 2 (failure)
-            if progress._child_exit != 0:
-                raise TransactionFailed(ERROR_INVALID_PACKAGE_FILE,
-                                        "Lintian check results for %s:"
-                                        "\n%s" % (path, progress.output))
-        try:
-            deb = apt.debfile.DebPackage(path, self._cache)
-        except IOError:
-            raise TransactionFailed(ERROR_UNREADABLE_PACKAGE_FILE, path)
-        except Exception as error:
-            raise TransactionFailed(ERROR_INVALID_PACKAGE_FILE, str(error))
-        try:
-            ret = deb.check()
-        except Exception as error:
-            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED, str(error))
-        if not ret:
-            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED,
-                                    deb._failure_string)
-        return deb
-
-    def clean(self, trans):
-        """Clean the download directories.
-
-        Keyword arguments:
-        trans -- the corresponding transaction
-        """
-        #FIXME: Use pkgAcquire.Clean(). Currently not part of python-apt.
-        trans.status = STATUS_CLEANING_UP
-        archive_path = apt_pkg.config.find_dir("Dir::Cache::archives")
-        for dir in [archive_path, os.path.join(archive_path, "partial")]:
-            for filename in os.listdir(dir):
-                if filename == "lock":
-                    continue
-                path = os.path.join(dir, filename)
-                if os.path.isfile(path):
-                    log.debug("Removing file %s", path)
-                    os.remove(path)
-
-    def add_license_key(self, trans, pkg_name, json_token, server_name):
-        """Add a license key data to the given package.
-
-        Keyword arguemnts:
-        trans -- the coresponding transaction
-        pkg_name -- the name of the corresponding package
-        json_token -- the oauth token as json
-        server_name -- the server to use (ubuntu-production, ubuntu-staging)
-        """
-        # set transaction state to downloading
-        trans.status = STATUS_DOWNLOADING
-        try:
-            license_key, license_key_path = (
-                self.plugins["get_license_key"][0](trans.uid, pkg_name,
-                                                   json_token, server_name))
-        except Exception as error:
-            logging.exception("get_license_key plugin failed")
-            raise TransactionFailed(ERROR_LICENSE_KEY_DOWNLOAD_FAILED,
-                                    str(error))
-        # ensure stuff is good
-        if not license_key_path or not license_key:
-            raise TransactionFailed(ERROR_LICENSE_KEY_DOWNLOAD_FAILED,
-                                    _("The license key is empty"))
-
-        # add license key if we have one
-        self._add_license_key_to_system(pkg_name, license_key,
-                                        license_key_path)
-
-    def _add_license_key_to_system(self, pkg_name, license_key,
-                                   license_key_path):
-        # fixup path
-        license_key_path = os.path.join(apt_pkg.config.find_dir("Dir"),
-                                        license_key_path.lstrip("/"))
-
-        # Check content of the key
-        if (license_key.strip().startswith("#!") or
-                license_key.startswith("\x7fELF")):
-            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
-                                    _("The license key is not allowed to "
-                                      "contain executable code."))
-        # Check the path of the license
-        license_key_path = os.path.normpath(license_key_path)
-        license_key_path_rootdir = os.path.join(
-            apt_pkg.config["Dir"], self.LICENSE_KEY_ROOTDIR.lstrip("/"),
-            pkg_name)
-        if not license_key_path.startswith(license_key_path_rootdir):
-            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
-                                    _("The license key path %s is invalid"),
-                                    license_key_path)
-        if os.path.lexists(license_key_path):
-            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
-                                    _("The license key already exists: %s"),
-                                    license_key_path)
-        # Symlink attacks!
-        if os.path.realpath(license_key_path) != license_key_path:
-            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
-                                    _("The location of the license key is "
-                                      "unsecure since it contains symbolic "
-                                      "links. The path %s maps to %s"),
-                                    license_key_path,
-                                    os.path.realpath(license_key_path))
-        # Check if the directory already exists
-        if not os.path.isdir(os.path.dirname(license_key_path)):
-            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
-                                    _("The directory where to install the key "
-                                      "to doesn't exist yet: %s"),
-                                    license_key_path)
-        # write it
-        log.info("Writing license key to '%s'" % license_key_path)
-        old_umask = os.umask(18)
-        try:
-            with open(license_key_path, "w") as license_file:
-                license_file.write(license_key)
-        except IOError:
-            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
-                                    _("Failed to write key file to: %s"),
-                                    license_key_path)
-        finally:
-            os.umask(old_umask)
-
-    def _iterate_mainloop(self):
-        """Process pending actions on the main loop."""
-        while GLib.main_context_default().pending():
-            GLib.main_context_default().iteration()
-
-    def _iterate_packages(self, interval=1000):
-        """Itarte von the packages of the cache and iterate on the
-        GObject main loop time for more responsiveness.
-
-        Keyword arguments:
-        interval - the number of packages after which we iterate on the
-            mainloop
-        """
-        for enum, pkg in enumerate(self._cache):
-            if not enum % interval:
-                self._iterate_mainloop()
-            yield pkg
-
-    def _get_broken_details(self, trans, now=True):
-        """Return a message which provides debugging information about
-        broken packages.
-
-        This method is basically a Python implementation of apt-get.cc's
-        ShowBroken.
-
-        Keyword arguments:
-        trans -- the corresponding transaction
-        now -- if we check currently broken dependecies or the installation
-               candidate
-        """
-        msg = trans.gettext("The following packages have unmet dependencies:")
-        msg += "\n\n"
-        for pkg in self._cache:
-            if not ((now and pkg.is_now_broken) or
-                    (not now and pkg.is_inst_broken)):
-                continue
-            msg += "%s: " % pkg.name
-            if now:
-                version = pkg.installed
-            else:
-                version = pkg.candidate
-            indent = " " * (len(pkg.name) + 2)
-            dep_msg = ""
-            for dep in version.dependencies:
-                or_msg = ""
-                for base_dep in dep.or_dependencies:
-                    if or_msg:
-                        or_msg += "or\n"
-                        or_msg += indent
-                    # Check if it's an important dependency
-                    # See apt-pkg/depcache.cc IsImportantDep
-                    # See apt-pkg/pkgcache.cc IsCritical()
-                    if not (base_dep.rawtype in ["Depends", "PreDepends",
-                                                 "Obsoletes", "DpkgBreaks",
-                                                 "Conflicts"] or
-                           (apt_pkg.config.find_b("APT::Install-Recommends",
-                                                  False) and
-                            base_dep.rawtype == "Recommends") or
-                           (apt_pkg.config.find_b("APT::Install-Suggests",
-                                                  False) and
-                            base_dep.rawtype == "Suggests")):
-                        continue
-                    # Get the version of the target package
-                    try:
-                        pkg_dep = self._cache[base_dep.name]
-                    except KeyError:
-                        dep_version = None
-                    else:
-                        if now:
-                            dep_version = pkg_dep.installed
-                        else:
-                            dep_version = pkg_dep.candidate
-                    # We only want to display dependencies which cannot
-                    # be satisfied
-                    if dep_version and not apt_pkg.check_dep(base_dep.version,
-                                                             base_dep.relation,
-                                                             version.version):
-                        break
-                    or_msg = "%s: %s " % (base_dep.rawtype, base_dep.name)
-                    if base_dep.version:
-                        or_msg += "(%s %s) " % (base_dep.relation,
-                                                base_dep.version)
-                    if self._cache.is_virtual_package(base_dep.name):
-                        or_msg += trans.gettext("but it is a virtual package")
-                    elif not dep_version:
-                        if now:
-                            or_msg += trans.gettext("but it is not installed")
-                        else:
-                            or_msg += trans.gettext("but it is not going to "
-                                                    "be installed")
-                    elif now:
-                        #TRANSLATORS: %s is a version number
-                        or_msg += (trans.gettext("but %s is installed") %
-                                   dep_version.version)
-                    else:
-                        #TRANSLATORS: %s is a version number
-                        or_msg += (trans.gettext("but %s is to be installed") %
-                                   dep_version.version)
-                else:
-                    # Only append an or-group if at least one of the
-                    # dependencies cannot be satisfied
-                    if dep_msg:
-                        dep_msg += indent
-                    dep_msg += or_msg
-                    dep_msg += "\n"
-            msg += dep_msg
-        return msg
-
-    def is_reboot_required(self):
-        """If a reboot is required to get all changes into effect."""
-        return os.path.exists(os.path.join(apt_pkg.config.find_dir("Dir"),
-                                           "var/run/reboot-required"))
-
-
-class DummyWorker(AptWorker):
-
-    """Allows to test the daemon without making any changes to the system."""
-
-    def run(self, transaction):
-        """Process the given transaction in the background.
-
-        Keyword argument:
-        transaction -- core.Transcation instance to run
-        """
-        log.info("Processing transaction %s", transaction.tid)
-        if self.trans:
-            raise Exception("There is already a running transaction")
-        self.trans = transaction
-        self.last_action_timestamp = time.time()
-        self.trans.status = STATUS_RUNNING
-        self.trans.progress = 0
-        self.trans.cancellable = True
-        GLib.timeout_add(200, self._process_transaction, transaction)
-
-    def _process_transaction(self, trans):
-        """Run the worker"""
-        if trans.cancelled:
-            trans.exit = EXIT_CANCELLED
-        elif trans.progress == 100:
-            trans.exit = EXIT_SUCCESS
-        elif trans.role == ROLE_UPDATE_CACHE:
-            trans.exit = EXIT_FAILED
-        elif trans.role == ROLE_UPGRADE_PACKAGES:
-            trans.exit = EXIT_SUCCESS
-        elif trans.role == ROLE_UPGRADE_SYSTEM:
-            trans.exit = EXIT_CANCELLED
-        else:
-            if trans.role == ROLE_INSTALL_PACKAGES:
-                if trans.progress == 1:
-                    trans.status = STATUS_RESOLVING_DEP
-                elif trans.progress == 5:
-                    trans.status = STATUS_DOWNLOADING
-                elif trans.progress == 50:
-                    trans.status = STATUS_COMMITTING
-                    trans.status_details = "Heyas!"
-                elif trans.progress == 55:
-                    trans.paused = True
-                    trans.status = STATUS_WAITING_CONFIG_FILE_PROMPT
-                    trans.config_file_conflict = "/etc/fstab", "/etc/mtab"
-                    while trans.paused:
-                        GLib.main_context_default().iteration()
-                    trans.config_file_conflict_resolution = None
-                    trans.config_file_conflict = None
-                    trans.status = STATUS_COMMITTING
-                elif trans.progress == 60:
-                    trans.required_medium = ("Debian Lenny 5.0 CD 1",
-                                             "USB CD-ROM")
-                    trans.paused = True
-                    trans.status = STATUS_WAITING_MEDIUM
-                    while trans.paused:
-                        GLib.main_context_default().iteration()
-                    trans.status = STATUS_DOWNLOADING
-                elif trans.progress == 70:
-                    trans.status_details = "Servus!"
-                elif trans.progress == 90:
-                    trans.status_deatils = ""
-                    trans.status = STATUS_CLEANING_UP
-            elif trans.role == ROLE_REMOVE_PACKAGES:
-                if trans.progress == 1:
-                    trans.status = STATUS_RESOLVING_DEP
-                elif trans.progress == 5:
-                    trans.status = STATUS_COMMITTING
-                    trans.status_details = "Heyas!"
-                elif trans.progress == 50:
-                    trans.status_details = "Hola!"
-                elif trans.progress == 70:
-                    trans.status_details = "Servus!"
-                elif trans.progress == 90:
-                    trans.status_deatils = ""
-                    trans.status = STATUS_CLEANING_UP
-            trans.progress += 1
-            return True
-        trans.status = STATUS_FINISHED
-        self.last_action_timestamp = time.time()
-        tid = self.trans.tid[:]
-        trans = self.trans
-        self.trans = None
-        self._emit_transaction_done(trans)
-        log.info("Finished transaction %s", tid)
-        return False
-
-    def simulate(self, trans):
-        depends = [[], [], [], [], [], [], []]
-        return depends, 0, 0, []
-
-
-# vim:ts=4:sw=4:et
diff -pruN 1.1.1-4/aptdaemon.egg-info/dependency_links.txt 1.1.1+bzr982-0ubuntu14/aptdaemon.egg-info/dependency_links.txt
--- 1.1.1-4/aptdaemon.egg-info/dependency_links.txt	2013-08-12 04:33:50.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon.egg-info/dependency_links.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-
diff -pruN 1.1.1-4/aptdaemon.egg-info/PKG-INFO 1.1.1+bzr982-0ubuntu14/aptdaemon.egg-info/PKG-INFO
--- 1.1.1-4/aptdaemon.egg-info/PKG-INFO	2013-08-12 04:33:50.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon.egg-info/PKG-INFO	1970-01-01 00:00:00.000000000 +0000
@@ -1,24 +0,0 @@
-Metadata-Version: 1.1
-Name: aptdaemon
-Version: 1.1.1
-Summary: DBus driven daemon for APT
-Home-page: http://launchpad.net/sessioninstaller
-Author: Sebastian Heinlein
-Author-email: devel@glatzor.de
-License: GNU LGPL
-Description: Aptdaemon allows to perform package management tasks in a background process
-        controlled by DBus. It is greatly inspired by PackageKit, which doesn't support
-        essential features of apt by policy.
-        
-        The project homepage is at https://launchpad.net/aptdaemon
-        
-        You can report errors and suggestion there.
-        
-Keywords: apt package manager deb dbus d-bus debian ubuntu dpkg
-Platform: posix
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: System Administrators
-Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Topic :: System :: Systems Administration
-Classifier: Topic :: System :: Software Distribution
diff -pruN 1.1.1-4/aptdaemon.egg-info/SOURCES.txt 1.1.1+bzr982-0ubuntu14/aptdaemon.egg-info/SOURCES.txt
--- 1.1.1-4/aptdaemon.egg-info/SOURCES.txt	2013-08-12 04:33:50.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon.egg-info/SOURCES.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,290 +0,0 @@
-AUTHORS
-COPYRIGHT
-ChangeLog
-MANIFEST.in
-NEWS
-README
-README.PackageKit
-README.tests
-TODO
-applet.py
-aptd
-aptdcon
-gtk-demo.py
-gtk3-demo.py
-pylintrc
-release.sh
-setup.cfg
-setup.py
-apport/aptdaemon.py
-aptdaemon/__init__.py
-aptdaemon/client.py
-aptdaemon/config.py
-aptdaemon/console.py
-aptdaemon/core.py
-aptdaemon/crash.py
-aptdaemon/debconf.py
-aptdaemon/enums.py
-aptdaemon/errors.py
-aptdaemon/gtk3widgets.py
-aptdaemon/gtkwidgets.py
-aptdaemon/lock.py
-aptdaemon/logger.py
-aptdaemon/loop.py
-aptdaemon/networking.py
-aptdaemon/pkcompat.py
-aptdaemon/pkenums.py
-aptdaemon/policykit1.py
-aptdaemon/progress.py
-aptdaemon/test.py
-aptdaemon/utils.py
-aptdaemon/worker.py
-aptdaemon.egg-info/PKG-INFO
-aptdaemon.egg-info/SOURCES.txt
-aptdaemon.egg-info/dependency_links.txt
-aptdaemon.egg-info/top_level.txt
-data/20dbus
-data/org.debian.apt.conf
-data/org.debian.apt.policy.in
-data/org.debian.apt.service
-data/org.freedesktop.PackageKit-aptd.conf
-data/org.freedesktop.PackageKit.service
-data/icons/clean_svg_icons.sh
-data/icons/generate_16x16_icons.sh
-data/icons/generate_24x24_icons.sh
-data/icons/generate_48x48_icons.sh
-data/icons/16x16/animations/aptdaemon-action-cleaning-up.png
-data/icons/16x16/animations/aptdaemon-action-downloading.png
-data/icons/16x16/animations/aptdaemon-action-installing.png
-data/icons/16x16/animations/aptdaemon-action-removing.png
-data/icons/16x16/animations/aptdaemon-action-resolving.png
-data/icons/16x16/animations/aptdaemon-action-updating-cache.png
-data/icons/16x16/animations/aptdaemon-action-waiting.png
-data/icons/16x16/status/aptdaemon-add.png
-data/icons/16x16/status/aptdaemon-cleanup.png
-data/icons/16x16/status/aptdaemon-delete.png
-data/icons/16x16/status/aptdaemon-download.png
-data/icons/16x16/status/aptdaemon-resolve.png
-data/icons/16x16/status/aptdaemon-update-cache.png
-data/icons/16x16/status/aptdaemon-upgrade.png
-data/icons/16x16/status/aptdaemon-wait.png
-data/icons/16x16/status/aptdaemon-working.png
-data/icons/22x22/animations/aptdaemon-action-cleaning-up.png
-data/icons/22x22/animations/aptdaemon-action-downloading.png
-data/icons/22x22/animations/aptdaemon-action-installing.png
-data/icons/22x22/animations/aptdaemon-action-removing.png
-data/icons/22x22/animations/aptdaemon-action-resolving.png
-data/icons/22x22/animations/aptdaemon-action-updating-cache.png
-data/icons/22x22/animations/aptdaemon-action-waiting.png
-data/icons/22x22/status/aptdaemon-add.png
-data/icons/22x22/status/aptdaemon-cleanup.png
-data/icons/22x22/status/aptdaemon-delete.png
-data/icons/22x22/status/aptdaemon-download.png
-data/icons/22x22/status/aptdaemon-resolve.png
-data/icons/22x22/status/aptdaemon-update-cache.png
-data/icons/22x22/status/aptdaemon-upgrade.png
-data/icons/22x22/status/aptdaemon-wait.png
-data/icons/22x22/status/aptdaemon-working.png
-data/icons/24x24/animations/aptdaemon-action-cleaning-up.png
-data/icons/24x24/animations/aptdaemon-action-downloading.png
-data/icons/24x24/animations/aptdaemon-action-installing.png
-data/icons/24x24/animations/aptdaemon-action-removing.png
-data/icons/24x24/animations/aptdaemon-action-resolving.png
-data/icons/24x24/animations/aptdaemon-action-updating-cache.png
-data/icons/24x24/animations/aptdaemon-action-waiting.png
-data/icons/24x24/status/aptdaemon-add.png
-data/icons/24x24/status/aptdaemon-cleanup.png
-data/icons/24x24/status/aptdaemon-delete.png
-data/icons/24x24/status/aptdaemon-download.png
-data/icons/24x24/status/aptdaemon-resolve.png
-data/icons/24x24/status/aptdaemon-update-cache.png
-data/icons/24x24/status/aptdaemon-upgrade.png
-data/icons/24x24/status/aptdaemon-wait.png
-data/icons/24x24/status/aptdaemon-working.png
-data/icons/48x48/animations/aptdaemon-action-cleaning-up.png
-data/icons/48x48/animations/aptdaemon-action-downloading.png
-data/icons/48x48/animations/aptdaemon-action-installing.png
-data/icons/48x48/animations/aptdaemon-action-removing.png
-data/icons/48x48/animations/aptdaemon-action-resolving.png
-data/icons/48x48/animations/aptdaemon-action-updating-cache.png
-data/icons/48x48/animations/aptdaemon-action-waiting.png
-data/icons/48x48/status/aptdaemon-add.png
-data/icons/48x48/status/aptdaemon-cleanup.png
-data/icons/48x48/status/aptdaemon-delete.png
-data/icons/48x48/status/aptdaemon-download.png
-data/icons/48x48/status/aptdaemon-resolve.png
-data/icons/48x48/status/aptdaemon-update-cache.png
-data/icons/48x48/status/aptdaemon-upgrade.png
-data/icons/48x48/status/aptdaemon-wait.png
-data/icons/48x48/status/aptdaemon-working.png
-data/icons/scalable/status/aptdaemon-add.svg
-data/icons/scalable/status/aptdaemon-cleanup.svg
-data/icons/scalable/status/aptdaemon-delete.svg
-data/icons/scalable/status/aptdaemon-download.svg
-data/icons/scalable/status/aptdaemon-resolve.svg
-data/icons/scalable/status/aptdaemon-setup.svg
-data/icons/scalable/status/aptdaemon-update-cache.svg
-data/icons/scalable/status/aptdaemon-upgrade.svg
-data/icons/scalable/status/aptdaemon-wait.svg
-data/lintian/debian/aptdaemon.profile
-data/lintian/ubuntu/aptdaemon.profile
-doc/aptd.1
-doc/aptdcon.1
-doc/org.debian.apt.7
-doc/org.debian.apt.transaction.7
-doc/examples/chained.py
-doc/source/aptdaemon.client.rst
-doc/source/aptdaemon.enums.rst
-doc/source/aptdaemon.gtk3widgets.rst
-doc/source/conf.py
-doc/source/dbus.rst
-doc/source/index.rst
-doc/source/plugins.rst
-doc/source/_ext/signals.py
-po/POTFILES.in
-po/af.po
-po/am.po
-po/ar.po
-po/ast.po
-po/az.po
-po/be.po
-po/bg.po
-po/bn.po
-po/br.po
-po/bs.po
-po/ca.po
-po/ca@valencia.po
-po/crh.po
-po/cs.po
-po/cy.po
-po/da.po
-po/de.po
-po/dv.po
-po/el.po
-po/en_AU.po
-po/en_CA.po
-po/en_GB.po
-po/eo.po
-po/es.po
-po/et.po
-po/eu.po
-po/fa.po
-po/fi.po
-po/fil.po
-po/fo.po
-po/fr.po
-po/gd.po
-po/gl.po
-po/he.po
-po/hi.po
-po/hr.po
-po/hu.po
-po/hy.po
-po/id.po
-po/is.po
-po/it.po
-po/ja.po
-po/kk.po
-po/km.po
-po/kn.po
-po/ko.po
-po/ku.po
-po/ky.po
-po/ln.po
-po/lt.po
-po/lv.po
-po/mi.po
-po/ml.po
-po/ms.po
-po/my.po
-po/nb.po
-po/nds.po
-po/ne.po
-po/nl.po
-po/nn.po
-po/oc.po
-po/pl.po
-po/pt.po
-po/pt_BR.po
-po/ro.po
-po/ru.po
-po/se.po
-po/shn.po
-po/si.po
-po/sk.po
-po/sl.po
-po/sq.po
-po/sr.po
-po/sv.po
-po/ta.po
-po/te.po
-po/th.po
-po/tr.po
-po/ug.po
-po/uk.po
-po/ur.po
-po/uz.po
-po/vi.po
-po/zh_CN.po
-po/zh_HK.po
-po/zh_TW.po
-tests/__init__.py
-tests/_test_py2_string_handling.py
-tests/_test_py3_string_handling.py
-tests/dbus.conf
-tests/dpkg-wrapper.sh
-tests/fake-polkitd.py
-tests/fakeroot-apt-key
-tests/test_cdrom.py
-tests/test_client.py
-tests/test_configfileprompt.py
-tests/test_configparser.py
-tests/test_dbus_type.py
-tests/test_debconf.py
-tests/test_gtk3widgets.py
-tests/test_high_trust_repository_whitelist.py
-tests/test_index.py
-tests/test_lock.py
-tests/test_lock_location.py
-tests/test_pep8.py
-tests/test_pk.py
-tests/test_progress.py
-tests/test_py2_string_handling.py
-tests/test_simulate.py
-tests/test_trans_chain.py
-tests/test_valid_package_names.py
-tests/test_worker.py
-tests/data/high-trust-repository-whitelist-broken.cfg
-tests/data/high-trust-repository-whitelist.cfg
-tests/debconf/aptdaemon.config
-tests/debconf/aptdaemon.templates
-tests/regressions/test_lp722228.py
-tests/regressions/test_lp768691.py
-tests/repo/Packages
-tests/repo/Release
-tests/repo/Release.gpg
-tests/repo/glatzor.gpg
-tests/repo/gstreamer0.10-silly_0.1-0_all.deb
-tests/repo/silly-base_0.1-0_all.deb
-tests/repo/silly-base_0.1-0update1_all.deb
-tests/repo/silly-broken_0.1-0_all.deb
-tests/repo/silly-bully_0.1-0_all.deb
-tests/repo/silly-config_0.1-0_all.deb
-tests/repo/silly-depend-base-lintian-broken_0.1-0_all.deb
-tests/repo/silly-depend-base_0.1-0_all.deb
-tests/repo/silly-essential_0.1-0_all.deb
-tests/repo/silly-fail_0.1-0_all.deb
-tests/repo/silly-important_0.1-0_all.deb
-tests/repo/silly-postinst-input_0.1-0_all.deb
-tests/repo/backports/Packages
-tests/repo/backports/Packages.gpg
-tests/repo/backports/Release
-tests/repo/backports/Release.gpg
-tests/repo/security/Packages
-tests/repo/security/Packages.gpg
-tests/repo/security/Release
-tests/repo/security/Release.gpg
-tests/repo/whitelisted/Packages
-tests/repo/whitelisted/Packages.gpg
-tests/repo/whitelisted/Release
-tests/repo/whitelisted/Release.gpg
\ No newline at end of file
diff -pruN 1.1.1-4/aptdaemon.egg-info/top_level.txt 1.1.1+bzr982-0ubuntu14/aptdaemon.egg-info/top_level.txt
--- 1.1.1-4/aptdaemon.egg-info/top_level.txt	2013-08-12 04:33:50.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/aptdaemon.egg-info/top_level.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-aptdaemon
diff -pruN 1.1.1-4/ChangeLog 1.1.1+bzr982-0ubuntu14/ChangeLog
--- 1.1.1-4/ChangeLog	2013-08-12 04:33:47.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/ChangeLog	1970-01-01 00:00:00.000000000 +0000
@@ -1,8653 +0,0 @@
-2013-08-12  Sebastian Heinlein  <devel@glatzor.de>
-
-	Push local changes
-
-2013-08-12  Sebastian Heinlein  <renate@renate-VirtualBox>
-
-	Merge fixes from trunk
-
-2013-07-27  Sebastian Heinlein  <devel@glatzor.de>
-
-	Push local changes
-
-2013-07-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Export Daemon(Fork|Lintian)Progress correctly
-
-2013-07-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Make sure to not remove transaction from the bus more than once
-
-2013-07-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Don't add an additional white space when releasing a new version
-
-2013-07-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix white space in release version
-
-2013-07-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Fix supported roles (add remove_pages and install_files)
-
-2013-08-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge 1.1 release into stable branch
-
-2013-07-16  Sebastian Heinlein  <devel@glatzor.de>
-
-	Release version 1.1
-
-2013-07-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update NEWS and README for 1.1 release
-
-2013-07-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Emit untrusted packages
-
-2013-07-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: move the code to skip simulation before auth for simulated transactions
-
-2013-07-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Trivial fix to make sure that Transaction._check_simualted is always a defferd
-
-2013-07-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Fix some weird formatings
-
-2013-07-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Avoid iterations on the complete cache if we only need the changes.
-
-2013-07-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Move the transaction simulation call from Queue.put() into a Transaction method and make sure that every transaction is simulated before the auth is checked.
-	
-	High trust packages require a simulation before.
-
-2013-07-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2013-07-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Ensure that the default encoding is set since Python's setlocale doesn't
-	allow to change it. This can be the case if D-Bus activation is used,
-	see LP: #1058038 and http://bugs.python.org/issue16162
-	
-	Thanks Michael for the investigation and the patch!
-
-2013-07-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge Ubuntu patch to work arround a random crash while resizing dialogs
-	
-	It seems that either the gtk.Window.get_size() method
-	doesn't always return a tuple or that the
-	gtk.Window.set_size() method doesn't correctly handle *
-	arguments correctly, see LP#898851
-
-2013-07-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: merge canauth branch to add support for the CanAuthorize() method
-	
-	The packagekit policies are mapped to aptdaemon ones. It would be nicer if
-	CanAuthorize would accept RoleEnums instead of policies.
-
-2013-07-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	implement canauthorize
-
-2013-07-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Use ItemProgress to improve download progress reporting
-
-2013-07-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Emit the dependencies with the full information including description since the simulate now happens inside the worker
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	Remove some obsolete FIXMEs
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	gtk3widgets: by default the configuration file conflict should be resolved by replacing the current one
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	Unset the title of GTK3 dialogs
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: remove some obsoleted code
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	pep8 fixes
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Fix group searching and add new Debian sections
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Merge filters branch which adds the ARCH and NOT_ARCH filters and fixes some smaller bugs
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: fix a typo in the is_package_free method
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Fixes in previous commits
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Fix a small typo in the resolve method
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Also add arch filter to the _is_package_visible() method
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Fix a small bug in the NOT_DEVELOPMENT filter
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Use apt_pkg.get_architectures() to get the native arch
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Add support for the ARCH filter
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Convert the Python 2 origin label str to unicode, Thanks Colin.
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	Push local changes
-
-2013-07-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: don't use monospace formatting in the update text, since it is not
-	supported by the GNOME PK markup parser
-
-2013-07-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Override core.Transaction._simulate_real to skip transactions with
-	a simulate flag to be simuated before running
-
-2013-07-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Only emit and set exit status of a simulated transaction if it
-	hasn't failed yet
-
-2013-07-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Merge simulate-in-worker-branch
-
-2013-07-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix a log message
-
-2013-07-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	Adapt _process_transaction
-
-2013-07-03  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge from trunk
-
-2013-07-03  Sebastian Heinlein  <devel@glatzor.de>
-
-	Override the check auth method to not require an authentication for simulations
-
-2013-07-02  Sebastian Heinlein  <devel@glatzor.de>
-
-	We don't need to let the transaction method call fail if the transaction failed
-
-2013-07-02  Sebastian Heinlein  <devel@glatzor.de>
-
-	Call the _run method of the MergedTransaction
-
-2013-07-02  Sebastian Heinlein  <devel@glatzor.de>
-
-	Move the simulate code into the PackageKitWorker
-
-2013-07-03  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Raise log level of D-Bus method calls to INFO
-	
-	Convert the D-Bus values to better strings (flags, and arrays)
-
-2013-07-02  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: don't use the debugger statement exit as a variable name
-
-2013-07-02  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Fix run call in UpdatePackages
-
-2013-06-30  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Add support for InstallFiles
-
-2013-06-30  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Fix type of emitted changed NetworkState value
-
-2013-06-30  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2013-06-30  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update NEWS
-
-2013-06-30  Sebastian Heinlein  <devel@glatzor.de>
-
-	Use a colored log output on the console
-
-2013-06-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: TransactionListChanged() signal still uses type as for the id list
-
-2013-06-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	packagekit: Also ignore packages with RUNNING_TRIGGER state
-
-2013-06-28  Sebastian Heinlein  <devel@glatzor.de>
-
-	Use pk.AuthorizeEnum instead of a hardoced string
-
-2013-06-28  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add a fake GetDaemonState() method to the PK interface
-
-2013-06-28  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix the Packagekit TransactionList type (changed from as to ao)
-
-2013-06-28  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix a small typoe = => == in the previous commit
-
-2013-06-28  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix setting the exit value of the PK transaction
-
-2013-06-28  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge the pkgpgcache branch.
-	
-	Report the correct PackageKit id for download/install progress including
-	the version, arch and origin
-
-2013-06-28  Sebastian Heinlein  <devel@glatzor.de>
-
-	Cache the PackageKit package ids of to be changed packages to emit the
-	correct id during download/install progress information
-
-2013-06-27  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update NEWS file
-
-2013-06-27  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge the PackageKit 0.8 branch
-
-2013-06-27  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge with trunk
-
-2013-06-26  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix typo in method name
-
-2013-06-26  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2013-06-26  Sebastian Heinlein  <devel@glatzor.de>
-
-	By default we report the network status as offline
-
-2013-06-25  Sebastian Heinlein  <devel@glatzor.de>
-
-	Start the deferred network state fetching after all default values have been specified
-
-2013-06-25  Sebastian Heinlein  <devel@glatzor.de>
-
-	IF there aren't any active connections report as being offline
-
-2013-06-25  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add cancel operations
-
-2013-06-25  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix group type in the Details signal
-
-2013-06-25  Sebastian Heinlein  <devel@glatzor.de>
-
-	The group map values should be the args for the sum method
-
-2013-06-25  Sebastian Heinlein  <devel@glatzor.de>
-
-	Set the version PK versionb correctly
-
-2013-06-25  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix a typo
-
-2013-06-24  Sebastian Heinlein  <devel@glatzor.de>
-
-	We don't support Ubuntu for the stable/testing/unstable state of update so remove it
-
-2013-06-24  Sebastian Heinlein  <devel@glatzor.de>
-
-	Take replaces into account for the UpdateDetails signal
-
-2013-06-24  Sebastian Heinlein  <devel@glatzor.de>
-
-	Allow to filter package versions and add a unit test
-
-2013-06-24  Sebastian Heinlein  <devel@glatzor.de>
-
-	Unify logging of signals and use the human readable strings for enums
-
-2013-06-24  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add mapping for STATUS_AUTHENTICATING and STATUS_QUERY
-
-2013-06-24  Sebastian Heinlein  <devel@glatzor.de>
-
-	Export STATUS_AUTHENTICATING
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update NEWS
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix what_provides
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update RequireRestart signal
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Use upgrade_system instead of the removed rollback method to test not implmented methods
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Port install packages test to 0.8
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Ignore the dpkg-exec pseudo Package during the installation
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix a File call
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update UpdateDetail signal
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update Transaction signal
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add a Message signal - nevertheless it is not used
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add the RepairSystem method
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add a non supported UpgradeSystem method
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Adapt File signal
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Remove UpdateSystem
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Remove Rollback transaction
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Use enums for InstallSignature
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Raise version number to 0.8.9
-
-2013-06-23  Sebastian Heinlein  <devel@glatzor.de>
-
-	Implement the simulate and only_trusted transaction flags
-	
-	The only_download is still missing. Furhtermore add some helpers to do
-	the bitfield operations correctly
-
-2013-06-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add support for DownloadSizeRemaining
-
-2013-06-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix Finished signature
-
-2013-06-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Set the status to UInt32 in the setter
-
-2013-06-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	adapt input types for dbus functions with filters
-
-2013-06-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Remove subpercentage
-
-2013-06-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix transaction properties role and status type
-
-2013-06-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	No need to split filters anymore
-
-2013-06-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix a filter bit removal
-
-2013-06-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Replace all pkenums references. Adapt filtering to bitfield operations
-
-2013-06-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Yeah! Port the PackageKit main D-Bus interface to 0.8.
-	
-	But the transaction interface is still missing.
-	Start migrating the enums to the Gir PackageKit library.
-
-2013-06-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Import Python PackageKit Enums from current master (0.8.9)
-
-2013-06-27  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add a test to check if installing from a CDrom works after failing
-
-2013-06-27  Sebastian Heinlein  <devel@glatzor.de>
-
-	Run the daemon always with debugging information in the test suite
-
-2013-06-27  Sebastian Heinlein  <devel@glatzor.de>
-
-	Export the STATUS_AUTHENTICATING enum
-
-2013-06-22  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix a copy and paste error which resultet in misleading download/elapsed time reports
-
-2013-06-06  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	data/lintian/ubuntu/aptdaemon.profile: Drop missing-pre-dependency-on-multiarch-support, it was dropped from saucy lintian
-
-2013-06-06  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	WorkerTestCase.test_install_file: Show actual error if we did not get the expected error
-
-2013-05-04  Sebastian Heinlein  <devel@glatzor.de>
-
-	Don't call the deprecated GObject.threads_init() method
-
-2013-05-04  Sebastian Heinlein  <devel@glatzor.de>
-
-	Push local changes
-
-2013-05-04  Sebastian Heinlein  <devel@glatzor.de>
-
-	The aptdcon command should not throw an exception on Ctrl+C
-
-2013-04-02  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged https://code.launchpad.net/~cjwatson/aptdaemon/debconf-flush/
-
-2013-04-02  Colin Watson  <cjwatson@canonical.com>
-
-	Flush debconf-communicate stdin after writing to it.
-
-2013-03-18  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	Fix some PEP-8 issues, caught by test suite.
-
-2013-03-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge with stable branch
-
-2013-03-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix PiPY upload in release script
-
-2013-03-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Push local changes
-
-2013-03-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Apply Ubuntu patch to fix backwards compatibility for GLib.io_add_watch()
-
-2013-03-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Release version 1.0
-
-2013-03-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update NEWS
-
-2013-03-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update translations
-
-2013-03-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix typos/formatting of the man page - Thank to Anskar
-
-2013-03-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Push local changes in preparation for the 1.0 release
-
-2013-03-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update NEWS
-
-2013-03-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Set a reasonable minimum size for the expanded child widget in the GTK2 dialog
-	
-	GTK3 has got a quite good balancing mechanism
-
-2013-03-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Disable the expander in expandable GTK(2|3) dialogs if there isn't any child widget
-
-2013-03-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Remove the gtk(3)widgets.AptMessageDialog since we don't support messages
-	
-	Rebase the gtkwidgtes.AptErrorDialog directly on _ExpandableDialog
-
-2013-03-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix backwards compatibility with the non introspectable gobject library
-
-2013-03-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix Python Gtk2 backwards compatibility
-
-2013-03-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	Allow release names to include a dot
-
-2013-03-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	Really fix the PEP8 issue
-
-2013-03-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	Trivial PEP8 fix
-
-2013-03-05  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add a small helper to make releasing more convinient
-
-2013-03-03  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge pkerrors branch
-
-2013-03-03  Sebastian Heinlein  <devel@glatzor.de>
-
-	Convert an authorization exception to the corresponding PackageKit one
-	
-	Otherwise the PK client will segfault if the auth fails since it cannot
-	parse the DBus error name
-
-2013-03-03  Sebastian Heinlein  <devel@glatzor.de>
-
-	Replace a depricated Glib.unix_signal_add_full() call
-
-2013-03-03  Sebastian Heinlein  <devel@glatzor.de>
-
-	Store the default values of PackageKit transaction properties with the correct DBus type
-
-2013-03-03  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix a missing PackageKit transaction property assignment
-	
-	Instead of Speed the property AllowCancel was set.
-
-2013-03-01  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged https://code.launchpad.net/~barry/aptdaemon/lp1120322/
-
-2013-03-01  Barry Warsaw  <barry@python.org>
-
-	Restore Python 2 compatibility in the tests.  Document that the tests still
-	need to be Python 2 compatible.
-
-2013-02-28  Barry Warsaw  <barry@python.org>
-
-	After better analysis by lifeless, fix LP: #1120322 in a complementary way:
-	
-	- Improve the REGEX_RANGE to allow for optional ,### parts, so that one line
-	diffs will properly match.
-	
-	- Move the constant to the module globals for better wrapping (and because
-	being a class instance isn't necessary).
-	
-	- Still initialize line_number to 0 because it can't hurt.
-	
-	- Be explicit about closing the file objects instead of hoping that gc does
-	its job.  This eliminates warnings in the test suite.
-	
-	- Add a test for both one line and multiline diffs, showing that LP: #1120322
-	is actually fixed, and doesn't regress.
-
-2013-02-28  Barry Warsaw  <barry@python.org>
-
-	Set it to 0 as per:
-	
-	https://bugs.launchpad.net/ubuntu/+source/aptdaemon/+bug/1120322/comments/7
-
-2013-02-28  Barry Warsaw  <barry@python.org>
-
-	Define line_number first outside the loop to prevent UnboundLocalError in
-	show_diff().  LP: #1120322
-	
-	The odd part is that I'm not sure how to get difflib to produce a diff that
-	doesn't start with the three lines:
-	
-	--- blah
-	+++ blah
-	@@ blah
-	
-	to trigger the bug.  This is clearly unexpected in the code (hence the
-	UnboundLocalError in the first place) and it it definitely not covered in the
-	test suite.  Hand crafting a call such as this does not trigger the bug:
-	
-	$ PYTHONPATH=. python3
-	>>> from aptdaemon.gtk3widgets import DiffView
-	>>> dv = DiffView()
-	>>> dv.show_diff('/etc/passwd', '/etc/group')
-
-2013-02-02  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix a grammer issue. Thanks Steve!
-
-2013-02-02  Steve Langasek  <steve.langasek@canonical.com>
-
-	Fix wrong grammar
-
-2012-12-31  Sebastian Heinlein  <devel@glatzor.de>
-
-	Adap to latest Python GLib changes (io_add_watch, child_watch_add)
-
-2012-12-30  Sebastian Heinlein  <devel@glatzor.de>
-
-	Unset an http_proxy in the test suite
-
-2012-12-30  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes and test for the test suite
-
-2012-12-30  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes for the test suite
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge PEP8 fixes and add test for PEP8 compliance
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	Some small pyflakes fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix lambda
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	Rename transaction_only_installs_packages_from_high_trusted_repos to a shorter name
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	Do not test the automatically generated PackageKit enums module
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	More PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes 
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add a PEP8 test case
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	More PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-29  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-12-16  Sebastian Heinlein  <devel@glatzor.de>
-
-	Don't fail if we want to remove a a package without a candidate during
-	transaction simulation.
-
-2012-12-16  Sebastian Heinlein  <devel@glatzor.de>
-
-	If the user cannot be autohrized (either missing privileges or a cancelled
-	password dialog) the transaction will fail.
-	
-	Therefor two new error enums have been introduced ERROR_AUTH_FAILED which
-	catches a cancelled password dialog or missing policykit agent and
-	ERROR_NOT_AUTHORIZED which catches missing privileges.
-	
-	This allows Unity to be notified about a cancelled installation.
-
-2012-12-16  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix a silly typo in a previous commit (= -> ==)
-
-2012-12-16  Sebastian Heinlein  <devel@glatzor.de>
-
-	Don't depend on dpkg-dev to select the correct lintian profile.
-	(Fixes LP: #1066457) - merged from Ubuntu
-
-2012-12-16  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add a regression test for LP: #750958
-
-2012-12-16  Sebastian Heinlein  <devel@glatzor.de>
-
-	Don't change the automatic installed state when upgrading packages.
-	
-	Thanks a lot to Daniel Hartwig for analyzing this issue and also providing
-	a set of patches (Fixes LP: #1078544)
-
-2012-11-30  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp:~mvo/aptdaemon/fix-lp1060505
-
-2012-11-29  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	data/lintian/ubuntu/aptdaemon.profile: the tag "file-in-etc-not-marked-as-conffile" is not critical
-
-2012-11-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged  lp:~mvo/aptdaemon/multiline-comments-fix 
-
-2012-11-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	support multi line comments in the configuration
-
-2012-11-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp:~mvo/aptdaemon/use-glib-unix-signal-handling
-
-2012-11-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: use GLib.unix_signal_add_full() to fix hang with latest python-gi. Its also conceptually cleaner
-
-2012-11-26  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tests/test_client.py: use the fake bus instead of the real one in test_tid_caching and fix kwargs parsing
-
-2012-11-26  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	Force debconf priority to high for test_debconf
-	
-	This allows the test to work even if the system debconf priority is set to
-	critical.
-	
-	Thanks Colin Watson <cjwatson@ubuntu.com>!
-
-2012-11-26  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	Fix deprecated GObject.* API
-	
-	Call GLib API through GLib.*, not GObject.*. The latter has been deprecated for
-	some time and causes PyGIDeprecationWarnings with PyGObject >= 3.7.2.
-	
-	This gets rid of 247 of the 311 deprecation warnings during the tests. The
-	remaining ones will need bumping the minimum pygobject version, and will be
-	fixed later.
-
-2012-11-26  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	Drop MemoizedTransaction mixin.
-	
-	This uses internal implementation details of PyGObject (GObject.GObjectMeta)
-	which stopped working with PyGObject 3.7.2. Replace it with overriding __new__
-	which does the caching.
-	
-	Extend ClientTest.test_tid_caching to ensure that different TIDs actually
-	generate different transactions.
-
-2012-11-26  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	Drop MemoizedTransaction mixin.
-	
-	This uses internal implementation details of PyGObject (GObject.GObjectMeta)
-	which stopped working with PyGObject 3.7.2. Replace it with overriding __new__
-	which does the caching.
-
-2012-11-26  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tests/test_pk.py: *cough* typo *cough*
-
-2012-11-26  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	setup.py: add workaround for nose failure
-
-2012-11-26  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tests/test_pk.py: fix long keyid test
-
-2012-11-26  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	Add test for TID caching
-	
-	aptdaemon.client has some metaclass magic to cache transactions with the same
-	transaction ID. Add a test case that this works properly.
-	
-	Suggested by Michael Vogt and spotted in
-	https://code.launchpad.net/~pitti/aptdaemon/pygobject-fixes/+merge/134942
-
-2012-10-08  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tests/test_py2_string_handling.py: fix import during python setup.py test
-
-2012-10-08  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp:~mvo/aptdaemon/lp846044 to fix LP: #846044
-
-2012-10-08  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	ensure we provide a unicode version of the error TransactionFailed and also return utf8 encoded string
-
-2012-10-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	PEP8 fixes
-
-2012-10-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix a typo
-
-2012-09-27  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	Open Apport crash report files in binary mode
-
-2012-09-26  Steve Langasek  <steve.langasek@canonical.com>
-
-	Open our crash report for writing in binary mode
-	
-	Recent versions of apport are more finicky about ensuring the crash report
-	handle supports writing binary output, so explicitly open the file in
-	binary mode.
-
-2012-09-13  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tests/test_high_trust_repository_whitelist.py: tiny robustness fixes
-
-2012-09-13  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tests/data/high-trust-repository-whitelist-broken.cfg, tests/test_high_trust_repository_whitelist.py: fix test to work with python2
-
-2012-09-13  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged  lp:~vorlon/aptdaemon/lp.1034806 
-
-2012-08-10  Steve Langasek  <steve.langasek@canonical.com>
-
-	Fix the string type handling of gettext functions.
-
-2012-09-13  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp:~mvo/aptdaemon/support-for-whitelisted-repositories
-
-2012-09-03  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	some more renames
-
-2012-09-03  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	data/org.debian.apt.policy.in: fix name to match org.debian.apt.install-packages.high-trust-repo
-
-2012-08-31  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	more renaming
-
-2012-08-31  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	trans.whitelisted_packages, -> trans.high_trust_packages
-
-2012-08-31  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	-PK_ACTION_INSTALL_PACKAGES_FROM_HIGH_TRUST_WHITELISTED_REPO -> +PK_ACTION_INSTALL_PACKAGES_FROM_HIGH_TRUST_REPO
-
-2012-08-31  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	rename AptWorker._whitelisted_repositories to _high_trust_repositories
-
-2012-08-31  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	read the high-trust repository whitelist from /etc/aptdaemon/high-trust-repository-whitelist.d by default and make it a .d directory to ensure packages like e.g. webapps can drop there whitelist in
-
-2012-08-31  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	rename /etc/aptdaemon/repository-whitelist.cfg to /etc/aptdaemon/high-trust-repository-whitelist.cfg
-
-2012-08-31  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	rename PK_ACTION_INSTALL_PACKAGES_FROM_WHITELISTED_REPO to PK_ACTION_INSTALL_PACKAGES_FROM_HIGH_TRUST_WHITELISTED_REPO
-
-2012-08-31  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	rename self._whitelisted_packages to self._high_trust_whitelisted_packages 
-
-2012-08-31  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	rename transaction_only_installs_packages_from_whitelisted_repos to transaction_only_installs_packages_from_high_trust_repos
-
-2012-08-31  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	rename read_repository_whitelist to read_high_trust_repository_whitelist
-
-2012-08-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	documation updates and ensure that the is install-from-whitelist only applies to install
-
-2012-08-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/test.py: make the debug in start_session_aptd option to have less noise
-
-2012-08-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	test that non-whitelisted package fails to install with aptdaemon.policykit1.PK_ACTION_INSTALL_PACKAGES_FROM_WHITELISTED_REPO
-
-2012-08-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	test that the right polkit action is used for whitelisted packages
-
-2012-08-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	move the whitelsit releated tests into a single file
-
-2012-08-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	small cleanup/comment updates
-
-2012-08-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	make config parser more robust against errors in the config file and add tests
-
-2012-08-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: more paranoia
-
-2012-08-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	never allow unauthenticated and log whitelist in use
-
-2012-08-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add support for /etc/aptdaemon/repository-whitelist.cfg to allow whitelisting specific repors for (potentially) passwordless installs
-
-2012-08-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	move transaction_only_installs_packages_from_whitelisted_repos back into worker
-
-2012-08-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: honor enums.ROLE_INSTALL_PACKAGES and enums.ROLE_COMMIT_PACKAGES when checking for the whitelist priv
-
-2012-08-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/policykit1.py: fix missing PK_ACTION_INSTALL_PACKAGES_FROM_WHITELISTED_REPO in __all__
-
-2012-08-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	data/org.debian.apt.policy.in: add new policykit priv org.debian.apt.install-packages-from-whitelisted-repo
-
-2012-08-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	improve tests and add another a repo for the whitelist tests
-
-2012-08-23  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	initial stab on the whitelisted repository support
-
-2012-09-12  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tests/test_worker.py: fix test on buildd when LANG/LANGUAGE is unset
-
-2012-09-07  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp:~mvo/aptdaemon/support-change-credentials-on-add-repo
-
-2012-09-07  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: use close() instead of flush(), thanks to Martin Pitt
-
-2012-09-05  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	use some special chars
-
-2012-09-05  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	address the first two review points from Martin (many thanks!) by using open(.., "rb") and read().decode("utf-8")
-
-2012-09-04  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tests/test_worker.py: rename test function to ensure it reflect better what its actually testing
-
-2012-09-04  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add code to ensure that if the regexp for replacing existing auth.conf entries does not work we just prepend as a fallback
-
-2012-09-03  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add comment
-
-2012-09-03  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: surround machine/login with \n
-
-2012-09-03  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	use tempfile.NamedTemporaryFile() instead of hardcoding a .tmp
-
-2012-09-03  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	preserve order/comments in auth.conf when updating a existing record
-
-2012-06-26  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	instead of simply appending to auth.conf allow updating credentials too
-
-2012-09-06  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	Fix crash in widget's diff view if a @@ line does not have a range
-
-2012-09-05  Brian Murray  <brian@canonical.com>
-
-	continue if there is no match in show diff
-
-2012-09-05  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp:~mvo/aptdaemon/lp1044900 to fix LP: #1044900 after review from Martin Pitt
-
-2012-09-05  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/policykit1.py: rework to be both py2 and py3 compatible, thanks to Martin Pitt
-
-2012-09-03  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/policykit1.pya: open /proc/%(pid)s/cmdline with utf8 encoding by default to avoid crash for cmdlines that contain a special char (LP: #1044900)
-
-2012-08-23  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	pkcompat: Fix get_files()
-	
-	Do not open the .list file in text mode and then call decode() on it, as that
-	will try to decode a string.
-	
-	Also narrow down the bare "except:" (which hid this bug) to only intercepting
-	IOErrors.
-	
-	Add test case.
-
-2012-08-10  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tests/test_worker.py: comment out spurious "import pdb"
-
-2012-08-10  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp:~evfool/aptdaemon/lp1030988 to fix #1030988
-
-2012-08-01  Robert Roth  <robert.roth.off@gmail.com>
-
-	Change the error message for installation required from unauthenticated sources (LP: #1030988)
-
-2012-08-10  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp:~dobey/aptdaemon/fix-imports, many thanks
-
-2012-08-09  Rodney Dawes  <rodney.dawes@canonical.com>
-
-	Check that the item in sys.modules is not None before trying to import it
-
-2012-08-02  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	fix "compatibilty" typo
-
-2012-07-12  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	aptdaemon/client.py: Prefer GI GObject module
-	
-	If 'gobject' is not available (such as in Python 3), but this module gets
-	imported before importing any gi.repository module, aptdaemon crashes with
-	
-	Traceback (most recent call last):
-	File "./software-properties-gtk", line 37, in <module>
-	from softwareproperties.gtk.SoftwarePropertiesGtk import SoftwarePropertiesGtk
-	File "/home/martin/ubuntu/software-properties-additional-drivers/softwareproperties/gtk/SoftwarePropertiesGtk.py", line 34, in <module>
-	from aptdaemon import client
-	File "/usr/lib/python3/dist-packages/aptdaemon/client.py", line 43, in <module>
-	import gobject as GObject
-	ImportError: No module named gobject
-	
-	Fix this by swapping the order around and only using gobject if it is already imported.
-
-2012-06-17  Sebastian Heinlein  <devel@glatzor.de>
-
-	lintian supports skipping user profiles since 2.5.9
-	
-	If $HOME is unset custom profiles of the user will be skipped. Make use of this.
-	Unfortunately we need  a complete LINTIAN_ROOT for the test case - so we have to copy it around.
-
-2012-06-14  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: Give the fake-polkitd more time to get known to DBus. Thanks Steve.
-	
-	Would be nice to switch this to dbus activation in the future
-
-2012-06-14  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: run the fake-polkitd also with Python 3. Thanks pitti for spotting
-
-2012-06-13  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge fixes from Steve! Thanks
-
-2012-06-13  Steve Langasek  <steve.langasek@canonical.com>
-
-	restore compatibility with python2, which doesn't have urllib.parse.
-
-2012-06-13  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix PK tests
-
-2012-06-13  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: Set the language of the pk.Client to C if we parse error messages
-
-2012-06-13  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: remove obsoleted setting of apt_pkg.config["Dir"]. Thanks to vorlon for fixing this issue generally
-
-2012-06-13  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: Re-use setUp() and tearDown() if the module is executed
-
-2012-06-13  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: Use an atexit handler to kill the PK dbus daemon
-	
-	The pk.Client uses a DBus connection with exit-on-disconnect set to
-	True which cannot be modified. Furthermore the registered signal
-	handlers cannot be removed. Since GIO would kill the test suite if
-	the daemon disappears we have to delay killing the daemon
-
-2012-06-13  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: Set apt_pkg.config["Dir"] to the chroot
-	
-	This is required by the key handling of apt.auth to use the chroot. In the
-	other tests it gets set by apt.Cache()
-
-2012-06-12  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp:~aptdaemon-developers/aptdaemon/lintian-profiles
-
-2012-06-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update NEWS
-
-2012-06-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge with trunk
-
-2012-06-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Push local changes
-
-2012-06-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Adopt the lintian test case
-
-2012-06-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Allow to overwrite the location of the lintian HOME by using the APTDAEMON_LINTIAN_HOME env var.
-
-2012-06-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Set $HOME to a temporary dir before executing lintian
-	
-	Setting LINTIAN_INTERNAL_TESTSUITE doesn't load any custom profiles
-	from /etc and would not allow admins to modify the installed policy easily
-
-2012-06-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Move the lintian handling to a new DaemonLintianProgress and add some enhancements
-	
-	This makes the lintian call unblocking by using existing infrastructure
-
-2012-06-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Convert the lintian tag files into lintian profiles. Thanks to Niels Thykier
-
-2012-06-12  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix package status enum description for an unknown status which resulted
-	in a type mismatch in the gettext call (fixes LP: #900982)
-
-2012-06-12  Sebastian Heinlein  <devel@glatzor.de>
-
-	Still report available blocked updates if the dependency system ist broken
-	(final partial fix to LP# 932581)
-
-2012-06-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update NEWS
-
-2012-06-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update NEWS from the 0.4x branch
-
-2012-06-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Support InstallSignature transaction of PackageKit. Thanks a lot Pitti!
-
-2012-06-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Use the fake keyserver of aptdaemon.test and apt.auth in the test
-
-2012-06-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add the fake keyserver to aptdaemon.test. Thanks a lot Pitti!
-
-2012-06-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add some basic sanity checks to parameters of the key handling
-
-2012-06-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fallback to hkp://keys.gnupg.net on non-Ubuntu systems as keyserver
-
-2012-06-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge with trunk
-
-2012-05-31  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	pkcompat: Implement InstallSignature
-
-2012-05-31  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	worker.py: Get along with apt-key returning non-zero on success
-	
-	With current apt, apt-key exits with code 2 even on success. In that case,
-	check the output and only raise an error if the total number of processed keys
-	is 0. Also change the decoding to work with Python 2.
-
-2012-06-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	Trun DaemonForkProgress into a context manager to avoid manual start_update() and finish_update() calls.
-
-2012-06-07  Sebastian Heinlein  <devel@glatzor.de>
-
-	Refactoring: Replace the DaemonAptAuthProgress class by a more generic DaemonForkProgress and inherant the DaemonInstallProgress from it.
-
-2012-06-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	Port aptdaemon to new apt.auth interfaces. This removes the dependency on
-	python3-software-properties
-	
-	A new DaemonAptAuthProgress class was introduced to fork and not block the
-	main daemon. The GetVendorKeys call needs some re-design.
-
-2012-06-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	Use apt.auth for test chroots
-
-2012-06-05  Sebastian Heinlein  <devel@glatzor.de>
-
-	client: Use INT64 in signals where required (Fixes LP: #981124)
-
-2012-06-04  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix another pkenums import
-
-2012-06-04  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix PK what provides test by using the shipped pkenums instead of packagekit.enums
-
-2012-06-04  Sebastian Heinlein  <devel@glatzor.de>
-
-	Don't test the worker with a DBus daemon. This isn't required sice we don't
-	check the client side.
-
-2012-06-04  Sebastian Heinlein  <devel@glatzor.de>
-
-	The client allows to be used with the old gobject and the introspection
-	based one. We have to make sure that the old one isn't imported
-	by the client
-
-2012-06-04  Sebastian Heinlein  <devel@glatzor.de>
-
-	Only ship the documentation for the gtk3 widgets
-
-2012-06-02  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: Clear the apt_pkg.config for each test case
-
-2012-05-31  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	aptdaemon/pkcompat.py: Add error message to _fail_not_implemented(), as the GLib.GError does not have the status code
-
-2012-05-31  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	pkcompat: Implement RepoEnable for adding a repository
-
-2012-05-31  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	tests/test_pk.py: Drop duplicated add_test_repository() calls, already done in setUp()
-
-2012-05-31  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	README.PackageKit: update WhatProvides() support status
-
-2012-05-26  Sebastian Heinlein  <devel@glatzor.de>
-
-	Import latest translations from upstream
-
-2012-05-23  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	aptdaemon/test.py: Create /etc/apt/preferences.d/ in the chroot, to stop a warning from apt
-
-2012-05-21  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	aptdaemon/test.py: Do not destroy environment when running with local D-BUS
-
-2012-05-16  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge fix from python2 branch
-
-2012-05-16  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix: Use the error string to represent a TransactionFailed error
-
-2012-05-15  Sebastian Heinlein  <devel@glatzor.de>
-
-	Push local changes
-
-2012-05-13  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: re-enable the Python2 string/unicode handling test again by using a loader module
-
-2012-05-13  Sebastian Heinlein  <devel@glatzor.de>
-
-	tests: Use a local copy:// repo instead of one hosted on a private server
-
-2012-05-13  Sebastian Heinlein  <devel@glatzor.de>
-
-	tests: Skip the debconf serialisation test under Python2 and nose.
-	
-	The test itself gets completed successfully, but results in a failing test later (test_simulation). No idea why.
-
-2012-05-13  Sebastian Heinlein  <devel@glatzor.de>
-
-	pkcompat: Fix relative imports
-
-2012-05-12  Sebastian Heinlein  <devel@glatzor.de>
-
-	Only run the client tests with python2
-
-2012-05-12  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: Always run the session aptdaemon with python3 since we also want to test Python2 clients
-
-2012-05-12  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge Python3 support
-
-2012-05-12  Sebastian Heinlein  <devel@glatzor.de>
-
-	Kill the dbus daemon in the pk test in a more friendly way and wait until it is gone
-
-2012-05-12  Sebastian Heinlein  <devel@glatzor.de>
-
-	gtk3widgets: Fix download progress
-	
-	10 / 3 isn't the same in pyhton2 and 3
-
-2012-05-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge fix from trunk
-
-2012-05-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Skip the worker tests for Python2
-
-2012-05-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Use system python interpretaros by default
-
-2012-05-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix pkenums import
-
-2012-05-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge with trunk
-
-2012-05-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Ship the PackageKit enums to get rid of the python-packagekit dependency
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Skip the update cache test if we are running nose. Needs some further investigation
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update README.tests
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: Use apt-key instead of direct gpg commands to add keys to test chroots
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Use with in some test cases to avoid not closed fds
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Allow to run the PK tests in nose by providing the same system dbus for the whole test suite
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Allow to start a dbus server outside of the TestCase
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Remove missed debugging breakpoint
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Skip the dbus type tests
-	
-	We need to use a type full client in the test, e.g. the gio based one
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Make the unsecure license key test compatible with python3
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Don't use 2to since the code is usable by python2 and 3
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	The unicode decoding test isn't required any more with python3 (yeah!)
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix debconf test
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix: Write config file prompt answers as bytes
-
-2012-05-10  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix not creating bytes for the error messages in Python3
-
-2012-05-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: actually use the same python version for the to be tested aptdaemon as the test is running in
-
-2012-05-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Add tests if dependency resolution errors get catched
-
-2012-05-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	gtk3-demo: Don't inspect exceptions by raising them.
-	
-	In python3 the exception will be deleted after.
-
-2012-05-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Run all scripts with Python3 by default
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	lock: close the fd finally
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix a non-closed file descriptor in the worker test
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update number of to be found packages in the cache loading test
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	use an octal number for chmod in the worker test
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Regenerate local repository package and Release
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	worker: fix handling strings in the deb file installation
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	utils: Port to latest ElementTree API
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Error: make sure to handle str/unicode/bytes correctly
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Convert debconf to py2/3
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Convert collected output in the pk test
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Use imp.reload() in the lock location test to by Python3 ready
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Port index test to Python3 
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Don't use any UTF8Strings in the dbus type test
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: Support python 2 and 3
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	client: Don't use dict.iteritems() anymore
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	console: Handle input differently for Python2 and 3
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	client: Make meta classes work with Python2 and 3 at the same time
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	client: Remove obsolete utf8_string in DBus call
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	console: Remove obsolete decode() statments
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	errors: the dbus.DBusException.message attrib is now gone for real
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Remove obsoleted decodes() from the worker
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Adapt to os.read() API changes
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Adapt to uuid API changes
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	core: remove some obsolete decodes
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Conversion to python by using 2to3. The client module is skipped currently
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Merge with trunk
-
-2012-05-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	pkcompat: Fix a changed NetworkState property
-
-2012-05-11  Sebastian Heinlein  <devel@glatzor.de>
-
-	Update the version number of the provided PackageKit Interface
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Simplify the distro detection.
-	
-	Use platform.dist() and apt_pkg.architectures() instead of a dpkg call and
-	the lsb_release tool.
-	
-	Thanks to mvo for the nice hint!
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	networking: Fix sanity of network monitors (fixes LP: 971748)
-	
-	The get_network_state() method should always update the cached state and
-	return it.
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix calling the networking.ProcNetworkMonitor.get_network_state() inline callback (Fixes LP: #971748)
-
-2012-05-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	pkcompat: Only report GetDistroUpgrade as supported if update-manager-core is available
-
-2012-04-13  Sebastian Heinlein  <devel@glatzor.de>
-
-	pkcompat: Catch unresolvable depedencies in GetUpdates (fixes LP: #932581)
-
-2012-04-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix: Raise NotImplementedError instead of NotImplemented if the pkcompat layer hasn't been loaded (the exception should only be raised theoretically)
-
-2012-04-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix: Allow to cancel a transaction which hasn't been queued yet and is still in limbo
-
-2012-04-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix cancelling: Raise StopIeration instead of using return in an inline callback
-
-2012-04-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	core: Keep a finished transaction longer on the DBus to give the clients enough time to call Sync() again
-
-2012-04-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	client: API change, rename Transaction.disconnect() to Transaction._disconnect_from_dbus() to not overwrite the GOBject.disconnect() method
-
-2012-04-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	client: Sync all properties of a transaction before calling its Finished signal (Fixes LP#747172)
-	
-	There isn't any gurantee in which order signals get received by a DBus client.
-	This could result in PropertyChanged signals being received after the
-	Finished signal, e.g. the transaction could be marked as failed but the
-	error property hasn't yet been set.
-
-2012-04-09  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix a variable name in the license key failed error message
-
-2012-04-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	progress: Fix a wrong variable name (country -> region) (fixes LP #976521)
-	Thanks Douglas.
-
-2012-04-08  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix: Convert exceptions to a string before sending to TransactionFailed() as details
-	
-	TransactionFailed.__init__ requires a string, so call str(execp) before.
-
-2012-04-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix: Catch a possible exception in apt.cache.Cache.required_download (Fixes LP# 659438)
-	
-	Under some strange circumstances APT fails processing the cache if the system was
-	rebooted during a debconf question. The issue shows when accessing
-	apt.cache.Cache.required_download. So we report an error here as a broken cache.
-	The situation can be recoverd by calling FixIncompleteInstall or running
-	sudo dpkg --configure -a
-
-2012-04-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fallback to the defatul terminal width of 80 chars if the width cannot be retrieved (fixes LP#948588)
-
-2012-04-05  Sebastian Heinlein  <devel@glatzor.de>
-
-	Don't show the name of aptdaemon in crash reports (fixes LP#973370)
-	
-	Remove the .desktop file which contained a short description of aptdaemon.
-	Aptdaemon is a system daemon and so has to work and fail silently in the
-	background - without having the user to bother about obscure parts of the
-	operating system in detail.
-
-2012-04-04  Sebastian Heinlein  <devel@glatzor.de>
-
-	progress: Catch a possible pipe reading error (fixes LP #733090)
-
-2012-04-04  Sebastian Heinlein  <devel@glatzor.de>
-
-	test: Add a test case for the config file prompting
-
-2012-04-02  Sebastian Heinlein  <devel@glatzor.de>
-
-	Fix wrong variable naming in the download progress (fixes LP #971839)
-
-2012-04-02  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	do not use __simulate but instead _simulate_real as __ has a special meaning in python and its not available outside of the class scope
-
-2012-04-02  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged patch for #959131
-
-2012-04-02  Sebastian Heinlein  <devel@glatzor.de>
-
-	pkcompat: Don't crash if the system time went backwards during a transaction (Fixes LP# 940367)
-
-2012-04-02  Sebastian Heinlein  <devel@glatzor.de>
-
-	worker: catch SystemErrors from python-apt when performing a system upgrade (fixes LP#932581)
-
-2012-04-01  Sebastian Heinlein  <devel@glatzor.de>
-
-	Push local bug fixes
-
-2012-04-01  sebi@glatzor.de
-
-	pkcompat: Don't crash if an unsupported locale is used for the transaction, fixes LP #944553
-
-2012-04-01  sebi@glatzor.de
-
-	Fix download progress information for translations of languages with an ISO 639 2T code (3 letters), e.g. Asturian (ast) - fixes LP #966111
-	
-	Use the ISO 639 2T code as a fallback for the ISO 639 1 code during lookup. If the locale cannot be converted to a human readable name show the code instead of failling.
-
-2012-03-19  sebi@glatzor.de
-
-	test: Add a test to ensure that every transaction is simulated before it gets
-	queued.
-
-2012-03-14  sebi@glatzor.de
-
-	tests: Fix use of chroot in the dbus test
-
-2012-03-14  sebi@glatzor.de
-
-	Push local changes
-
-2012-03-14  sebi@glatzor.de
-
-	lock: Fix an exception if the lock file doesn't exists (fixes LP:#954581)
-
-2012-03-14  sebi@glatzor.de
-
-	Decrease the priority of the daemon to avoid blocking the user interface (fixes LP:#942437)
-
-2012-03-13  sebi@glatzor.de
-
-	Push local bug fixe changes
-
-2012-03-13  sebi@glatzor.de
-
-	Make the network detection code more robust (Fixes LP:#933597)
-	
-	If we fail to detect the network or get an error from network-manager report
-	the networking state as unknown.
-
-2012-03-13  sebi@glatzor.de
-
-	pkcompat: Make use of the PropertiesChanged signal, since it is required by the 0.7.x clients after the switch to GDbus
-
-2012-03-13  sebi@glatzor.de
-
-	core: Add support for the "new" standardizised PropertiesChanged signal (which
-	was introduced in 2010 to the Dbus Specification)
-
-2012-03-13  sebi@glatzor.de
-
-	pkcompat: Fix RestartRequired detection if a non PK-transaction is processed by the PKWorker
-
-2012-03-13  sebi@glatzor.de
-
-	pkcompat: Fail correctly if update-manager-core isn't installed
-
-2012-03-13  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	Add missing file to POTFILES.in. (LP: #953938)
-
-2012-03-13  Gabor Kelemen  <kelemeng@ubuntu.com>
-
-	Add missing file to POTFILES.in. LP: #953938
-
-2012-03-11  sebi@glatzor.de
-
-	Merge local changes
-
-2012-03-11  sebi@glatzor.de
-
-	gtk3: Fix resizing of dialog because of a long status label
-	
-	GTK3 requires to set gtk_label_set_max_width to define a
-	minimum width
-
-2012-03-09  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/pkcompat.py: run _emit_require_restart() with the transaction as argument
-
-2012-03-09  sebi@glatzor.de
-
-	Push local changes
-
-2012-03-09  sebi@glatzor.de
-
-	Merge use-apt-auth-conf branch from mvo! Thanks a lot also to pitti for reviewing
-
-2012-03-09  sebi@glatzor.de
-
-	Clean up the test
-
-2012-03-09  sebi@glatzor.de
-
-	Merge latest updates from mvo
-
-2012-03-08  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	fix review comments from Martin Pitt: a) typo fix b) do not chmod/chown but instead set umask c) check for exceptions in splituri()
-
-2012-03-09  sebi@glatzor.de
-
-	Clean ups
-
-2012-03-06  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add a comment when credentials are moved
-
-2012-03-05  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	write the netrc as a multi-line output for easier readability, parsability with a rfc822 parser (even though the netrc parser in apt will use a simple strtok() approach)
-
-2012-03-05  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	REFACTOR: remove no longer needed chown/chmod code
-
-2012-03-05  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	GREEN: username/password data is written to /etc/apt/auth.conf
-
-2012-03-05  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	RED: add failing test for auth.conf writing
-
-2012-03-08  sebi@glatzor.de
-
-	Push local changes
-
-2012-03-08  sebi@glatzor.de
-
-	pkcompat: Support the RequireRestart signal
-	
-	The signal gets emitted if an upgrade gets installed (e.g. UpgradeSystem,
-	UpgradePackages) or if GetUpdates is called. The later one is an enhancement
-	to the reference packagekitd. There isn't any persistent restart required
-	notification in packagekitd/yum.
-
-2012-03-08  sebi@glatzor.de
-
-	pkcompat: Add a test to detect required system upgrades
-
-2012-03-08  sebi@glatzor.de
-
-	core: Move the reboot-required stamp check to the worker
-
-2012-03-08  sebi@glatzor.de
-
-	pkcompat: Add the RestartRequired signal to the transaction interface
-
-2012-03-06  sebi@glatzor.de
-
-	worker: Allow to install an alternative version (by number or by origin) of
-	an already installed package
-
-2012-03-06  sebi@glatzor.de
-
-	Simplify the version/origin comparision by using a single if statement
-
-2012-02-14  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: allow install if pkg_ver or pkg_rel is different
-
-2012-03-01  sebi@glatzor.de
-
-	pkcompat: improve UpdatesChanged signal emission
-	
-	If a new signal should be scheduled and there is already one scheduled the
-	former signal is re-scheduled with the timeout of the new one. Furthermore the
-	default timeout is raised to 60 seconds and the one for cache updates to 30
-	seconds. 
-	
-	This helps to avoid races with non-aptdaemon tools (e.g. dist-upgrade.py)
-
-2012-02-28  sebi@glatzor.de
-
-	pkcompat: Add a note about the time outs of PK clients prior 0.7.3 (not yet released)
-
-2012-02-28  sebi@glatzor.de
-
-	pkcompat: Completely adapt to the python-apt 0.8 API
-
-2012-02-17  sebi@glatzor.de
-
-	pkcompat: Don't throw an error if we try to cancel a native pk transaction
-
-2012-02-17  sebi@glatzor.de
-
-	Replace some obsolete APT api calls (apt.package.Package.isInstalled)
-
-2012-02-02  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	Add plugin support to PackageKit compat layer
-	
-	Support plugins for PackageKit's apt backend, to easily extend the
-	functionality of "what-provides".
-	
-	This is a pretty straightforward port of the corresponding commit in
-	PackageKit:
-	https://gitorious.org/packagekit/packagekit/commit/b516f18e2
-
-2012-02-01  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	test_pk.py: Properly clean up local dbus-daemon
-	
-	Kill the locally spawned D-BUS daemon even if a test fails.
-
-2012-02-01  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	tests: Add tagged gstreamer package
-	
-	Update gstreamer0.10-silly_0.1-0_all.deb to have actual gstreamer tags, and add
-	it to "Packages".
-
-2012-01-31  sebi@glatzor.de
-
-	Use gobject introspection in the client test
-
-2012-01-27  sebi@glatzor.de
-
-	Remove a debug trace statement
-
-2012-01-24  sebi@glatzor.de
-
-	Apply print and import fixes of 2to3
-
-2012-01-23  sebi@glatzor.de
-
-	Don't fail if we cannot get the hostname of a download (in the case of local files)
-
-2012-01-23  sebi@glatzor.de
-
-	Fix bug in error creation by using a tuple for the string format arguments
-
-2012-01-23  sebi@glatzor.de
-
-	Disable system plugins in all unit tests
-
-2012-01-23  sebi@glatzor.de
-
-	Merge the gir branch which ports aptdaemon to gobject introspection
-
-2012-01-23  sebi@glatzor.de
-
-	Fix  a missing tempfile import in pkcompat
-
-2012-01-23  sebi@glatzor.de
-
-	Fix GioFileMonitor creation
-
-2012-01-23  sebi@glatzor.de
-
-	Merge with trunk
-
-2012-01-23  sebi@glatzor.de
-
-	Trigger the loading of the gi client in the cdrom test
-
-2012-01-23  sebi@glatzor.de
-
-	Fix Gio.File creation
-
-2012-01-23  sebi@glatzor.de
-
-	Convert the daemon to gobject introspection using the conversion tool
-
-2012-01-23  sebi@glatzor.de
-
-	Add an option to the daemon to disable the loading of plugins. Make use of this in the tests.
-
-2012-01-03  sebi@glatzor.de
-
-	This reverts r757 because 
-	a) DebFile.check() will do the same
-	b) apt_pkg.config.value_list("APT::Architectures") is empty even on a multiarch system (arguably a bug in apt)
-
-2012-01-03  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: revert check for architecture, because "DebFile.check()" will do that too plus apt_pkg.config.value_list("APT::Architectures") is empty even on a multiarch system
-
-2011-12-16  sebi@glatzor.de
-
-	Check if the architecture of a debian package is supported before installing
-
-2011-12-16  sebi@glatzor.de
-
-	Catch exceptions in apt.debfile.DebFile.check()
-
-2011-12-16  sebi@glatzor.de
-
-	Thankfully merging a fix from Chris!
-
-2011-12-16  Chris Coulson  <chris.coulson@canonical.com>
-
-	After simulating a transaction, correctly disconnect from the "transaction-simulated" signal
-
-2011-12-15  sebi@glatzor.de
-
-	Fix downgrade option of aptdcon
-
-2011-12-14  sebi@glatzor.de
-
-	Push local changes
-
-2011-12-14  sebi@glatzor.de
-
-	Always set the overall progress of the repository downloader to unknown
-
-2011-12-14  sebi@glatzor.de
-
-	Fix expanding the dialog to the previous size
-
-2011-12-14  sebi@glatzor.de
-
-	Ensure that the transaction cannot be simulated concurrently
-
-2011-12-14  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged typo fixes from lp:~evfool/aptdaemon/lp903911, many thanks
-
-2011-12-13  Robert Roth  <robert.roth.off@gmail.com>
-
-	Change from up-to-date to up to date for consistency (LP: #864336)
-
-2011-12-13  Robert Roth  <robert.roth.off@gmail.com>
-
-	Fix license typo (LP: #903911)
-
-2011-12-13  sebi@glatzor.de
-
-	Do not force v as type for values in MetaData
-
-2011-12-07  sebi@glatzor.de
-
-	Push local changes
-
-2011-12-06  sebi@glatzor.de
-
-	Update the PackageKit README
-
-2011-12-06  sebi@glatzor.de
-
-	Add a test case for detecting security updates and backports correctly.
-
-2011-12-05  sebi@glatzor.de
-
-	Add support for cancelling the transaction in PK
-
-2011-12-05  sebi@glatzor.de
-
-	Fix PK transaction status emitting (copy and paste error)
-
-2011-12-02  sebi@glatzor.de
-
-	Fix changelog cache clean up (typo os.rm -> os.remove)
-
-2011-12-02  sebi@glatzor.de
-
-	Don't break API and still accept sv as MetaData
-
-2011-12-02  sebi@glatzor.de
-
-	Accept only strings for the meta data key and value. Already convert the
-	dictionary on the client side. So we don't fail anymore if a client tries to set an empty dict, see LP: #898879
-
-2011-12-02  sebi@glatzor.de
-
-	Trivial typo fix
-
-2011-12-02  sebi@glatzor.de
-
-	Fix a patch merging error which resulted in the obsoleted dependency check crashing (Fixes LP: #898756)
-	
-	Also add a test suite for obsoleted dependency removing.
-
-2011-12-01  sebi@glatzor.de
-
-	Separate bewteen InRelase and Relase file in the download progress to avoid showing the same item twice
-
-2011-12-01  sebi@glatzor.de
-
-	Resizing for simple textbuffers works quite well so we don't need to add extra width and height. 
-
-2011-12-01  sebi@glatzor.de
-
-	Fix the sizing of details dialog (LP #892607)
-	
-	Rebase the error and message dialog on _ExpandableDialog. Fix storing the initial unexpanded size as expanded size. Furthermore resize the window by 100x150 pixels if there isn't any stored expanded size. Wrap the details message by words.
-
-2011-12-01  sebi@glatzor.de
-
-	Fix resizing the GTK3 progress dialog (LP# 840942)
-	
-	Unfortunately the expander only resize to a good size for its children if
-	they are show on the first rendering of the window. Afterwards we have to
-	deal with the resizes on our own. This resulted in a 2 line terminal widget.
-
-2011-11-28  sebi@glatzor.de
-
-	test.py: Remove unused import and export AptDaemonTestCase
-
-2011-11-28  sebi@glatzor.de
-
-	Merge more exception fixes by mvo. Thanks!
-
-2011-11-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	some more new style exception fixes
-
-2011-11-27  sebi@glatzor.de
-
-	Map DOWNLOADING_REPO to the packagekit enum
-
-2011-11-27  sebi@glatzor.de
-
-	Update GetUpdates: it was still using the old python-apt API and emitting only updates which don't require to remove any installed software. This is obsolete nowadays (since SimulateUpdatePackages exists) and quite resource hungry.
-
-2011-11-27  sebi@glatzor.de
-
-	Use apt_pkg.version_compare to detect up-to-date packages
-
-2011-11-26  sebi@glatzor.de
-
-	Merge pretty repo branch
-
-2011-11-26  sebi@glatzor.de
-
-	Use the translated language/country name in the language of the transaction
-
-2011-11-26  sebi@glatzor.de
-
-	Fixed description of download items
-
-2011-11-25  sebi@glatzor.de
-
-	Also show the dist and section in the details
-
-2011-11-25  sebi@glatzor.de
-
-	Show an human readable description durch the cache update for the to be downloaded files
-
-2011-11-25  sebi@glatzor.de
-
-	Add IsoCodes class which allows to access the iso-codes language and country names database
-
-2011-11-24  sebi@glatzor.de
-
-	Also show the details in the gtk progress dialogs for STATUS_DOWNLOADING_REPO
-
-2011-11-24  sebi@glatzor.de
-
-	Add a new DaemonAcquireRepoProgress which shows the hostnames of the repositories in the status details instead of the "Downloading Packages"
-
-2011-11-23  sebi@glatzor.de
-
-	Add a new enum to indicate downloading repository information
-
-2011-11-26  sebi@glatzor.de
-
-	Remove obsolete socket module, since the timeout is already set by python-apt
-
-2011-11-26  sebi@glatzor.de
-
-	Rename the Changelog cache to Changelogs
-
-2011-11-25  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged from lp:~aptdaemon-developers/aptdaemon/cached-changelogs
-
-2011-11-25  sebi@glatzor.de
-
-	Cache the downloaded changelogs
-
-2011-11-25  sebi@glatzor.de
-
-	Fix a missing reference to the pk_enums module
-
-2011-11-25  sebi@glatzor.de
-
-	Push local changes
-
-2011-11-25  sebi@glatzor.de
-
-	Use the except Exception as excep syntax in more places
-
-2011-11-25  sebi@glatzor.de
-
-	Merge branch from mvo. thanks
-
-2011-11-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	move exception from "except Error, e" to "except Error as e"
-
-2011-11-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: fix typo
-
-2011-11-24  sebi@glatzor.de
-
-	Update PackageKit README
-
-2011-11-24  sebi@glatzor.de
-
-	Add a delayed UpdatesChanged after we return from resume (180 seconds to avoid too much activity after resume)
-
-2011-11-24  sebi@glatzor.de
-
-	Small fix
-
-2011-11-24  sebi@glatzor.de
-
-	Also emit UpdatesChanged after StateHasChanged was called
-
-2011-11-24  sebi@glatzor.de
-
-	Emit the UpdatesChanged signal after the cache has been modified
-
-2011-11-22  sebi@glatzor.de
-
-	Update NEWS
-
-2011-11-22  sebi@glatzor.de
-
-	Add a packagekit error mapping for the new enum
-
-2011-11-22  sebi@glatzor.de
-
-	Add a new error enum to indicate that the system is already uptodate. But don't use it yet, since this would break API (in the case of no upgrades the transaction would fail.
-
-2011-11-22  sebi@glatzor.de
-
-	Remove partially uncommented check for updates in upgrade_system. If the user is interested in blocked updates simulate should be used beforehand
-
-2011-11-22  sebi@glatzor.de
-
-	Don't fail on date parsing errors in the changelog
-
-2011-11-22  sebi@glatzor.de
-
-	Skip marking the changes of a transaction twice after simulating
-	
-	Store the tid of the transaction whose changes are currently marked in the
-	cache. If the transaction gets committed just after being simulated we don't
-	need to mark the changes again.
-
-2011-11-21  sebi@glatzor.de
-
-	Merge Ubuntu's patch to do an additional resolver run to ensure that 
-	autoremove does not leave the cache inconsistent. Thanks mvo.
-
-2011-11-21  sebi@glatzor.de
-
-	Add a document about the PackageKit compat
-
-2011-11-21  sebi@glatzor.de
-
-	Add support for the store_in_cache argument of DownloadPackages
-
-2011-11-21  sebi@glatzor.de
-
-	Adapt worker test cases to the new simulated callback
-
-2011-11-21  sebi@glatzor.de
-
-	Don't fail if pkcompat isn't avaliable or packagekitd is already running
-
-2011-11-21  sebi@glatzor.de
-
-	Merge with simulatecb branch
-
-2011-11-21  sebi@glatzor.de
-
-	Make the simulate call non-blocking
-
-2011-11-21  sebi@glatzor.de
-
-	Iterate the mainloop more often to improve responsiveness
-	
-	This is done by adding a small helper which iterates the mainloop on an iteration of the available packages after a specified interval
-
-2011-11-20  sebi@glatzor.de
-
-	Push local changes
-
-2011-11-18  sebi@glatzor.de
-
-	Specify the exact type of the inital packagekit properties
-
-2011-11-18  sebi@glatzor.de
-
-	Add support for introspection of properties of type unsinged integer
-
-2011-11-18  sebi@glatzor.de
-
-	Ship the PackageKit dbus configuration files which are overwritten by the native ones if PackageKit is installed
-
-2011-11-18  sebi@glatzor.de
-
-	Merge the PackageKit compatibility branch
-
-2011-11-18  sebi@glatzor.de
-
-	Remove not used control fields
-
-2011-11-18  sebi@glatzor.de
-
-	Also connect PackageKit to the same bus
-
-2011-11-18  sebi@glatzor.de
-
-	Also use the connect statement for packagekit
-
-2011-11-18  sebi@glatzor.de
-
-	Fix add license key test
-
-2011-11-18  sebi@glatzor.de
-
-	Push local changes
-
-2011-11-18  sebi@glatzor.de
-
-	Merge with trunk
-
-2011-11-17  sebi@glatzor.de
-
-	Fix a wrong enum and using the C time locale to parse debian changelogs
-
-2011-11-17  sebi@glatzor.de
-
-	Push local changes
-
-2011-11-17  sebi@glatzor.de
-
-	Implement download packages and remove support for what provides. Should be handled by session-installer
-
-2011-11-17  sebi@glatzor.de
-
-	Add Gstreamer information to test Packages
-
-2011-11-17  sebi@glatzor.de
-
-	Add a test for downloading packages
-
-2011-11-17  sebi@glatzor.de
-
-	Use the gi PK client for the tests
-
-2011-11-14  sebi@glatzor.de
-
-	Add a new enum to indicate that a transaction role is not yet supported
-
-2011-10-21  sebi@glatzor.de
-
-	Fix automatic network monitor selection
-
-2011-10-21  sebi@glatzor.de
-
-	Add tests for Get(Requires|Depends)
-
-2011-10-21  sebi@glatzor.de
-
-	Add support for GetDepends and GetRequires
-
-2011-10-19  sebi@glatzor.de
-
-	Provide better status and progress informsation in get-update-detail
-
-2011-10-19  sebi@glatzor.de
-
-	Some small fixes to the GetUpdateDetail method
-
-2011-10-19  sebi@glatzor.de
-
-	Use the network state monitor in the packagekit backend
-
-2011-10-19  sebi@glatzor.de
-
-	Set the state in the get_network_state call directly to make reusing in aptdaemon easier
-
-2011-10-19  sebi@glatzor.de
-
-	Some small fixes and automatic monitor selection
-
-2011-10-19  sebi@glatzor.de
-
-	Implement get_network_state for all monitors
-
-2011-10-19  sebi@glatzor.de
-
-	Add a fallback network monitor which makes use of the /proc/net/route file - taken from PackageKit
-
-2011-10-19  sebi@glatzor.de
-
-	Monitor the default active connections' Default property and the active connections
-
-2011-10-19  sebi@glatzor.de
-
-	Use deferreds for async calls to network manager
-
-2011-10-19  sebi@glatzor.de
-
-	Adapt to latest NM api, remove modem detection, since not usable by packagekit, a lot of sanitizing
-
-2011-10-19  sebi@glatzor.de
-
-	Merge AlertWatcher and roam to networking
-
-2011-10-19  sebi@glatzor.de
-
-	Add an old copy of UpdateManagers AlertWatcher which still uses the old gobject
-
-2011-10-19  sebi@glatzor.de
-
-	Set the default network state to online
-
-2011-10-18  sebi@glatzor.de
-
-	Add supported filter and fix a missing role setting
-
-2011-10-18  sebi@glatzor.de
-
-	Add a test for get updates
-
-2011-10-18  sebi@glatzor.de
-
-	NotImplemented exception doesn't support any messages so use the TransactionFailed one
-
-2011-10-18  sebi@glatzor.de
-
-	Check if pkcon is availbale before running the tests
-
-2011-10-18  sebi@glatzor.de
-
-	Add a test case for the resolve and install transaction by using pkcon
-
-2011-10-17  sebi@glatzor.de
-
-	Do not crash on set_locale("C")
-
-2011-10-17  sebi@glatzor.de
-
-	Use a custom dbus config and fake a system bus daemon (preparation for the pk tests)
-
-2011-10-17  sebi@glatzor.de
-
-	Adapt tests to latest API changes
-
-2011-10-17  sebi@glatzor.de
-
-	Create the tid if not provided - makes testing easier
-
-2011-10-16  sebi@glatzor.de
-
-	Support (Get)TransactionList(Changed)
-
-2011-10-16  sebi@glatzor.de
-
-	Emit Package signals for progress information during installation - currently lacks arch and version information.
-
-2011-10-16  sebi@glatzor.de
-
-	Add a package progress (will be used by the packagekit layer only)
-
-2011-10-16  sebi@glatzor.de
-
-	Merge with trunk
-
-2011-10-15  sebi@glatzor.de
-
-	Cherry pick cmdline support from pkcompat branch
-
-2011-10-07  sebi@glatzor.de
-
-	Fix setting locale and debconf
-
-2011-10-07  sebi@glatzor.de
-
-	Simulate should only emit dependencies
-
-2011-10-07  sebi@glatzor.de
-
-	Add all Transaction methods and fail if not implemented by aptdaemon
-
-2011-10-06  sebi@glatzor.de
-
-	Add support for debconf and fix multiarch support
-
-2011-10-06  sebi@glatzor.de
-
-	Handle multiarch
-
-2011-10-06  sebi@glatzor.de
-
-	Unify package_ids argument
-
-2011-10-06  sebi@glatzor.de
-
-	Also queue query transactions
-
-2011-10-06  sebi@glatzor.de
-
-	Implement support for PackageKit deeper into aptdameon by allowing running query transaction on the queue
-
-2011-10-06  sebi@glatzor.de
-
-	Implement GetDetails
-
-2011-10-06  sebi@glatzor.de
-
-	Add support for the Search* methods
-
-2011-10-06  sebi@glatzor.de
-
-	Push local changes
-
-2011-10-06  sebi@glatzor.de
-
-	Implement GetPackages
-
-2011-10-05  sebi@glatzor.de
-
-	Implement GetFiles
-
-2011-10-05  sebi@glatzor.de
-
-	Rough implementation of GetUpdateDetail
-
-2011-10-05  sebi@glatzor.de
-
-	Sort imports
-
-2011-10-05  sebi@glatzor.de
-
-	Use the worker for getting updates
-
-2011-10-05  sebi@glatzor.de
-
-	Don't loop remove from connection
-
-2011-10-05  sebi@glatzor.de
-
-	Add support for resolving!
-
-2011-10-05  sebi@glatzor.de
-
-	Load the PackageKitWorker
-
-2011-10-05  sebi@glatzor.de
-
-	Add a status enum to indicate searching
-
-2011-10-05  sebi@glatzor.de
-
-	Start again with a custom AptWorker to handle query transactions
-
-2011-10-04  sebi@glatzor.de
-
-	Add a method to emit package signals in the merged transaction
-
-2011-10-04  sebi@glatzor.de
-
-	Add an enum for merged transaction whihc perform a PK query
-
-2011-09-30  sebi@glatzor.de
-
-	Allow to set the locale
-
-2011-09-30  sebi@glatzor.de
-
-	Fix package ids handling
-
-2011-09-30  sebi@glatzor.de
-
-	Push local changes
-
-2011-09-30  sebi@glatzor.de
-
-	A lot of fixes and StateHasChanged support
-
-2011-09-30  sebi@glatzor.de
-
-	Fixes to the getdistroupgrade call
-
-2011-09-30  sebi@glatzor.de
-
-	Add distro upgrade support
-
-2011-09-30  sebi@glatzor.de
-
-	Safe a lot of typing work by using simpler names for the enums modules
-
-2011-09-30  sebi@glatzor.de
-
-	Unify creation of merged transactions
-
-2011-09-30  sebi@glatzor.de
-
-	Release references if done
-
-2011-09-30  sebi@glatzor.de
-
-	Store the MergedTransaction in the PackageKit Transaction
-
-2011-09-29  sebi@glatzor.de
-
-	Add support for UpdateSystem
-
-2011-09-29  sebi@glatzor.de
-
-	Updates supported role enums
-
-2011-09-29  sebi@glatzor.de
-
-	Add support for removing packages and fix some minor bugs
-
-2011-09-29  sebi@glatzor.de
-
-	Add support for UpdatePackages and SimulateUpdatePackages
-
-2011-09-29  sebi@glatzor.de
-
-	Remove not existing Categories property
-
-2011-09-29  sebi@glatzor.de
-
-	Remove unsused imports
-
-2011-09-29  sebi@glatzor.de
-
-	Remove the PackageKitWorker. For the first time we stay with mapping aptdaemon transactions.
-
-2011-09-29  sebi@glatzor.de
-
-	Fixes and clean ups to the property handling
-
-2011-09-28  sebi@glatzor.de
-
-	Add support for GetUpdates by simulating UpgradeSystem
-
-2011-09-28  sebi@glatzor.de
-
-	Use the PackageKit worker in compat mode
-
-2011-09-28  sebi@glatzor.de
-
-	Perform the simulate call during idle times to avoid time outs on the Dbus method
-
-2011-09-28  sebi@glatzor.de
-
-	Add support for InstallPackages and SimulateInstallPackages
-
-2011-09-27  sebi@glatzor.de
-
-	Rename enum convert methods 
-
-2011-09-27  sebi@glatzor.de
-
-	Use setter/getter for PackageKitTransaction properties to emit the Changed signal automatically
-
-2011-09-27  sebi@glatzor.de
-
-	Set the error in case of a cancel
-
-2011-09-26  sebi@glatzor.de
-
-	Big code drop to get a working PackageKit RefreshCache, yeah!
-
-2011-11-18  sebi@glatzor.de
-
-	Merge the AddLicenseKey method! Has been a long way ...
-
-2011-11-18  sebi@glatzor.de
-
-	Add the new plugin to the sphinx documentation
-
-2011-11-18  sebi@glatzor.de
-
-	Minor variable name fix
-
-2011-11-18  sebi@glatzor.de
-
-	Reduce the license key error enums
-
-2011-11-18  sebi@glatzor.de
-
-	Merge local changes
-
-2011-11-18  sebi@glatzor.de
-
-	Merge with mvo's branch
-
-2011-11-18  sebi@glatzor.de
-
-	Remove obsolete imports
-
-2011-11-18  sebi@glatzor.de
-
-	Minor setup fixes
-
-2011-11-18  sebi@glatzor.de
-
-	Remove obsolete tests
-
-2011-11-18  sebi@glatzor.de
-
-	Remove the no longer needed helper
-
-2011-11-18  sebi@glatzor.de
-
-	Move getting the license key to a plugin
-
-2011-11-18  sebi@glatzor.de
-
-	Doc string fixes
-
-2011-11-18  sebi@glatzor.de
-
-	Reorder NEWS
-
-2011-11-18  sebi@glatzor.de
-
-	Merge trunk
-
-2011-11-10  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	more test fixes, fix indent
-
-2011-11-10  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add simple helper test
-
-2011-11-10  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	move the license-key acquire into its own helper for easier testing, readability, extensability
-
-2011-11-09  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	fix failing test, this needs refactor more to avoid the special "mock" target in worker
-
-2011-11-09  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	use multiprocessing to avoid the blocking call
-
-2011-11-09  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	first cut on the new add_license_key system
-
-2011-09-20  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged from trunk
-
-2011-08-25  sebi@glatzor.de
-
-	Minor fix for the NEWS file. upside, down you turn me ...
-
-2011-08-25  sebi@glatzor.de
-
-	We don't need to change the LICENSE_ROOTDIR in the worker test anymore
-
-2011-08-25  sebi@glatzor.de
-
-	Set the umask to aovid creating executable files
-
-2011-08-25  sebi@glatzor.de
-
-	UPdate news
-
-2011-08-25  sebi@glatzor.de
-
-	Fix client test case.
-
-2011-08-25  sebi@glatzor.de
-
-	Fix variable names in the DBus method
-
-2011-08-25  sebi@glatzor.de
-
-	Take the apt root dir into account when building the license key root dir
-
-2011-08-23  sebi@glatzor.de
-
-	Adapt client side
-
-2011-08-23  sebi@glatzor.de
-
-	Allow to install the license key directly after installing a package without entering the password
-
-2011-08-23  sebi@glatzor.de
-
-	Adapt DBus API
-
-2011-08-23  sebi@glatzor.de
-
-	Handle a not available pkg
-
-2011-08-23  sebi@glatzor.de
-
-	Fix small typo, sorry richard
-
-2011-08-23  sebi@glatzor.de
-
-	Rework license key installation by retrieving the license key path from the package records
-
-2011-08-23  sebi@glatzor.de
-
-	Add some error enums for the license key installation. The descriptions are still missing.
-
-2011-08-23  sebi@glatzor.de
-
-	Add an enhanced test suite for the license key installation.
-
-2011-08-23  sebi@glatzor.de
-
-	Add a new silly-license package to the test repo
-
-2011-08-23  sebi@glatzor.de
-
-	Remove LicenseKeyLocationInvalid error
-
-2011-08-19  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add new "AddLicenseKey call
-
-2011-11-18  sebi@glatzor.de
-
-	Replace the backported unittest2 framework by the native one of
-	Python 2.7 and Nose to collect the tests
-
-2011-10-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	lp:~mpt/aptdaemon/bug-635138: merged string fix, many thanks!
-
-2011-09-08  Matthew Paul Thomas  <mpt@canonical.com>
-
-	Fixes bug 635138 (Apt cache repair 'In Progress' text is 'Repairing broken deps').
-
-2011-10-08  sebi@glatzor.de
-
-	Map messages from apt on the status-fd to enums to provide better terms and translations in the future - fixes LP#641262
-
-2011-09-30  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/progress.py: fix crash when a translation has the wrong number of %s (LP: #858684)
-
-2011-09-19  sebi@glatzor.de
-
-	Use constructor of super class instead of the gobject one for gtk3 widgets
-
-2011-09-19  sebi@glatzor.de
-
-	Push local changes
-
-2011-09-19  sebi@glatzor.de
-
-	Merge non-blocking-lintian branch
-
-2011-09-18  sebi@glatzor.de
-
-	Don't block on lintian calls to avoid time outs on the DBus by making use
-	of the excellent preexec_fn of subprocess.
-
-2011-09-18  sebi@glatzor.de
-
-	Minor improvement to error message in worker test
-
-2011-09-19  sebi@glatzor.de
-
-	Push local changes
-
-2011-09-15  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	pyflakes based import fixes, this fixes a unneeded glib import that can cause crashes with gtk2/gtk3 (pygtk/pygi)
-
-2011-09-07  sebi@glatzor.de
-
-	Workaround a bug in apt's ListUpdate which doesn't handle cancellation properly
-
-2011-08-27  sebi@glatzor.de
-
-	Push local changes
-
-2011-08-27  sebi@glatzor.de
-
-	Unset the apt-listbugs frontend if in interactive mode
-
-2011-08-27  sebi@glatzor.de
-
-	Push local changes
-
-2011-08-27  sebi@glatzor.de
-
-	Avoid creating an apport crash report for valid DBusExceptions that
-	are send to the client (subclasses of AptDaemonError)
-
-2011-08-26  sebi@glatzor.de
-
-	Merge mvo's defer branch with some minor changes and fixes
-
-2011-08-17  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	make aptdaemon.gtk3widgets.AptProgressDialog.run() deferable
-
-2011-08-26  sebi@glatzor.de
-
-	Avoid apport crash reports for the forked child, e.g. on dpkg failure, fixes LP# 799982
-
-2011-08-26  sebi@glatzor.de
-
-	Rename "shutdown" to "quit" to avoid confusions, see lp# 834104
-
-2011-08-26  sebi@glatzor.de
-
-	Python Dbus automatically converts the unsigend long to a long. So we just stick with a signed long for the elapsed time.
-
-2011-08-26  sebi@glatzor.de
-
-	Enhance dbus type test to also take double and unsigned long into account
-
-2011-08-26  sebi@glatzor.de
-
-	Finally handle use the same types as in apt for elapsed time and download speed. This should resolve all outstanding overflow errors.
-
-2011-08-26  sebi@glatzor.de
-
-	Push local changes
-
-2011-08-26  sebi@glatzor.de
-
-	Provide additional debug information in the case of a failed dbus type conversion
-
-2011-08-26  sebi@glatzor.de
-
-	Fix install of apport package hook
-
-2011-08-26  sebi@glatzor.de
-
-	Move showing a nicer name in apport reports to the package hook
-
-2011-08-26  sebi@glatzor.de
-
-	Re-enable the purge test again since the bug is now fixed in python-apt
-
-2011-08-25  sebi@glatzor.de
-
-	Refactor apport integration by moving some of the code from the crash module to an apport package hook. This will allow us to get information on crashes which are not handled by the crash module, e.g. in the core.
-
-2011-08-25  sebi@glatzor.de
-
-	Fix cdrom test case. It failed because apt-cdrom refused to add an untrusted cdrom
-
-2011-08-25  sebi@glatzor.de
-
-	Only create an apport crash report if we are running as a system service with / as the working directory. This helps as to avoid crash reports if we are running in a test environment
-
-2011-08-25  sebi@glatzor.de
-
-	Fix default values for the ProgressDetails using long
-
-2011-08-25  sebi@glatzor.de
-
-	Improve error message if a type doesn't match in the dbus test
-
-2011-08-25  sebi@glatzor.de
-
-	Merge local changes
-
-2011-08-25  sebi@glatzor.de
-
-	Update NEWS
-
-2011-08-24  sebi@glatzor.de
-
-	Make the handling of exceptions in the forked child process more robust
-
-2011-08-24  sebi@glatzor.de
-
-	push local changes
-
-2011-08-24  sebi@glatzor.de
-
-	Fix showing the header of the translation (.mo file) if we try to translate an empty string
-
-2011-08-23  sebi@glatzor.de
-
-	Remove white spaces
-
-2011-08-23  sebi@glatzor.de
-
-	Merge the apt command history log integration. Thanks to MVO!
-
-2011-08-23  sebi@glatzor.de
-
-	Move the command history creation into the progress to also get direct dpkg calls. Minor changes to the test.
-
-2011-06-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: move the log writing down into _apply_changes()
-
-2011-06-27  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	set apts CommandLine::AsString with the actions that are going to be performed to have this information in the apt history log file
-
-2011-08-22  sebi@glatzor.de
-
-	Merge mvo's little branch witch fixes total and done bytes in the ProgressDetails. Thanks!
-
-2011-08-22  sebi@glatzor.de
-
-	Add API changes to the NEWS file
-
-2011-08-22  sebi@glatzor.de
-
-	Merge mvo's branch
-
-2011-08-19  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	switch bytes_{done,total} to 64bit to follow a change in apt
-
-2011-08-22  sebi@glatzor.de
-
-	Merge mvo's multi arch branch with some minor adoptions
-
-2011-08-22  sebi@glatzor.de
-
-	Remove obsolete valid arch regex
-
-2011-08-22  sebi@glatzor.de
-
-	Harden vaild package name regex to catch names like "apt:123:"
-
-2011-08-22  sebi@glatzor.de
-
-	Add some nasty package names to the test.
-
-2011-08-22  sebi@glatzor.de
-
-	Only test packages with release if there is actually any release information
-
-2011-08-22  sebi@glatzor.de
-
-	Merge mvo's mutli arch branch
-
-2011-08-19  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	fix multiarch names
-
-2011-08-17  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	fix previous patch to only use GObject when using gi
-
-2011-08-17  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	convert aptdaemon/client.py and aptdaemon/debconf.py from gobject to GObject as well; works with earlier pygobject versions and gtkclient.py, and makes this work with pygobject 2.90
-
-2011-08-17  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	aptdaemon/gtk3widgets.py: Drop unnecessary dbus import and main loop setup, this is client code only
-
-2011-08-17  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	Move from static gobject to GI GObject module, to be compatible to upcoming pygobject 3.0.
-
-2011-08-12  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp:~mvo/aptdaemon/fix825056
-
-2011-08-12  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: fix crash in python where _parse_localename() does not handle dbus.String()
-
-2011-08-09  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp:~mvo/aptdaemon/setup2to3 
-
-2011-08-09  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	setup.py: build py3 version using 2to3
-
-2011-08-03  sebi@glatzor.de
-
-	Implement the missing PropertyChanged signal for the daemon (fixes LP#818521)
-
-2011-07-28  sebi@glatzor.de
-
-	Merge the reboot required property! Thanks to mvo
-
-2011-07-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add reboot-required property to aptdaemon
-
-2011-06-28  sebi@glatzor.de
-
-	Merge the fixoverflow branch of Robert Roth. Thanks a lot for the work!
-
-2011-06-28  sebi@glatzor.de
-
-	Add a note to the NEWS file about the api change
-
-2011-06-27  Robert Roth  <robert.roth.off@gmail.com>
-
-	Use int64 for transaction space and download, as these might overflow (lp:#771678, lp:#758837)
-
-2011-06-16  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	aptdaemon/crash.py: only create crash reports if apport is enabled; also fix the __main__ test to actually work
-
-2011-06-15  Brian Murray  <brian@canonical.com>
-
-	aptdaemon/crash.py: only create crash reports if apport is enabled
-
-2011-06-01  sebi@glatzor.de
-
-	Let aptdamen take advantage of traceback processing tools in Launchpad. Thanks Brian!
-
-2011-05-26  Brian Murray  <brian@canonical.com>
-
-	aptdaemon/crash.py: title attachments Traceback to be consistent with apport
-
-2011-05-25  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp:~kelemeng/aptdaemon/bug786500, many thanks!
-
-2011-05-22  Gabor Kelemen  <kelemeng@gnome.hu>
-
-	Add missing files to POTFILES.in, fixes LP:786500
-
-2011-05-13  sebi@glatzor.de
-
-	The TransactionCancelledError() doesn't provide any details by default
-
-2011-04-28  sebi@glatzor.de
-
-	Overwrite the dbus.exceptions.DBusExption.get_dbus_message() method to handle unicode error messages.
-
-2011-04-28  sebi@glatzor.de
-
-	Just one more comment :)
-
-2011-04-28  sebi@glatzor.de
-
-	Add some comments to the dbus exception test
-
-2011-04-28  sebi@glatzor.de
-
-	Add a small test which demonstrates the encoding/decoding problems regarding Dbus exceptions
-
-2011-04-20  sebi@glatzor.de
-
-	Handle interrupts in the forked child.
-	Otherwise the atexit methods would be called, e.g. the frozen status decorator.
-
-2011-04-20  sebi@glatzor.de
-
-	Return the file descriptor of a lock if it was already acquire to avoid leaking file descriptors.
-
-2011-04-19  sebi@glatzor.de
-
-	Convert the message of AptDaemonErrors to unicode
-
-2011-04-19  sebi@glatzor.de
-
-	Update NEWS
-
-2011-04-18  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp:~evfool/aptdaemon/fix764422 , many thanks!
-
-2011-04-18  Robert Roth  <robert.roth.off@gmail.com>
-
-	Fixed bad parameter name (LP: #764422)
-
-2011-04-18  sebi@glatzor.de
-
-	Don't fail if the master_fd was already closed at the end of the run() call and the io callback was still queued on the main loop
-
-2011-04-18  sebi@glatzor.de
-
-	Don't crash on the dpkg disappear status by adding a mapping
-
-2011-04-17  sebi@glatzor.de
-
-	Fix argument handling in wait_for_lock call. Fixes LP #763642
-
-2011-04-15  sebi@glatzor.de
-
-	Catch broken and really large install sizes specified in third party
-	packages which result in an overflow error, LP #758837
-
-2011-04-15  sebi@glatzor.de
-
-	Set the status of queued transaction to waiting instead of running (running is set by the worker)
-
-2011-04-15  sebi@glatzor.de
-
-	Unify cache opening method to catch cache breakages
-
-2011-04-15  sebi@glatzor.de
-
-	Don't require a dependency on libc in the lintian check - lsb packages don't have it.
-
-2011-04-14  sebi@glatzor.de
-
-	Configure the mount point for the cdrom test via files instead of hardcoding in the worker
-
-2011-04-14  sebi@glatzor.de
-
-	Test cdrom test now works perfectly. No need to skip it anymore.
-
-2011-04-14  sebi@glatzor.de
-
-	The worker should read configurations file from a given chroot. Also specify
-	the dpkg-wrapper in the test.Chroot in aconfig file (fixes the cdrom test)
-
-2011-04-14  sebi@glatzor.de
-
-	Fix the deferred client test
-
-2011-04-14  sebi@glatzor.de
-
-	Add a test for the cdrom installation - unluckily the dpkg call in the chroot seems to fail.
-
-2011-04-14  sebi@glatzor.de
-
-	Hardcode the media mount point iif a chroot is used
-
-2011-04-14  sebi@glatzor.de
-
-	aptdaemon.test.Chroot now has got new methods to handle faked cdrom
-	repositories: add_cdrom_repository(), mount_cdrom() and unmount_cdrom()
-
-2011-04-14  sebi@glatzor.de
-
-	Fix remaining refactoring issues in watch_lock
-
-2011-04-13  sebi@glatzor.de
-
-	Fix detection of a failed lintian check by convert the exit status
-	correctly
-
-2011-04-13  sebi@glatzor.de
-
-	Fix the string decode helper.
-	
-	Decode() method doesn't support key word arguments and actually return a
-	converted string.
-
-2011-04-13  sebi@glatzor.de
-
-	Freeze (copy) the dpkg status file during a dpkg call to allow
-	simulating other transactions with the frozen dpkg status.
-	
-	This is a small revival of the former future status.
-
-2011-04-13  sebi@glatzor.de
-
-	Important fix: call apt.cache.Cache.open() after update(). Could be the cause for some strange errors.
-
-2011-04-12  sebi@glatzor.de
-
-	Fix a small logging message typo, thanks johnnyboy0y
-
-2011-04-12  sebi@glatzor.de
-
-	Update NEWS
-
-2011-04-12  sebi@glatzor.de
-
-	merge local changes
-
-2011-04-12  sebi@glatzor.de
-
-	Don't treat a lintian error as a policy violation (using correct exit states)
-
-2011-04-09  sebi@glatzor.de
-
-	Don't segfault if we cannot read the status of the process holding a lock - fixes LP #745517 
-
-2011-04-09  sebi@glatzor.de
-
-	Fix closing a not used terminal file descriptor
-
-2011-04-09  sebi@glatzor.de
-
-	Add a small reminder that we need to remove the unused AptMessageDialog in the future
-
-2011-04-09  sebi@glatzor.de
-
-	Fix a wrong reference to arch
-
-2011-04-09  sebi@glatzor.de
-
-	Fix some refactoring leftofters in the lock module (thanks to Barry Warsaw and pylint)
-
-2011-04-08  sebi@glatzor.de
-
-	Fix errors from last commit.
-
-2011-04-08  sebi@glatzor.de
-
-	Make the get_dbus_string method more pythonic. Thanks juliank
-
-2011-04-08  sebi@glatzor.de
-
-	Open the controlling terminal of the client when it is needed and don't keep open fds around. Furthermore fallback to non-interactive mode if the terminal isn't available. Fixes a lot of bugs.
-
-2011-04-07  sebi@glatzor.de
-
-	Switch to non-interactive mode if the terminal cannot be attached
-
-2011-04-07  sebi@glatzor.de
-
-	Don't keep the terminal fd open by reverting 596.1.1
-
-2011-04-07  sebi@glatzor.de
-
-	Fix copy and paste error: do not call logging in the lock module (fixes LP #752220)
-
-2011-04-07  sebi@glatzor.de
-
-	Merge the relax lintian branch
-
-2011-04-06  sebi@glatzor.de
-
-	Merge with trunk
-
-2011-04-06  sebi@glatzor.de
-
-	Improve lintian handling: Run lintian twice once with the fatal and a second time with the non fatal tags. Allow distributions to ship alternative tag files.
-
-2011-04-06  sebi@glatzor.de
-
-	Allow to install files in opt
-
-2011-04-06  sebi@glatzor.de
-
-	Use the the lintian tags from the lintian package (2.5.0RC2) as a starting point.
-
-2011-04-06  sebi@glatzor.de
-
-	Install the lintian tags file
-
-2011-04-06  sebi@glatzor.de
-
-	Remove the tags provided by mvo
-
-2011-04-06  sebi@glatzor.de
-
-	Allow to install files in /opt
-
-2011-04-06  sebi@glatzor.de
-
-	Add lintian tags from the Debian ftp masters
-
-2011-03-26  sebi@glatzor.de
-
-	Uncomment the not used test instead of removing to make changes more transparent
-
-2011-03-26  sebi@glatzor.de
-
-	Revert the original lintian checks
-
-2011-03-23  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tweak checks, add really broken package, update tests
-
-2011-03-23  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add initial lintian check list based on ftpmaster tags
-
-2011-04-06  sebi@glatzor.de
-
-	Fix unicode decoding test
-
-2011-04-06  sebi@glatzor.de
-
-	Merge local changes - mostly unicode decoding fixes
-
-2011-04-06  sebi@glatzor.de
-
-	Put an end to UnicodeDecodeErrors!
-	
-	Make sure to convert all strings to unicode before processing.
-
-2011-04-05  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/gtkwidgets.py: remove leftover debugging pdb import
-
-2011-04-05  sebi@glatzor.de
-
-	Make the run method of the GTK2 progress dialog deferable
-
-2011-04-05  sebi@glatzor.de
-
-	Client: Exit the transaction processing if there has been an error
-
-2011-04-05  sebi@glatzor.de
-
-	API adoption: The Transation.attach() method was replaced by sync()
-
-2011-04-05  sebi@glatzor.de
-
-	Allow to specify package names with an architecture
-
-2011-04-05  sebi@glatzor.de
-
-	Remove the url to the aptdaemon bug tracker since we nowadays use apport directly
-
-2011-04-05  sebi@glatzor.de
-
-	Merge the no future branch
-
-2011-04-05  sebi@glatzor.de
-
-	Remove the support for the future status. It allowed to simulate a transaction
-	with the queued changes. Multi arch adds more syntax and complexity
-
-2011-04-05  sebi@glatzor.de
-
-	Merge mvo's workaround of lp #724735 with some minor changes.
-
-2011-04-01  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py, tests/test_worker.py: fix i18n crash (#724735) and add test
-
-2011-04-05  sebi@glatzor.de
-
-	Instead of failing wait for the dpkg status lock after a transaction was processed.
-	
-	The lock_cache moves to the lock module as wait_for_lock and is reused by
-	the progress for the status lock.
-
-2011-03-24  sebi@glatzor.de
-
-	Merge local changes
-
-2011-03-24  sebi@glatzor.de
-
-	Don't override DBusException.args in TransactionFailed
-
-2011-03-23  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/config.py: rename "last_char" to "prev_char" to avoid confusing it with the last char of a line, fix parser when a // is found inside a value (like for http urls); tests/test_configparser.py: add regression test
-
-2011-03-23  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: simplify verification by using the split code from the worker and verifying each regexp individually; tests/test_valid_package_names.py: add more test cases
-
-2011-03-23  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py, tests/test_valid_package_names.py: fix the verification of the packagenames, based on http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source and http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version and add test
-
-2011-03-22  sebi@glatzor.de
-
-	Fix variable name in the Finished signal
-
-2011-03-22  sebi@glatzor.de
-
-	Don't raise an error if trying to close an already closed fd
-
-2011-03-22  sebi@glatzor.de
-
-	Merge local changes
-
-2011-03-22  sebi@glatzor.de
-
-	Check the package names
-
-2011-03-22  sebi@glatzor.de
-
-	Open the controlling terminal already at the SetTerminal call time and keep it open. This way we don't get into problems if the client dies before we start executing the transaction.
-
-2011-03-22  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: fix typo (LP: #733732), thanks to seb128
-
-2011-03-17  Martin Pitt  <martin.pitt@ubuntu.com>
-
-	./data/org.debian.apt.policy.in: Drop gettext domain field, it will be added during package build. (LP: #690270)
-
-2011-03-16  sebi@glatzor.de
-
-	Name Sergey in the security issue test. Thanks.
-
-2011-03-08  sebi@glatzor.de
-
-	Fix the installation of local packages which are not yet known to the cache.
-	
-	There have been two small bugs: One that assigns the packages to the depends andanother one trying to item assign in a dbus.Struct.
-
-2011-03-03  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tests/test_client.py: simplify (thanks to Sebastian Heinlein for his suggestions)
-
-2011-03-02  Martin Pitt  <martin@piware.de>
-
-	gtk3widgets.py: Fix require_version usage.
-	
-	Drop usage of require_version() from gtk3widgets.py; this was meant to be
-	commented out, and doesn't belong in a library. Instead, move the (now really
-	commented) call to gtk3-demo.py.
-
-2011-03-02  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py, tests/test_client.py: fix crash in client.add_repository(), add test for client.add_repository(), refactor test for enable_component() to make it more generic
-
-2011-03-02  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py, tests/test_client.py: fix crash in enable_distro_component and add test, update docstring (and fix docstring for remove_vendor_key along the way)
-
-2011-03-01  sebi@glatzor.de
-
-	Call waitpid after reading the output from lintian to avoid interrupted system calls on systems under heavy load
-
-2011-03-01  sebi@glatzor.de
-
-	Update NEWS
-
-2011-03-01  sebi@glatzor.de
-
-	Show details about broken dependencies
-
-2011-02-24  sebi@glatzor.de
-
-	Merge
-
-2011-02-24  sebi@glatzor.de
-
-	Merge security fix for LP #722228 an update NEWS for a new release
-
-2011-02-22  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged lp722228 fix from glatzor
-
-2011-02-22  sebi@glatzor.de
-
-	Fix the security issue CVE-2011-0725 tracked in LP #722228 and add a
-	regression test.
-	
-	The UpdateCache method allows to specify an alternative sources.list
-	snippet to only update the repositories specified in the corresponding
-	configuration file.
-	
-	Aptdaemon did not restrict the path to the sources.list.d directory and
-	allowed to inject packages from malicious sources specified in a custom
-	sources.list and even to read every file on the system.
-	
-	Thanks to Michael Vogt for the inital patch and test!
-
-2011-02-22  sebi@glatzor.de
-
-	get_tests_dir should return a normalized path which already resolved any symbolic links
-
-2011-02-22  sebi@glatzor.de
-
-	Only report packages as kept back if marked as keep - otherwise we also get upgradable packages which would get removed.
-
-2011-02-19  sebi@glatzor.de
-
-	Merge the set-candidate-release branch
-
-2011-02-19  sebi@glatzor.de
-
-	Update the documentation
-
-2011-02-19  sebi@glatzor.de
-
-	Make use of the new SetCandidateRelease function of APT to allow selecting the release of a package. The traditional apt-get syntax package/release will be used to specify the release.
-
-2011-02-09  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tests/test_lock_location.py: ensure that aptdaemon.lock gets reloaded in the test (this should fix the test failure during build)
-
-2011-02-08  sebi@glatzor.de
-
-	Make sure to test a newly initiated aptdaemon.lock module. Otherwise we get the lock pathes of previous tests.
-
-2011-02-08  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tests/test_lock_location.py, tests/test_lock.py: split LockFileLocationTest into its own file to avoid pollution of apt_pkg.config from one test to the next
-
-2011-02-08  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	tests/test_lock.py: make tests work when Dpkg::Post-Invoke has root only commands
-
-2011-02-08  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: clear DPkg::Post-Invoke when inside chroot mode
-
-2011-02-08  sebi@glatzor.de
-
-	Don't hardcode UTF-8 encoding for the worker child process. Convert the output from the child process to unicode before adding to the error message in the case of an package manager failure
-
-2011-02-08  sebi@glatzor.de
-
-	Don't show the same short desc of a download twice if e.g. two Packages files are downloaded simultaneously.
-
-2011-02-07  sebi@glatzor.de
-
-	Push today's train ride outcome
-
-2011-02-07  sebi@glatzor.de
-
-	The io_add_watch callback should either return True or False. By default it should be True.
-
-2011-02-07  sebi@glatzor.de
-
-	The install local package file now includes detecting of invalid packages using lintian.
-
-2011-02-07  sebi@glatzor.de
-
-	Convert status_messages of apt from the default fs encoding to unicode.
-
-2011-02-06  sebi@glatzor.de
-
-	Instead of using sudo, fork and change uid to run linitan
-
-2011-02-02  sebi@glatzor.de
-
-	Only try to remove a listener for the debconf socket if one is running
-
-2011-02-01  sebi@glatzor.de
-
-	If there isn't any transaction on the queue we send an early
-	progress information. Otherwise it juse seems that aptdaemon
-	hangs since it doesn't send any progress information after the
-	the transaction has been started. Thanks Gary for the hint!
-
-2011-01-31  sebi@glatzor.de
-
-	Push local changes
-
-2011-01-31  sebi@glatzor.de
-
-	Start a private dbus-daemon for the tests and automatically use it for the started aptd and fake polkitd
-
-2011-01-30  sebi@glatzor.de
-
-	Don't replace another testing aptdaemon
-
-2011-01-30  sebi@glatzor.de
-
-	Fix dbus type test
-
-2011-01-30  sebi@glatzor.de
-
-	Switch the dbus type test to unittest2 to get support for cleanups
-
-2011-01-30  sebi@glatzor.de
-
-	Add a patch from mvo to protect sources.list files which contain passwords. Thanks!
-
-2011-01-30  sebi@glatzor.de
-
-	Remove the test chroot in a cleanup. So we also remove chroots of failed tests
-
-2011-01-30  sebi@glatzor.de
-
-	Add a new class aptdaemon.test.AptDaemonTestCase which provides the start_session_aptd and start_fake_polkitd methods. Use cleanups to kill the helper processes even if the test failed. Make use of the new class in the client test.
-
-2011-01-29  sebi@glatzor.de
-
-	Move tests/utils.py to aptdaemon.test to allow writting tests for aptdaemon
-	clients easily. Furthermore system wide installed test data is used optionally.
-
-2011-01-27  sebi@glatzor.de
-
-	Push local changes
-
-2011-01-27  sebi@glatzor.de
-
-	Update NEWS file for release
-
-2011-01-25  sebi@glatzor.de
-
-	Add the transaction error to apport report
-
-2011-01-22  sebi@glatzor.de
-
-	Remove the execute privileges from the crash module
-
-2011-01-22  sebi@glatzor.de
-
-	Remove unused import of sys in crash
-
-2011-01-22  sebi@glatzor.de
-
-	Respect the flags argument in the policykit1.check_authorization_by_pid method.
-
-2011-01-22  sebi@glatzor.de
-
-	Fix missing trans arguments in the worker
-
-2011-01-22  sebi@glatzor.de
-
-	Adapt the future status test to the latest API changes
-
-2011-01-22  sebi@glatzor.de
-
-	Use an AptWorker in the lock test to set the lock pathes to the chroot.
-
-2011-01-27  Martin Pitt  <martin@piware.de>
-
-	adjust gtk3widgets.py to work with current pygobject/gtk
-
-2011-01-21  sebi@glatzor.de
-
-	Make sure to output the details of a TransactioNFailed error if it gets raised
-
-2011-01-21  sebi@glatzor.de
-
-	Fix Packages remove failure test. Chroot env won't be set anymore by utils.Chroot.setup()
-
-2011-01-21  sebi@glatzor.de
-
-	Push local changes!
-
-2011-01-21  sebi@glatzor.de
-
-	Add a test for the client module
-
-2011-01-21  sebi@glatzor.de
-
-	Allow aptdaemon to apply changes to a chroot. Move the code from the test utils to the worker.
-
-2011-01-21  sebi@glatzor.de
-
-	Add a small policykit fake daemon which can listen on the session bus.
-
-2011-01-21  sebi@glatzor.de
-
-	Minor clean up in the worker test
-
-2011-01-21  sebi@glatzor.de
-
-	Allow to run aptdaemon on the session bus
-
-2011-01-20  sebi@glatzor.de
-
-	Add a test which tiggers a nasty bug in apt: If Packages lists are removed the
-	apt.Cache.required_download method fails. This is corner case if the repository
-	lists are updated.
-
-2011-01-19  sebi@glatzor.de
-
-	Push today's train ride outcome!
-
-2011-01-19  sebi@glatzor.de
-
-	Store the output of all progresses in the transaction. Add the output to the apport crash report. Furthermore raise an PACKAGE_MANAGER_FAILED error instead of an unknown error if the dpkg call failed.
-
-2011-01-19  sebi@glatzor.de
-
-	Respect the Dir::bin:DPkg and Dpkg::Options settings when launching dpkg.
-
-2011-01-18  sebi@glatzor.de
-
-	Push local changes!
-
-2011-01-18  sebi@glatzor.de
-
-	Update the test worker
-
-2011-01-18  sebi@glatzor.de
-
-	Move setting the transaction properties from the simulate results to the worker
-
-2011-01-18  sebi@glatzor.de
-
-	Reuse the processing code for simulating a transaction. Unify the install/remove/upgrade_packages methods to use commit_packages.
-
-2011-01-17  sebi@glatzor.de
-
-	Simualte and test fix_broken_depends transaction
-
-2011-01-17  sebi@glatzor.de
-
-	Allow to install packages with broken depends into the test chroot.
-
-2011-01-13  sebi@glatzor.de
-
-	Switch the worker test to unittest2 and skip the purge test, since it is known to fail.
-
-2011-01-13  sebi@glatzor.de
-
-	Skip the archives lock list if there isn't any internet connection
-
-2011-01-13  sebi@glatzor.de
-
-	Switch to unittest2 for test collection and discovery. Seems to handle apt_pkg better.
-
-2011-01-13  sebi@glatzor.de
-
-	Add the process and path to the LockFailedError message.
-
-2011-01-13  sebi@glatzor.de
-
-	Call apt_pkg.init in the lock module to make sure using the correct pathes
-
-2011-01-13  sebi@glatzor.de
-
-	Replace sys path modification by a symlink
-
-2011-01-13  sebi@glatzor.de
-
-	Add a tests for the locking mechanisms.
-
-2011-01-13  sebi@glatzor.de
-
-	Add missing spaces to error messages. Thanks, Adnane Belmadiaf
-
-2011-01-13  sebi@glatzor.de
-
-	Merge mvo's fixes for the cache open progress! Thanks!
-
-2011-01-12  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	make the cache-open progress emit the signal and add test for it
-
-2011-01-12  sebi@glatzor.de
-
-	Don't capture the logging in tests by default
-
-2011-01-12  sebi@glatzor.de
-
-	Make the tests work again (except of the trans chaining one). Allow to launch the tests by setup.py. Add a test for the worker.
-
-2011-01-12  sebi@glatzor.de
-
-	Fix clearing apt_pkg config values in the utils
-
-2011-01-12  sebi@glatzor.de
-
-	Allow to add a prefix to the chroot path and reset the root dir and status file config in the apt configuration during clean up
-
-2011-01-12  sebi@glatzor.de
-
-	Make sure to reset the status file in future status test.
-
-2011-01-12  sebi@glatzor.de
-
-	Use the tests dir location helper in the debconf test
-
-2011-01-12  sebi@glatzor.de
-
-	Add a small helper to detect the path to the tests direcotry. Allows to launch each test by file or by a global collector, e.g. nose.
-
-2011-01-12  sebi@glatzor.de
-
-	Adapt future status test to latest API
-
-2011-01-12  sebi@glatzor.de
-
-	Don' start the debugger on test failures. Disable non working test coverage
-
-2011-01-12  sebi@glatzor.de
-
-	Temporarilly disable the transaction chain tests. Require a running aptdaemon
-
-2011-01-10  sebi@glatzor.de
-
-	Remove no longer needed test for dpkg_journal_clean. It is now part of python-apt
-
-2011-01-10  sebi@glatzor.de
-
-	Use a real chroot for the dbus type test
-
-2011-01-10  sebi@glatzor.de
-
-	Move all chroot related methods to a separate class utils.Chroot
-
-2011-01-10  sebi@glatzor.de
-
-	Add a wrapper to run dpkg with fakeroot
-
-2011-01-10  sebi@glatzor.de
-
-	Move the chroot creation to a separate module for easier reuse
-
-2011-01-10  sebi@glatzor.de
-
-	Add a test for the aptworker
-
-2011-01-10  sebi@glatzor.de
-
-	Add a test repo with the silly packages
-
-2011-01-07  sebi@glatzor.de
-
-	Move test folder to project root
-
-2011-01-07  sebi@glatzor.de
-
-	Use UTF8Strings
-
-2011-01-12  sebi@glatzor.de
-
-	The sizes in the ProgressDownload are now of type long - following the API
-	changes in APT. Therefor the signature of the ProgressDownload struct
-	changed to "ssxxs".
-
-2011-01-05  sebi@glatzor.de
-
-	The sizes in the ProgressDownload are now of type long - following the API
-	changes in APT. Therefor the signature of the ProgressDownload struct
-	changed to "ssxxs".
-
-2010-12-21  sebi@glatzor.de
-
-	Make sure to convert the content of dbus structs correctly. The dbus bindinges don't seem to enforce the types speficed in the signature of the struct.
-
-2011-01-10  Martin Pitt  <martin@piware.de>
-
-	gtk3widgets.py: Make work with GTK2, too
-	
-	- Rename variables which are GObject properties, as with GTK2-gi they are not
-	writable.
-	- Work around GTK2 Gdk.WMFunction enum bug.
-	- Drop GTK 3 requirement from gtk3-demo.py, as it now also works with 2.
-
-2011-01-09  Martin Pitt  <martin@piware.de>
-
-	aptdaemon/gtk3widgets.py: When using GTK 2, import the correct Vte GIR version
-
-2011-01-09  Martin Pitt  <martin@piware.de>
-
-	gtk3widgets.py: Put back AptTerminal class, now that vte has a GTK3 GIR
-
-2010-12-14  sebi@glatzor.de
-
-	Merge lp:~mvo/aptdaemon/python-apt-0.8
-
-2010-12-13  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/progress.py: python-apt 0.8 does not call with percent argument anymore
-
-2010-12-14  sebi@glatzor.de
-
-	Push local changes
-
-2010-12-14  sebi@glatzor.de
-
-	Allow to change the packages property of a transaction. Set the packages correctly if installing localfiles.
-
-2010-12-14  sebi@glatzor.de
-
-	Fix two small errors: self.trans isn't used in simulate. Error messages have to be converted to string, since the replace method in the gettext call
-
-2010-12-14  sebi@glatzor.de
-
-	Run lintian as the user who initiated the transaction using sudo instead of root
-
-2010-12-13  sebi@glatzor.de
-
-	White space fixes
-
-2010-12-10  sebi@glatzor.de
-
-	Fix: Don't inject empty string in the packages and dependency property. We now set the signature.
-
-2010-12-10  sebi@glatzor.de
-
-	Update NEWS
-
-2010-12-10  sebi@glatzor.de
-
-	Convert properties to the documented dbus types before emitting: Dependencies, Packages, MetaData, ProgressDownload, UnattendedUpgrades.
-	
-	Fix documentation of ProgressDownload (missing status message) and typo in ConfigFileConflict.
-
-2010-12-10  sebi@glatzor.de
-
-	Add support for nested structures and aptdaemon properties to the type check.
-
-2010-12-09  sebi@glatzor.de
-
-	Convert values of transaction properties to the final dbus type in the setter calls.
-
-2010-12-09  sebi@glatzor.de
-
-	Add a test to check if the correct types are emitted by the dbus daemon
-
-2010-12-09  sebi@glatzor.de
-
-	Fix minor spelling error in documentation
-
-2010-12-07  sebi@glatzor.de
-
-	Push local changes
-
-2010-12-07  sebi@glatzor.de
-
-	Call the __init__ of gobject.GObject instead of the Gtk class one in subclasses
-
-2010-12-07  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: do not raise if there is no aptdaemon translation for the given locale
-
-2010-12-07  sebi@glatzor.de
-
-	Merge GTK3 support. Thanks a lot Martin!
-
-2010-12-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	Use new style classes for the GTK(2|3) demo class
-
-2010-12-06  Sebastian Heinlein  <devel@glatzor.de>
-
-	GTK3: call the __init__ method of the parent class instead the one of gobject.Gobject
-
-2010-12-06  sebi@glatzor.de
-
-	Merge with trunk
-
-2010-12-02  Martin Pitt  <martin@piware.de>
-
-	remove workaround for GNOME#636043, fixed now
-
-2010-11-30  Martin Pitt  <martin@piware.de>
-
-	Fix NEWS entry
-
-2010-11-30  Martin Pitt  <martin@piware.de>
-
-	gtk3widgets.py: Put back text tagging
-
-2010-11-29  Martin Pitt  <martin@piware.de>
-
-	gtk3widgets.py: Do not wrap title label in AptConfirmDialog, looks ugly
-
-2010-11-29  Martin Pitt  <martin@piware.de>
-
-	Port gtk3widgets.py and gtk3-demo.py to GTK-3.0 and gobject-introspection
-
-2010-11-27  Martin Pitt  <martin@piware.de>
-
-	create gtk3-demo.py and gtk3widgets.py as copies of gtk-demo.py and gtkwidgets.py (will be ported next)
-
-2010-11-27  Martin Pitt  <martin@piware.de>
-
-	core.py: Fix documentation of "packages" property
-
-2010-12-04  sebi@glatzor.de
-
-	Don't fail if an error string contains a % but doesn't make use of string replacements.
-
-2010-12-04  sebi@glatzor.de
-
-	Push local changes
-
-2010-12-04  sebi@glatzor.de
-
-	Fix transfering the force parameter in the install file call. Furthermore reuse could between simualte and the actual function.
-
-2010-11-22  sebi@glatzor.de
-
-	Store the exception in the error property of the transaction. It allows to easily raise it again.
-
-2010-11-18  sebi@glatzor.de
-
-	Release 0.40
-
-2010-11-18  sebi@glatzor.de
-
-	Push local changes
-
-2010-11-18  sebi@glatzor.de
-
-	Update NEWS
-
-2010-10-26  sebi@glatzor.de
-
-	Fix localtion of the lists lock
-
-2010-10-22  sebi@glatzor.de
-
-	Don't use unnamed arguments in string formating of ngettext calls. Thanks David!
-
-2010-10-22  sebi@glatzor.de
-
-	Use gettext domain in policy file
-
-2010-10-22  sebi@glatzor.de
-
-	Raise invalid package file error if the Installed-Size is invalid
-
-2010-10-22  sebi@glatzor.de
-
-	Add a force option to InstallFile which allows to install packages which violate the Debian/Ubuntu policy.
-
-2010-10-22  sebi@glatzor.de
-
-	Use lintian to check local deb file before installing
-
-2010-10-22  sebi@glatzor.de
-
-	Add two new error enums to handle unreadable and invalid package files
-
-2010-10-21  sebi@glatzor.de
-
-	Add a desktop file to show a nicer error message in apport
-
-2010-10-21  sebi@glatzor.de
-
-	Use the Crash type
-
-2010-10-21  sebi@glatzor.de
-
-	Remove passwords from the sources list in crash reports
-
-2010-10-21  sebi@glatzor.de
-
-	Send custom error reports to Launchpad with additional information about the transaction and the apt configuration.
-
-2010-10-20  sebi@glatzor.de
-
-	Fix more variable names
-
-2010-10-20  sebi@glatzor.de
-
-	Fix variable name
-
-2010-10-20  sebi@glatzor.de
-
-	Fix gettext call
-
-2010-10-20  sebi@glatzor.de
-
-	Code cleanup with a little help from my friend pylint
-
-2010-10-20  sebi@glatzor.de
-
-	More pylint clean ups
-
-2010-10-20  sebi@glatzor.de
-
-	More pylint fixes!
-
-2010-10-20  sebi@glatzor.de
-
-	A lot of code improvements and bug fixes thanks to pylint!
-
-2010-10-19  sebi@glatzor.de
-
-	Be more robust in the installed-size conversion
-
-2010-10-19  sebi@glatzor.de
-
-	Push local changes
-
-2010-10-19  sebi@glatzor.de
-
-	Fix thousands commas in debian packages.
-
-2010-10-18  sebi@glatzor.de
-
-	Add documentation for daemon properties
-
-2010-10-08  sebi@glatzor.de
-
-	Push local changes.
-
-2010-10-08  sebi@glatzor.de
-
-	Move plugin documentation to sphinx
-
-2010-10-08  sebi@glatzor.de
-
-	Add a new privilege to change the APT config
-
-2010-10-07  sebi@glatzor.de
-
-	Update NEWS
-
-2010-10-07  sebi@glatzor.de
-
-	Allow to change apt configuration files!
-
-2010-10-07  sebi@glatzor.de
-
-	Use the new ConfigWriter to allow persistent changes of the apt configuration!
-
-2010-10-07  sebi@glatzor.de
-
-	Convert the value to string, check if a value needs to be changed at all. Use logging for logging.
-
-2010-10-07  sebi@glatzor.de
-
-	Add a set_value mehtod to the configuration writer.
-
-2010-10-07  sebi@glatzor.de
-
-	Add test for the configuration parser
-
-2010-10-07  sebi@glatzor.de
-
-	Move parsing of the configuration file to a separate method. Use a Value class which stores the coordinates of the value in the config file.
-
-2010-10-05  sebi@glatzor.de
-
-	Add a basic APT configuration parser.
-
-2010-10-01  sebi@glatzor.de
-
-	Allow to read and change the popcon participation using a property of the org.debian.apt interface
-
-2010-10-01  sebi@glatzor.de
-
-	Move properties support to a more generic DBusObject class
-
-2010-10-01  sebi@glatzor.de
-
-	Push local changes
-
-2010-10-01  sebi@glatzor.de
-
-	Add properties to the org.debian.apt interface to configure apt peridoic
-
-2010-09-30  sebi@glatzor.de
-
-	Add a transaction to reconfigure already installed packages using debconf.
-
-2010-09-29  sebi@glatzor.de
-
-	Add a new transaction to clean up the downloaded package files.
-
-2010-09-28  sebi@glatzor.de
-
-	Remove the defer argument in the chained exampled
-
-2010-09-28  sebi@glatzor.de
-
-	Add documentation for the unauthenticated property
-
-2010-09-28  sebi@glatzor.de
-
-	Include the chained.py example in the documentation
-
-2010-09-28  sebi@glatzor.de
-
-	Merge changes from the stable branch
-
-2010-09-28  sebi@glatzor.de
-
-	release 0.33
-
-2010-09-28  sebi@glatzor.de
-
-	Merge latest translation updates! Thanks a lot to all the translators!
-
-2010-09-28  sebi@glatzor.de
-
-	Update documentation
-
-2010-09-28  sebi@glatzor.de
-
-	If the lists are locked by e.g. apt-get update raise an error lock error instead of a "programming error". The locking was reworked in the trunk branch.
-
-2010-09-28  sebi@glatzor.de
-
-	Push local changes
-
-2010-09-28  sebi@glatzor.de
-
-	Merge michaels changes with some small adoptions. Thanks a lot!
-
-2010-09-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	make "unauthenticated" property fully work
-
-2010-09-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add unauthenticated property
-
-2010-09-27  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/enums.py: show correct error text when a key can not be installed (copy/paste error in the source)
-
-2010-09-27  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: do not crash if sys.stdin.encoding returns None
-
-2010-09-18  sebi@glatzor.de
-
-	Fix gettext string - thanks gabor!
-
-2010-09-27  sebi@glatzor.de
-
-	Push train ride work
-
-2010-09-27  sebi@glatzor.de
-
-	Fix property signatures in the documentation. minor improvements to the dbus doc
-
-2010-09-27  sebi@glatzor.de
-
-	Inject the properties into the xml introspection data
-
-2010-09-27  sebi@glatzor.de
-
-	Be more strict with the type of the properties
-
-2010-09-25  sebi@glatzor.de
-
-	Document the use of PolicyKit and properties. Many minor doc fixes.
-
-2010-09-24  sebi@glatzor.de
-
-	Push local changes
-
-2010-09-24  sebi@glatzor.de
-
-	More documentation fixes.
-
-2010-09-24  sebi@glatzor.de
-
-	Fix references in the documentation
-
-2010-09-24  sebi@glatzor.de
-
-	Improve setup.py
-
-2010-09-22  sebi@glatzor.de
-
-	More documentation ...
-
-2010-09-21  sebi@glatzor.de
-
-	only release all locks if one of them failed and not always.
-
-2010-09-21  sebi@glatzor.de
-
-	Upload today's train work
-
-2010-09-21  sebi@glatzor.de
-
-	Even more documentation in reStructuredText
-
-2010-09-21  sebi@glatzor.de
-
-	Copy a deb file which is located on a gvfs (FUSE) directory to /tmp before
-	installing, since root is not allowed to access it.
-
-2010-09-20  sebi@glatzor.de
-
-	Rework locking: Lock the lists too. During an installation the lock on the archives/lists is still hold and we only unlock the dpkg status. This should fix races between apt-get and aptdaemon.
-
-2010-09-17  sebi@glatzor.de
-
-	Small refractoring: move the get_lock_fd method to the module level
-
-2010-09-17  sebi@glatzor.de
-
-	Refractor the lock module: move the lock holder name detection to a separate method
-
-2010-09-17  sebi@glatzor.de
-
-	Update NEWS
-
-2010-09-17  sebi@glatzor.de
-
-	Merge the auth-later branch which moves the authentication to the run method
-	of the transaction. This allows to simulate transaction without having to authenticate.
-
-2010-09-13  sebi@glatzor.de
-
-	Set authentication and running state for the transaction
-
-2010-09-13  sebi@glatzor.de
-
-	Add a new status STATUS_AUTHENTICATING
-
-2010-09-13  sebi@glatzor.de
-
-	Convert CommitPackages to use the _create_trans helper
-
-2010-09-13  sebi@glatzor.de
-
-	Remove the action argument from the _create_trans helper
-
-2010-09-13  sebi@glatzor.de
-
-	Require authentication at running the transaction and not on creation
-
-2010-09-13  sebi@glatzor.de
-
-	Do not export a removed privilege
-
-2010-09-17  sebi@glatzor.de
-
-	Fix package argument for (Remove|Install|Upgrade)Packages
-
-2010-09-17  sebi@glatzor.de
-
-	Fixes to the async wait statement: It should only return the exit state instead of the transaction. Furthermore disconnect the signal handler for the finished signal if the transaction has been completed.
-
-2010-09-17  sebi@glatzor.de
-
-	Merge with 0.3 branch
-
-2010-09-16  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/client.py: ensure that deferred_wait.callback() is called only once (the subsequent one will raise anyway). this can happen e.g. when AptClient.get_transaction() is called, this will sync the properties and lead to the "finished" signal getting emited again
-
-2010-09-16  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: remove unneeded inline_callbacks decorator
-
-2010-09-16  sebi@glatzor.de
-
-	Allow to purge already removed packages which still have config files left on the system.
-
-2010-09-16  sebi@glatzor.de
-
-	Fix looping logic in the client to fix a combined wait and sync call e.g.
-	
-	client.install_packages(["angi"])
-
-2010-09-15  sebi@glatzor.de
-
-	Fix wrong wait default value for enable_distro_component - thanks mvo
-
-2010-09-15  sebi@glatzor.de
-
-	Set STATUS_WAITING if a transaction is queued.
-
-2010-09-11  sebi@glatzor.de
-
-	Merge with stable branch
-
-2010-09-10  sebi@glatzor.de
-
-	Fix local dpkg installation from unicode pathes by converting the strings to UTF-8
-
-2010-09-10  sebi@glatzor.de
-
-	Fix mapping of the Transaction error property. Set the default error code to "" since we now use strings as enums.
-
-2010-09-10  sebi@glatzor.de
-
-	Remove obsolete defer arguments
-
-2010-09-10  sebi@glatzor.de
-
-	Cherry pick automatic deferreds in the deferable decorator.
-
-2010-09-09  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: allow enums.ROLE_ADD_VENDOR_KEY_FROM_KEYSERVER as well for INSTALL_PURCHASED_PACKAGES
-
-2010-09-09  sebi@glatzor.de
-
-	Fix a typo
-
-2010-09-09  sebi@glatzor.de
-
-	Fix queuing the after transactions
-
-2010-09-09  sebi@glatzor.de
-
-	defer: fix missing warnings import
-
-2010-09-09  sebi@glatzor.de
-
-	handle a non available traceback in the inline_callbacks
-
-2010-09-09  sebi@glatzor.de
-
-	Merge the auth me less branch!
-
-2010-09-09  sebi@glatzor.de
-
-	Fix allowing every non high level transaction.
-
-2010-09-09  sebi@glatzor.de
-
-	Add an example script
-
-2010-09-09  sebi@glatzor.de
-
-	Modify the auth-me-less patch to accept the new privileges
-
-2010-09-09  sebi@glatzor.de
-
-	Add new privileges install-packages-from-new-repo and install-purchased-packages
-
-2010-09-09  sebi@glatzor.de
-
-	Apply auth-me-less patch
-
-2010-09-09  sebi@glatzor.de
-
-	Revert some accidental changes to the policykit1 module
-
-2010-09-09  sebi@glatzor.de
-
-	Update NEWS
-
-2010-09-09  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: if sources_list for a partial cache update is not a absolute path, use dir::etc::sourceparts
-
-2010-09-09  sebi@glatzor.de
-
-	Merge the update-cache-partially branch
-
-2010-09-09  sebi@glatzor.de
-
-	Update documentation
-
-2010-09-09  sebi@glatzor.de
-
-	Add the sources_list as an optional argument to client.AptClient.update_cache.
-
-2010-09-09  sebi@glatzor.de
-
-	Add a new method UpdateCachePartially() to the org.debian.apt D-Bus interface which allows to update only the repositories from a given sources.list snippet.
-
-2010-09-09  sebi@glatzor.de
-
-	Don't fail if LC_ALL cannot be unset
-
-2010-09-08  sebi@glatzor.de
-
-	There isn't any need to unset LC_ALL in the console client
-
-2010-09-08  sebi@glatzor.de
-
-	Don't set the textdomain in the gtkwidgets (this overwrite's the domain of
-	the application importing the module). Thanks mvo! Fixes LP:#631675
-
-2010-09-04  sebi@glatzor.de
-
-	Cherry pick from stable branch
-
-2010-09-04  sebi@glatzor.de
-
-	Fix: Also add CommitPackages transactions to the limbo
-
-2010-09-04  sebi@glatzor.de
-
-	Fix a wrong reference to the defer module
-
-2010-09-04  sebi@glatzor.de
-
-	Fix: export new role enums and add documentation string
-
-2010-09-04  sebi@glatzor.de
-
-	Merge with stable and update documentation
-
-2010-09-04  sebi@glatzor.de
-
-	Update NEWS
-
-2010-09-04  sebi@glatzor.de
-
-	Merge with make-trans branch.
-
-2010-09-04  sebi@glatzor.de
-
-	Make AddRepository and EnableDistroComp transaction based
-
-2010-09-04  sebi@glatzor.de
-
-	Add a small example on how to use transaction chaining
-
-2010-09-04  sebi@glatzor.de
-
-	Merge stable branch and update documentation
-
-2010-09-03  sebi@glatzor.de
-
-	Push local merge of run_After branch
-
-2010-09-03  sebi@glatzor.de
-
-	Merge the run_after branch 
-
-2010-09-03  sebi@glatzor.de
-
-	Add a test for chaining of transactions
-
-2010-09-03  sebi@glatzor.de
-
-	Fix an arg rename 
-
-2010-09-03  sebi@glatzor.de
-
-	Add a new RunAfter method to the transaction which allows to chain transactions. It is only required to call the Run method on the first transaction in the chain. If a transaction in the chain fails all other one which follow will fail too with the new exit state EXIT_PREVIOUS_FAILED.
-
-2010-09-03  sebi@glatzor.de
-
-	Add a new exit state to indicate if a transaction failed because of a previously chained one.
-
-2010-09-03  sebi@glatzor.de
-
-	Enhance the DummyWorker to have transaction which fail or succeed automatically.
-	Furthermore set the transaction of the worker to none after before emitting the transaction-done signal.
-
-2010-09-03  sebi@glatzor.de
-
-	Let the update_cache and upgrade_system transaction fail in the dummy worker for testing
-
-2010-09-03  sebi@glatzor.de
-
-	Add a limbo to keep track of not yet queued transactions
-
-2010-09-03  sebi@glatzor.de
-
-	Send the transaction object instead of only its tid to the queue after completing
-
-2010-08-31  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	data/org.debian.apt.policy.in: add missing gettext prefixes
-
-2010-09-04  sebi@glatzor.de
-
-	New reStructuredText documentation for AptTransaction
-
-2010-09-03  sebi@glatzor.de
-
-	Fix spelling errors in aptdaemon.enums.__all__
-
-2010-09-02  sebi@glatzor.de
-
-	Add a short introduction to the usage of the client module
-
-2010-09-02  sebi@glatzor.de
-
-	Fix sections
-
-2010-09-02  sebi@glatzor.de
-
-	Strip white spaces from signal parameters
-
-2010-09-02  sebi@glatzor.de
-
-	Big beautification and documentation update of the enums module.
-
-2010-09-01  sebi@glatzor.de
-
-	Add a new signal directive to the sphinx documentation
-
-2010-08-27  sebi@glatzor.de
-
-	Cherry pick from stable
-
-2010-08-27  sebi@glatzor.de
-
-	Allow set the transaction of the AptCancelButton later
-
-2010-08-26  sebi@glatzor.de
-
-	Adapt docstrings to sphinx for the org.debian.apt interface
-
-2010-08-26  sebi@glatzor.de
-
-	Add a basic sphinx-based documentation
-
-2010-08-25  sebi@glatzor.de
-
-	Merge from stable branch
-
-2010-08-25  sebi@glatzor.de
-
-	Fix __all__ of lock
-
-2010-08-25  sebi@glatzor.de
-
-	Fix defer imports
-
-2010-08-25  sebi@glatzor.de
-
-	Remove defer module from aptdaemon project
-
-2010-08-25  sebi@glatzor.de
-
-	Merge changes from the stable branch
-
-2010-08-25  sebi@glatzor.de
-
-	Lock the cache before running fix incomplete install
-
-2010-08-25  sebi@glatzor.de
-
-	Move the locking to a separte module to get a SystemLock singelton. Furthermore use this to keep the apt system locked during downloading. Fixes LP #616470
-
-2010-08-25  sebi@glatzor.de
-
-	Try to fix an incomplete install instead of failing
-
-2010-08-25  sebi@glatzor.de
-
-	Use an unkown progress range for dpkg operations by default
-
-2010-08-25  sebi@glatzor.de
-
-	Handle unkown progress better. Emit an unkown progress for dpkg operations instead of 0
-
-2010-08-25  sebi@glatzor.de
-
-	Translate messages in the progress to the lang of the transaction
-
-2010-08-25  sebi@glatzor.de
-
-	Add plural gettext to the transaction
-
-2010-08-25  sebi@glatzor.de
-
-	Merge stable changes
-
-2010-08-24  sebi@glatzor.de
-
-	Give the user more time to authenticate - to be exactly a whole day - fixes LP#623424
-
-2010-08-24  sebi@glatzor.de
-
-	Actually only a fake _ function is required in worker. the translation itself is performed by the Transaction instance later on.
-
-2010-08-24  sebi@glatzor.de
-
-	A lot of work just to translate a short string.
-
-2010-08-24  sebi@glatzor.de
-
-	Forward port changes from the stable branch
-
-2010-08-24  sebi@glatzor.de
-
-	Merge local changes
-
-2010-08-24  sebi@glatzor.de
-
-	Don't construct a list in the arguments spec
-
-2010-08-24  sebi@glatzor.de
-
-	Call missed Exception.__init__ in LockFailedError
-
-2010-08-24  sebi@glatzor.de
-
-	Remove add-or-remove-vendor-key privilege and use change-repository instead
-
-2010-08-24  sebi@glatzor.de
-
-	Merge local changes
-
-2010-08-24  sebi@glatzor.de
-
-	Use with statement for the actiongroup
-
-2010-08-23  sebi@glatzor.de
-
-	Forward port changes from the stable branch
-
-2010-08-23  sebi@glatzor.de
-
-	Clean up news
-
-2010-08-23  sebi@glatzor.de
-
-	Add a small suggestion in the docs to use the system-wide proxy instead of set-proxy
-
-2010-08-23  sebi@glatzor.de
-
-	Don't reuse the user's proxy by default in the gtkwidgets. The system proxy should be used instead.
-
-2010-08-23  sebi@glatzor.de
-
-	Fix a small typo
-
-2010-08-23  sebi@glatzor.de
-
-	Adapt aptd to the changed privileges
-
-2010-08-23  sebi@glatzor.de
-
-	Allow every active user to update the cache
-
-2010-08-23  sebi@glatzor.de
-
-	Require to auth every time to cancel a foreign transaction
-
-2010-08-23  sebi@glatzor.de
-
-	Require an admin to authenticate every time a proxy should be set. If a user wants to use a custom proxy it should be set as the system wide.
-
-2010-08-23  sebi@glatzor.de
-
-	Remove upgrade-system privilege. upgrade-packages should be used instead
-
-2010-08-23  sebi@glatzor.de
-
-	Merge add- and remove-vendor-key privileges
-
-2010-08-23  sebi@glatzor.de
-
-	Remove install-packages, remove-packages and fix privilege in favour of the new install-or-remove-packages
-
-2010-08-23  sebi@glatzor.de
-
-	Merge changes from the high-level-pk branch without the high level logic :)
-
-2010-08-22  sebi@glatzor.de
-
-	Add a new high level privilege install-or-remove
-
-2010-08-22  sebi@glatzor.de
-
-	Make the AuthorizationFailed error an inheritance of NotAuthorizedError
-
-2010-08-22  sebi@glatzor.de
-
-	Raise an AuthorizationFailed exception in a non-interactive check if the 
-	user could obtain the privilege in interactive-mode (is_challenged)
-
-2010-08-22  sebi@glatzor.de
-
-	Forward port changes from stable branch
-
-2010-08-21  sebi@glatzor.de
-
-	Workaround a bug in optparser which doesn't handle unicode/str correctly, see http://bugs.python.org/issue4391
-	
-	Fixes LP:#613147
-
-2010-08-21  sebi@glatzor.de
-
-	Unset LC_ALL to get translations from APT, fixes LP:#620978
-
-2010-08-21  sebi@glatzor.de
-
-	Cherry pick: fix translation of console client
-
-2010-08-20  sebi@glatzor.de
-
-	Cherry pick language fixes
-
-2010-08-21  sebi@glatzor.de
-
-	Allow to translate messages from aptdcon
-
-2010-08-21  sebi@glatzor.de
-
-	Allow to translate TransactionFailed errors in the worker by using a gettext translation instance for each transaction.
-
-2010-08-20  sebi@glatzor.de
-
-	Merge language fixes from mpt thanks!
-
-2010-08-17  Matthew Paul Thomas  <mpt@canonical.com>
-
-	Adds a missing word.
-
-2010-08-17  Matthew Paul Thomas  <mpt@canonical.com>
-
-	Alters PolicyKit text to put the task at the start of the sentence.
-
-2010-08-17  Matthew Paul Thomas  <mpt@canonical.com>
-
-	Miscellaneous spelling and grammar fixes.
-
-2010-08-13  sebi@glatzor.de
-
-	Fix the version splitting
-
-2010-08-12  sebi@glatzor.de
-
-	Merge version branch: Allow to select version of packages and downgrades.
-	
-	ATTENTION: API break in CommitPackages which now requires an additional downgrades argument.
-
-2010-08-12  sebi@glatzor.de
-
-	Add --details option to the console client to show version information of to be changed packages
-
-2010-08-12  sebi@glatzor.de
-
-	Fix not defined names
-
-2010-08-12  sebi@glatzor.de
-
-	Format version information in GTK confirmation dialog
-
-2010-08-12  sebi@glatzor.de
-
-	Break API and add a downgrade argument to CommitPackages.
-
-2010-08-12  sebi@glatzor.de
-
-	Show the version number in the dependencies
-
-2010-08-12  sebi@glatzor.de
-
-	Allow to specify the to be installed/removed version of package. The package
-	name and version are separated by "=", e.g. "xterm=258-1". The CommitPackage 
-	method allows to downgrade packages by reinstalling a package with a former 
-	version number
-
-2010-08-05  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/client.py: make sure we have a _signal_matcher before we delete it
-
-2010-08-05  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: only check _cache if its not None (it will be None for transactions like add-vendor-key-from-keyserver
-
-2010-07-21  sebi@glatzor.de
-
-	Merge local changes
-
-2010-07-20  sebi@glatzor.de
-
-	Update NEWS
-
-2010-07-20  sebi@glatzor.de
-
-	Introduce a new privilege org.debian.apt.set-proxy which allows to specify a proxy server for a transaction. By default this is granted to every active user.
-
-2010-07-18  sebi@glatzor.de
-
-	Introduce errors.PolicyKitError which is used as a parent class for NotAuthorizedError and AuthorizationFailed. Use the new error class in the console client.
-
-2010-07-17  sebi@glatzor.de
-
-	Only Raise the AuthorizationError if the auth request was interactive
-
-2010-07-17  sebi@glatzor.de
-
-	Raise the AuthorizationFailed error if there isn't any polkit agent who could authenticate the user
-
-2010-07-17  sebi@glatzor.de
-
-	Fix a wrong variable reference - LP #602091
-
-2010-07-17  sebi@glatzor.de
-
-	Update translations from Launchpad
-
-2010-07-17  sebi@glatzor.de
-
-	Add a warning to convert_dbus_exception that it requires introspection.
-
-2010-07-17  sebi@glatzor.de
-
-	Don't use any introspection to detect the existance of the reply_handler and error_handler arguments in the decorated function. Nested decorators won't keep the calling signature.
-
-2010-07-17  sebi@glatzor.de
-
-	Rename deferable_function to deferable
-
-2010-07-15  sebi@glatzor.de
-
-	Fix missing textdomain in the gtkwidgets
-
-2010-07-14  sebi@glatzor.de
-
-	Only ask for confirmation of changes in the console client if there are any
-
-2010-07-14  sebi@glatzor.de
-
-	Add an error string for the new download enum from the previous commit
-
-2010-07-14  sebi@glatzor.de
-
-	Workaround a bug in python-apt: The StatTransientNetworkError status isn't
-	mapped
-
-2010-07-14  sebi@glatzor.de
-
-	Fix a wrong reference in the previous commit
-
-2010-07-14  sebi@glatzor.de
-
-	Stop the idle watcher if the transaction has been simulated, to give the user enough time to review the changes.
-
-2010-07-14  sebi@glatzor.de
-
-	Don't try to simulate adding a key from a keyserver
-
-2010-07-14  sebi@glatzor.de
-
-	Unlock the cache before updating
-
-2010-07-14  sebi@glatzor.de
-
-	Update NEWS file
-
-2010-07-14  sebi@glatzor.de
-
-	More status and pulse information in the worker
-
-2010-07-14  sebi@glatzor.de
-
-	Merge an enhanced lp:~mvo/aptdaemon/download-vendor-keys
-
-2010-07-14  sebi@glatzor.de
-
-	Don't require a cache for the key handling
-
-2010-07-14  sebi@glatzor.de
-
-	Update man page of aptdcon
-
-2010-07-14  sebi@glatzor.de
-
-	Document the new method in the man page
-
-2010-07-14  sebi@glatzor.de
-
-	Emit status and pulse
-
-2010-07-14  sebi@glatzor.de
-
-	Show the stout of the apt-key call in the error message. Minor cleanups
-
-2010-07-14  sebi@glatzor.de
-
-	Merge from mvo
-
-2010-06-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	move add_vendor_key_from_keyserver from gio to subprocess.call() because gio-http does not work with uid == 0
-
-2010-06-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add aptdcon support, fix typos
-
-2010-06-24  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add downlaod key feature using gio
-
-2010-07-11  sebi@glatzor.de
-
-	Fix imports in the defer test
-
-2010-07-10  sebi@glatzor.de
-
-	core: Fixes to the sender watch
-
-2010-07-10  sebi@glatzor.de
-
-	defer: Fix a typo
-
-2010-07-10  sebi@glatzor.de
-
-	defer: Fix deferrable decorator which required a set reply_handler and error_handler to be tiggered. But we only want to check if the function supports both arguments. Furthermore make sure to return a DeferredException to the error callback.
-
-2010-07-10  sebi@glatzor.de
-
-	client: Convert a DeferredException in the initialisation of the transaction to a normal exception
-
-2010-07-09  sebi@glatzor.de
-
-	Keep track of the initial client of a transaction
-
-2010-07-09  sebi@glatzor.de
-
-	Use a dist upgrade by default in the gtk demo
-
-2010-07-09  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: EnableDistroComponent does not return a boolean value, if it fails it will raise a exception
-
-2010-07-09  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/gtkwidgets.py: on a delete event (eg. from user pressing ESC) behave as if cancel was clicked
-
-2010-07-06  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/test/test_defer.py: add tests for defer.inline_callbacks
-
-2010-07-06  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add README.tests and import unittest aptdaemon/test/test_defer.py
-
-2010-06-08  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: fix incorrect argument passed in self._add_repository()
-
-2010-06-08  sebi@glatzor.de
-
-	Merge local changes
-
-2010-06-08  sebi@glatzor.de
-
-	Make sure that we only try to convert DBusExceptions
-
-2010-06-08  sebi@glatzor.de
-
-	Show uri of download as tooltip and improve the description
-
-2010-06-08  sebi@glatzor.de
-
-	Remove a temp debconf socket
-
-2010-06-05  sebi@glatzor.de
-
-	Merge local changes
-
-2010-06-05  sebi@glatzor.de
-
-	Import the whole defer module in the client
-
-2010-06-05  sebi@glatzor.de
-
-	Workaround a bug in python-apt which reports the partial download size as 0 in the done callback, see LP: #589941
-
-2010-06-03  sebi@glatzor.de
-
-	Remove an obsolete debugging statement
-
-2010-06-03  sebi@glatzor.de
-
-	Fix a missing enums prefix
-
-2010-06-02  sebi@glatzor.de
-
-	Use inline callbacks and Deferreds to reimplement the _run_transaction code in the AptClient. This gives us support for the wait arguement, simplifies code and reduces complexity.
-
-2010-06-01  sebi@glatzor.de
-
-	Replace * import of enums in the core
-
-2010-05-31  sebi@glatzor.de
-
-	Fix an enum typo
-
-2010-05-31  sebi@glatzor.de
-
-	Set the debconf frontend and http proxy in AptTransactionProgress.run instead
-	of in AptTransactionProgress.set_transaction and make use of inline callbacks
-
-2010-05-30  sebi@glatzor.de
-
-	make the progress dialog only resizable if the expander is activated. try to restore the previous size of the expanded dialog
-
-2010-05-30  sebi@glatzor.de
-
-	Show the sub progress of the downloads in the gtkwidgets!
-
-2010-05-27  sebi@glatzor.de
-
-	Set the transaction status to STATUS_FINISHED before sending the Finished signal. The client stops listening after the finished signal and so missed the final status update.
-
-2010-05-27  sebi@glatzor.de
-
-	Fix typo in STATUS_DOWNLOADING
-
-2010-05-27  sebi@glatzor.de
-
-	Fix download size of an item by using the information from the worker
-
-2010-05-27  sebi@glatzor.de
-
-	Add support for download progress information
-
-2010-05-27  sebi@glatzor.de
-
-	Fix a type in the error handling of gtk-demo
-
-2010-05-27  sebi@glatzor.de
-
-	Fix arguments in the UpgradePackages call
-
-2010-05-25  sebi@glatzor.de
-
-	Fix a segfault in the error conversion.
-
-2010-05-25  sebi@glatzor.de
-
-	Allow to convert all client methods into Deferreds by using the deferable_function.
-
-2010-05-25  sebi@glatzor.de
-
-	Add deferable_function decorator which adds a defer attribute to the
-	decorated function. If defer is True return a Deferred and map the 
-	reply_handler and error_handler of the function to the callback and 
-	errback of the Deferred. This allows to write deferred DBus clients easily.
-
-2010-05-25  sebi@glatzor.de
-
-	Allow to override the objects and icons shown in AptConfirmDialog
-
-2010-05-23  sebi@glatzor.de
-
-	Minor improvements to logging and loading of plugins
-
-2010-05-22  sebi@glatzor.de
-
-	Update NEWS
-
-2010-05-22  sebi@glatzor.de
-
-	Port and make use of Twisted inline_callbacks! This makes the async code much
-	more readable.
-
-2010-05-22  sebi@glatzor.de
-
-	Use inline callbacks in policykit1
-
-2010-05-22  sebi@glatzor.de
-
-	Port the core daemon to inline callbacks
-
-2010-05-22  sebi@glatzor.de
-
-	Adapt the inline_callbacks to the stripped down deferreds
-
-2010-05-22  sebi@glatzor.de
-
-	Copy inline callbacks from twisted
-
-2010-05-21  sebi@glatzor.de
-
-	Add a plugin system! Allows to modify the marked changes of a transaction.
-
-2010-05-16  sebi@glatzor.de
-
-	Respect the MIT license of twisted
-
-2010-05-14  sebi@glatzor.de
-
-	Remove old future status files
-
-2010-05-03  sebi@glatzor.de
-
-	Add a new line between package name and summary in the confirm dialog
-
-2010-05-03  sebi@glatzor.de
-
-	Add a small script to prepare a new release
-
-2010-05-03  sebi@glatzor.de
-
-	Catch possilbe segfaults in the DiffView
-
-2010-05-03  sebi@glatzor.de
-
-	Also add all for gtkwidgets
-
-2010-05-03  sebi@glatzor.de
-
-	Use __all__ to get a more fine grained control of the api
-
-2010-05-03  sebi@glatzor.de
-
-	gtk-demo: Fix aborting of the transaction if it doesn't contain any dependencies 
-
-2010-05-03  sebi@glatzor.de
-
-	Fix a small bug in the client handling of the error property.
-
-2010-05-02  sebi@glatzor.de
-
-	Merge patch from Ubuntu which allows to EnableDistroComponents
-
-2010-05-02  sebi@glatzor.de
-
-	Add a new enum to mark a transaction as not yet finished
-
-2010-05-02  sebi@glatzor.de
-
-	Update man page of the transaction interface
-
-2010-05-02  sebi@glatzor.de
-
-	Fix a macro in the man page
-
-2010-04-27  sebi@glatzor.de
-
-	Let the Confirmation dialog accpet a gtk.gdk.Window as parent and fix some errors in the previous commit
-
-2010-04-27  sebi@glatzor.de
-
-	Fix an indention error
-
-2010-04-27  sebi@glatzor.de
-
-	Wording changes in the confirmation dialog
-
-2010-04-27  sebi@glatzor.de
-
-	Change the layout of the confirmation dialog depending on the number of packages to show to avoid useless white space.
-
-2010-04-27  sebi@glatzor.de
-
-	Use strings instead of integers for the Exit, Role, Status and Error properties and the Finished signal of the D-Bus Transaction.
-
-2010-04-25  sebi@glatzor.de
-
-	Change order of error and reply handler in AptTransaction.run to be in sync with the other moethods
-
-2010-04-25  sebi@glatzor.de
-
-	Fix args handling in the convert_dbus_exception callback: the args are a tuple
-	and not a list. furthermore replace the value in the args instead of moving
-	it to the kwargs (otherwise we would change the order of args)
-
-2010-04-25  sebi@glatzor.de
-
-	Improve error handling in the GTK demo
-
-2010-04-25  sebi@glatzor.de
-
-	Update NEWS
-
-2010-04-25  sebi@glatzor.de
-
-	Move policykit error into the errors module
-
-2010-04-25  sebi@glatzor.de
-
-	Fix error conversion
-
-2010-04-25  sebi@glatzor.de
-
-	Update api changes in the NEWS
-
-2010-04-25  sebi@glatzor.de
-
-	TransactioNFailed conversion fixes. You should not overwrite the __str__ of 
-	a DBusException
-
-2010-04-25  sebi@glatzor.de
-
-	Use the convert_dbus_exception decorator in the client
-
-2010-04-25  sebi@glatzor.de
-
-	Rename AptdaemonError to AptDaemonError for readability reasons :)
-
-2010-04-25  sebi@glatzor.de
-
-	Remove client.AptDaemonError and use a errors.TransactionFailed error instead
-	for the client.AptTransaction.error attribute
-
-2010-04-25  sebi@glatzor.de
-
-	Remove duplicated checks if the transaction was already running
-
-2010-04-25  sebi@glatzor.de
-
-	Rename APTDError to AptdaemonError for pure aesthetic reasons
-
-2010-04-25  sebi@glatzor.de
-
-	Add a decorator which converts DBus exception to native ones.
-
-2010-04-24  sebi@glatzor.de
-
-	Raise corectly in the simulate method
-
-2010-04-23  sebi@glatzor.de
-
-	Fix small typo
-
-2010-04-23  sebi@glatzor.de
-
-	Set the status of the transaction during simulate to STATUS_RESOLVING_DEP
-
-2010-04-23  sebi@glatzor.de
-
-	Only allow to call simulate on a not yet started transaction
-
-2010-04-23  sebi@glatzor.de
-
-	Merge the future status branch! This adds dependency handling by also taking queued transactions into accout to aptdaemon!
-
-2010-04-23  sebi@glatzor.de
-
-	Use the new simulate/confirm in the gtk demo
-
-2010-04-23  sebi@glatzor.de
-
-	Add a new AptConfirmDialog which allows to confirm the dependencies of a transaction
-
-2010-04-20  sebi@glatzor.de
-
-	Reuse the fixed DaemonOpenProgress again in the worker.
-
-2010-04-20  sebi@glatzor.de
-
-	Do not ierate on the main loop during sensible actions like opening the cache or forking. This could lead to a cache race with the transaction simulation
-
-2010-04-20  sebi@glatzor.de
-
-	Use the same order in Transaction.packages and Transaction.depends and extend depends accordingly. Use the new enums.
-
-2010-04-20  sebi@glatzor.de
-
-	Add an enum for the package group index in the Transaction.depends and Transaction.packages lists
-
-2010-04-20  sebi@glatzor.de
-
-	Worker: Check for skipped updates in the simulation
-
-2010-04-19  sebi@glatzor.de
-
-	Improve status messages in the console client
-
-2010-04-18  sebi@glatzor.de
-
-	WORKER: Fix local install by unlocking the cache
-
-2010-04-18  sebi@glatzor.de
-
-	Worker: Show the package file as install if not installed before and as reinstall in the other case
-
-2010-04-18  sebi@glatzor.de
-
-	Console: Fix packages order
-
-2010-04-18  sebi@glatzor.de
-
-	Core: Fix packages signal (copy paste error)
-
-2010-04-18  sebi@glatzor.de
-
-	Console: Fix transaction confirmation
-
-2010-04-18  sebi@glatzor.de
-
-	Console: Allow to install package files by --install PATH
-
-2010-04-18  sebi@glatzor.de
-
-	Worker: Add Support for simulating file installs
-
-2010-04-18  sebi@glatzor.de
-
-	CORE: Allow to modify the packages attribute of a transaction after creation
-
-2010-04-18  sebi@glatzor.de
-
-	CORE: set the idle timeout of a transaction to 5 minutes
-
-2010-04-18  sebi@glatzor.de
-
-	CORE: Use seconds for the timeout
-
-2010-04-18  sebi@glatzor.de
-
-	CONSOLE: Add full-upgrade and safe-upgrade options (see aptitude)
-
-2010-04-18  sebi@glatzor.de
-
-	CONSOLE: take APT::Get::Assume-Yes into account
-
-2010-04-18  sebi@glatzor.de
-
-	CONSOLE: make use of ngettext for the package listing
-
-2010-04-18  sebi@glatzor.de
-
-	Fix showing the download size
-
-2010-04-18  sebi@glatzor.de
-
-	Accept return as yes
-
-2010-04-18  sebi@glatzor.de
-
-	Remove some blank lines in the console client to safe screen space
-
-2010-04-18  sebi@glatzor.de
-
-	Do not show changes for some transaction roles, e.g. update cache
-
-2010-04-18  sebi@glatzor.de
-
-	Use the private transaction property
-
-2010-04-18  sebi@glatzor.de
-
-	Check if upgrades are already installed
-
-2010-04-18  sebi@glatzor.de
-
-	Allow to cancel the simulate call in the console client
-
-2010-04-18  sebi@glatzor.de
-
-	Make use of simulate in the console client!
-
-2010-04-18  sebi@glatzor.de
-
-	Add support for the server core and the client side!
-
-2010-04-18  sebi@glatzor.de
-
-	Add reinstalls to the dependencies
-
-2010-04-18  sebi@glatzor.de
-
-	A lot of fixes in the future status creation
-
-2010-04-18  sebi@glatzor.de
-
-	Future test improvements: The transaction requires now a tid, test if the future cache is broken, add some informative messages to the fails
-
-2010-04-17  sebi@glatzor.de
-
-	Check for broken packages and incomplete installations in simulate
-
-2010-04-17  sebi@glatzor.de
-
-	Add a small logging info
-
-2010-04-17  sebi@glatzor.de
-
-	Always open the cache for the processing with the original status file. Disable daemonopenprogress temporarily since there could be a race condition with simulate
-
-2010-04-17  sebi@glatzor.de
-
-	Move is_dpkg_journal_clean and lock_pkg_system to the AptWorker class to make sure that the original status file is used.
-
-2010-04-17  sebi@glatzor.de
-
-	Add a unit test for the simulating
-
-2010-04-17  sebi@glatzor.de
-
-	Add exception handling to simulate
-
-2010-04-17  sebi@glatzor.de
-
-	Fix _cache reference in the worker and rename simulate
-
-2010-04-17  sebi@glatzor.de
-
-	Fix an obsolete else statement
-
-2010-04-17  sebi@glatzor.de
-
-	Only handle package management transaction. Special case for upgrade system
-
-2010-04-17  sebi@glatzor.de
-
-	Add a simulate transaction method to the worker
-
-2010-04-23  sebi@glatzor.de
-
-	Fix a small typo
-
-2010-04-17  sebi@glatzor.de
-
-	Fix emitting of finished signal in dummy worker
-
-2010-04-16  sebi@glatzor.de
-
-	Do not allow to remove aptdaemon, essential or required packages.
-
-2010-04-01  sebi@glatzor.de
-
-	Allow to specify authorization flags to policykit
-
-2010-04-01  sebi@glatzor.de
-
-	Add a better description for the unkown error
-
-2010-04-01  sebi@glatzor.de
-
-	Merge release update of 0.20
-
-2010-04-01  sebi@glatzor.de
-
-	Merge translation updates
-
-2010-04-01  sebi@glatzor.de
-
-	Cherry pick error handling fix in the client
-
-2010-04-01  sebi@glatzor.de
-
-	Push local changes
-
-2010-04-01  sebi@glatzor.de
-
-	Fix a typo. Thanks to Dave Walker.
-
-2010-03-31  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	cherry pick fix from the 0.2.x branch for incorrect return value of AddRepository
-
-2010-03-30  sebi@glatzor.de
-
-	Push local changes
-
-2010-03-30  sebi@glatzor.de
-
-	Merge proposed changes from Julian Andres Klode to finalize API transition
-
-2010-03-29  sebi@glatzor.de
-
-	Match for the Template and not the Name
-
-2010-03-26  sebi@glatzor.de
-
-	Allow to specify custom input values for debconf tests
-
-2010-03-26  sebi@glatzor.de
-
-	Fix some minor issues in the previous commit
-
-2010-03-26  sebi@glatzor.de
-
-	Make the debconf test helper methods more general and use gobject.spawn_async instead of python's subprocess. It seems that child_add_watch won't be called in some rare situations.
-
-2010-03-24  sebi@glatzor.de
-
-	Add tests for serial and concurrent debconf operations to catch races.
-
-2010-03-24  sebi@glatzor.de
-
-	Add a unittest for the debconf forwarding
-
-2010-03-21  sebi@glatzor.de
-
-	Debconf Handling: Run the io handlers as long as possible and close the stdin/out and connection in the corresponding io handlers instead of in a central hangup script. Furthermore delay a new connection until the former has been closed.
-
-2010-03-17  sebi@glatzor.de
-
-	Fix a typo in the recover progress
-
-2010-03-17  sebi@glatzor.de
-
-	Raise prioriy of the _hangup callback. This should make sure it's executed before accept_connection
-
-2010-03-17  sebi@glatzor.de
-
-	Minor code clean up in the debcon module
-
-2010-03-17  sebi@glatzor.de
-
-	Stop reading from the debconf socket after closing it.
-
-2010-03-17  sebi@glatzor.de
-
-	Merge dpkg journal check fixes. Thanks MVO!
-
-2010-03-17  sebi@glatzor.de
-
-	Use str.isdigit() instead of a regex
-
-2010-03-16  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/test/test_dpkg_journal.py: improve is_dpkg_journal_clean() tests
-
-2010-03-16  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: make dpkg journal test match the test in apt
-
-2010-02-21  sebi@glatzor.de
-
-	Merge local changes
-
-2010-02-21  sebi@glatzor.de
-
-	Cherry pick documentation updates from main
-
-2010-02-28  sebi@glatzor.de
-
-	Do not try to process a package management task which doesn't contain any
-	changes
-
-2010-02-21  sebi@glatzor.de
-
-	Update documentation of the Python client module
-
-2010-02-10  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merge typo fix from 0.2.x
-
-2010-02-10  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: fix typo
-
-2010-02-10  sebi@glatzor.de
-
-	Port to the latest python-apt 0.7.9x API
-
-2010-01-13  sebi@glatzor.de
-
-	Allow to remove obsoleted automatic depedencies, by introducing a new transaction property RemoveObsoletedDepends. Thanks to mvo for the initial work!
-
-2010-01-13  sebi@glatzor.de
-
-	Update NEWS file
-
-2010-01-13  sebi@glatzor.de
-
-	Show the output of the dpkg --configure -a call also in the error message after a failed transaction.
-
-2010-01-08  sebi@glatzor.de
-
-	Some transaction don't require a consistent dep cache
-
-2010-01-08  sebi@glatzor.de
-
-	Update man pages
-
-2010-01-08  sebi@glatzor.de
-
-	Fix cache unlocking
-
-2010-01-08  sebi@glatzor.de
-
-	Add a FixBrokenDepends method
-
-2010-01-08  sebi@glatzor.de
-
-	Add a FixIncompleteInstall method to run dpkg --configure -a and fix the unlocking of the cache.
-
-2010-01-08  sebi@glatzor.de
-
-	Add a new polkit action to fix apt
-
-2010-01-08  sebi@glatzor.de
-
-	Rename enum ERROR_INCOMPLETE_INSTALLS to ERROR_INCOMPLETE_INSTALL and add a new role enum ROLE_FIX_INCOMPLETE_INSTALL
-
-2010-01-08  sebi@glatzor.de
-
-	Move the locking and checking of the dpkg journal to separate standalone methods.
-
-2010-01-08  sebi@glatzor.de
-
-	Add a new error enum for incomplete dpkg configure runs.
-
-2010-01-07  sebi@glatzor.de
-
-	Use a shorter waiting status message and show the package manager we are waiting for if the lock cannot be obtained. Fixes LP:444261 
-
-2009-12-16  sebi@glatzor.de
-
-	Push local changes
-
-2009-12-16  sebi@glatzor.de
-
-	Add an ored true to the dbus send hook for the post cache update
-
-2009-12-15  sebi@glatzor.de
-
-	Add a new set of strings to get a failed message by role
-
-2009-12-14  sebi@glatzor.de
-
-	Allow to call the run method of the AptProgressDialog async
-
-2009-12-14  sebi@glatzor.de
-
-	Add a finished signal to AptProgressDialog
-
-2009-12-13  sebi@glatzor.de
-
-	Add failed downloads to the exception and and don't fail on not available Packages.diffs
-
-2009-12-13  sebi@glatzor.de
-
-	Rename aptdaemon-setup icon to aptdaemon-working and use it as a general fallback icon
-
-2009-12-12  sebi@glatzor.de
-
-	Fix handling of changed ProgressDetails in the client
-
-2009-12-12  sebi@glatzor.de
-
-	Use the new raiseOnError paramter of apt.Cache.update()
-
-2009-12-12  sebi@glatzor.de
-
-	Don't fail on temporily not available master fd
-
-2009-12-12  sebi@glatzor.de
-
-	Fix handling of reposnse from conflict dialog 
-
-2009-12-12  sebi@glatzor.de
-
-	Use a shorter message in the conflict dialog and change button order
-
-2009-12-12  sebi@glatzor.de
-
-	minor improvements to the medium change dialog. 
-
-2009-12-12  sebi@glatzor.de
-
-	Add an enahnced TextView which shows the changes between two files and a dialog with an expander. Make use of both in the config file conflict dialog.
-
-2009-12-12  sebi@glatzor.de
-
-	Fix a typo in the logging of ProvideMedium
-
-2009-12-12  sebi@glatzor.de
-
-	Speed up dummy transaction
-
-2009-12-12  sebi@glatzor.de
-
-	Add a config file prompt and a medium change request to the dummy installation
-
-2009-12-11  sebi@glatzor.de
-
-	Fix: Sync all properties - even empty strings and zeros
-
-2009-12-11  sebi@glatzor.de
-
-	There isn't any need to wrap the sync call in get_transaction since it already returns the transaction instance
-
-2009-12-11  sebi@glatzor.de
-
-	Fix use of lambda in async client methods
-
-2009-12-10  sebi@glatzor.de
-
-	Allow to store meta data in the transaction
-
-2009-12-09  sebi@glatzor.de
-
-	Emit some status messages in the dummy worker and speed up the processing
-
-2009-12-09  sebi@glatzor.de
-
-	Add --dummy command line option which only shows a progress for the transaction without applying any changes
-
-2009-12-09  sebi@glatzor.de
-
-	Fix a typo
-
-2009-12-09  sebi@glatzor.de
-
-	Allow to call get_transaction async
-
-2009-12-08  sebi@glatzor.de
-
-	Fix transaction without any package changes
-
-2009-12-08  sebi@glatzor.de
-
-	Push local changes
-
-2009-12-08  sebi@glatzor.de
-
-	Update NEWS
-
-2009-12-08  sebi@glatzor.de
-
-	Make the packages property of the transaction public.
-
-2009-12-08  sebi@glatzor.de
-
-	Fine grain logging levels. Log INFO to syslog
-
-2009-12-07  sebi@glatzor.de
-
-	Don't segfault on not supported locale
-
-2009-12-07  sebi@glatzor.de
-
-	Man page updates
-
-2009-12-07  sebi@glatzor.de
-
-	Install D-Bus interface documentation
-
-2009-12-07  sebi@glatzor.de
-
-	Add a man page for the transaction interface
-
-2009-12-07  sebi@glatzor.de
-
-	Merge local changes
-
-2009-12-07  sebi@glatzor.de
-
-	Update man page of main interface
-
-2009-12-07  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/progress.py: fix minor typo
-
-2009-12-07  sebi@glatzor.de
-
-	Add a small sleep time after quiting an already running daemon to give D-Bus enough time to clean up the taken D-Bus names.
-
-2009-12-07  sebi@glatzor.de
-
-	Update the NEWS
-
-2009-12-07  sebi@glatzor.de
-
-	Rename aptdaemon.client.Transaction.detach() to disconnect
-
-2009-12-07  sebi@glatzor.de
-
-	Also remove attach method from the client side
-
-2009-12-07  sebi@glatzor.de
-
-	Remove deprecated Attach method on the Transaction interface. GetAll properties should be used instead. The sync method of the client transaction does a better job.
-
-2009-12-07  sebi@glatzor.de
-
-	handle properties more carefully on the client side. Handle invalid/cleared values in Finished, ConfigFileConflcit and RequiredMedium. Fix emitting of http-propxy-changed-signal
-
-2009-12-07  sebi@glatzor.de
-
-	Use sane defaults for the transaction properties
-
-2009-12-07  sebi@glatzor.de
-
-	Update NEWS
-
-2009-12-07  sebi@glatzor.de
-
-	Missed a renamed method in the gtkwidgets
-
-2009-12-07  sebi@glatzor.de
-
-	Rename config file prompt to config file conflict and answer to resolve/resolution
-
-2009-12-07  sebi@glatzor.de
-
-	The role of the transaction is now known on creation time. So show it early in the gtk widgets
-
-2009-12-07  sebi@glatzor.de
-
-	Shutdown the console client if there isn't any transaction on cancel
-
-2009-12-07  sebi@glatzor.de
-
-	Paradigma change: instead of requesting a transaction and calling a package mangement task, the action is called on the daemon interface which returns a not yet running transaction. After setting up the client has to call the new Run method of the transaction.
-
-2009-12-06  sebi@glatzor.de
-
-	Add a man page for the dbus interface
-
-2009-12-05  sebi@glatzor.de
-
-	Remove depreacted signals
-
-2009-12-05  sebi@glatzor.de
-
-	Fix man page path
-
-2009-12-05  sebi@glatzor.de
-
-	Fix a comma
-
-2009-12-05  sebi@glatzor.de
-
-	Fix a missing bracket
-
-2009-12-05  sebi@glatzor.de
-
-	Merge local changes
-
-2009-12-05  sebi@glatzor.de
-
-	Install man pages
-
-2009-12-05  sebi@glatzor.de
-
-	Add man pages for aptd and aptdcon
-
-2009-12-04  sebi@glatzor.de
-
-	Fix a typo
-
-2009-12-04  sebi@glatzor.de
-
-	Merge http proxy support from mvo with some small changes. Thanks mvo!
-
-2009-12-04  sebi@glatzor.de
-
-	Merge http proxy support from mvo with some small changes. Thanks!
-
-2009-10-09  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	* aptdaemon/client.py:
-	- add set_http_proxy() method to the transaction
-	* aptdaemon/core.py:
-	- add new dbus Property "HttpProxy"
-	* aptdaemon/gtkwidgets.py:
-	- setup http proxy from gconf automatically
-	* data/org.debian.apt.policy.in:
-	- change from "allow_active" "yes" to "auth_admin_keep"
-	The reasons is that now that a unpriviledged user can
-	set a proxy this may leak passwords from sources.list
-	(deb http://user:pass@machine/) when a rouge proxy is set
-
-2009-12-03  sebi@glatzor.de
-
-	Remove bzr-buildpackage configuration
-
-2009-12-03  sebi@glatzor.de
-
-	Rename TerminalAttachable to TerminalAttached
-
-2009-12-03  sebi@glatzor.de
-
-	Update TODO
-
-2009-12-03  sebi@glatzor.de
-
-	Merge properties branch: The API changes are documented in the NEWS file
-
-2009-12-03  sebi@glatzor.de
-
-	Add a NEWS file which contains a description of the latest API changes
-
-2009-12-03  sebi@glatzor.de
-
-	Add a TODO file
-
-2009-12-03  sebi@glatzor.de
-
-	Convert PyGTK demo to latest API
-
-2009-12-03  sebi@glatzor.de
-
-	Fix a variable typo
-
-2009-12-03  sebi@glatzor.de
-
-	Convert gtkwidgets to latest API
-
-2009-12-03  sebi@glatzor.de
-
-	Code clean up in the console module
-
-2009-12-03  sebi@glatzor.de
-
-	Code clean up of the client module
-
-2009-12-03  sebi@glatzor.de
-
-	Convert console application to latest API
-
-2009-12-03  sebi@glatzor.de
-
-	Add true async support to all AptDaemonClient and Transaction methods by adding
-	reply_handler and error_handler. Furthermore replace the exit_handler by a 
-	not yet implemented wait argument.
-
-2009-12-02  sebi@glatzor.de
-
-	Use a tuple instead of a list for dbus variant
-
-2009-12-02  sebi@glatzor.de
-
-	Export locale, terminal, allow_unauthenticated and debconf socket to the
-	Transaction properties
-
-2009-12-02  sebi@glatzor.de
-
-	Port console client to the new API
-
-2009-12-02  sebi@glatzor.de
-
-	Fix TerminalAttachable signal in the client
-
-2009-12-02  sebi@glatzor.de
-
-	Only emit the new value in PropertyChanged
-
-2009-12-02  sebi@glatzor.de
-
-	Adopt Cancellable and TerminalAttachable in the client
-
-2009-12-02  sebi@glatzor.de
-
-	Rename transaction property AllowCancel to Cancellable and AllowTerminal to 
-	TerminalAttachable
-
-2009-12-02  sebi@glatzor.de
-
-	Remove Message concept. It is not up to the daemon to judge if a problem is critical or not. It is up to the client to decide if a not uptodate system is critical.
-
-2009-12-02  sebi@glatzor.de
-
-	Only listen to the PropertyChanged signal of the transaction interface
-
-2009-12-01  sebi@glatzor.de
-
-	Make all properties available through the dbus properties interface, rename ExitCode to ExitState and ErrorCode to Error
-
-2009-12-01  sebi@glatzor.de
-
-	Add an additional PropertyChanged signal to most signals
-
-2009-12-01  sebi@glatzor.de
-
-	Small fix setting of role
-
-2009-12-01  sebi@glatzor.de
-
-	New line fixes
-
-2009-12-01  sebi@glatzor.de
-
-	Add a PropertyChanged signal to the transaction interface
-
-2009-11-30  sebi@glatzor.de
-
-	Import latest translations from Ubuntu
-
-2009-11-30  sebi@glatzor.de
-
-	Fix detection of running D-Bus system daemon in the apt update hook
-
-2009-11-30  sebi@glatzor.de
-
-	Apply Julian's fix for Python 2.5 support. Thanks.
-
-2009-11-18  sebi@glatzor.de
-
-	Fix path in the service file
-
-2009-10-14  sebi@glatzor.de
-
-	Fix po file naming
-
-2009-10-13  sebi@glatzor.de
-
-	Trival coding style fix
-
-2009-10-13  sebi@glatzor.de
-
-	Import translations from Launchpad - fixes LP #445603 
-
-2009-10-13  sebi@glatzor.de
-
-	If the cache refresh was cancelled do not show a download failed error - fixes LP #440941
-
-2009-10-12  sebi@glatzor.de
-
-	Merge fix for killing randomly user processes on long taking dpkg operations - fixes LP #446534 
-
-2009-10-12  sebi@glatzor.de
-
-	Make sure that we only start killing processes if the child pid is set
-
-2009-10-12  sebi@glatzor.de
-
-	Set the child pid correctly - LP #446534 
-
-2009-10-12  sebi@glatzor.de
-
-	Update last activity - partitally fixes LP #446534 
-
-2009-10-09  sebi@glatzor.de
-
-	Merge latest changes from mvo
-
-2009-10-06  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: move default log level for _syslog_handler into the try: except: block
-
-2009-10-06  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged from trunk/
-
-2009-10-06  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: try locking the download dir too in _lock_cache
-
-2009-10-04  sebi@glatzor.de
-
-	Fix a copy%paste error
-
-2009-10-04  sebi@glatzor.de
-
-	Merge with mvo's allow unauthencticated branch! Thanks a lot!
-
-2009-10-04  sebi@glatzor.de
-
-	Use a list instead of a set to store not authenticated packages
-
-2009-10-04  sebi@glatzor.de
-
-	Replace UnauthenticatedPackageError by a transaction error
-
-2009-10-04  sebi@glatzor.de
-
-	Merge with main
-
-2009-09-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add AllowUnauthenticated property
-
-2009-10-04  sebi@glatzor.de
-
-	Fix handling of cancelled transactions
-
-2009-10-04  sebi@glatzor.de
-
-	Handle failed dependency resolution and make sure all requested package operations are performed by protecting the corresponding packages
-
-2009-10-04  sebi@glatzor.de
-
-	Do not make any assumptions about the user interface in the error enum
-
-2009-10-04  sebi@glatzor.de
-
-	Rename ERROR_DEPENDENCIES_BROKEN to ERROR_DEP_RESOLUTION_FAILED
-
-2009-10-04  sebi@glatzor.de
-
-	Introduce a new error enum: ERROR_CACHE_BROKEN, since this should be handled separately from broken dependencies during e.g. an installation
-
-2009-10-04  sebi@glatzor.de
-
-	If packages are broken attach the names to the error message. Furthermore make use of new apt.cache.Cache.broken_count
-
-2009-10-04  sebi@glatzor.de
-
-	Make use of apt.cache.Cache.actiongroup to avoid calling the private _depcache
-
-2009-10-04  sebi@glatzor.de
-
-	Replace the nested main loop in the AptProgressDialog by an iteration on the default context. Furthermore call the Transaction.run method async to avoid blocking the user interface - fixes LP #426720
-
-2009-10-04  sebi@glatzor.de
-
-	Allow the Transaction.run client method to be called async. This currently results in a small mess - but retains API compatibility
-
-2009-10-04  sebi@glatzor.de
-
-	Add the deprecated decorator from the python decorator library
-
-2009-10-03  sebi@glatzor.de
-
-	Don't ask for upgrade privilege if the user already has got the install privilge in CommitPackages - fixes LP #437094
-
-2009-10-03  sebi@glatzor.de
-
-	Trivial line length fix
-
-2009-10-03  sebi@glatzor.de
-
-	Catch authorization errors in the console client and print an error message instead of crashing
-
-2009-10-03  sebi@glatzor.de
-
-	Merge a lot of bug fixes from mvo's branch. Thanks a lot.
-
-2009-10-02  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/debconf.py: fix race in _accept_connection() LP: #432607
-
-2009-10-02  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/client.py: add the _owner_watcher earlier to avoid crash if no more match rules from dbus can be used
-
-2009-09-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/enums.py: do not modify gettext.textdomain(), use dgettext("aptdaemon", msg) instead (LP: #438077)
-
-2009-09-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/worker.py: check the apt download dir lock in _watch_lock to avoid possible race with apt-get LP: #437709
-
-2009-09-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/progress.py: fix crash in error handling (LP: #436808)
-
-2009-09-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/progress.py: fix crash in INSTALL_TIMEOUT handling (LP: #430860)
-
-2009-09-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/gtkwidgets.py: make the dialog resizable and add bigger default size
-
-2009-09-28  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: add _remove_from_connection_no_raise() that will discard errors if the object is not exported
-
-2009-09-26  sebi@glatzor.de
-
-	Do not fail on a not running syslog daemon
-
-2009-09-22  sebi@glatzor.de
-
-	Merge logging branch
-
-2009-09-22  sebi@glatzor.de
-
-	Buffer the output from dpkg and attach it to an error message
-
-2009-09-22  sebi@glatzor.de
-
-	Catch an exception in the forked child
-
-2009-09-22  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: allow reseting of Transaction.config_file_prompt without triggering a signal
-
-2009-09-22  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/progress.py: remove setting --force-confdef, --force-confold
-
-2009-09-22  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: errors.AptDError got renamed to errors.APTDError, update the code
-
-2009-09-22  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/client.py: fix order of the arguments to match what core.py expectes
-
-2009-09-21  sebi@glatzor.de
-
-	Allow to cancel a running transaction in the console client - fixes LP# 424436
-
-2009-09-21  sebi@glatzor.de
-
-	Lower the log level of the "Shutdown was requested message" to not confuse users - se LP #432937
-
-2009-09-21  sebi@glatzor.de
-
-	Only send the dbus chace changed signal in the apt update post hook if the system dbus is running. Fixes LP #432310
-
-2009-09-18  sebi@glatzor.de
-
-	Merge logging branch
-
-2009-09-18  sebi@glatzor.de
-
-	Don't raise exceptions in the progress - fixes LP #428964
-
-2009-09-18  sebi@glatzor.de
-
-	Merge bug fixes for the forking
-
-2009-09-17  sebi@glatzor.de
-
-	Do not sent log messages to the child console
-
-2009-09-17  sebi@glatzor.de
-
-	Copy_io should not fail if the target is not available. This allows to support crashed clients
-
-2009-09-17  sebi@glatzor.de
-
-	Return the correct exit status from the install progress
-
-2009-09-17  sebi@glatzor.de
-
-	Use os.forkpty instead the home brown child pty handling
-
-2009-09-18  sebi@glatzor.de
-
-	Merge config file conflicts support from the lovely mvo! Thanks.
-
-2009-09-18  sebi@glatzor.de
-
-	Handle config file prompt answers on the terminal
-
-2009-09-18  sebi@glatzor.de
-
-	Update the gtkwidgets to the latest api and use nicer buttons
-
-2009-09-18  sebi@glatzor.de
-
-	Update client to config file API change
-
-2009-09-18  sebi@glatzor.de
-
-	Only accept keep and replace values for the config file answer. Do not write the pure user string to the terminal
-
-2009-09-18  sebi@glatzor.de
-
-	Perform some checks in the ConfigFilePromptAnswer
-
-2009-09-17  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add configuration file prompt handling
-
-2009-09-17  sebi@glatzor.de
-
-	Merge fixes from mvo
-
-2009-09-17  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: fix duplicated check for foreign user
-
-2009-09-17  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	remove transaction cache (glatzor did a better one)
-
-2009-09-17  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/client.py: add missing MediumRequired signal connect
-
-2009-09-17  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merge from trunk
-
-2009-08-26  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged from trunk
-
-2009-08-26  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	revert r218
-
-2009-08-20  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merge from trunk
-
-2009-08-20  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	use utf8_strings by default
-
-2009-08-19  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/client.py: add dettach method and disconnect from the bus when a transaction is finished
-
-2009-08-19  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/client.py: add (simple) TransactionCache
-
-2009-09-17  sebi@glatzor.de
-
-	Introduce a new ERROR_PACKAGE_MANAGER_FAILED enum
-
-2009-09-17  sebi@glatzor.de
-
-	Use utf-8 strings in the client side signal matcher
-
-2009-08-29  devel@glatzor.de
-
-	Push local changes
-
-2009-08-29  devel@glatzor.de
-
-	Whitespace and tabs clean up
-
-2009-08-29  devel@glatzor.de
-
-	Set the term env var to "linux" to satisfy less.
-
-2009-08-29  devel@glatzor.de
-
-	Instead of failing on a locked dpkg wait until it is unlocked. Thanks mvo for this suggestion.
-
-2009-08-29  devel@glatzor.de
-
-	Catch an exception if the icon theme is None
-
-2009-08-27  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/client.py: fixup arguments for the dbus call if a empty components list is used
-
-2009-08-27  sebi@glatzor.de
-
-	Merge AddRepository feature from Michael Vogt. Thanks a lot!
-
-2009-08-26  devel@glatzor.de
-
-	Use the debline as argument for the add-repository option. Add a sanity check by using SourceEntry. Add an extra option to specify an alternative sources.list.d file.
-
-2009-08-27  sebi@glatzor.de
-
-	Minor code cleanup
-
-2009-08-27  sebi@glatzor.de
-
-	Fix GetTrustedVendorKeys call in the client
-
-2009-08-27  sebi@glatzor.de
-
-	Replace the add-repository privilege by a more general change-repository one
-
-2009-08-27  sebi@glatzor.de
-
-	Merge mvo's add repository branch
-
-2009-08-26  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: fix writing the sourcesfile 
-
-2009-08-26  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	* do not use a debline as argument for AddRepository() but use
-	a argument list like (type, uri, dist, comps, comment, sourcesfile)
-	instead
-
-2009-08-26  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	* aptdaemon/core.py:
-	- raise Exceptions on error instead of returning True, False
-	* aptdaemon/errors.py:
-	- add RepositoryAlreadyExistsError, RepositoryInvalidError
-
-2009-08-26  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	add new add-repository method
-
-2009-08-27  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/core.py: fix incorrect access to self.work (its now self.queue.worker) LP: #403467
-
-2009-08-21  sebi@glatzor.de
-
-	Fix upgrade in the console client
-
-2009-08-20  devel@glatzor.de
-
-	Stop monitoring the transaction on the D-Bus if it is finished
-
-2009-08-20  devel@glatzor.de
-
-	Cache transaction by their tid using a metaclass
-
-2009-08-20  sebi@glatzor.de
-
-	Merge local changes
-
-2009-08-19  devel@glatzor.de
-
-	Rename INACTIVITY_TIMEOUT and INACTIVITY_CHECK_INTERVALL to APTDAEMON_IDLE_*. Makes the difference to the transaction timeouts clearer
-
-2009-08-19  devel@glatzor.de
-
-	Remove transactions from the bus idling after creation or after beeing done
-
-2009-08-02  devel@glatzor.de
-
-	Push local changes: mainly PolicyKit-1 support
-
-2009-08-02  devel@glatzor.de
-
-	Rename CreateTransaction to RequestTransaction
-
-2009-08-02  devel@glatzor.de
-
-	Allow the client to decide if the methods should be run sync or async
-
-2009-08-02  devel@glatzor.de
-
-	Lower the policykit default timeout to 300 seconds
-
-2009-08-02  devel@glatzor.de
-
-	Merge PolicyKit1 branch
-
-2009-08-02  devel@glatzor.de
-
-	Remove never used import of policykit in gtkwidgets
-
-2009-08-02  devel@glatzor.de
-
-	Remove policykit calls from gtk example
-
-2009-08-02  devel@glatzor.de
-
-	Update setuptools
-
-2009-08-02  devel@glatzor.de
-
-	Use the PolicyKit-1 D-Bus API in the policykit module
-
-2009-08-02  devel@glatzor.de
-
-	Remove old policykit
-
-2009-08-02  devel@glatzor.de
-
-	Make use of new policykit api in the core daemon
-
-2009-08-02  devel@glatzor.de
-
-	Update policy definitions
-
-2009-08-02  devel@glatzor.de
-
-	PolicyKit wrapper isn't required anymore in the client
-
-2009-07-31  devel@glatzor.de
-
-	Use policykit1 action definitions
-
-2009-07-31  devel@glatzor.de
-
-	Convert to get_uid_from_dbus_name and modify _check_foreign_user
-
-2009-07-31  devel@glatzor.de
-
-	Start using policykit1 for CreateTransaction and only store the uid of the initial sender of the transaction.
-
-2009-07-31  devel@glatzor.de
-
-	We only need one D-Bus call now for PolicyKit!
-
-2009-07-31  devel@glatzor.de
-
-	Start on PolicyKit1 support using the deferreds only
-
-2009-07-30  sebi@glatzor.de
-
-	Merge local changes: Mainly replacing Twisted dependency with a local
-	stripped down defer mechanism
-
-2009-07-30  sebi@glatzor.de
-
-	Add policykit package to setup.py
-
-2009-07-30  sebi@glatzor.de
-
-	Merge the gobject branch: Add a stripped down version of Twisted's Deferreds
-	and replace all depedencies on Twisted.
-
-2009-07-30  sebi@glatzor.de
-
-	Add some ascii art to the documentation
-
-2009-07-30  sebi@glatzor.de
-
-	make use of the new _add_callbacks
-
-2009-07-30  sebi@glatzor.de
-
-	No need to iterate the gobject context in the test anymore
-
-2009-07-30  sebi@glatzor.de
-
-	Rename test for defer and replace some leftovers
-
-2009-07-30  sebi@glatzor.de
-
-	Remove some gdefer remainings in the doctests
-
-2009-07-30  sebi@glatzor.de
-
-	Remove all references to Twisted methods. Rename gdefer to defer and policykit.gdeferred to policykit.deferred. Call policykit.deferred directly without using the defer.defer wrapper.
-
-2009-07-30  sebi@glatzor.de
-
-	Port all Methods from twisted to gdefer
-
-2009-07-30  sebi@glatzor.de
-
-	Gdefer now is really a simplifed Twisted defer: Don't use gobject.idle_add
-	anymore. Add pairs of callback/errback to follow the chain processing of
-	Twisted.
-
-2009-07-30  sebi@glatzor.de
-
-	Trivial documentation fixes
-
-2009-07-30  sebi@glatzor.de
-
-	Convert Get and Set to gdefer
-
-2009-07-30  sebi@glatzor.de
-
-	Conver UpdateCache to gdefer
-
-2009-07-29  sebi@glatzor.de
-
-	Convert CommitPackages to gdefer
-
-2009-07-29  sebi@glatzor.de
-
-	Convert all policykit methods to the latest gdefer API
-
-2009-07-29  sebi@glatzor.de
-
-	Fix defer: make use of DeferredException. Fix dbus decorator: raise exception
-	after calling the dbus callback to ensure that the deferred does not continue
-	processing the callback chain
-
-2009-07-29  sebi@glatzor.de
-
-	Introduce DeferredException(s) and a lot more doctests
-
-2009-07-29  sebi@glatzor.de
-
-	Do not use errbacks in the chained callbacks test
-
-2009-07-28  sebi@glatzor.de
-
-	Merge local changes: Documentation and tests for gdefer
-
-2009-07-28  sebi@glatzor.de
-
-	Use nose as test suite and enable doctests
-
-2009-07-28  sebi@glatzor.de
-
-	Remove old test folder
-
-2009-07-28  sebi@glatzor.de
-
-	Rename gdefer test module
-
-2009-07-28  sebi@glatzor.de
-
-	Add documentation and doctests to gdefer
-
-2009-07-27  sebi@glatzor.de
-
-	Add Unittests for gdefer
-
-2009-07-23  sebi@glatzor.de
-
-	Adapt GetTrustedVendorKeys to the new gdefer
-
-2009-07-23  sebi@glatzor.de
-
-	Add a policykit module with gdefer support (Currently only is_authorized_sender is adapted)
-
-2009-07-23  sebi@glatzor.de
-
-	Add async Deferreds inspired by Twisted framework but using gobject directly
-
-2009-07-23  sebi@glatzor.de
-
-	Adapt rename of twisted policykit module
-
-2009-07-23  sebi@glatzor.de
-
-	Rename twisted module of policykit to tdeferred
-
-2009-07-23  sebi@glatzor.de
-
-	Rename dbus_deferred_method to dbus_twisted_method
-
-2009-07-23  sebi@glatzor.de
-
-	Rename policykit.deferred to policykit.twisted
-
-2009-07-23  sebi@glatzor.de
-
-	Fix a typo
-
-2009-07-22  sebi@glatzor.de
-
-	Revert the easy one deferred Set/Get methods 
-
-2009-07-22  sebi@glatzor.de
-
-	Use the gobject main loop instead of the reactor
-
-2009-07-22  sebi@glatzor.de
-
-	Add Vendor prefix to all key handling names
-
-2009-07-22  sebi@glatzor.de
-
-	Merge from Olof Kindgren: Support for trusted repo keys handling. Thanks a lot.
-
-2009-07-22  sebi@glatzor.de
-
-	Use deferreds in the key operations
-
-2009-07-22  sebi@glatzor.de
-
-	Call AptAuth directly instead of through the SoftwareProperties layer
-
-2009-07-22  sebi@glatzor.de
-
-	Merge main
-
-2009-07-09  Olof Kindgren  <olof@ubuntu-vb>
-
-	Fix some typos
-
-2009-07-09  Olof Kindgren  <olof@ubuntu-vb>
-
-	RemoveKey implemented. Typos fixed
-
-2009-07-09  Olof Kindgren  <olof@ubuntu-vb>
-
-	Merged from main branch
-
-2009-07-09  Olof Kindgren  <olof@ubuntu-vb>
-
-	Completed GetTrustedKeys (was ListTrustedKeys), code cleanup, restored i18n hints in policyfile
-
-2009-07-09  Olof Kindgren  <olof@ubuntu-vb>
-
-	Check for auth in ListTustedKeys
-
-2009-07-08  Olof Kindgren  <olof@lammy>
-
-	Added ListTrustedKeys without checking for authorization
-
-2009-07-08  Olof Kindgren  <olof@ubuntu-vb>
-
-	Error handling for add key. rough idea for list keys (if it is to be in daemon)
-
-2009-07-08  Olof Kindgren  <olof@ubuntu-vb>
-
-	Created error message when key file couldn't be installed
-
-2009-07-08  Olof Kindgren  <olof@ubuntu-vb>
-
-	Merge from main branch
-
-2009-07-07  Olof Kindgren  <olof@lammy>
-
-	install_repo_key_file implemented, without error handling
-
-2009-07-07  Olof Kindgren  <olof@lammy>
-
-	Added container logic for install repo key file
-
-2009-07-18  sebi@glatzor.de
-
-	Make use of dbus properties in the transaction object. Replace SetTerminal, SetDebconf and SetLocale by properties.
-
-2009-07-17  sebi@glatzor.de
-
-	Fix progress calculation in the install progress
-
-2009-07-17  sebi@glatzor.de
-
-	Allow to call nearly all policykit methods asynchromous
-
-2009-07-16  sebi@glatzor.de
-
-	Merge of the async branch: Make use of Twisted deferreds. This allows to handle async calls to policykit in a clean way.
-
-2009-07-16  sebi@glatzor.de
-
-	Use inline callbacks to simplify the code
-
-2009-07-14  sebi@glatzor.de
-
-	Fix: compare a possible policykit error with the modified dbus name
-
-2009-07-12  sebi@glatzor.de
-
-	Use deferreds in all DBus Transaction methods
-
-2009-07-12  sebi@glatzor.de
-
-	Add PolicyKit support mixed with Twisted deferreds
-
-2009-07-12  sebi@glatzor.de
-
-	Allow to compare Caller instances
-
-2009-07-11  sebi@glatzor.de
-
-	add an dbus exception that looks like the policykit error
-
-2009-07-11  sebi@glatzor.de
-
-	Move the policykit methods into a separate package
-
-2009-07-10  sebi@glatzor.de
-
-	If a deferred method returns at least None, ignore it
-
-2009-07-10  sebi@glatzor.de
-
-	Use twisted reactor instead of a pure gobject main loop and add the
-	deferred dbus method decorator from James Henstridge. Thanks!
-
-2009-07-09  sebi@glatzor.de
-
-	Add a small epilog to the apdtcon help indicating to use quotation marks to specify several package names
-
-2009-07-09  sebi@glatzor.de
-
-	Trivial: fix description of --remove option
-
-2009-07-09  sebi@glatzor.de
-
-	Trivial: tweak status information in the console client
-
-2009-07-09  sebi@glatzor.de
-
-	Show --- instead of an illegal progress percentage in the conosle client
-
-2009-07-09  sebi@glatzor.de
-
-	Show a spinner in the console client to indicate a running transaction
-
-2009-07-08  sebi@glatzor.de
-
-	dist-upgrade option of aptdcon doesn't require an argument
-
-2009-07-08  sebi@glatzor.de
-
-	Add a refresh-cache command to the cli command
-
-2009-07-07  sebi@glatzor.de
-
-	Remove obsolete import from console
-
-2009-07-07  sebi@glatzor.de
-
-	Add a status notifcation icon service which allows to attach to already running transactions.
-
-2009-07-07  sebi@glatzor.de
-
-	Rename GetTransactions to GetActiveTransactions and clean up
-
-2009-07-07  sebi@glatzor.de
-
-	Rename the TransactionQueueChanged signal to ActiveTransactionsChanged which also provides the tid of the currently running transaction and of all queued ones.
-
-2009-07-07  sebi@glatzor.de
-
-	Replace the AptWorker.busy by querying AptWorker.trans
-
-2009-07-07  sebi@glatzor.de
-
-	Move the worker to the queue and use direct calls to the worker to run a new transaction
-
-2009-07-07  sebi@glatzor.de
-
-	Fix the wrong progress type in the client signal which resulted in an always pulsing progress
-
-2009-07-07  sebi@glatzor.de
-
-	Remove the threaded decorator from the misc module
-
-2009-07-07  sebi@glatzor.de
-
-	Use a singelton main loop instead of forwarding the main loop of the daemon to
-	the progress instances.
-
-2009-07-07  sebi@glatzor.de
-
-	Do not use MANIFEST since it is additional work to keep in sync
-
-2009-07-07  sebi@glatzor.de
-
-	Remove TODO file and instead use bugs on Launchpad
-
-2009-07-07  sebi@glatzor.de
-
-	Use the gobject Transaction instead of the dbus interface in the console client
-
-2009-07-07  sebi@glatzor.de
-
-	Convert the client side AptTransaction to a gobject to handle a killed daemon 
-	in a better way
-
-2009-07-07  sebi@glatzor.de
-
-	Convert the ROLE_UNSET enum to an empty string
-
-2009-07-07  sebi@glatzor.de
-
-	Add an enum for a not yet set role
-
-2009-07-06  sebi@glatzor.de
-
-	Merge local changes
-
-2009-07-06  sebi@glatzor.de
-
-	Use a smaller step size in the progress dialog.
-
-2009-07-06  sebi@glatzor.de
-
-	Send an illegal progress (101) if the progress runs backwards
-
-2009-07-05  sebi@glatzor.de
-
-	Set the progress dialog as parent window for the medium required dialog
-
-2009-07-05  sebi@glatzor.de
-
-	Attach the transaction in get_transaction to fill it with data
-
-2009-07-05  sebi@glatzor.de
-
-	Use correct spelling of aptderror
-
-2009-07-04  sebi@glatzor.de
-
-	Merge local changes
-
-2009-07-04  sebi@glatzor.de
-
-	Sanitize allow_cancel calls. Allow to cancel every transaction before the 
-	changes get committed.
-
-2009-07-04  sebi@glatzor.de
-
-	Add constructor methods for the AptTransaction and daemon dbus interface to
-	the client module
-
-2009-07-04  sebi@glatzor.de
-
-	Add missing module name to exception in the core
-
-2009-07-04  sebi@glatzor.de
-
-	ProgressDialog:If attach is True call the attach method of the transaction to synchronize.
-
-2009-07-04  sebi@glatzor.de
-
-	Add an attach method to the client. to synchronize with a running transaction.
-	if the bus of a Transaction is none default to the SystemBus.
-
-2009-07-04  sebi@glatzor.de
-
-	Allow to disable debconf support in the progress dialog
-
-2009-07-04  sebi@glatzor.de
-
-	Add an AptRoleLabel widget
-
-2009-07-04  sebi@glatzor.de
-
-	Merge GetQueuedTransactions and GetCurrentTransaction method of the daemon into a single
-	GetTransaction one. Turn the items method of the Queue into a property
-
-2009-07-04  sebi@glatzor.de
-
-	Add an option to not start the transaction in the progress dialog
-
-2009-07-04  sebi@glatzor.de
-
-	Remove leftovers from the threading area
-
-2009-07-03  sebi@glatzor.de
-
-	Remove another item from the TODO list
-
-2009-07-03  sebi@glatzor.de
-
-	Use TransactionFailed instead of a wrong spelled aptderror
-
-2009-07-03  sebi@glatzor.de
-
-	Run dpkg --configure -a after a failed installation
-
-2009-07-03  sebi@glatzor.de
-
-	remove another item from the TODO list
-
-2009-07-03  sebi@glatzor.de
-
-	Make sure the progress is always at 100 after processing the transaction
-
-2009-07-03  sebi@glatzor.de
-
-	Add an Attach method to the Transaction which allows to re-emit all signals. This helps
-	to attach a client to an already running transaction.
-
-2009-07-03  sebi@glatzor.de
-
-	Final message of the console client should cover the whole line
-
-2009-07-03  sebi@glatzor.de
-
-	Do set attributes in the signal emitting method
-
-2009-07-03  sebi@glatzor.de
-
-	Remove another item form the TODO
-
-2009-07-03  sebi@glatzor.de
-
-	Show the progress and status details in the console client. Take terminal resize into account.
-
-2009-07-02  sebi@glatzor.de
-
-	Show a final progress information in the console client
-
-2009-07-02  sebi@glatzor.de
-
-	Add an option to hide the terminal in the console client
-
-2009-07-02  sebi@glatzor.de
-
-	Show the progress and status in the console application
-
-2009-07-02  sebi@glatzor.de
-
-	Move detaching the console client to a separate method
-
-2009-07-02  sebi@glatzor.de
-
-	Update TODO list
-
-2009-07-02  sebi@glatzor.de
-
-	Only allow the user who initiated the transaction to modify it. Further allow
-	to cancel the transaction by the original user and the one who has the
-	privilige to cancel foreign transactions.
-
-2009-07-02  sebi@glatzor.de
-
-	Add a policy to cancel the transaction of another user.
-
-2009-07-02  sebi@glatzor.de
-
-	Add a policy for upgrading packages
-
-2009-07-02  sebi@glatzor.de
-
-	Fix call to _mark_for_removal in the worker.
-
-2009-07-02  sebi@glatzor.de
-
-	Check if a transaction is already set up or running
-
-2009-07-02  sebi@glatzor.de
-
-	Merge today's train ride changes
-
-2009-07-02  sebi@glatzor.de
-
-	Remove useless _terminal assignment.
-
-2009-07-02  sebi@glatzor.de
-
-	Update TODO
-
-2009-07-02  sebi@glatzor.de
-
-	Use gobject.io_add_watch instead of threading in the console client
-
-2009-07-02  sebi@glatzor.de
-
-	Add an UpgradePackages method to the daemon
-
-2009-07-02  sebi@glatzor.de
-
-	Rename ROLE_UPDATE_PACKAGES to ROLE_UPGRADE_PACKAGES
-
-2009-07-02  sebi@glatzor.de
-
-	Remove obsolete try/exceptions from the worker
-
-2009-07-02  sebi@glatzor.de
-
-	Use an action group for install and remove too
-
-2009-07-02  sebi@glatzor.de
-
-	Fix marking packages for installation
-
-2009-07-02  sebi@glatzor.de
-
-	Only switch to non-interactive debconf mode if there isn't any terminal
-
-2009-07-02  sebi@glatzor.de
-
-	Only use debconf debugging if log level is DEBUG
-
-2009-07-02  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/console.py: commit() is called commit_packages()
-
-2009-07-02  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	MANIFEST.in: add data and gtk-demo.py
-
-2009-07-02  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	* MANIFEST.in:
-	- include po/* in the sdist file
-	* aptd, aptdcon:
-	- use /usr/bin/python
-	* aptdaemon/__init__.py:
-	- change version to 0.10
-
-2009-07-01  sebi@glatzor.de
-
-	Rename commit to commit_packages.
-
-2009-07-01  sebi@glatzor.de
-
-	Update TODO
-
-2009-07-01  sebi@glatzor.de
-
-	Merge train work
-
-2009-07-01  sebi@glatzor.de
-
-	Use the commit method in the console client.
-
-2009-07-01  sebi@glatzor.de
-
-	Add a Commit method which allows to install, remove and upgrade packages in 
-	one transaction
-
-2009-06-30  sebi@glatzor.de
-
-	Update TODO
-
-2009-06-30  sebi@glatzor.de
-
-	Add missing bracket
-
-2009-06-30  sebi@glatzor.de
-
-	Fix locale in the client
-
-2009-06-30  sebi@glatzor.de
-
-	Remove an obsolete debug statement
-
-2009-06-30  sebi@glatzor.de
-
-	Use a correct return value
-
-2009-06-30  sebi@glatzor.de
-
-	Fix DaemonDpkgInstallProgress for local file installation
-
-2009-06-30  sebi@glatzor.de
-
-	Replace hotshot by profile
-
-2009-06-30  sebi@glatzor.de
-
-	Improve removing ANSI control chars from the console log
-
-2009-06-30  sebi@glatzor.de
-
-	Make sure that the terminal slave of the client does not take over the
-	daemon
-
-2009-06-30  sebi@glatzor.de
-
-	Remove resolved items from TODO
-
-2009-06-30  sebi@glatzor.de
-
-	Merge local changes
-
-2009-06-30  sebi@glatzor.de
-
-	Do not install the gtk demo application.
-
-2009-06-30  sebi@glatzor.de
-
-	Do not ship the demo application in the aptdaemon package.
-
-2009-06-29  sebi@glatzor.de
-
-	Merge fixes from mvo! Thanks
-
-2009-06-29  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	deal with canceling the frontend and error conditions, fix debconf-communicate zombie
-
-2009-06-29  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	merged from trunk
-
-2009-06-18  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	update todo
-
-2009-06-18  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/gtkwidgets.py: fix zombie problem, add teardown function
-
-2009-06-29  sebi@glatzor.de
-
-	The worker doesn't need to by a gobject
-
-2009-06-29  sebi@glatzor.de
-
-	Merge my gobject branch: instead of threading the gobject main loop is used in
-	the daemon. Simple reads from fd are replaced by gobject.io_watch_add.
-
-2009-06-29  sebi@glatzor.de
-
-	Use gobject.io_watch_add instead of duplicating file descriptors to get access
-	to the controlling terminal of the forked child. This way we can even support
-	re-attaching and logging.
-
-2009-06-29  sebi@glatzor.de
-
-	Only store the ttyname and not the openend file descriptor of the transacion
-
-2009-06-29  sebi@glatzor.de
-
-	Trivial typo fix in the OpenProgress
-
-2009-06-29  sebi@glatzor.de
-
-	Do not wildcard import enums
-
-2009-06-29  sebi@glatzor.de
-
-	Polish the DaemonOpenProgress
-
-2009-06-29  sebi@glatzor.de
-
-	Use block to iterate the main loop while waiting for a media change, since the
-	action cannot be continued before another dbus call has been recieved.
-
-2009-06-29  sebi@glatzor.de
-
-	Provide traceback information in the transaction error message
-
-2009-06-29  sebi@glatzor.de
-
-	Merge the GObject* progresses with the Daemon* ones. Communicating to the worker
-	by signals would add too much complexity compared to the benefits.
-
-2009-06-29  sebi@glatzor.de
-
-	There isn't any need to reset the cancelled flag.
-
-2009-06-29  sebi@glatzor.de
-
-	Follow attribute changes of Transaction class
-
-2009-06-29  sebi@glatzor.de
-
-	Make all attributes of the Transaction class public, since we don't require locking
-
-2009-06-29  sebi@glatzor.de
-
-	Use the GObjectFetchProgress for updating the cache
-
-2009-06-29  sebi@glatzor.de
-
-	Only emit a new transaction if there is one in the queue
-
-2009-06-28  sebi@glatzor.de
-
-	Remove threading.Events of the Transaction class
-
-2009-06-28  sebi@glatzor.de
-
-	Remove locks from the Transaction class
-
-2009-06-28  sebi@glatzor.de
-
-	There isn't any need for a thread safe queue. So use a gobject signal to
-	notify the worker about a new item to process.
-
-2009-06-28  sebi@glatzor.de
-
-	Add a busy attribute to the worker
-
-2009-06-28  sebi@glatzor.de
-
-	Run the worker as a gobject idle function instead of a spearate thread
-
-2009-06-28  sebi@glatzor.de
-
-	Fixes in the progress code
-
-2009-06-26  sebi@glatzor.de
-
-	trivial formatting
-
-2009-06-26  sebi@glatzor.de
-
-	Add a basic gobject based fetch progress
-
-2009-06-26  sebi@glatzor.de
-
-	Do not export useless methods. emit signals directly in _on_status_change. Rename methods.
-
-2009-06-26  sebi@glatzor.de
-
-	Add signal emitting to the progress
-
-2009-06-26  sebi@glatzor.de
-
-	Use a separate fork method
-
-2009-06-26  sebi@glatzor.de
-
-	Add a basic Goject based install progress
-
-2009-06-29  sebi@glatzor.de
-
-	Push local changes
-
-2009-06-26  sebi@glatzor.de
-
-	Cancel the dbus name owner watcher in the client when the transaction is finished
-
-2009-06-29  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	aptdaemon/demo.py: add debugging option
-
-2009-06-26  sebi@glatzor.de
-
-	Store the debconf_helper as private attribute of the client transaction
-
-2009-06-26  sebi@glatzor.de
-
-	Use gobject.io_add_watch instead of threading in the client
-
-2009-06-25  sebi@glatzor.de
-
-	Watch the dbus name to detect a crashed aptdaemon
-
-2009-06-24  sebi@glatzor.de
-
-	Set the cancel button sensitive by default
-
-2009-06-24  sebi@glatzor.de
-
-	Push local changes
-
-2009-06-24  sebi@glatzor.de
-
-	Clean up the debconf module. Assign copyright to mvo!
-
-2009-06-24  sebi@glatzor.de
-
-	Introduce an event to the client transaction which indicates if the transaction
-	is running. Make use of the running event in the debconf proxy.
-
-2009-06-24  sebi@glatzor.de
-
-	Add support for easy profiling of the daemon
-
-2009-06-23  sebi@glatzor.de
-
-	Remove the RemovableQueue and instead enhance the TransactionQueue. Allow to
-	shutdown the worker client by adding None to the queue.
-
-2009-06-22  sebi@glatzor.de
-
-	Merge local changes
-
-2009-06-22  sebi@glatzor.de
-
-	Update inline dowcumentation of the worker module.
-
-2009-06-22  sebi@glatzor.de
-
-	Update inline documentation
-
-2009-06-22  sebi@glatzor.de
-
-	Update copyright headers
-
-2009-06-22  sebi@glatzor.de
-
-	Add mvo to the authors
-
-2009-06-22  sebi@glatzor.de
-
-	Add a lot of documentation to the core module
-
-2009-06-21  sebi@glatzor.de
-
-	store the Message instances and not only its enum
-
-2009-06-21  sebi@glatzor.de
-
-	Add support for media changes
-
-2009-06-21  sebi@glatzor.de
-
-	Allow to specify the test package in the demo application
-
-2009-06-21  sebi@glatzor.de
-
-	Connect to the slave end of the controlling terminal later
-
-2009-06-21  devel@glatzor.de
-
-	Fix: Use uuid4 for the transaction id 
-
-2009-06-21  devel@glatzor.de
-
-	Switch to non interactive mode of debconf only if there is no debcon socket specified. Configure terminal master/slave before setting transaction details.
-
-2009-06-21  devel@glatzor.de
-
-	Clean up logging in the progress module
-
-2009-06-21  devel@glatzor.de
-
-	Make use of logging as a singelton
-
-2009-06-21  devel@glatzor.de
-
-	Fix missing import
-
-2009-06-20  devel@glatzor.de
-
-	Move the threaded decorator to a separate module misc
-
-2009-06-10  devel@glatzor.de
-
-	Merge Debconf support introduced by Michael Vogt!
-
-2009-06-10  devel@glatzor.de
-
-	Move the debconf code to the AptTransaction class and use threads instead of
-	processes
-
-2009-06-18  Michael Vogt  <michael.vogt@ubuntu.com>
-
-	inital support for debconf added
-
-2009-06-10  devel@glatzor.de
-
-	Push local changes
-
-2009-06-10  devel@glatzor.de
-
-	Fix a s missing self
-
-2009-06-10  devel@glatzor.de
-
-	Only retrieve the locale once
-
-2009-06-10  devel@glatzor.de
-
-	Use introspection for DBus objects
-
-2009-06-10  devel@glatzor.de
-
-	Only give the bus  connection and the tid to AptTransaction
-
-2009-05-31  devel@glatzor.de
-
-	Push local changes
-
-2009-06-09  Sebastian Heinlein  <renate@unstable.virtual>
-
-	Only change the language in the forked chil process
-
-2009-06-09  Sebastian Heinlein  <renate@unstable.virtual>
-
-	Move transaction init and clean up to the run method
-
-2009-06-09  Sebastian Heinlein  <renate@unstable.virtual>
-
-	Make use of the modern Python language and its exceptions instead of thousands if and else statements
-
-2009-06-09  Sebastian Heinlein  <renate@unstable.virtual>
-
-	Fix attribute assignment in TransactionError
-
-2009-06-09  Sebastian Heinlein  <renate@unstable.virtual>
-
-	Make message of TransactionError optional
-
-2009-06-09  Sebastian Heinlein  <renate@unstable.virtual>
-
-	Use simpler error names
-
-2009-04-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	The tid should include the full path to the transaction dbus object
-
-2009-03-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Remove packaging
-
-2009-02-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Set the text in the progress bar to a blank space to avoid flickering
-
-2009-02-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add GetCurrentTransaction and GetQueuedTransactions method to the dbus interface
-
-2009-02-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Push local changes
-
-2009-02-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Split the enhanced Queue which supports removing into a separata class. Turn TranasactionQueue into a gobject and emit the TransactionQueueChanged signal on dbus.
-
-2009-02-11  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Remove obsolete service name from the dbus policy
-
-2009-02-10  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	The transaction object should be registered witht the same bus name
-
-2009-02-10  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Use a sane default size for the terminal
-
-2009-02-10  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix old copy and paste error
-
-2009-02-01  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Use a persistant cache to avoid large memory leaks! creating a new cache, does
-	not remove the old one from memory.
-
-2009-02-01  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Make initial release
-
-2009-02-01  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Don't fail on a not before locked cache during processing. locking is quite racy
-
-2009-02-01  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Try to get the window id of a terminal widget from the environment
-
-2009-02-01  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Simplify authmanager call
-
-2009-02-01  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Set path for daemon mode
-
-2009-02-01  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Rename cli module to console and add install_file support
-
-2009-02-01  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Don't wait on a joining worker thread in the case it already died
-
-2009-02-01  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Return the correct exit state of dpkg calls
-
-2009-02-01  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Make DaemonDpkgInstallProgress more generic and add DaemonDpkgRecoverProgress
-
-2009-02-01  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Raise minimum python-apt version
-
-2009-02-01  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add support for installing local package files
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Trivial fix
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Default of boolean options should False
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Allow to replace an already running daemon
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Beautification of the demo application
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Close progress window before showing errors and messages
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	The cancel button should not affect the dialog
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Replace ifilter and imap
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Allow to specify the size of the animation widget
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Use the role icon in the dialog
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Show missing image for mmissing status images :)
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix animations and missing icons
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Use better variable names in gtwidgets
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Make use of the role signal in the gtkwidgets
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix small typo
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a role signal to the transaction
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a role icon widget
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Don't search for icons in the PK data
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Adapt icon name changes in enums
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix namespace of resolving animation
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add icons for resolving from PackageKit
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Ship icons
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Mention the icon artits in AUTHORS
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Rename Icons to the aptdaemon name space
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add icons from PackageKit gnome
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Merge local changes
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix a broken strin replacement
-
-2009-01-31  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Clean up the parameters of dbus objects
-
-2009-01-29  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Remove obsolete test
-
-2009-01-28  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Do not require as init para of Transaction and make caller a required one
-
-2009-01-28  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Set caller at init time
-
-2009-01-28  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Merge local changes
-
-2009-01-28  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Create tid during init of transaction
-
-2009-01-28  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Allow to not connect the transaction to the bus
-
-2009-01-27  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Initialize the exception object with a correct message instead of overriding
-	the string method
-
-2009-01-27  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	I should really keep in mind that "if a:" is not the same as "if a is not None"
-
-2009-01-27  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Remove obsolete trans.get_error() call
-
-2009-01-27  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix mail formatted policykit action
-
-2009-01-27  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Do not include the copyright information in the docstring
-
-2009-01-27  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Code clean up
-
-2009-01-27  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	More to do
-
-2009-01-27  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Code cleanup
-
-2009-01-27  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Code clean up
-
-2009-01-27  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix typo in variable name
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Code clean up
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a TODO
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Push local changes
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Code cleanup in the client
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Install cli client
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Rename gtk demo app
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a pylint config
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix a variable renaming
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix AptDError call
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Code clean up
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Use docstrings in errors and base AptDError on DBusException
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Extract strings from the core module
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Set the default log level to warnings
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add an option to turn on debugging mode
-
-2009-01-26  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a command line option to disable the inactivity timeout
-
-2009-01-25  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Push local changes
-
-2009-01-25  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Use an empty string to clean the text in the progress bar
-
-2009-01-25  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Allow to reset the progress details
-
-2009-01-25  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Replace ''' by """ only for cosmetic reasons
-
-2009-01-25  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Remove obsolete comments
-
-2009-01-25  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Emit the current downloaded package in the fetcher
-
-2009-01-25  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fi open_cache parameters
-
-2009-01-25  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Merge local changes
-
-2009-01-25  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Set the locale
-
-2009-01-24  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Show a nice error message in the cli client
-
-2009-01-24  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	The client should only throw an exception if not any exit handler was specified
-
-2009-01-24  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Always close the master fd in the client
-
-2009-01-24  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Dettach the controlling terminal after the transaction is done.
-
-2009-01-24  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Suppress signal int and quit in the cli client
-
-2009-01-24  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Emit the human readable status string from apt and show it in the gtk progress
-	label. Therefor added the signal StatusDetails
-
-2009-01-24  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Merge local changes
-
-2009-01-24  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Show download progress in the gtk dialog
-
-2009-01-23  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Always unlock the cache after running a transaction
-
-2009-01-23  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Rename StatusChanged signal to Status
-
-2009-01-23  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Remove state chaecking of downloads - This error doesn't appear anymore
-
-2009-01-23  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a ProgressDetails signal
-
-2009-01-23  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Rename ProgressChanged to Progress
-
-2009-01-23  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Merge local changes
-
-2009-01-23  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a very basic command line client
-
-2009-01-23  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add block parameter to the run method of transactions. Furthermore return the
-	exit state instead of the unused results
-
-2009-01-23  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	The repository fetcher reports failed downloads as system error
-
-2009-01-22  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Set the terminal of a new transaction in the client
-
-2009-01-22  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add AllowTerminal signal handling to client
-
-2009-01-15  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	UPload local changes
-
-2009-01-15  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Use threading.Event instead of a mutex wrapped boolean for allow_cancel and allow_terminal
-
-2009-01-14  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Merge local changes
-
-2009-01-14  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	The details of a message/error are not None but empty strings
-
-2009-01-14  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Update last action time stamp after processing a transaction to reset the timeout
-
-2009-01-14  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Check for skipped updates in UpgradeSystem and report them as a new message
-
-2009-01-14  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Check for available updates before making an upgrade and notify the user
-	about an up-to-date system
-
-2009-01-14  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a message system for non-critical information and warnings from the daemon
-
-2009-01-14  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	apt.Cache.update() doesn't report any failed downloads. So we have to check themmanually.
-
-2009-01-13  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Minor cleanup in the fetch progress
-
-2009-01-13  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Do not use a terminal for the update cache call in the demo app
-
-2009-01-13  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Allow to setup the AptProgressDialog without any terminal widget
-
-2009-01-13  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Emit AllowCancel and ProgressChanged(0) at the beginning of each worker method
-
-2009-01-13  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Install apt conf snippet
-
-2009-01-13  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add an apt config snippet which emits the CacheChanged signal after an cache update
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix missing gettext statement
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Merge local changes
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Follow the naming of apt and rename refresh cache to update cache
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add an upgrade button to the demo app
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix a wrong reference in the worker
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Merge local changes
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add an idle shutdown after 5 minutes
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Use the exception message explicitly in the ErrorCode signal
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix a silly copy & paste error in the policy file
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add upgrade system method
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Merge local changes.
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Quit the main loop after forking in the child
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Shutdown the daemon in a nice way if requested
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Set the status of a transaction to cancelled or failed if we encounter an 
-	exception during processing
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix a silly paramter assignment
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Share the main loop with the worker thread
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix a vi typo
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Only allow to connect a controlling terminal durint wait and setup phase of a transaction
-
-2009-01-12  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	If not any terminal was specified the worker should work non-interactively
-
-2009-01-09  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Merge local changes
-
-2009-01-09  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a SetTerminal method to the transaction and connect the tty as controlling
-	terminal for the forked apt process
-
-2009-01-09  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Change the Terminal signal into AllowTerminal which just indicates if 
-	interaction through a terminal is possible
-
-2009-01-09  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Use the master end for the fork again. The other direction would be nice, but
-	doesn't work correctly
-
-2009-01-08  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Set an empty _cache attr in the worker on init. And fix a call to trans
-
-2009-01-08  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Make the forked child the session lead to own the controling terminal
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix a missing self. prefix in the demo code
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add support for removing packages
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Merge local changes
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Install the gaptd-client script
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Move demo application from gtkwidgets to demo and create an executable
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Reimplement the polkit_auth_wrapper for aptdaemon
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Report the sender to all transaction methods
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Depend on python 2.5
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Depend on a policykit version => 0.9, since the DBus API of prior releases is worthless
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add build dep on python-distutils-extra
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Merge local changes
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Use the new policykit module in the core
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add the NotAuthError to the error class
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Make use of the new policykit method in the gtkwidgets
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Remove policykit handler taken from PackageKit in the client.
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Make use of distutils-extra to support i10n. Install dbus config files
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add POTFILES.in
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add policykit policy
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a dbus activation file
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Rename the dbus config file to relfect the interface name
-
-2009-01-07  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Policykit improvements: Add a caller cache, add new methods obtain_auth, is_auth and is_auth_sender
-
-2009-01-05  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Remove obsolete import
-
-2009-01-05  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Merge with packaging branch
-
-2009-01-05  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add packaging
-
-2009-01-05  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add setup script
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Clear canceled event after processing a transaction
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Change AllowCancel default to False again
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Clean up cancel method of Transaction class. Check if a transaction is queued during cancel.
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add handler for the cancel call in the client
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Change default of allow_cancel to True
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix a dead lock in the cancel code
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add support for cancelling to the client
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix name of exit state attribute in the client
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add RemovePackages method to the transacion
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a remove xterm button to the gtk example
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Minor comment clean up
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add remove to the client
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Make GetRole call async in gtkwidgets
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Improve logging of signals by using clear text
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Make sure to release the cache after a failed operation
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Clear cancel event in the worker
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Rename PercentageChanged signal to ProgressChanged and clean up the gtk progress handling.
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add support for the terminal widget
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add some maintenance files
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Adopt gtkwidgets
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix client exit_handler call: we don't supply runtime
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Adapt latest enum changes
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add messages and icon maps for the enums
-
-2009-01-04  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add refresh cache method
-
-2009-01-03  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix a wrong enum
-
-2009-01-03  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix a wrong message call in the client
-
-2009-01-03  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Extend cancel to queued transactions and add a GetStatus method
-
-2009-01-03  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix spelling error in the enums. Add status enums for waiting and cancelling 
-
-2009-01-03  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Enhance the Queue class to support removal of items
-
-2009-01-03  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Implement canceling
-
-2009-01-03  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Move the actual package management into a separate worker thread. Make the transaction thread safe and add a transaction queue.
-
-2009-01-03  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add the enums package under version control.
-
-2009-01-03  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Workaround a list to string conversion. Needs furhter investigation
-
-2009-01-03  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Workaround strange behavior of the client, converting a list to string
-
-2009-01-03  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix: use correct transaction class
-
-2009-01-03  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Adapt client for aptdaemon
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Include the gtk widgets from gnome-packagekit for a later adoption
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Use the packagekit client as a base for the aptdaemon client
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Replace test.sh script by a setup.cfg configuration
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a testing infrastructure
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Remove obsole output collecting references in the install progress. Send signal 15 to the child process in case of a timeout. Set the owner to the pty device to the calling user.
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a Terminal signal, allow to control the forked apt process by a slave tty
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add a working install_packages method and helper methods
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Fix error imports and progress reporting in the progress handlers
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Set the version in the aptdaemon package
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Adapt latest code moval in the progress module
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Move errors to a separate module
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Move logging facility to a separate module
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Use more sane parameters for the open cache
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add unlock cache code directly to the decorator
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Replace backend references by transaction
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add unlock_cache_afterwards decorator from PackageKit backend
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add threading support
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add an error class
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Adapt progress code
-
-2009-01-02  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add my progress handlers from PackageKit
-
-2009-01-01  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Rename log handler
-
-2008-12-30  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Add transactions
-
-2008-12-30  Sebastian Heinlein  <renate@klapprechner.daheim>
-
-	Initial commit
-
diff -pruN 1.1.1-4/data/lintian/ubuntu/aptdaemon.profile 1.1.1+bzr982-0ubuntu14/data/lintian/ubuntu/aptdaemon.profile
--- 1.1.1-4/data/lintian/ubuntu/aptdaemon.profile	2013-08-11 19:05:47.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/data/lintian/ubuntu/aptdaemon.profile	2015-10-12 18:06:10.000000000 +0000
@@ -5,9 +5,8 @@ Disable-Tags:
 	FSSTND-dir-in-usr,
 	FSSTND-dir-in-var,
 	arch-dependent-file-in-usr-share,
-        binary-file-compressed-with-upx,
 	binary-or-shlib-defines-rpath,
-        control-interpreter-in-usr-local,
+	control-interpreter-in-usr-local,
 	copyright-contains-dh_make-todo-boilerplate,
 	copyright-file-compressed,
  	copyright-file-is-symlink,
diff -pruN 1.1.1-4/debian/changelog 1.1.1+bzr982-0ubuntu14/debian/changelog
--- 1.1.1-4/debian/changelog	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/changelog	2015-10-12 16:02:49.000000000 +0000
@@ -1,59 +1,183 @@
-aptdaemon (1.1.1-4) unstable; urgency=medium
+aptdaemon (1.1.1+bzr982-0ubuntu14) wily; urgency=medium
 
-  * Merge all changes from Ubuntu trusty.
+  * debian/patches/lp1439769-aptdaemon-autoinstall.patch: Display the flag
+    name in the error message, not the package name.
 
-  [ Brian Murray (1.1.1-1ubuntu5.1) ]
-  * debian/patches/upstream-include-pkg-version.patch:
-    - include the package version in the crashfile (LP: #1324833)
-
-  [ Michael Vogt (1.1.1-1ubuntu5) ]
-  * debian/python3-aptdaemon.test.install:
-    - install all test deb files
-  * debian/patches/dbus_timeout.patch:
-    - fix pep8 issue
-  * debian/patches/fix-configparser.patch:
-    - do not crash when "#" are in comments
-  * debian/patches/py3_inheritable.patch:
-    - set status-fds inheritable to fix InstallFiles()
-  * debian/tests/control:
-    - add missing fakeroot dependency
-    - add missing lintian dependency
-
-  [ Michael Vogt (1.1.1-1ubuntu4) ]
-  * debian/patches/dbus_timeout.patch
-    - increase dbus timeouts to avoid a dbus timeout error if a
-      policykit authentication dialog is not answered for a while
-  * debian/patches/lp1266844.patch:
-    - workaround for LP: #1266844, thanks to Brian Murray
-
- -- Julian Andres Klode <jak@debian.org>  Fri, 26 Sep 2014 18:25:06 +0200
-
-aptdaemon (1.1.1-3) unstable; urgency=medium
-
-  * cve_2014.patch: Update for long CVE IDs, patch by Thijs Kinkhorst
-    (Closes: #731438)
-  * debian/control: Fix typo (module -> modules) (Closes: #622592)
-  * debian/tests/control: Depend on xauth, hopefully makes autopkgtests work
-
- -- Julian Andres Klode <jak@debian.org>  Sun, 23 Mar 2014 20:16:29 +0100
-
-aptdaemon (1.1.1-2) unstable; urgency=medium
-
-  * Swap Breaks and Conflicts where needed (Closes: #719964)
-  * Update Vcs urls to the anonscm.debian.org ones
-  * debian/copyright: Switch to copyright-format 1.0
-  * Merge fixes from Ubuntu trusty (Closes: #725531)
-  * debian/control: Standards-Version 3.9.5
-
- -- Julian Andres Klode <jak@debian.org>  Sun, 23 Mar 2014 18:44:37 +0100
-
-aptdaemon (1.1.1-1ubuntu5.1) trusty-proposed; urgency=low
-
-  [ Brian Murray ]
-  * debian/patches/upstream-include-pkg-version.patch:
-    - include the package version in the crashfile (LP: #1324833)
+ -- Brian Murray <brian@ubuntu.com>  Mon, 12 Oct 2015 09:02:44 -0700
 
- -- Michael Vogt <michael.vogt@ubuntu.com>  Fri, 06 Jun 2014 13:14:02 +0200
+aptdaemon (1.1.1+bzr982-0ubuntu13) wily; urgency=medium
+
+  * Drop Vcs-Bzr from debian/control:
+    - The branch pointed to is "ubuntu-vivid".  This is obviously incorrect
+      for wily; and you shouldn't have to do a busywork update of Vcs-Bzr
+      with each release.
+    - Uploaders do not have commit rights on the listed branch.  A Vcs-Bzr
+      field should only point to a branch that uploaders have rights to,
+      otherwise it can never be authoritative.
+  * debian/patches/lp1439769-aptdaemon-autoinstall.patch: Take a flag to
+    indicate whether a requested package is auto-installed.  Thanks to
+    Michael Vogt <mvo@ubuntu.com>.  Closes LP: #1439769.
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Tue, 06 Oct 2015 11:33:41 -0700
+
+aptdaemon (1.1.1+bzr982-0ubuntu12) wily; urgency=medium
+
+  * debian/patches/fix-observed-linitian-error.diff: drop Ubuntu patch that
+    was added this cycle, it's not needed with the recent lintian change
+
+ -- Sebastien Bacher <seb128@ubuntu.com>  Thu, 01 Oct 2015 12:22:11 +0200
+
+aptdaemon (1.1.1+bzr982-0ubuntu11) wily; urgency=medium
+
+  * debian/patches/lintian_deprecated_error.patch:
+    - don't list the binary-file-compressed-with-upx lintian error, it was
+      removed from Debian/Ubuntu and is leading software-center to display
+      warnings about skype or chrome debs (lp: #1490169)
+
+ -- Sebastien Bacher <seb128@ubuntu.com>  Wed, 30 Sep 2015 16:46:03 +0200
+
+aptdaemon (1.1.1+bzr982-0ubuntu10) wily; urgency=medium
+
+  * debian/control: let python(3)-aptdaemon Depends on 
+      gir1.2-packagekitglib-1.0 (<< 0.9) (restrict the version because 
+      0.9 is incompatible, also that version was uploaded to 
+      wily-proposed and deleted but some users got it installed, that 
+      way apt knows there is a conflict to resolve) (lp: #1496292)
+  * debian/patches/key_value_typo.patch:
+    - remove trailing "," causing a TypeError, thanks Justin McPherson
+
+ -- Sebastien Bacher <seb128@ubuntu.com>  Tue, 29 Sep 2015 16:40:25 +0200
+
+aptdaemon (1.1.1+bzr982-0ubuntu9) wily; urgency=medium
+
+  * Fix package installation by not considering the "data" which is bogus to
+    pass to apt. (LP: #1352654)
+  * Fix undefined NATIVE_ARCH by getting it from the worker.
+
+ -- Iain Lane <iain@orangesquash.org.uk>  Mon, 28 Sep 2015 18:10:56 +0100
+
+aptdaemon (1.1.1+bzr982-0ubuntu8) wily; urgency=medium
+
+  * debian/patches/lp1487087.diff: Always avoid the bogus mock
+    .assert_called() call.
+
+ -- Barry Warsaw <barry@ubuntu.com>  Thu, 20 Aug 2015 15:33:06 -0400
+
+aptdaemon (1.1.1+bzr982-0ubuntu7) wily; urgency=medium
+
+  * debian/patches/lp1487087.diff: Added to skip a bogus .assert_called()
+    call on a mock which no longer exists, but only under Python 3.5.
+
+ -- Barry Warsaw <barry@ubuntu.com>  Thu, 20 Aug 2015 10:17:28 -0400
+
+aptdaemon (1.1.1+bzr982-0ubuntu6) wily; urgency=medium
+
+  * debian/patches/pep8-accommodations.diff: Added to make the PEP 8 test
+    not fail autopkgtests due to pep8 tool bogosity.
+  * debian/patches/fix-observed-linitian-error.diff: Adjust the test to
+    check for the lintian error actually observed.
+
+ -- Barry Warsaw <barry@ubuntu.com>  Wed, 19 Aug 2015 11:40:43 -0400
+
+aptdaemon (1.1.1+bzr982-0ubuntu5) wily; urgency=medium
+
+  * No-change rebuild for python3.5 transition
+
+ -- Steve Langasek <steve.langasek@ubuntu.com>  Wed, 22 Jul 2015 04:09:09 +0000
+
+aptdaemon (1.1.1+bzr982-0ubuntu4) wily; urgency=low
+
+  [ Michael Vogt ]
+  * SECURITY UPDATE: information disclosure via simulate dbus method
+    (LP: #1449587)
+    - debian/patches/lp1449587.diff: drop privileges when running lintian,
+      update tests.
+    - CVE-2015-1323
+
+ -- Marc Deslauriers <marc.deslauriers@ubuntu.com>  Tue, 16 Jun 2015 13:38:47 -0400
+
+aptdaemon (1.1.1+bzr982-0ubuntu3) vivid; urgency=low
+
+  * debian/patches/lp1356823.diff:
+    - try harder to fix crash #1356823
+
+ -- Michael Vogt <michael.vogt@ubuntu.com>  Thu, 16 Apr 2015 10:05:07 -0500
+
+aptdaemon (1.1.1+bzr982-0ubuntu2) vivid; urgency=low
+
+  * debian/patches/lp1356823.diff:
+    - fix crash #1356823
+
+ -- Michael Vogt <michael.vogt@ubuntu.com>  Fri, 10 Apr 2015 10:01:10 +0200
+
+aptdaemon (1.1.1+bzr982-0ubuntu1) vivid; urgency=low
+
+  * fix crash in _on_progress_details() (LP: #1436725)
+
+ -- Michael Vogt <michael.vogt@ubuntu.com>  Tue, 07 Apr 2015 11:34:02 +0200
+
+aptdaemon (1.1.1+bzr981-0ubuntu2) vivid; urgency=medium
+
+  * autopkgtest: Don't let root reports in /var/crash fail the test.
+
+ -- Martin Pitt <martin.pitt@ubuntu.com>  Mon, 01 Dec 2014 08:01:17 +0100
+
+aptdaemon (1.1.1+bzr981-0ubuntu1) vivid; urgency=medium
+
+  * New bzr snapshot:
+    + Port to VTE 2.91
+  * Update Vcs-* to point to vivid branch
+  * Standards-Version → 3.9.6, no changes required
+
+ -- Iain Lane <iain@orangesquash.org.uk>  Tue, 11 Nov 2014 16:05:26 +0000
+
+aptdaemon (1.1.1+bzr980-0ubuntu1) utopic; urgency=medium
+
+  * New bzr snapshot:
+    - Drop obsolete gobject compatibility and gtkwidgets
+    - Drop obsolete dbus.glib imports
+    - Do not crash when "#" are in comments
+  * Drop fix-configparser.patch, applied upstream.
+  * Refresh other patches.
+  * Drop python-aptdaemon.gtkwidgets and python-aptdaemon-gtk binaries. These
+    have been obsolete for a long time, unmaintained/untested, and there are
+    no reverse dependencies any more.
+
+ -- Martin Pitt <martin.pitt@ubuntu.com>  Thu, 21 Aug 2014 15:47:42 +0200
+
+aptdaemon (1.1.1+bzr973-1ubuntu4) utopic; urgency=medium
+
+  * debian/python3-aptdaemon.pkcompat.install:
+    - install pkutils.py, which is required by pkcompat.py.
+
+ -- Alberto Milone <alberto.milone@canonical.com>  Wed, 30 Jul 2014 15:47:24 +0200
+
+aptdaemon (1.1.1+bzr973-1ubuntu3) utopic; urgency=medium
+
+  * New bzr snapshot to fix PEP-8 errors.
+  * Update Vcs-* for utopic branch.
+
+ -- Martin Pitt <martin.pitt@ubuntu.com>  Thu, 26 Jun 2014 09:26:20 +0200
+
+aptdaemon (1.1.1+bzr970-1ubuntu2) utopic; urgency=low
+
+  * debian/patches/lp1153725-temporary-workaround.patch:
+    - dropped, tests work fine (LP: #1153725)
+
+ -- Michael Vogt <michael.vogt@ubuntu.com>  Thu, 12 Jun 2014 10:36:33 +0200
+
+aptdaemon (1.1.1+bzr970-1ubuntu1) utopic; urgency=low
+
+  * New bzr snapshot
+    - lp:~brian-murray/aptdaemon/package-version-in-crash
+      + include package version in crash reports
+  * patches already upstream:
+    + upstream_lintian_2.5.18.patch 
+    + upstream_lp1024590.patch
+    + lp1266844.patch
+    + fix-ftbs.patch
+
+ -- Michael Vogt <michael.vogt@ubuntu.com>  Fri, 06 Jun 2014 11:27:25 +0200
 
 aptdaemon (1.1.1-1ubuntu5) trusty; urgency=low
 
diff -pruN 1.1.1-4/debian/control 1.1.1+bzr982-0ubuntu14/debian/control
--- 1.1.1-4/debian/control	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/control	2015-10-12 15:57:01.000000000 +0000
@@ -1,11 +1,13 @@
 Source: aptdaemon
 Section: admin
 Priority: extra
-Maintainer: Julian Andres Klode <jak@debian.org>
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
+XSBC-Original-Maintainer: Julian Andres Klode <jak@debian.org>
 Build-Depends: debhelper (>= 7.3),
                debconf-i18n,
                dbus,
                lintian,
+               dh-translations,
                python-all,
                python-setuptools,
                python-distutils-extra,
@@ -17,7 +19,7 @@ Build-Depends: debhelper (>= 7.3),
                gir1.2-glib-2.0,
                gir1.2-gtk-3.0,
                gir1.2-packagekitglib-1.0 (>= 0.8.9),
-               gir1.2-vte-2.90,
+               gir1.2-vte-2.91,
                python3-apt (>= 0.8.5~ubuntu1),
                python3-defer (>= 1.0.6),
                python3-dbus,
@@ -34,10 +36,10 @@ Build-Depends: debhelper (>= 7.3),
                pep8,
                xauth,
                xvfb
-Standards-Version: 3.9.5
+Standards-Version: 3.9.6
 Homepage: https://launchpad.net/aptdaemon
-Vcs-Bzr: nosmart+http://anonscm.debian.org/bzr/apt/aptdaemon/debian-sid
-Vcs-Browser: http://anonscm.debian.org/loggerhead/apt/aptdaemon/debian-sid
+XS-Original-Vcs-Bzr: nosmart+http://bzr.debian.org/bzr/apt/aptdaemon/debian-sid
+XS-Original-Vcs-Browser: http://bzr.debian.org/loggerhead/apt/aptdaemon/debian-sid
 X-Python-Version: >= 2.7
 X-Python3-Version: >= 3.2
 XS-Testsuite: autopkgtest
@@ -78,6 +80,7 @@ Section: python
 Depends: ${misc:Depends},
          ${python3:Depends},
          gir1.2-glib-2.0,
+         gir1.2-packagekitglib-1.0 (<< 0.9), 
          python3-apt (>= 0.8.5~ubuntu1),
          python3-defer (>= 1.0.6),
          python3-dbus,
@@ -85,7 +88,7 @@ Depends: ${misc:Depends},
          python3-pkg-resources,
          iso-codes,
 Recommends: aptdaemon
-Description: Python 3 modules for the server and client of aptdaemon
+Description: Python 3 module for the server and client of aptdaemon
  Aptdaemon is a transaction based package management service. It allows 
  normal users to perform package management tasks, e.g. refreshing the 
  cache, upgrading the system, installing or removing software packages.
@@ -105,10 +108,11 @@ Depends: ${misc:Depends},
          python-dbus,
          python-gi,
          gir1.2-glib-2.0,
+         gir1.2-packagekitglib-1.0 (<< 0.9), 
          python-pkg-resources,
          iso-codes,
 Recommends: aptdaemon
-Description: Python 2 modules for the server and client of aptdaemon
+Description: Python 2 module for the server and client of aptdaemon
  Aptdaemon is a transaction based package management service. It allows 
  normal users to perform package management tasks, e.g. refreshing the 
  cache, upgrading the system, installing or removing software packages.
@@ -145,24 +149,6 @@ Description: data files for clients
  This package provides common data files (e.g. icons) for aptdaemon
  clients.
  
-Package: python-aptdaemon-gtk
-Architecture: all
-Section: python
-Depends: ${misc:Depends},
-         ${python:Depends},
-         python-aptdaemon.gtkwidgets (= ${binary:Version}),
-         python-aptdaemon.gtk3widgets (= ${binary:Version})
-Description: Transitional dummy package
- Aptdaemon is a transaction based package management daemon. It allows 
- normal users to perform package management tasks, e.g. refreshing the 
- cache, upgrading the system, installing or removing software packages.
- .
- This is a transitional dummy package to ease the migration
- from the python-aptdaemon-gtk to the new python-aptdaemon.gtk(3)widgets
- packages.
- .
- You can remove it safely.
-
 Package: python3-aptdaemon.pkcompat
 Architecture: all
 Section: python
@@ -170,11 +156,11 @@ Depends: ${misc:Depends},
          ${python3:Depends},
          python3-aptdaemon (= ${binary:Version}),
          gir1.2-packagekitglib-1.0 (>=0.8.9),
+Breaks: libpackagekit-glib2-14,
+        libpackagekit-qt2-2
 Provides: packagekit-system-interface
 Conflicts: packagekit,
            python-aptdaemon.pkcompat,
-           libpackagekit-glib2-14,
-           libpackagekit-qt2-2
 Replaces: python-aptdaemon.pkcompat
 Description: PackageKit compatibilty for AptDaemon
  Aptdaemon is a transaction based package management daemon. It allows 
@@ -183,26 +169,6 @@ Description: PackageKit compatibilty for
  .
  This package adds a PackageKit DBus interface to AptDaemon.
 
-Package: python-aptdaemon.gtkwidgets
-Architecture: all
-Section: python
-Depends: ${misc:Depends},
-         ${python:Depends},
-         python-aptdaemon (= ${binary:Version}),
-         python-gtk2,
-         python-vte,
-         aptdaemon-data
-Breaks: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
-Replaces: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
-Description: Python GTK+ 2 widgets to run an aptdaemon client
- Aptdaemon is a transaction based package management daemon. It allows 
- normal users to perform package management tasks, e.g. refreshing the 
- cache, upgrading the system, installing or removing software packages.
- .
- This package provides the Python GTK+ widgets to implement a fully working
- graphical client. The widgets can be used to initiate, to monitor and
- to control a transaction. The API is not stable yet.
-
 Package: python3-aptdaemon.gtk3widgets
 Architecture: all
 Section: python
@@ -211,9 +177,9 @@ Depends: ${misc:Depends},
          python3-aptdaemon (= ${binary:Version}),
          python3-gi,
          gir1.2-gtk-3.0,
-         gir1.2-vte-2.90,
+         gir1.2-vte-2.91,
          aptdaemon-data
-Breaks: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
+Conflicts: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
 Replaces: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
 Description: Python 3 GTK+ 3 widgets to run an aptdaemon client
  Aptdaemon is a transaction based package management daemon. It allows 
@@ -232,9 +198,9 @@ Depends: ${misc:Depends},
          python-aptdaemon (= ${binary:Version}),
          python-gi,
          gir1.2-gtk-3.0,
-         gir1.2-vte-2.90,
+         gir1.2-vte-2.91,
          aptdaemon-data
-Breaks: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
+Conflicts: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
 Replaces: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
 Description: Python 2 GTK+ 3 widgets to run an aptdaemon client
  Aptdaemon is a transaction based package management daemon. It allows 
diff -pruN 1.1.1-4/debian/copyright 1.1.1+bzr982-0ubuntu14/debian/copyright
--- 1.1.1-4/debian/copyright	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/copyright	2015-10-12 15:57:01.000000000 +0000
@@ -1,4 +1,4 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?rev=59
 Source: https://launchpad.net/aptdaemon
 
 Files: *
diff -pruN 1.1.1-4/debian/patches/cve_2014.patch 1.1.1+bzr982-0ubuntu14/debian/patches/cve_2014.patch
--- 1.1.1-4/debian/patches/cve_2014.patch	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/cve_2014.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,29 +0,0 @@
-From: Thijs Kinkhorst <thijs@debian.org>
-Subject: Update CVE regexp for extended CVE format
-
-Hi,
-
-CVE syntax will be extended per 2014-01-01, see:
-https://cve.mitre.org/cve/identifiers/syntaxchange.html
-
-Attached patch updates the regexp in this package to also detect the
-longer forms.
-
-
-Cheers,
-Thijs
-
-Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=731438
-
-diff -Nur aptdaemon-1.1.1.old/aptdaemon/pkcompat.py aptdaemon-1.1.1/aptdaemon/pkcompat.py
---- aptdaemon-1.1.1.old/aptdaemon/pkcompat.py	2013-08-11 21:07:59.000000000 +0200
-+++ aptdaemon-1.1.1/aptdaemon/pkcompat.py	2013-12-05 14:16:03.190690491 +0100
-@@ -92,7 +92,7 @@
- HREF_BUG_UBUNTU = "https://bugs.launchpad.net/bugs/%s"
- 
- # Regular expression to find cve references
--MATCH_CVE = "CVE-\d{4}-\d{4}"
-+MATCH_CVE = "CVE-\d{4}-\d{4,}"
- HREF_CVE = "http://web.nvd.nist.gov/view/vuln/detail?vulnId=%s"
- 
- # Map Debian sections to the PackageKit group name space
diff -pruN 1.1.1-4/debian/patches/dbus_timeout.patch 1.1.1+bzr982-0ubuntu14/debian/patches/dbus_timeout.patch
--- 1.1.1-4/debian/patches/dbus_timeout.patch	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/dbus_timeout.patch	2015-10-12 15:57:01.000000000 +0000
@@ -1,7 +1,9 @@
 === modified file 'aptdaemon/client.py'
---- a/aptdaemon/client.py	2013-07-27 10:00:04 +0000
-+++ b/aptdaemon/client.py	2014-04-10 13:36:32 +0000
-@@ -54,6 +54,10 @@
+Index: aptdaemon/aptdaemon/client.py
+===================================================================
+--- aptdaemon.orig/aptdaemon/client.py
++++ aptdaemon/aptdaemon/client.py
+@@ -47,6 +47,10 @@ from .errors import convert_dbus_excepti
  __all__ = ("AptTransaction", "AptClient", "get_transaction", "get_aptdaemon")
  
  
@@ -9,10 +11,10 @@
 +_APTDAEMON_DBUS_TIMEOUT = 86400
 +
 +
- class AptTransaction(_GObject):
+ class AptTransaction(GObject.Object):
  
      """Represents an aptdaemon transaction.
-@@ -711,7 +715,8 @@
+@@ -704,7 +708,8 @@ class AptTransaction(GObject.Object):
          try:
              return self._iface.RunAfter(transaction.tid,
                                          error_handler=error_handler,
@@ -22,7 +24,7 @@
          except Exception as error:
              if error_handler:
                  error_handler(error)
-@@ -734,7 +739,8 @@
+@@ -727,7 +732,8 @@ class AptTransaction(GObject.Object):
          """
          try:
              return self._iface.Run(error_handler=error_handler,
@@ -32,7 +34,7 @@
          except Exception as error:
              if error_handler:
                  error_handler(error)
-@@ -1616,10 +1622,11 @@
+@@ -1609,10 +1615,11 @@ class AptClient(object):
          if async:
              deferred = defer.Deferred()
              dbus_method(reply_handler=deferred.callback,
@@ -46,11 +48,11 @@
          trans = AptTransaction(tid, self.bus)
          if self._locale:
              yield trans.set_locale(self._locale)
-
-=== modified file 'aptdaemon/core.py'
---- a/aptdaemon/core.py	2014-02-07 20:40:15 +0000
-+++ b/aptdaemon/core.py	2014-04-10 14:18:29 +0000
-@@ -84,7 +84,7 @@
+Index: aptdaemon/aptdaemon/core.py
+===================================================================
+--- aptdaemon.orig/aptdaemon/core.py
++++ aptdaemon/aptdaemon/core.py
+@@ -83,7 +83,7 @@ APTDAEMON_DBUS_SERVICE = 'org.debian.apt
  APTDAEMON_TRANSACTION_DBUS_INTERFACE = 'org.debian.apt.transaction'
  
  APTDAEMON_IDLE_CHECK_INTERVAL = 60
@@ -59,4 +61,3 @@
  
  # Maximum allowed time between the creation of a transaction and its queuing
  TRANSACTION_IDLE_TIMEOUT = 300
-
diff -pruN 1.1.1-4/debian/patches/fix-configparser.patch 1.1.1+bzr982-0ubuntu14/debian/patches/fix-configparser.patch
--- 1.1.1-4/debian/patches/fix-configparser.patch	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/fix-configparser.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,29 +0,0 @@
-=== modified file 'aptdaemon/config.py'
---- a/aptdaemon/config.py	2012-12-29 19:27:25 +0000
-+++ b/aptdaemon/config.py	2014-04-11 09:39:58 +0000
-@@ -100,7 +100,8 @@
-                 elif in_comment:
-                     # We ignore the content of multiline comments
-                     pass
--                elif not in_value and char == "/" and prev_char == "/":
-+                elif not in_value and ((char == "/" and prev_char == "/") or
-+                                       char == "#"):
-                     # In the case of a line comment continue processing
-                     # the next line
-                     prev_char = ""
-
-=== modified file 'tests/test_configparser.py'
---- a/tests/test_configparser.py	2012-12-29 23:40:46 +0000
-+++ b/tests/test_configparser.py	2014-04-11 09:39:58 +0000
-@@ -42,8 +42,8 @@
-         """ ensure that comment strings in values are parsed correctly """
-         s = """// Server information for apt-changelog
-         APT {
--         Changelogs {
--          Server "http://changelogs.ubuntu.com/changelogs";
-+         Changelogs { # bar
-+          Server "http://changelogs.ubuntu.com/changelogs"; // foo
-          }
-         }
-         """
-
diff -pruN 1.1.1-4/debian/patches/fix-ftbs.patch 1.1.1+bzr982-0ubuntu14/debian/patches/fix-ftbs.patch
--- 1.1.1-4/debian/patches/fix-ftbs.patch	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/fix-ftbs.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,13 +0,0 @@
-=== modified file 'aptdaemon/gtk3widgets.py'
---- old/aptdaemon/gtk3widgets.py	2013-07-08 05:18:57 +0000
-+++ new/aptdaemon/gtk3widgets.py	2013-09-17 05:00:21 +0000
-@@ -508,7 +508,7 @@
-         if status == DOWNLOAD_FETCHING:
-             text += (_("Downloaded %sB of %sB") %
-                      (apt_pkg.size_to_str(downloaded),
--                     apt_pkg.size_to_str(full_size)))
-+                      apt_pkg.size_to_str(full_size)))
-         elif status == DOWNLOAD_DONE:
-             if full_size != 0:
-                 text += _("Downloaded %sB") % apt_pkg.size_to_str(full_size)
-
diff -pruN 1.1.1-4/debian/patches/fix-high-trust-pkcompat.diff 1.1.1+bzr982-0ubuntu14/debian/patches/fix-high-trust-pkcompat.diff
--- 1.1.1-4/debian/patches/fix-high-trust-pkcompat.diff	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/fix-high-trust-pkcompat.diff	2015-10-12 15:57:01.000000000 +0000
@@ -1,8 +1,8 @@
-Index: aptdaemon-1.0/aptdaemon/worker.py
+Index: aptdaemon/aptdaemon/worker/aptworker.py
 ===================================================================
---- aptdaemon-1.0.orig/aptdaemon/worker.py	2013-03-10 15:04:40.000000000 +0100
-+++ aptdaemon-1.0/aptdaemon/worker.py	2013-03-10 15:19:03.647159451 +0100
-@@ -98,8 +98,10 @@
+--- aptdaemon.orig/aptdaemon/worker/aptworker.py
++++ aptdaemon/aptdaemon/worker/aptworker.py
+@@ -113,8 +113,10 @@ def trans_only_installs_pkgs_from_high_t
      # paranoia(2): we must want to install something
      if not trans.packages[PKGS_INSTALL]:
          return False
diff -pruN 1.1.1-4/debian/patches/fix-installation.patch 1.1.1+bzr982-0ubuntu14/debian/patches/fix-installation.patch
--- 1.1.1-4/debian/patches/fix-installation.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/fix-installation.patch	2015-10-12 15:57:01.000000000 +0000
@@ -0,0 +1,18 @@
+Description: Don't consider the "data" when installing a package - this is usually "Ubuntu" and isn't useful to pass to apt.
+Author: Justin McPherson <justin.mcpherson@canonical.com>
+Forwarded: https://code.launchpad.net/~justinmcp/aptdaemon/1352654/+merge/243354
+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/aptdaemon/+bug/1352654
+
+Index: b/aptdaemon/pkcompat.py
+===================================================================
+--- a/aptdaemon/pkcompat.py
++++ b/aptdaemon/pkcompat.py
+@@ -1904,8 +1904,6 @@
+             id += ":%s" % arch
+         if version:
+             id += "=%s" % version
+-        if data and data not in ["local", "installed"]:
+-            id += "/%s" % data
+         return id
+ 
+     def _get_merged_trans(self, role, pkg_ids=None, pkg_type=None,
diff -pruN 1.1.1-4/debian/patches/key_value_typo.patch 1.1.1+bzr982-0ubuntu14/debian/patches/key_value_typo.patch
--- 1.1.1-4/debian/patches/key_value_typo.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/key_value_typo.patch	2015-10-12 15:57:01.000000000 +0000
@@ -0,0 +1,18 @@
+Description: Remove trailing comma, was causing a TypeError.
+Author: Justin McPherson <justin.mcpherson@canonical.com>
+Forwarded: https://code.launchpad.net/~justinmcp/aptdaemon/1352654/+merge/243354
+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/aptdaemon/+bug/1352654
+=== modified file 'aptdaemon/aptdaemon/worker/aptworker.py'
+Index: aptdaemon-1.1.1+bzr982/aptdaemon/worker/aptworker.py
+===================================================================
+--- aptdaemon-1.1.1+bzr982.orig/aptdaemon/worker/aptworker.py
++++ aptdaemon-1.1.1+bzr982/aptdaemon/worker/aptworker.py
+@@ -1511,7 +1511,7 @@ class AptWorker(BaseWorker):
+             key = "APT::Periodic::AutocleanInterval"
+             return apt_pkg.config.find_i(key, 0)
+         elif option == "UnattendedUpgrade":
+-            key = "APT::Periodic::Unattended-Upgrade",
++            key = "APT::Periodic::Unattended-Upgrade"
+             return apt_pkg.config.find_b(key, False)
+         elif option == "GetPopconParticipation":
+             return self._get_popcon_pariticipation()
diff -pruN 1.1.1-4/debian/patches/lintian_deprecated_error.patch 1.1.1+bzr982-0ubuntu14/debian/patches/lintian_deprecated_error.patch
--- 1.1.1-4/debian/patches/lintian_deprecated_error.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/lintian_deprecated_error.patch	2015-10-12 15:57:01.000000000 +0000
@@ -0,0 +1,20 @@
+Description: don't list deprecated lintian case
+Author: Sebastien Bacher <seb128@ubuntu.com>
+Forwarded: https://code.launchpad.net/~seb128/aptdaemon/lintian-upx-deprecated/+merge/272924
+Bug-Ubuntu: https://launchpad.net/bugs/1490169
+=== modified file 'aptdaemon/data/lintian/ubuntu/aptdaemon.profile'
+Index: aptdaemon-1.1.1+bzr982/data/lintian/ubuntu/aptdaemon.profile
+===================================================================
+--- aptdaemon-1.1.1+bzr982.orig/data/lintian/ubuntu/aptdaemon.profile
++++ aptdaemon-1.1.1+bzr982/data/lintian/ubuntu/aptdaemon.profile
+@@ -5,9 +5,8 @@ Disable-Tags:
+ 	FSSTND-dir-in-usr,
+ 	FSSTND-dir-in-var,
+ 	arch-dependent-file-in-usr-share,
+-        binary-file-compressed-with-upx,
+ 	binary-or-shlib-defines-rpath,
+-        control-interpreter-in-usr-local,
++	control-interpreter-in-usr-local,
+ 	copyright-contains-dh_make-todo-boilerplate,
+ 	copyright-file-compressed,
+  	copyright-file-is-symlink,
diff -pruN 1.1.1-4/debian/patches/lp1266844.patch 1.1.1+bzr982-0ubuntu14/debian/patches/lp1266844.patch
--- 1.1.1-4/debian/patches/lp1266844.patch	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/lp1266844.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,13 +0,0 @@
-=== modified file 'aptdaemon/gtk3widgets.py'
---- a/aptdaemon/gtk3widgets.py	2013-12-03 10:16:52 +0000
-+++ b/aptdaemon/gtk3widgets.py	2014-02-19 18:19:33 +0000
-@@ -520,6 +520,8 @@
-             text += get_download_status_from_enum(status)
-         text += "</small>"
-         model = self.get_model()
-+        if not model:
-+            return
-         try:
-             iter = self._download_map[uri]
-         except KeyError:
-
diff -pruN 1.1.1-4/debian/patches/lp1356823.diff 1.1.1+bzr982-0ubuntu14/debian/patches/lp1356823.diff
--- 1.1.1-4/debian/patches/lp1356823.diff	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/lp1356823.diff	2015-10-12 15:57:01.000000000 +0000
@@ -0,0 +1,13 @@
+=== modified file 'aptdaemon/pkcompat.py'
+--- old/aptdaemon/pkcompat.py	2014-06-26 07:07:15 +0000
++++ new/aptdaemon/pkcompat.py	2015-04-16 15:04:08 +0000
+@@ -586,6 +586,8 @@
+ 
+     def _remove_from_connection_no_raise(self):
+         core.Transaction._remove_from_connection_no_raise(self)
++        if self.pktrans is None:
++            return False
+         self.pktrans.Destroy()
+         try:
+             self.pktrans.remove_from_connection()
+
diff -pruN 1.1.1-4/debian/patches/lp1439769-aptdaemon-autoinstall.patch 1.1.1+bzr982-0ubuntu14/debian/patches/lp1439769-aptdaemon-autoinstall.patch
--- 1.1.1-4/debian/patches/lp1439769-aptdaemon-autoinstall.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/lp1439769-aptdaemon-autoinstall.patch	2015-10-12 16:00:08.000000000 +0000
@@ -0,0 +1,50 @@
+Description: Take a flag to indicate whether a requested package is auto-installed
+ The aptdaemon API takes a complete list of packages to be installed,
+ including dependencies.  This means that all packages are marked as
+ "selected" by the "user" for installation, even if on the other end of the
+ API they were selected for installation only to resolve dependencies of
+ other packages.
+ .
+ This patch adds an optional "auto" flag to the list of packages passed from
+ the client, so that aptdaemon can pass this information on to apt.
+Author: Michael Vogt <mvo@ubuntu.com>
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1439769
+
+=== modified file 'aptdaemon/core.py'
+Index: wily/aptdaemon/core.py
+===================================================================
+--- wily.orig/aptdaemon/core.py
++++ wily/aptdaemon/core.py
+@@ -2069,6 +2069,10 @@ class AptDaemon(DBusObject):
+         """
+         for fullname in pkg_names:
+             name, version, release = split_package_id(fullname)
++            name, sep, auto_flag = name.partition("#")
++            if not auto_flag in ("", "auto"):
++                raise errors.AptDaemonError("%s isn't a valid flag" %
++                                            auto_flag)
+             if not re.match(REGEX_VALID_PACKAGENAME, name):
+                 raise errors.AptDaemonError("%s isn't a valid package name" %
+                                             name)
+Index: wily/aptdaemon/worker/aptworker.py
+===================================================================
+--- wily.orig/aptdaemon/worker/aptworker.py
++++ wily/aptdaemon/worker/aptworker.py
+@@ -388,6 +388,8 @@ class AptWorker(BaseWorker):
+         """Mark packages for installation."""
+         for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
+                                            for pkg in packages]:
++            pkg_name, sep, auto_marker = pkg_name.partition("#")
++            from_user = (auto_marker != "auto")
+             try:
+                 pkg = self._cache[pkg_name]
+             except KeyError:
+@@ -417,7 +419,7 @@ class AptWorker(BaseWorker):
+                         raise TransactionFailed(
+                             ERROR_PACKAGE_ALREADY_INSTALLED,
+                             _("Package %s is already installed"), pkg_name)
+-            pkg.mark_install(False, True, True)
++            pkg.mark_install(False, True, from_user)
+             resolver.clear(pkg)
+             resolver.protect(pkg)
+             if pkg_ver:
diff -pruN 1.1.1-4/debian/patches/lp1449587.diff 1.1.1+bzr982-0ubuntu14/debian/patches/lp1449587.diff
--- 1.1.1-4/debian/patches/lp1449587.diff	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/lp1449587.diff	2015-10-12 15:57:01.000000000 +0000
@@ -0,0 +1,363 @@
+=== modified file 'aptdaemon/core.py'
+Index: aptdaemon-1.1.1+bzr982/aptdaemon/core.py
+===================================================================
+--- aptdaemon-1.1.1+bzr982.orig/aptdaemon/core.py	2015-06-11 09:18:21.910695506 -0400
++++ aptdaemon-1.1.1+bzr982/aptdaemon/core.py	2015-06-11 09:18:21.906695457 -0400
+@@ -324,7 +324,7 @@
+                            "DebconfSocket", "MetaData", "Locale",
+                            "RemoveObsoleteDepends")
+ 
+-    def __init__(self, tid, role, queue, pid, uid, cmdline, sender,
++    def __init__(self, tid, role, queue, pid, uid, gid, cmdline, sender,
+                  connect=True, bus=None, packages=None, kwargs=None):
+         """Initialize a new Transaction instance.
+ 
+@@ -360,6 +360,7 @@
+             kwargs = {}
+         self.queue = queue
+         self.uid = uid
++        self.gid = gid
+         self.locale = dbus.String("")
+         self.allow_unauthenticated = dbus.Boolean(False)
+         self.remove_obsoleted_depends = dbus.Boolean(False)
+@@ -1521,11 +1522,12 @@
+     @inline_callbacks
+     def _create_trans(self, role, sender, packages=None, kwargs=None):
+         """Helper method which returns the tid of a new transaction."""
+-        pid, uid, cmdline = (
++        pid, uid, gid, cmdline = (
+             yield policykit1.get_proc_info_from_dbus_name(sender, self.bus))
+         tid = uuid.uuid4().hex
+-        trans = Transaction(tid, role, self.queue, pid, uid, cmdline, sender,
+-                            packages=packages, kwargs=kwargs, bus=self.bus)
++        trans = Transaction(
++            tid, role, self.queue, pid, uid, gid, cmdline, sender,
++            packages=packages, kwargs=kwargs, bus=self.bus)
+         self.queue.limbo[trans.tid] = trans
+         return_value(trans.tid)
+ 
+Index: aptdaemon-1.1.1+bzr982/aptdaemon/pkcompat.py
+===================================================================
+--- aptdaemon-1.1.1+bzr982.orig/aptdaemon/pkcompat.py	2015-06-11 09:18:21.910695506 -0400
++++ aptdaemon-1.1.1+bzr982/aptdaemon/pkcompat.py	2015-06-11 09:18:21.910695506 -0400
+@@ -334,9 +334,10 @@
+ 
+     @inline_callbacks
+     def _create_transaction(self, sender):
+-        pid, uid, cmdline = yield policykit1.get_proc_info_from_dbus_name(
++        pid, uid, gid, cmdline = yield policykit1.get_proc_info_from_dbus_name(
+             sender, self.bus)
+-        pktrans = PackageKitTransaction(pid, uid, cmdline, self.queue, sender)
++        pktrans = PackageKitTransaction(
++            pid, uid, gid, cmdline, self.queue, sender)
+         return_value(pktrans.tid)
+ 
+     # pylint: disable-msg=C0103,C0322
+@@ -468,7 +469,7 @@
+     def __init__(self, pktrans, role, queue, connect=True,
+                  bus=None, packages=None, kwargs=None):
+         core.Transaction.__init__(self, pktrans.tid[1:], role, queue,
+-                                  pktrans.pid, pktrans.uid,
++                                  pktrans.pid, pktrans.uid, pktrans.gid,
+                                   pktrans.cmdline, pktrans.sender,
+                                   connect, bus, packages, kwargs)
+         self.pktrans = pktrans
+@@ -626,7 +627,7 @@
+ 
+     """Provides a PackageKit transaction object."""
+ 
+-    def __init__(self, pid, uid, cmdline, queue, sender,
++    def __init__(self, pid, uid, gid, cmdline, queue, sender,
+                  connect=True, bus=None):
+         pklog.info("Initializing PackageKit transaction")
+         bus_name = None
+@@ -652,6 +653,7 @@
+         self._status = pk.StatusEnum.SETUP
+         self._last_package = ""
+         self.uid = dbus.UInt32(uid)
++        self.gid = dbus.UInt32(gid)
+         self.pid = pid
+         self.cmdline = cmdline
+         self.role = pk.RoleEnum.UNKNOWN
+Index: aptdaemon-1.1.1+bzr982/aptdaemon/policykit1.py
+===================================================================
+--- aptdaemon-1.1.1+bzr982.orig/aptdaemon/policykit1.py	2015-06-11 09:18:21.910695506 -0400
++++ aptdaemon-1.1.1+bzr982/aptdaemon/policykit1.py	2015-06-11 09:18:21.910695506 -0400
+@@ -161,12 +161,15 @@
+         bus = dbus.SystemBus()
+     pid = yield get_pid_from_dbus_name(dbus_name, bus)
+     with open("/proc/%s/status" % pid) as proc:
+-        values = [v for v in proc.readlines() if v.startswith("Uid:")]
++        lines = proc.readlines()
++        uid_values = [v for v in lines if v.startswith("Uid:")]
++        gid_values = [v for v in lines if v.startswith("Gid:")]
+     # instead of ", encoding='utf8'" we use the "rb"/decode() here for
+     # py2 compatibility
+     with open("/proc/%s/cmdline" % pid, "rb") as cmdline_file:
+         cmdline = cmdline_file.read().decode("utf-8")
+-    uid = int(values[0].split()[1])
+-    return_value((pid, uid, cmdline))
++    uid = int(uid_values[0].split()[1])
++    gid = int(gid_values[0].split()[1])
++    return_value((pid, uid, gid, cmdline))
+ 
+ # vim:ts=4:sw=4:et
+Index: aptdaemon-1.1.1+bzr982/aptdaemon/progress.py
+===================================================================
+--- aptdaemon-1.1.1+bzr982.orig/aptdaemon/progress.py	2015-06-11 09:18:21.910695506 -0400
++++ aptdaemon-1.1.1+bzr982/aptdaemon/progress.py	2015-06-11 09:18:21.910695506 -0400
+@@ -628,6 +628,11 @@
+ 
+     def _child(self, path):
+         # Avoid running lintian as root
++        try:
++            os.setgroups([self.transaction.gid])
++        except OSError:
++            pass
++        os.setgid(self.transaction.gid)
+         os.setuid(self.transaction.uid)
+ 
+         if platform.dist()[1] == "debian":
+Index: aptdaemon-1.1.1+bzr982/aptdaemon/worker/aptworker.py
+===================================================================
+--- aptdaemon-1.1.1+bzr982.orig/aptdaemon/worker/aptworker.py	2015-06-11 09:18:21.910695506 -0400
++++ aptdaemon-1.1.1+bzr982/aptdaemon/worker/aptworker.py	2015-06-11 09:18:21.910695506 -0400
+@@ -91,6 +91,25 @@
+ """
+ 
+ 
++@contextlib.contextmanager
++def set_euid_egid(uid, gid):
++    # no need to drop privs
++    if os.getuid() != 0 and os.getgid() != 0:
++        yield
++        return
++    # temporary drop privs
++    os.setegid(gid)
++    old_groups = os.getgroups()
++    os.setgroups([gid])
++    os.seteuid(uid)
++    try:
++        yield
++    finally:
++        os.seteuid(os.getuid())
++        os.setegid(os.getgid())
++        os.setgroups(old_groups)
++
++
+ def trans_only_installs_pkgs_from_high_trust_repos(trans,
+                                                    whitelist=set()):
+     """Return True if this transaction only touches packages in the
+@@ -1199,8 +1218,16 @@
+ 
+         :returns: An apt.debfile.Debfile instance.
+         """
+-        if not os.path.isfile(path):
+-            raise TransactionFailed(ERROR_UNREADABLE_PACKAGE_FILE, path)
++        # This code runs as root for simulate and simulate requires no
++        # authentication - so we need to ensure we do not leak information
++        # about files here (LP: #1449587, CVE-2015-1323)
++        #
++        # Note that the actual lintian run is also droping privs (real,
++        # not just seteuid)
++        with set_euid_egid(trans.uid, trans.gid):
++            if not os.path.isfile(path):
++                raise TransactionFailed(ERROR_UNREADABLE_PACKAGE_FILE, path)
++
+         if not force and os.path.isfile("/usr/bin/lintian"):
+             with DaemonLintianProgress(trans) as progress:
+                 progress.run(path)
+Index: aptdaemon-1.1.1+bzr982/tests/test_high_trust_repository_whitelist.py
+===================================================================
+--- aptdaemon-1.1.1+bzr982.orig/tests/test_high_trust_repository_whitelist.py	2015-06-11 09:18:21.910695506 -0400
++++ aptdaemon-1.1.1+bzr982/tests/test_high_trust_repository_whitelist.py	2015-06-11 09:18:21.910695506 -0400
+@@ -115,7 +115,7 @@
+             ("Ubuntu", "", "silly.*"))
+         # a high-trust whitelisted pkg and a non-whitelisted one
+         trans = Transaction(None, enums.ROLE_INSTALL_PACKAGES, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             packages=[["silly-base", "other-pkg"], [], [], [],
+                                       [], []])
+@@ -127,7 +127,7 @@
+                 trans, self.worker._high_trust_repositories))
+         # whitelisted only
+         trans = Transaction(None, enums.ROLE_INSTALL_PACKAGES, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             packages=[["silly-base"], [], [], [], [], []])
+         self.worker.simulate(trans)
+Index: aptdaemon-1.1.1+bzr982/tests/test_worker.py
+===================================================================
+--- aptdaemon-1.1.1+bzr982.orig/tests/test_worker.py	2015-06-11 09:18:21.910695506 -0400
++++ aptdaemon-1.1.1+bzr982/tests/test_worker.py	2015-06-11 09:18:21.910695506 -0400
+@@ -77,7 +77,8 @@
+         self.chroot.add_repository("/does/not/exist", copy_list=False)
+         # Only update the repository from the working snippet
+         trans = Transaction(None, enums.ROLE_UPDATE_CACHE,
+-                            self.queue, os.getpid(), os.getuid(), sys.argv[0],
++                            self.queue, os.getpid(), os.getuid(),
++                            os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             kwargs={"sources_list": "test.list"})
+         self.worker.simulate(trans)
+@@ -99,7 +100,7 @@
+                                                  "silly-base_0.1-0_all.deb"))
+         # Install the package
+         trans = Transaction(None, enums.ROLE_UPGRADE_SYSTEM,
+-                            self.queue, os.getpid(),
++                            self.queue, os.getpid(), os.getgid(),
+                             os.getuid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             kwargs={"safe_mode": False})
+@@ -130,7 +131,7 @@
+         self.chroot.add_test_repository(copy_sig=False)
+         # Install the package
+         trans = Transaction(None, enums.ROLE_INSTALL_PACKAGES, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             packages=[["silly-base"], [], [], [], [], []])
+         self.worker.simulate(trans)
+@@ -144,7 +145,7 @@
+ 
+         # Allow installation of unauthenticated packages
+         trans = Transaction(None, enums.ROLE_INSTALL_PACKAGES, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             packages=[["silly-base"], [], [], [], [], []])
+         trans.allow_unauthenticated = True
+@@ -164,7 +165,7 @@
+         self.chroot.add_test_repository()
+         # Install the package
+         trans = Transaction(None, enums.ROLE_INSTALL_PACKAGES, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             packages=[["silly-depend-base"], [], [], [],
+                                       [], []])
+@@ -193,7 +194,7 @@
+ Architecture: all
+ Auto-Installed: 1""")
+         trans = Transaction(None, enums.ROLE_REMOVE_PACKAGES, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             packages=[[], [], ["silly-depend-base"], [],
+                                       [], []])
+@@ -219,7 +220,7 @@
+                     "silly-depend-base_0.1-0_all.deb"]:
+             self.chroot.install_debfile(os.path.join(REPO_PATH, pkg))
+         trans = Transaction(None, enums.ROLE_REMOVE_PACKAGES, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             packages=[[], [], ["silly-base"], [], [], []])
+         self.worker.simulate(trans)
+@@ -240,7 +241,7 @@
+             pass
+         # Don't allow to remove essential packages
+         trans = Transaction(None, enums.ROLE_REMOVE_PACKAGES, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             packages=[[], [], ["silly-essential"], [], [], []])
+         self.worker.run(trans)
+@@ -263,7 +264,7 @@
+ Architecture: all
+ Auto-Installed: 1""")
+         trans = Transaction(None, enums.ROLE_COMMIT_PACKAGES, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             packages=[[], [], [], [],
+                                       ["silly-base=0.1-0update1"], []])
+@@ -283,7 +284,7 @@
+         pkg = os.path.join(REPO_PATH, "silly-base_0.1-0update1_all.deb")
+         self.chroot.install_debfile(pkg)
+         trans = Transaction(None, enums.ROLE_COMMIT_PACKAGES, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             packages=[[], [], [], [], [],
+                                       ["silly-base=0.1-0"]])
+@@ -301,7 +302,7 @@
+         for pkg in ["silly-base_0.1-0_all.deb", "silly-config_0.1-0_all.deb"]:
+             self.chroot.install_debfile(os.path.join(REPO_PATH, pkg))
+         trans = Transaction(None, enums.ROLE_REMOVE_PACKAGES, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             packages=[[], [], [], ["silly-config"], [], []])
+         self.worker.run(trans)
+@@ -324,7 +325,7 @@
+         pkg = os.path.join(REPO_PATH,
+                            "silly-depend-base-lintian-broken_0.1-0_all.deb")
+         trans = Transaction(None, enums.ROLE_INSTALL_FILE, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             kwargs={"path": os.path.join(REPO_PATH, pkg),
+                                     "force": False})
+@@ -359,7 +360,7 @@
+         self.chroot.install_debfile(os.path.join(REPO_PATH, pkg_base))
+         pkg = os.path.join(REPO_PATH, "silly-bully_0.1-0_all.deb")
+         trans = Transaction(None, enums.ROLE_INSTALL_FILE, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             kwargs={"path": os.path.join(REPO_PATH, pkg),
+                                     "force": True})
+@@ -379,7 +380,7 @@
+         """
+         pkg = os.path.join(REPO_PATH, "silly-base_0.1-0_all.deb")
+         trans = Transaction(None, enums.ROLE_INSTALL_FILE, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False,
+                             kwargs={"path": os.path.join(REPO_PATH, pkg),
+                                     "force": True})
+@@ -400,7 +401,7 @@
+         for pkg in ["silly-base_0.1-0_all.deb", "silly-broken_0.1-0_all.deb"]:
+             self.chroot.install_debfile(os.path.join(REPO_PATH, pkg), True)
+         trans = Transaction(None, enums.ROLE_FIX_BROKEN_DEPENDS, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test", connect=False)
+         self.worker.simulate(trans)
+         self.loop.run()
+@@ -420,7 +421,7 @@
+         """
+         self.chroot.add_test_repository()
+         trans = Transaction(None, enums.ROLE_COMMIT_PACKAGES, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test",
+                             packages=[["silly-broken"], [], [], [], [], []],
+                             connect=False)
+@@ -459,7 +460,7 @@
+ 
+         self.chroot.add_test_repository()
+         trans = Transaction(None, enums.ROLE_ADD_LICENSE_KEY, self.queue,
+-                            os.getpid(), os.getuid(), sys.argv[0],
++                            os.getpid(), os.getuid(), os.getgid(), sys.argv[0],
+                             "org.debian.apt.test",
+                             kwargs={"pkg_name": "silly-license",
+                                     "json_token": "lalelu",
+Index: aptdaemon-1.1.1+bzr982/tests/_test_py2_string_handling.py
+===================================================================
+--- aptdaemon-1.1.1+bzr982.orig/tests/_test_py2_string_handling.py	2012-12-29 18:40:46.000000000 -0500
++++ aptdaemon-1.1.1+bzr982/tests/_test_py2_string_handling.py	2015-06-11 09:47:02.608070571 -0400
+@@ -49,7 +49,8 @@
+         self.start_dbus_daemon()
+         self.dbus = dbus.bus.BusConnection(self.dbus_address)
+         self.trans = Transaction(None, "role-test", None,
+-                                 os.getpid(), os.getuid(), sys.argv[0],
++                                 os.getpid(), os.getuid(), os.getgid(),
++                                 sys.argv[0],
+                                  "org.debian.apt.test", bus=self.dbus)
+ 
+     def test(self):
diff -pruN 1.1.1-4/debian/patches/lp1487087.diff 1.1.1+bzr982-0ubuntu14/debian/patches/lp1487087.diff
--- 1.1.1-4/debian/patches/lp1487087.diff	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/lp1487087.diff	2015-10-12 15:57:01.000000000 +0000
@@ -0,0 +1,21 @@
+Description: .assert_called() is not a valid mock method, and its presence
+ masks a failing test.  Under Python 3.5, an AttributeError is raised whereas
+ in earlier Python's this just silently passed.  Since the intent of the test
+ can't be determined, for now just skip it.  We don't use @unittest.skip
+ though because there is apparently some test leakage, so that if this entire
+ test is skipped, other tests fail.
+Author: Barry Warsaw <barry@ubuntu.com>
+Bug: https://bugs.launchpad.net/aptdaemon/+bug/1487087
+
+--- a/tests/test_high_trust_repository_whitelist.py
++++ b/tests/test_high_trust_repository_whitelist.py
+@@ -96,7 +96,8 @@
+                          "data/high-trust-repository-whitelist-broken.cfg"))
+         self.assertEqual(whitelist, set())
+         # ensure we log a error if the config file is broken
+-        mock_log.error.assert_called()
++        # Skip due to LP: #1487087
++        #mock_log.error.assert_called()
+ 
+     @patch("aptdaemon.worker.log")
+     def test_read_high_trust_repository_whitelist_not_there(self, mock_log):
diff -pruN 1.1.1-4/debian/patches/native-arch.patch 1.1.1+bzr982-0ubuntu14/debian/patches/native-arch.patch
--- 1.1.1-4/debian/patches/native-arch.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/native-arch.patch	2015-10-12 15:57:01.000000000 +0000
@@ -0,0 +1,17 @@
+Description: Fix NATIVE_ARCH not being defined
+Author: Justin McPherson <justin.mcpherson@canonical.com>
+Forwarded: https://code.launchpad.net/~justinmcp/aptdaemon/1352654/+merge/243354
+
+Index: b/aptdaemon/pkcompat.py
+===================================================================
+--- a/aptdaemon/pkcompat.py
++++ b/aptdaemon/pkcompat.py
+@@ -392,7 +392,7 @@
+             distro, version, _codename = platform.dist()
+             self._distro_id = "%s;%s;%s" % (distro or "unknown",
+                                             version or "unknown",
+-                                            NATIVE_ARCH)
++                                            self.queue.worker.NATIVE_ARCH)
+         return self._distro_id
+ 
+     def _on_network_state_changed(self, mon, state):
diff -pruN 1.1.1-4/debian/patches/pep8-accommodations.diff 1.1.1+bzr982-0ubuntu14/debian/patches/pep8-accommodations.diff
--- 1.1.1-4/debian/patches/pep8-accommodations.diff	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/pep8-accommodations.diff	2015-10-12 15:57:01.000000000 +0000
@@ -0,0 +1,35 @@
+Description: Various accommodations so that the PEP 8 tests don't cause
+ autopkgtests to fail.  These include fixing the --exclude argument, adding
+ more files to the exclude pattern, and ignoring E402, which is bogus; see
+ https://github.com/PyCQA/pep8/issues/394.  I also fixed one legitimate
+ looking violation.
+Author: Barry Warsaw <barry@ubuntu.com>
+Bug: https://bugs.launchpad.net/aptdaemon/+bug/1486646
+
+--- a/tests/test_pep8.py
++++ b/tests/test_pep8.py
+@@ -30,9 +30,11 @@
+ 
+     def test(self):
+         """Check if the source code matches the PEP8 style conventions."""
+-        subprocess.check_call(["pep8", "--statistics", "--show-source",
+-                               "--show-pep8", "--exclude", "pkenums.py",
+-                               "aptdaemon", "tests"])
++        subprocess.check_call([
++            "pep8", "--statistics", "--show-source",
++            "--show-pep8", "--exclude",
++            "pkenums.py,aptdaemon,tests,debian,doc,.pc,gtk3-demo.py,setup.py",
++            "--ignore=E402"])
+ 
+ 
+ if __name__ == "__main__":
+--- a/apport/aptdaemon.py
++++ b/apport/aptdaemon.py
+@@ -28,6 +28,7 @@
+ 
+ apt_pkg.init()
+ 
++
+ def add_info(report):
+     """Collect and append additional information about a crash.
+ 
diff -pruN 1.1.1-4/debian/patches/series 1.1.1+bzr982-0ubuntu14/debian/patches/series
--- 1.1.1-4/debian/patches/series	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/series	2015-10-12 15:57:01.000000000 +0000
@@ -1,11 +1,12 @@
-upstream_lintian_2.5.18.patch
-upstream_lp1024590.patch
 fix-high-trust-pkcompat.diff
-lp1153725-temporary-workaround.patch
-fix-ftbs.patch
-cve_2014.patch
 dbus_timeout.patch
-lp1266844.patch
-fix-configparser.patch
 py3_inheritable.patch
-upstream-include-pkg-version.patch
+lp1356823.diff
+lp1449587.diff
+pep8-accommodations.diff
+lp1487087.diff
+fix-installation.patch
+native-arch.patch
+key_value_typo.patch
+lintian_deprecated_error.patch
+lp1439769-aptdaemon-autoinstall.patch
diff -pruN 1.1.1-4/debian/patches/upstream-include-pkg-version.patch 1.1.1+bzr982-0ubuntu14/debian/patches/upstream-include-pkg-version.patch
--- 1.1.1-4/debian/patches/upstream-include-pkg-version.patch	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/upstream-include-pkg-version.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,18 +0,0 @@
-=== modified file 'aptdaemon/crash.py'
---- a/aptdaemon/crash.py	2012-12-29 15:19:44 +0000
-+++ b/aptdaemon/crash.py	2014-05-30 09:30:33 +0000
-@@ -43,7 +43,13 @@
-     uid = 0
-     report = apport.Report("Crash")
-     report["Title"] = error
--    report["Package"] = "aptdaemon"
-+    package = "aptdaemon"
-+    try:
-+        package_version = apport.packaging.get_version(package)
-+    except ValueError as e:
-+        if 'does not exist' in e.message:
-+            package_version = 'unknown'
-+    report['Package'] = '%s %s' % (package, package_version)
-     report["SourcePackage"] = "aptdaemon"
-     report["Traceback"] = traceback
-     report["ExecutablePath"] = "/usr/sbin/aptd"
diff -pruN 1.1.1-4/debian/patches/upstream_lintian_2.5.18.patch 1.1.1+bzr982-0ubuntu14/debian/patches/upstream_lintian_2.5.18.patch
--- 1.1.1-4/debian/patches/upstream_lintian_2.5.18.patch	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/upstream_lintian_2.5.18.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,37 +0,0 @@
-=== modified file 'tests/test_worker.py'
---- old/tests/test_worker.py	2013-07-22 13:33:31 +0000
-+++ new/tests/test_worker.py	2013-10-14 13:24:15 +0000
-@@ -314,19 +314,11 @@
-                                         "etc/silly-packages.cfg")),
-             "Configuration file wasn't removed.")
- 
-+    @unittest.skipUnless(
-+        os.path.exists('/usr/share/lintian/profiles/debian/aptdaemon.profile'),
-+        'this test needs aptdaemon installed, for the lintian profiles')
-     def test_install_file(self):
-         """Test the installation of a local package file."""
--        # add custom lintian file
--        lintian_root = os.path.join(self.chroot.path, "lintian")
--        os.environ["LINTIAN_ROOT"] = lintian_root
--        self.addCleanup(os.unsetenv, "LINTIAN_ROOT")
--        #import pdb; pdb.set_trace()
--        shutil.copytree("/usr/share/lintian", lintian_root)
--        for profile in glob.glob(os.path.join(aptdaemon.test.get_tests_dir(),
--                                              "../data/lintian/*/*.profile")):
--            dst = [lintian_root, "profiles"]
--            dst.extend(profile.split("/")[-2:])
--            shutil.copy(profile, os.path.join(*dst))
-         # test
-         self.chroot.add_test_repository()
-         pkg = os.path.join(REPO_PATH,
-@@ -338,8 +330,7 @@
-                                     "force": False})
-         self.worker.simulate(trans)
-         self.loop.run()
--        self.assertTrue("wrong-file-owner-uid-or-gid" in trans.error.details,
--                        trans.error.details)
-+        self.assertIn("wrong-file-owner-uid-or-gid", trans.error.details)
-         self.assertEqual(trans.error.code, enums.ERROR_INVALID_PACKAGE_FILE,
-                          "Lintian failed to detect a broken package")
-         # Now allow to install invalid packages
-
diff -pruN 1.1.1-4/debian/patches/upstream_lp1024590.patch 1.1.1+bzr982-0ubuntu14/debian/patches/upstream_lp1024590.patch
--- 1.1.1-4/debian/patches/upstream_lp1024590.patch	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/patches/upstream_lp1024590.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,37 +0,0 @@
-Description: Backport fix for LP: #1024590 from trunk r963
-Author: Michael Vogt <mvo@ubuntu.com>
-Forwarded: yes
-
-=== modified file 'aptdaemon/gtk3widgets.py'
---- a/aptdaemon/gtk3widgets.py	2013-07-27 10:00:04 +0000
-+++ b/aptdaemon/gtk3widgets.py	2013-12-03 10:16:52 +0000
-@@ -523,16 +523,20 @@
-         try:
-             iter = self._download_map[uri]
-         except KeyError:
--            adj = self.get_vadjustment()
--            is_scrolled_down = (adj.get_value() + adj.get_page_size() ==
--                                adj.get_upper())
-+            # we we haven't seen the uri yet, add it now
-             iter = model.append((text, progress, uri))
-             self._download_map[uri] = iter
--            if is_scrolled_down:
--                # If the treeview was scrolled to the end, do this again
--                # after appending a new item
--                self.scroll_to_cell(model.get_path(iter), None, False, False,
--                                    False)
-+            # and update the adj if needed
-+            adj = self.get_vadjustment()
-+            # this may be None (LP: #1024590)
-+            if adj:
-+                is_scrolled_down = (
-+                    adj.get_value() + adj.get_page_size() == adj.get_upper())
-+                if is_scrolled_down:
-+                    # If the treeview was scrolled to the end, do this again
-+                    # after appending a new item
-+                    self.scroll_to_cell(
-+                        model.get_path(iter), None, False, False, False)
-         else:
-             model.set_value(iter, self.COL_TEXT, text)
-             model.set_value(iter, self.COL_PROGRESS, progress)
-
diff -pruN 1.1.1-4/debian/python3-aptdaemon.install 1.1.1+bzr982-0ubuntu14/debian/python3-aptdaemon.install
--- 1.1.1-4/debian/python3-aptdaemon.install	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/python3-aptdaemon.install	2015-10-12 15:57:01.000000000 +0000
@@ -14,4 +14,4 @@ usr/lib/python3*/*-packages/aptdaemon/ne
 usr/lib/python3*/*-packages/aptdaemon/policykit1.py
 usr/lib/python3*/*-packages/aptdaemon/progress.py
 usr/lib/python3*/*-packages/aptdaemon/utils.py
-usr/lib/python3*/*-packages/aptdaemon/worker.py
+usr/lib/python3*/*-packages/aptdaemon/worker/*.py
diff -pruN 1.1.1-4/debian/python3-aptdaemon.pkcompat.install 1.1.1+bzr982-0ubuntu14/debian/python3-aptdaemon.pkcompat.install
--- 1.1.1-4/debian/python3-aptdaemon.pkcompat.install	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/python3-aptdaemon.pkcompat.install	2015-10-12 15:57:01.000000000 +0000
@@ -1,4 +1,5 @@
 usr/lib/python3*/*-packages/aptdaemon/pkcompat.py
 usr/lib/python3*/*-packages/aptdaemon/pkenums.py
+usr/lib/python3*/*-packages/aptdaemon/pkutils.py
 usr/share/dbus-1/system-services/org.freedesktop.PackageKit.service
 etc/dbus-1/system.d/org.freedesktop.PackageKit-aptd.conf
diff -pruN 1.1.1-4/debian/python-aptdaemon.gtkwidgets.examples 1.1.1+bzr982-0ubuntu14/debian/python-aptdaemon.gtkwidgets.examples
--- 1.1.1-4/debian/python-aptdaemon.gtkwidgets.examples	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/python-aptdaemon.gtkwidgets.examples	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-gtk-demo.py
diff -pruN 1.1.1-4/debian/python-aptdaemon.gtkwidgets.install 1.1.1+bzr982-0ubuntu14/debian/python-aptdaemon.gtkwidgets.install
--- 1.1.1-4/debian/python-aptdaemon.gtkwidgets.install	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/python-aptdaemon.gtkwidgets.install	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-usr/lib/python2.*/*-packages/aptdaemon/gtkwidgets.py
diff -pruN 1.1.1-4/debian/python-aptdaemon.install 1.1.1+bzr982-0ubuntu14/debian/python-aptdaemon.install
--- 1.1.1-4/debian/python-aptdaemon.install	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/python-aptdaemon.install	2015-10-12 15:57:01.000000000 +0000
@@ -13,4 +13,4 @@ usr/lib/python2.*/*-packages/aptdaemon/n
 usr/lib/python2.*/*-packages/aptdaemon/policykit1.py
 usr/lib/python2.*/*-packages/aptdaemon/progress.py
 usr/lib/python2.*/*-packages/aptdaemon/utils.py
-usr/lib/python2.*/*-packages/aptdaemon/worker.py
+usr/lib/python2.*/*-packages/aptdaemon/worker/*.py
diff -pruN 1.1.1-4/debian/rules 1.1.1+bzr982-0ubuntu14/debian/rules
--- 1.1.1-4/debian/rules	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/rules	2015-10-12 15:57:01.000000000 +0000
@@ -6,7 +6,7 @@ PYTHON2=$(shell pyversions -vr)
 PYTHON3=$(shell py3versions -vr)
 
 %:
-	dh $@ --with=python2,python3
+	dh $@ --with=python2,python3,translations
 
 build-python%:
 	python$* setup.py build
diff -pruN 1.1.1-4/debian/tests/control 1.1.1+bzr982-0ubuntu14/debian/tests/control
--- 1.1.1-4/debian/tests/control	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/tests/control	2015-10-12 15:57:01.000000000 +0000
@@ -1,2 +1,2 @@
 Tests: run-test
-Depends: @, xvfb, xauth, pep8, python3-nose, python3-setuptools, python3-distutils-extra, python3-mock, gir1.2-packagekitglib-1.0, gir1.2-gtk-3.0, gir1.2-vte-2.90, fakeroot, lintian
+Depends: @, xvfb, pep8, python3-nose, python3-setuptools, python3-distutils-extra, python3-mock, gir1.2-packagekitglib-1.0, gir1.2-gtk-3.0, gir1.2-vte-2.90, fakeroot, lintian
diff -pruN 1.1.1-4/debian/tests/run-test 1.1.1+bzr982-0ubuntu14/debian/tests/run-test
--- 1.1.1-4/debian/tests/run-test	2014-09-26 16:28:57.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/debian/tests/run-test	2015-10-12 15:57:01.000000000 +0000
@@ -2,7 +2,7 @@
 set -e
 
 # clean up old crash reports
-rm -rf /var/crash/*
+rm -rf /var/crash/* 2>&1 || true
 
 # succeeding test must not write anything to stderr, as per DEP-8
 # work around LP #972324
diff -pruN 1.1.1-4/doc/examples/chained.py 1.1.1+bzr982-0ubuntu14/doc/examples/chained.py
--- 1.1.1-4/doc/examples/chained.py	2013-03-11 06:00:59.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/doc/examples/chained.py	2014-08-21 12:56:35.000000000 +0000
@@ -1,13 +1,14 @@
 #!/usr/bin/python
 
 import dbus
-import gobject
+
+from gi.repository import GLib
 
 from aptdaemon.client import AptClient
 from aptdaemon.defer import inline_callbacks
 from aptdaemon import policykit1
 
-loop = gobject.MainLoop()
+loop = GLib.MainLoop()
 
 def on_finished(trans, exit):
     loop.quit()
diff -pruN 1.1.1-4/gtk-demo.py 1.1.1+bzr982-0ubuntu14/gtk-demo.py
--- 1.1.1-4/gtk-demo.py	2013-03-11 06:00:59.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/gtk-demo.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,165 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-"""
-Provides a graphical demo application for aptdaemon
-"""
-# Copyright (C) 2008-2009 Sebastian Heinlein <sevel@glatzor.de>
-#
-# 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.
-
-__author__ = "Sebastian Heinlein <devel@glatzor.de>"
-
-from optparse import OptionParser
-import logging
-
-import gobject
-import gtk
-
-import aptdaemon.client
-from aptdaemon.enums import *
-from aptdaemon.gtkwidgets import AptErrorDialog, \
-                                 AptConfirmDialog, \
-                                 AptProgressDialog
-import aptdaemon.errors
-
-
-class AptDaemonDemo(object):
-
-    """Provides a graphical test application."""
-
-    def _run_transaction(self, transaction):
-        dia = AptProgressDialog(transaction, parent=self.win)
-        dia.run(close_on_finished=True, show_error=True,
-                reply_handler=lambda: True,
-                error_handler=self._on_error)
-
-    def _simulate_trans(self, trans):
-        trans.simulate(reply_handler=lambda: self._confirm_deps(trans),
-                       error_handler=self._on_error)
-
-    def _confirm_deps(self, trans):
-        if [pkgs for pkgs in trans.dependencies if pkgs]:
-            dia = AptConfirmDialog(trans, parent=self.win)
-            res = dia.run()
-            dia.hide()
-            if res != gtk.RESPONSE_OK:
-                return
-        self._run_transaction(trans)
-
-    def _on_error(self, error):
-        try:
-            raise error
-        except aptdaemon.errors.NotAuthorizedError:
-            # Silently ignore auth failures
-            return
-        except aptdaemon.errors.TransactionFailed as error:
-            pass
-        except Exception as error:
-            error = aptdaemon.errors.TransactionFailed(ERROR_UNKNOWN,
-                                                       str(error))
-        dia = AptErrorDialog(error)
-        dia.run()
-        dia.hide()
-
-    def _on_upgrade_clicked(self, *args):
-        self.ac.upgrade_system(safe_mode=False, 
-                               reply_handler=self._simulate_trans,
-                               error_handler=self._on_error)
-
-    def _on_update_clicked(self, *args):
-        self.ac.update_cache(reply_handler=self._run_transaction,
-                             error_handler=self._on_error)
-
-    def _on_install_clicked(self, *args):
-        self.ac.install_packages([self.package],
-                                 reply_handler=self._simulate_trans,
-                                 error_handler=self._on_error)
-
-    def _on_install_file_clicked(self, *args):
-        chooser = gtk.FileChooserDialog(parent=self.win,
-                                        action=gtk.FILE_CHOOSER_ACTION_OPEN,
-                                        buttons=(gtk.STOCK_CANCEL,
-                                                 gtk.RESPONSE_CANCEL,
-                                                 gtk.STOCK_OPEN,
-                                                 gtk.RESPONSE_OK))
-        chooser.set_local_only(True)
-        chooser.run()
-        chooser.hide()
-        path = chooser.get_filename()
-        self.ac.install_file(path, reply_handler=self._simulate_trans,
-                             error_handler=self._on_error)
-
-    def _on_remove_clicked(self, *args):
-        self.ac.remove_packages([self.package],
-                                reply_handler=self._simulate_trans,
-                                error_handler=self._on_error)
-
-    def __init__(self, package):
-        self.win = gtk.Window()
-        self.package = package
-        self.win.set_resizable(False)
-        self.win.set_title("Aptdaemon Demo")
-        icon_theme = gtk.icon_theme_get_default()
-        try:
-            gtk.window_set_default_icon(icon_theme.load_icon("aptdaemon-setup",
-                                                              32, 0))
-        except (gobject.GError, AttributeError):
-            pass
-        button_update = gtk.Button(label="_Update")
-        button_install = gtk.Button(label="_Install %s" % self.package)
-        button_install_file = gtk.Button(label="Install _file...")
-        button_remove = gtk.Button(label="_Remove %s" % self.package)
-        button_upgrade = gtk.Button(label="Upgrade _System")
-        button_update.connect("clicked", self._on_update_clicked)
-        button_install.connect("clicked", self._on_install_clicked)
-        button_install_file.connect("clicked", self._on_install_file_clicked)
-        button_remove.connect("clicked", self._on_remove_clicked)
-        button_upgrade.connect("clicked", self._on_upgrade_clicked)
-        vbox = gtk.VBox()
-        vbox.add(button_update)
-        vbox.add(button_install)
-        vbox.add(button_install_file)
-        vbox.add(button_remove)
-        vbox.add(button_upgrade)
-        self.win.add(vbox)
-        self.loop = gobject.MainLoop()
-        self.win.connect("delete-event", lambda w, e: self.loop.quit())
-        self.win.show_all()
-        self.ac = aptdaemon.client.AptClient()
-
-    def run(self):
-        self.loop.run()
-
-
-def main():
-    parser = OptionParser()
-    parser.add_option("-p", "--package", default="cw", action="store",
-                      dest="package",
-                      help="Use this package for installation and removal")
-    parser.add_option("-d", "--debug", default=False, action="store_true",
-                      help="Verbose debugging")
-    options, args = parser.parse_args()
-    if options.debug:
-        logging.basicConfig(level=logging.DEBUG)
-
-    demo = AptDaemonDemo(options.package)
-    demo.run()
-
-if __name__ == "__main__":
-    main()
-
-# vim:ts=4:sw=4:et
diff -pruN 1.1.1-4/MANIFEST.in 1.1.1+bzr982-0ubuntu14/MANIFEST.in
--- 1.1.1-4/MANIFEST.in	2013-08-12 04:33:47.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/MANIFEST.in	1970-01-01 00:00:00.000000000 +0000
@@ -1,285 +0,0 @@
-include AUTHORS
-include COPYRIGHT
-include NEWS
-include README
-include README.PackageKit
-include README.tests
-include TODO
-include applet.py
-include apport/aptdaemon.py
-include aptd
-include aptdaemon/__init__.py
-include aptdaemon/client.py
-include aptdaemon/config.py
-include aptdaemon/console.py
-include aptdaemon/core.py
-include aptdaemon/crash.py
-include aptdaemon/debconf.py
-include aptdaemon/enums.py
-include aptdaemon/errors.py
-include aptdaemon/gtk3widgets.py
-include aptdaemon/gtkwidgets.py
-include aptdaemon/lock.py
-include aptdaemon/logger.py
-include aptdaemon/loop.py
-include aptdaemon/networking.py
-include aptdaemon/pkcompat.py
-include aptdaemon/pkenums.py
-include aptdaemon/policykit1.py
-include aptdaemon/progress.py
-include aptdaemon/test.py
-include aptdaemon/utils.py
-include aptdaemon/worker.py
-include aptdcon
-include data/20dbus
-include data/icons/16x16/animations/aptdaemon-action-cleaning-up.png
-include data/icons/16x16/animations/aptdaemon-action-downloading.png
-include data/icons/16x16/animations/aptdaemon-action-installing.png
-include data/icons/16x16/animations/aptdaemon-action-removing.png
-include data/icons/16x16/animations/aptdaemon-action-resolving.png
-include data/icons/16x16/animations/aptdaemon-action-updating-cache.png
-include data/icons/16x16/animations/aptdaemon-action-waiting.png
-include data/icons/16x16/status/aptdaemon-add.png
-include data/icons/16x16/status/aptdaemon-cleanup.png
-include data/icons/16x16/status/aptdaemon-delete.png
-include data/icons/16x16/status/aptdaemon-download.png
-include data/icons/16x16/status/aptdaemon-resolve.png
-include data/icons/16x16/status/aptdaemon-update-cache.png
-include data/icons/16x16/status/aptdaemon-upgrade.png
-include data/icons/16x16/status/aptdaemon-wait.png
-include data/icons/16x16/status/aptdaemon-working.png
-include data/icons/22x22/animations/aptdaemon-action-cleaning-up.png
-include data/icons/22x22/animations/aptdaemon-action-downloading.png
-include data/icons/22x22/animations/aptdaemon-action-installing.png
-include data/icons/22x22/animations/aptdaemon-action-removing.png
-include data/icons/22x22/animations/aptdaemon-action-resolving.png
-include data/icons/22x22/animations/aptdaemon-action-updating-cache.png
-include data/icons/22x22/animations/aptdaemon-action-waiting.png
-include data/icons/22x22/status/aptdaemon-add.png
-include data/icons/22x22/status/aptdaemon-cleanup.png
-include data/icons/22x22/status/aptdaemon-delete.png
-include data/icons/22x22/status/aptdaemon-download.png
-include data/icons/22x22/status/aptdaemon-resolve.png
-include data/icons/22x22/status/aptdaemon-update-cache.png
-include data/icons/22x22/status/aptdaemon-upgrade.png
-include data/icons/22x22/status/aptdaemon-wait.png
-include data/icons/22x22/status/aptdaemon-working.png
-include data/icons/24x24/animations/aptdaemon-action-cleaning-up.png
-include data/icons/24x24/animations/aptdaemon-action-downloading.png
-include data/icons/24x24/animations/aptdaemon-action-installing.png
-include data/icons/24x24/animations/aptdaemon-action-removing.png
-include data/icons/24x24/animations/aptdaemon-action-resolving.png
-include data/icons/24x24/animations/aptdaemon-action-updating-cache.png
-include data/icons/24x24/animations/aptdaemon-action-waiting.png
-include data/icons/24x24/status/aptdaemon-add.png
-include data/icons/24x24/status/aptdaemon-cleanup.png
-include data/icons/24x24/status/aptdaemon-delete.png
-include data/icons/24x24/status/aptdaemon-download.png
-include data/icons/24x24/status/aptdaemon-resolve.png
-include data/icons/24x24/status/aptdaemon-update-cache.png
-include data/icons/24x24/status/aptdaemon-upgrade.png
-include data/icons/24x24/status/aptdaemon-wait.png
-include data/icons/24x24/status/aptdaemon-working.png
-include data/icons/48x48/animations/aptdaemon-action-cleaning-up.png
-include data/icons/48x48/animations/aptdaemon-action-downloading.png
-include data/icons/48x48/animations/aptdaemon-action-installing.png
-include data/icons/48x48/animations/aptdaemon-action-removing.png
-include data/icons/48x48/animations/aptdaemon-action-resolving.png
-include data/icons/48x48/animations/aptdaemon-action-updating-cache.png
-include data/icons/48x48/animations/aptdaemon-action-waiting.png
-include data/icons/48x48/status/aptdaemon-add.png
-include data/icons/48x48/status/aptdaemon-cleanup.png
-include data/icons/48x48/status/aptdaemon-delete.png
-include data/icons/48x48/status/aptdaemon-download.png
-include data/icons/48x48/status/aptdaemon-resolve.png
-include data/icons/48x48/status/aptdaemon-update-cache.png
-include data/icons/48x48/status/aptdaemon-upgrade.png
-include data/icons/48x48/status/aptdaemon-wait.png
-include data/icons/48x48/status/aptdaemon-working.png
-include data/icons/clean_svg_icons.sh
-include data/icons/generate_16x16_icons.sh
-include data/icons/generate_24x24_icons.sh
-include data/icons/generate_48x48_icons.sh
-include data/icons/scalable/status/aptdaemon-add.svg
-include data/icons/scalable/status/aptdaemon-cleanup.svg
-include data/icons/scalable/status/aptdaemon-delete.svg
-include data/icons/scalable/status/aptdaemon-download.svg
-include data/icons/scalable/status/aptdaemon-resolve.svg
-include data/icons/scalable/status/aptdaemon-setup.svg
-include data/icons/scalable/status/aptdaemon-update-cache.svg
-include data/icons/scalable/status/aptdaemon-upgrade.svg
-include data/icons/scalable/status/aptdaemon-wait.svg
-include data/lintian/debian/aptdaemon.profile
-include data/lintian/ubuntu/aptdaemon.profile
-include data/org.debian.apt.conf
-include data/org.debian.apt.policy.in
-include data/org.debian.apt.service
-include data/org.freedesktop.PackageKit-aptd.conf
-include data/org.freedesktop.PackageKit.service
-include doc/aptd.1
-include doc/aptdcon.1
-include doc/examples/chained.py
-include doc/org.debian.apt.7
-include doc/org.debian.apt.transaction.7
-include doc/source/_ext/signals.py
-include doc/source/aptdaemon.client.rst
-include doc/source/aptdaemon.enums.rst
-include doc/source/aptdaemon.gtk3widgets.rst
-include doc/source/conf.py
-include doc/source/dbus.rst
-include doc/source/index.rst
-include doc/source/plugins.rst
-include gtk-demo.py
-include gtk3-demo.py
-include po/POTFILES.in
-include po/af.po
-include po/am.po
-include po/ar.po
-include po/ast.po
-include po/az.po
-include po/be.po
-include po/bg.po
-include po/bn.po
-include po/br.po
-include po/bs.po
-include po/ca.po
-include po/ca@valencia.po
-include po/crh.po
-include po/cs.po
-include po/cy.po
-include po/da.po
-include po/de.po
-include po/dv.po
-include po/el.po
-include po/en_AU.po
-include po/en_CA.po
-include po/en_GB.po
-include po/eo.po
-include po/es.po
-include po/et.po
-include po/eu.po
-include po/fa.po
-include po/fi.po
-include po/fil.po
-include po/fo.po
-include po/fr.po
-include po/gd.po
-include po/gl.po
-include po/he.po
-include po/hi.po
-include po/hr.po
-include po/hu.po
-include po/hy.po
-include po/id.po
-include po/is.po
-include po/it.po
-include po/ja.po
-include po/kk.po
-include po/km.po
-include po/kn.po
-include po/ko.po
-include po/ku.po
-include po/ky.po
-include po/ln.po
-include po/lt.po
-include po/lv.po
-include po/mi.po
-include po/ml.po
-include po/ms.po
-include po/my.po
-include po/nb.po
-include po/nds.po
-include po/ne.po
-include po/nl.po
-include po/nn.po
-include po/oc.po
-include po/pl.po
-include po/pt.po
-include po/pt_BR.po
-include po/ro.po
-include po/ru.po
-include po/se.po
-include po/shn.po
-include po/si.po
-include po/sk.po
-include po/sl.po
-include po/sq.po
-include po/sr.po
-include po/sv.po
-include po/ta.po
-include po/te.po
-include po/th.po
-include po/tr.po
-include po/ug.po
-include po/uk.po
-include po/ur.po
-include po/uz.po
-include po/vi.po
-include po/zh_CN.po
-include po/zh_HK.po
-include po/zh_TW.po
-include pylintrc
-include release.sh
-include setup.cfg
-include setup.py
-include tests/__init__.py
-include tests/_test_py2_string_handling.py
-include tests/_test_py3_string_handling.py
-include tests/data/high-trust-repository-whitelist-broken.cfg
-include tests/data/high-trust-repository-whitelist.cfg
-include tests/dbus.conf
-include tests/debconf/aptdaemon.config
-include tests/debconf/aptdaemon.templates
-include tests/dpkg-wrapper.sh
-include tests/fake-polkitd.py
-include tests/fakeroot-apt-key
-include tests/regressions/test_lp722228.py
-include tests/regressions/test_lp768691.py
-include tests/repo/Packages
-include tests/repo/Release
-include tests/repo/Release.gpg
-include tests/repo/backports/Packages
-include tests/repo/backports/Packages.gpg
-include tests/repo/backports/Release
-include tests/repo/backports/Release.gpg
-include tests/repo/glatzor.gpg
-include tests/repo/gstreamer0.10-silly_0.1-0_all.deb
-include tests/repo/security/Packages
-include tests/repo/security/Packages.gpg
-include tests/repo/security/Release
-include tests/repo/security/Release.gpg
-include tests/repo/silly-base_0.1-0_all.deb
-include tests/repo/silly-base_0.1-0update1_all.deb
-include tests/repo/silly-broken_0.1-0_all.deb
-include tests/repo/silly-bully_0.1-0_all.deb
-include tests/repo/silly-config_0.1-0_all.deb
-include tests/repo/silly-depend-base-lintian-broken_0.1-0_all.deb
-include tests/repo/silly-depend-base_0.1-0_all.deb
-include tests/repo/silly-essential_0.1-0_all.deb
-include tests/repo/silly-fail_0.1-0_all.deb
-include tests/repo/silly-important_0.1-0_all.deb
-include tests/repo/silly-postinst-input_0.1-0_all.deb
-include tests/repo/whitelisted/Packages
-include tests/repo/whitelisted/Packages.gpg
-include tests/repo/whitelisted/Release
-include tests/repo/whitelisted/Release.gpg
-include tests/test_cdrom.py
-include tests/test_client.py
-include tests/test_configfileprompt.py
-include tests/test_configparser.py
-include tests/test_dbus_type.py
-include tests/test_debconf.py
-include tests/test_gtk3widgets.py
-include tests/test_high_trust_repository_whitelist.py
-include tests/test_index.py
-include tests/test_lock.py
-include tests/test_lock_location.py
-include tests/test_pep8.py
-include tests/test_pk.py
-include tests/test_progress.py
-include tests/test_py2_string_handling.py
-include tests/test_simulate.py
-include tests/test_trans_chain.py
-include tests/test_valid_package_names.py
-include tests/test_worker.py
-include ChangeLog
diff -pruN 1.1.1-4/.pc/applied-patches 1.1.1+bzr982-0ubuntu14/.pc/applied-patches
--- 1.1.1-4/.pc/applied-patches	2015-10-12 18:06:09.946512042 +0000
+++ 1.1.1+bzr982-0ubuntu14/.pc/applied-patches	2015-10-12 18:06:10.266520824 +0000
@@ -1,11 +1,12 @@
-upstream_lintian_2.5.18.patch
-upstream_lp1024590.patch
 fix-high-trust-pkcompat.diff
-lp1153725-temporary-workaround.patch
-fix-ftbs.patch
-cve_2014.patch
 dbus_timeout.patch
-lp1266844.patch
-fix-configparser.patch
 py3_inheritable.patch
-upstream-include-pkg-version.patch
+lp1356823.diff
+lp1449587.diff
+pep8-accommodations.diff
+lp1487087.diff
+fix-installation.patch
+native-arch.patch
+key_value_typo.patch
+lintian_deprecated_error.patch
+lp1439769-aptdaemon-autoinstall.patch
diff -pruN 1.1.1-4/.pc/cve_2014.patch/aptdaemon/pkcompat.py 1.1.1+bzr982-0ubuntu14/.pc/cve_2014.patch/aptdaemon/pkcompat.py
--- 1.1.1-4/.pc/cve_2014.patch/aptdaemon/pkcompat.py	2013-08-11 19:07:59.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/.pc/cve_2014.patch/aptdaemon/pkcompat.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,3288 +0,0 @@
-# !/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""
-Provides a limited compatibility layer to PackageKit
-
-Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
-Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
-Copyright (C) 2008-2011 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>"
-
-import datetime
-import glob
-import gzip
-import locale
-import logging
-import os
-import platform
-import re
-import subprocess
-import tempfile
-import time
-import uuid
-
-import apt_pkg
-from defer import inline_callbacks, return_value
-from defer.utils import dbus_deferred_method
-import dbus
-from gi.repository import GObject, GLib
-from gi.repository import PackageKitGlib as pk
-
-# for optional plugin support
-try:
-    import pkg_resources
-except ImportError:
-    pkg_resources = None
-
-from . import policykit1
-from . import core
-from .core import APTDAEMON_TRANSACTION_DBUS_INTERFACE
-from . import enums as aptd_enums
-from .errors import TransactionFailed
-from . import errors
-from .progress import DaemonAcquireProgress
-from . import worker
-from . import networking
-
-
-pklog = logging.getLogger("AptDaemon.PackageKit")
-
-# Check if update-manager-core is installed to get aware of the
-# latest distro releases
-try:
-    from UpdateManager.Core.MetaRelease import MetaReleaseCore
-except ImportError:
-    META_RELEASE_SUPPORT = False
-else:
-    META_RELEASE_SUPPORT = True
-
-# Xapian database is optionally used to speed up package description search
-XAPIAN_DB_PATH = os.environ.get("AXI_DB_PATH", "/var/lib/apt-xapian-index")
-XAPIAN_DB = XAPIAN_DB_PATH + "/index"
-XAPIAN_DB_VALUES = XAPIAN_DB_PATH + "/values"
-XAPIAN_SUPPORT = False
-try:
-    import xapian
-except ImportError:
-    pass
-else:
-    if os.access(XAPIAN_DB, os.R_OK):
-        pklog.debug("Use XAPIAN for the search")
-        XAPIAN_SUPPORT = True
-
-# Regular expressions to detect bug numbers in changelogs according to the
-# Debian Policy Chapter 4.4. For details see the footnote 16:
-# http://www.debian.org/doc/debian-policy/footnotes.html#f16
-MATCH_BUG_CLOSES_DEBIAN = (
-    r"closes:\s*(?:bug)?\#?\s?\d+(?:,\s*(?:bug)?\#?\s?\d+)*")
-MATCH_BUG_NUMBERS = r"\#?\s?(\d+)"
-# URL pointing to a bug in the Debian bug tracker
-HREF_BUG_DEBIAN = "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s"
-
-MATCH_BUG_CLOSES_UBUNTU = r"lp:\s+\#\d+(?:,\s*\#\d+)*"
-HREF_BUG_UBUNTU = "https://bugs.launchpad.net/bugs/%s"
-
-# Regular expression to find cve references
-MATCH_CVE = "CVE-\d{4}-\d{4}"
-HREF_CVE = "http://web.nvd.nist.gov/view/vuln/detail?vulnId=%s"
-
-# Map Debian sections to the PackageKit group name space
-SECTION_GROUP_MAP = {
-    "admin": pk.GroupEnum.ADMIN_TOOLS,
-    "base": pk.GroupEnum.SYSTEM,
-    "cli-mono": pk.GroupEnum.PROGRAMMING,
-    "comm": pk.GroupEnum.COMMUNICATION,
-    "database": pk.GroupEnum.SERVERS,
-    "debian-installer": pk.GroupEnum.SYSTEM,
-    "debug": pk.GroupEnum.PROGRAMMING,
-    "devel": pk.GroupEnum.PROGRAMMING,
-    "doc": pk.GroupEnum.DOCUMENTATION,
-    "editors": pk.GroupEnum.PUBLISHING,
-    "education": pk.GroupEnum.EDUCATION,
-    "electronics": pk.GroupEnum.ELECTRONICS,
-    "embedded": pk.GroupEnum.SYSTEM,
-    "fonts": pk.GroupEnum.FONTS,
-    "games": pk.GroupEnum.GAMES,
-    "gnome": pk.GroupEnum.DESKTOP_GNOME,
-    "gnu-r": pk.GroupEnum.PROGRAMMING,
-    "gnustep": pk.GroupEnum.DESKTOP_OTHER,
-    "graphics": pk.GroupEnum.GRAPHICS,
-    "hamradio": pk.GroupEnum.COMMUNICATION,
-    "haskell": pk.GroupEnum.PROGRAMMING,
-    "httpd": pk.GroupEnum.SERVERS,
-    "interpreters": pk.GroupEnum.PROGRAMMING,
-    "introspection": pk.GroupEnum.PROGRAMMING,
-    "java": pk.GroupEnum.PROGRAMMING,
-    "kde": pk.GroupEnum.DESKTOP_KDE,
-    "kernel": pk.GroupEnum.SYSTEM,
-    "libdevel": pk.GroupEnum.PROGRAMMING,
-    "libs": pk.GroupEnum.SYSTEM,
-    "lisp": pk.GroupEnum.PROGRAMMING,
-    "localization": pk.GroupEnum.LOCALIZATION,
-    "mail": pk.GroupEnum.INTERNET,
-    "math": pk.GroupEnum.SCIENCE,
-    "misc": pk.GroupEnum.OTHER,
-    "net": pk.GroupEnum.NETWORK,
-    "news": pk.GroupEnum.INTERNET,
-    "ocaml": pk.GroupEnum.PROGRAMMING,
-    "oldlibs": pk.GroupEnum.LEGACY,
-    "otherosfs": pk.GroupEnum.SYSTEM,
-    "perl": pk.GroupEnum.PROGRAMMING,
-    "php": pk.GroupEnum.PROGRAMMING,
-    "python": pk.GroupEnum.PROGRAMMING,
-    "ruby": pk.GroupEnum.PROGRAMMING,
-    "science": pk.GroupEnum.SCIENCE,
-    "shells": pk.GroupEnum.ADMIN_TOOLS,
-    "sound": pk.GroupEnum.MULTIMEDIA,
-    "tex": pk.GroupEnum.PUBLISHING,
-    "text": pk.GroupEnum.PUBLISHING,
-    "utils": pk.GroupEnum.ACCESSORIES,
-    "vcs": pk.GroupEnum.PROGRAMMING,
-    "video": pk.GroupEnum.MULTIMEDIA,
-    "virtual": pk.GroupEnum.COLLECTIONS,
-    "web": pk.GroupEnum.INTERNET,
-    "xfce": pk.GroupEnum.DESKTOP_OTHER,
-    "x11": pk.GroupEnum.DESKTOP_OTHER,
-    "zope": pk.GroupEnum.PROGRAMMING,
-    "unknown": pk.GroupEnum.UNKNOWN,
-    "alien": pk.GroupEnum.UNKNOWN,
-    "translations": pk.GroupEnum.LOCALIZATION,
-    "metapackages": pk.GroupEnum.COLLECTIONS,
-    "tasks": pk.GroupEnum.COLLECTIONS}
-
-PACKAGEKIT_DBUS_INTERFACE = "org.freedesktop.PackageKit"
-PACKAGEKIT_DBUS_SERVICE = "org.freedesktop.PackageKit"
-PACKAGEKIT_DBUS_PATH = "/org/freedesktop/PackageKit"
-
-PACKAGEKIT_TRANS_DBUS_INTERFACE = "org.freedesktop.PackageKit.Transaction"
-PACKAGEKIT_TRANS_DBUS_SERVICE = "org.freedesktop.PackageKit.Transaction"
-
-MAP_EXIT_ENUM = {
-    aptd_enums.EXIT_SUCCESS: pk.ExitEnum.SUCCESS,
-    aptd_enums.EXIT_CANCELLED: pk.ExitEnum.CANCELLED,
-    aptd_enums.EXIT_FAILED: pk.ExitEnum.FAILED,
-    aptd_enums.EXIT_FAILED: pk.ExitEnum.FAILED,
-    aptd_enums.EXIT_PREVIOUS_FAILED: pk.ExitEnum.FAILED}
-
-MAP_STATUS_ENUM = {
-    aptd_enums.STATUS_AUTHENTICATING: pk.StatusEnum.WAITING_FOR_AUTH,
-    aptd_enums.STATUS_SETTING_UP: pk.StatusEnum.SETUP,
-    aptd_enums.STATUS_QUERY: pk.StatusEnum.QUERY,
-    aptd_enums.STATUS_WAITING: pk.StatusEnum.WAIT,
-    aptd_enums.STATUS_RUNNING: pk.StatusEnum.RUNNING,
-    aptd_enums.STATUS_CANCELLING: pk.StatusEnum.CANCEL,
-    aptd_enums.STATUS_CLEANING_UP: pk.StatusEnum.CLEANUP,
-    aptd_enums.STATUS_COMMITTING: pk.StatusEnum.COMMIT,
-    aptd_enums.STATUS_DOWNLOADING: pk.StatusEnum.DOWNLOAD,
-    aptd_enums.STATUS_DOWNLOADING_REPO: pk.StatusEnum.DOWNLOAD_REPOSITORY,
-    aptd_enums.STATUS_FINISHED: pk.StatusEnum.FINISHED,
-    aptd_enums.STATUS_LOADING_CACHE: pk.StatusEnum.LOADING_CACHE,
-    aptd_enums.STATUS_RESOLVING_DEP: pk.StatusEnum.DEP_RESOLVE,
-    aptd_enums.STATUS_RUNNING: pk.StatusEnum.RUNNING,
-    aptd_enums.STATUS_WAITING_LOCK: pk.StatusEnum.WAITING_FOR_LOCK,
-    aptd_enums.STATUS_WAITING_MEDIUM: pk.StatusEnum.UNKNOWN,
-    aptd_enums.STATUS_WAITING_CONFIG_FILE_PROMPT: pk.StatusEnum.UNKNOWN}
-
-MAP_ERROR_ENUM = {
-    aptd_enums.ERROR_CACHE_BROKEN: pk.ErrorEnum.NO_CACHE,
-    aptd_enums.ERROR_DEP_RESOLUTION_FAILED: (
-        pk.ErrorEnum.DEP_RESOLUTION_FAILED),
-    aptd_enums.ERROR_INCOMPLETE_INSTALL: pk.ErrorEnum.NO_CACHE,
-    aptd_enums.ERROR_INVALID_PACKAGE_FILE: (
-        pk.ErrorEnum.PACKAGE_CORRUPT),
-    aptd_enums.ERROR_KEY_NOT_INSTALLED: pk.ErrorEnum.GPG_FAILURE,
-    aptd_enums.ERROR_KEY_NOT_REMOVED: pk.ErrorEnum.GPG_FAILURE,
-    aptd_enums.ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE: (
-        pk.ErrorEnum.PACKAGE_FAILED_TO_REMOVE),
-    aptd_enums.ERROR_NO_CACHE: pk.ErrorEnum.NO_CACHE,
-    aptd_enums.ERROR_NO_LOCK: pk.ErrorEnum.CANNOT_GET_LOCK,
-    aptd_enums.ERROR_NO_PACKAGE: pk.ErrorEnum.PACKAGE_NOT_FOUND,
-    aptd_enums.ERROR_PACKAGE_ALREADY_INSTALLED: (
-        pk.ErrorEnum.PACKAGE_ALREADY_INSTALLED),
-    aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED: (
-        pk.ErrorEnum.PACKAGE_DOWNLOAD_FAILED),
-    aptd_enums.ERROR_PACKAGE_MANAGER_FAILED: (
-        pk.ErrorEnum.TRANSACTION_ERROR),
-    aptd_enums.ERROR_PACKAGE_NOT_INSTALLED: (
-        pk.ErrorEnum.PACKAGE_NOT_INSTALLED),
-    aptd_enums.ERROR_PACKAGE_UNAUTHENTICATED: (
-        pk.ErrorEnum.BAD_GPG_SIGNATURE),
-    aptd_enums.ERROR_PACKAGE_UPTODATE: (
-        pk.ErrorEnum.NO_PACKAGES_TO_UPDATE),
-    aptd_enums.ERROR_REPO_DOWNLOAD_FAILED: (
-        pk.ErrorEnum.REPO_NOT_AVAILABLE),
-    aptd_enums.ERROR_UNREADABLE_PACKAGE_FILE: (
-        pk.ErrorEnum.INVALID_PACKAGE_FILE),
-    aptd_enums.ERROR_SYSTEM_ALREADY_UPTODATE: (
-        pk.ErrorEnum.NO_PACKAGES_TO_UPDATE),
-    aptd_enums.ERROR_NOT_AUTHORIZED: pk.ErrorEnum.NOT_AUTHORIZED,
-    aptd_enums.ERROR_AUTH_FAILED: pk.ErrorEnum.NOT_AUTHORIZED}
-
-MAP_PACKAGE_ENUM = {
-    aptd_enums.PKG_CONFIGURING: pk.InfoEnum.INSTALLING,
-    aptd_enums.PKG_DISAPPEARING: pk.InfoEnum.UNKNOWN,
-    aptd_enums.PKG_INSTALLED: pk.InfoEnum.FINISHED,
-    aptd_enums.PKG_INSTALLING: pk.InfoEnum.INSTALLING,
-    aptd_enums.PKG_PREPARING_INSTALL: pk.InfoEnum.PREPARING,
-    aptd_enums.PKG_PREPARING_PURGE: pk.InfoEnum.PREPARING,
-    aptd_enums.PKG_PREPARING_REMOVE: pk.InfoEnum.PREPARING,
-    aptd_enums.PKG_PURGED: pk.InfoEnum.FINISHED,
-    aptd_enums.PKG_PURGING: pk.InfoEnum.REMOVING,
-    aptd_enums.PKG_REMOVED: pk.InfoEnum.FINISHED,
-    aptd_enums.PKG_REMOVING: pk.InfoEnum.REMOVING,
-    aptd_enums.PKG_RUNNING_TRIGGER: pk.InfoEnum.CLEANUP,
-    aptd_enums.PKG_UNKNOWN: pk.InfoEnum.UNKNOWN,
-    aptd_enums.PKG_UNPACKING: pk.InfoEnum.DECOMPRESSING,
-    aptd_enums.PKG_UPGRADING: pk.InfoEnum.UPDATING}
-
-MAP_POLICY = {
-    "org.freedesktop.packagekit.cancel-foreign": (
-        policykit1.PK_ACTION_CANCEL_FOREIGN),
-    "org.freedesktop.packagekit.package-install": (
-        policykit1.PK_ACTION_INSTALL_OR_REMOVE_PACKAGES),
-    "org.freedesktop.packagekit.package-install-untrusted": (
-        policykit1.PK_ACTION_INSTALL_OR_REMOVE_PACKAGES),
-    "org.freedesktop.packagekit.system-trust-signing-key": (
-        policykit1.PK_ACTION_CHANGE_REPOSITORY),
-    "org.freedesktop.packagekit.package-eula-accept": (
-        policykit1.PK_ACTION_INSTALL_OR_REMOVE_PACKAGES),
-    "org.freedesktop.packagekit.package-remove": (
-        policykit1.PK_ACTION_INSTALL_OR_REMOVE_PACKAGES),
-    "org.freedesktop.packagekit.system-update": (
-        policykit1.PK_ACTION_UPGRADE_PACKAGES),
-    "org.freedesktop.packagekit.system-sources-configure": (
-        policykit1.PK_ACTION_CHANGE_REPOSITORY),
-    "org.freedesktop.packagekit.system-sources-refresh": (
-        policykit1.PK_ACTION_UPDATE_CACHE),
-    "org.freedesktop.packagekit.system-network-proxy-configure": (
-        policykit1.PK_ACTION_SET_PROXY),
-    "org.freedesktop.packagekit.device-rebind": (
-        policykit1.PK_ACTION_INSTALL_OR_REMOVE_PACKAGES),
-    "org.freedesktop.packagekit.upgrade-system": (
-        policykit1.PK_ACTION_UPGRADE_PACKAGES),
-    "org.freedesktop.packagekit.repair-system": (
-        policykit1.PK_ACTION_INSTALL_OR_REMOVE_PACKAGES),
-    "org.freedesktop.packagekit.trigger-offline-update": (
-        policykit1.PK_ACTION_UPGRADE_PACKAGES),
-    "org.freedesktop.packagekit.clear-offline-update": (
-        policykit1.PK_ACTION_UPGRADE_PACKAGES)}
-
-NATIVE_ARCH = apt_pkg.get_architectures()[0]
-
-
-class PackageKit(core.DBusObject):
-
-    """Provides a limited set of the PackageKit system D-Bus API."""
-
-    def __init__(self, queue, connect=True, bus=None):
-        """Initialize a new PackageKit compatibility layer.
-
-        Keyword arguments:
-        connect -- if the daemon should connect to the D-Bus (default is True)
-        bus -- the D-Bus to connect to (defaults to the system bus)
-        """
-        pklog.info("Initializing PackageKit compat layer")
-        bus_name = None
-        bus_path = None
-        if connect is True:
-            if bus is None:
-                bus = dbus.SystemBus()
-            self.bus = bus
-            bus_path = PACKAGEKIT_DBUS_PATH
-            bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, self.bus)
-        core.DBusObject.__init__(self, bus_name, bus_path)
-        self._updates_changed_timeout_id = None
-        self._updates_changed = False
-        self.queue = queue
-        self.queue.worker.connect("transaction-done",
-                                  self._on_transaction_done)
-        self.queue.connect("queue-changed", self._on_queue_changed)
-        self._distro_id = None
-        self.netmon = networking.get_network_monitor()
-        self.netmon.connect("network-state-changed",
-                            self._on_network_state_changed)
-        self.roles = bitfield_summarize(pk.RoleEnum.REFRESH_CACHE,
-                                        pk.RoleEnum.UPDATE_PACKAGES,
-                                        pk.RoleEnum.INSTALL_PACKAGES,
-                                        pk.RoleEnum.INSTALL_FILES,
-                                        pk.RoleEnum.REMOVE_PACKAGES,
-                                        pk.RoleEnum.GET_UPDATES,
-                                        pk.RoleEnum.GET_UPDATE_DETAIL,
-                                        pk.RoleEnum.GET_PACKAGES,
-                                        pk.RoleEnum.GET_DETAILS,
-                                        pk.RoleEnum.GET_DEPENDS,
-                                        pk.RoleEnum.GET_REQUIRES,
-                                        pk.RoleEnum.SEARCH_NAME,
-                                        pk.RoleEnum.SEARCH_DETAILS,
-                                        pk.RoleEnum.SEARCH_GROUP,
-                                        pk.RoleEnum.SEARCH_FILE,
-                                        pk.RoleEnum.WHAT_PROVIDES,
-                                        pk.RoleEnum.REPO_ENABLE,
-                                        pk.RoleEnum.INSTALL_SIGNATURE,
-                                        pk.RoleEnum.REPAIR_SYSTEM,
-                                        pk.RoleEnum.CANCEL,
-                                        pk.RoleEnum.DOWNLOAD_PACKAGES)
-        if META_RELEASE_SUPPORT:
-            self.roles = bitfield_add(self.roles,
-                                      pk.RoleEnum.GET_DISTRO_UPGRADES)
-        self.filters = bitfield_summarize(pk.FilterEnum.INSTALLED,
-                                          pk.FilterEnum.NOT_INSTALLED,
-                                          pk.FilterEnum.FREE,
-                                          pk.FilterEnum.NOT_FREE,
-                                          pk.FilterEnum.GUI,
-                                          pk.FilterEnum.NOT_GUI,
-                                          pk.FilterEnum.COLLECTIONS,
-                                          pk.FilterEnum.NOT_COLLECTIONS,
-                                          pk.FilterEnum.SUPPORTED,
-                                          pk.FilterEnum.NOT_SUPPORTED,
-                                          pk.FilterEnum.ARCH,
-                                          pk.FilterEnum.NOT_ARCH,
-                                          pk.FilterEnum.NEWEST)
-        self.groups = bitfield_summarize(*SECTION_GROUP_MAP.values())
-        #FIXME: Add support for Plugins
-        self.provides = (pk.ProvidesEnum.ANY)
-
-        self._get_network_state()
-
-    @inline_callbacks
-    def _get_network_state(self):
-        """Helper to defer the network state checking."""
-        yield self.netmon.get_network_state()
-
-    # SIGNALS
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
-                         signature="")
-    def RestartSchedule(self):
-        """A system restart has been sceduled."""
-        pass
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
-                         signature="as")
-    def TransactionListChanged(self, transactions):
-        """The transaction list has changed, because either a transaction
-        has finished or a new transaction created.
-
-        :param transactions: A list of transaction ID's.
-        :type transactions: as
-        """
-        pklog.debug("Emitting TransactionListChanged signal: %s", transactions)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
-                         signature="")
-    def UpdatesChanged(self):
-        """This signal is emitted when the number of updates has changed."""
-        pklog.debug("Emitting UpdatesChanged signal")
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
-                         signature="")
-    def RepoListChanged(self):
-        """This signal is emitted when the repository list has changed."""
-        pass
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
-                         signature="")
-    def Changed(self):
-        """This signal is emitted when a property on the interface changes."""
-        pklog.debug("Emitting PackageKit Changed()")
-
-    # METHODS
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus_deferred_method(PACKAGEKIT_DBUS_INTERFACE,
-                          in_signature="s", out_signature="u",
-                          sender_keyword="sender")
-    def CanAuthorize(self, action_id, sender):
-        """Allows a client to find out if it would be allowed to authorize
-        an action.
-
-        :param action_id: The action ID, e.g.
-                org.freedesktop.packagekit.system-network-proxy-configure
-        :returns: The result, either yes, no or interactive.
-        """
-        pklog.info("CanAuthorize() was called: %s", str(action_id))
-        return self._can_authorize(action_id, sender)
-
-    @inline_callbacks
-    def _can_authorize(self, action_id, sender):
-        try:
-            action_id_aptd = MAP_POLICY[action_id]
-        except KeyError:
-            return_value(pk.AuthorizeEnum.UNKNOWN)
-        try:
-            policykit1.check_authorization_by_name(
-                self, action_id, flags=policykit1.CHECK_AUTH_NONE)
-        except policykit1.NotAuthorizedError:
-            return_value(pk.AuthorizeEnum.NO)
-        except policykit1.AuthorizationFailed:
-            # check_authorization_* behaves a little bit different if the
-            # flags are set to NONE instead of INTERACTIVE
-            return_value(pk.AuthorizeEnum.INTERACTIVE)
-        except:
-            return_value(pk.AuthorizeEnum.UNKNOWN)
-        return_value(pk.AuthorizeEnum.YES)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
-                         in_signature="s", out_signature="")
-    def StateHasChanged(self, reason):
-        """This method suggests to PackageKit that the package backend state
-        may have changed. This allows plugins to the native package manager
-        to suggest that PackageKit drops it's caches.
-
-        :param reason:
-            The reason of the state change. Valid reasons are resume or
-            posttrans. Resume is given a lower priority than posttrans.
-        """
-        pklog.info("StateHasChanged() was called: %s", str(reason))
-        self._updates_changed = True
-        if reason == "cache-update":
-            self._check_updates_changed(timeout=30)
-        elif reason == "resume":
-            self._check_updates_changed(timeout=180)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus_deferred_method(PACKAGEKIT_DBUS_INTERFACE,
-                          in_signature="", out_signature="o",
-                          sender_keyword="sender")
-    def CreateTransaction(self, sender):
-        """Gets a new transaction ID from the daemon.
-
-        :returns: The tid, e.g. 45_dafeca_checkpoint32
-        """
-        pklog.info("CreateTransaction() was called")
-        return self._create_transaction(sender)
-
-    @inline_callbacks
-    def _create_transaction(self, sender):
-        pid, uid, cmdline = yield policykit1.get_proc_info_from_dbus_name(
-            sender, self.bus)
-        pktrans = PackageKitTransaction(pid, uid, cmdline, self.queue, sender)
-        return_value(pktrans.tid)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
-                         in_signature="", out_signature="s")
-    def GetDaemonState(self):
-        """Return the state of the currently running transactions."""
-        pklog.info("GetDaemonState() was called")
-        #FIXME: Add some useful data here
-        return "All is fine!"
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
-                         in_signature="", out_signature="ao")
-    def GetTransactionList(self):
-        """Gets the transaction list of any transactions that are in
-        progress.
-
-        :returns: A list of transaction ID's
-        """
-        pklog.info("GetTransactionList() was called")
-        return self._get_transaction_list()
-
-    # HELPERS
-
-    def _get_properties(self, iface):
-        """Helper to get the properties of a D-Bus interface."""
-        if iface == PACKAGEKIT_DBUS_INTERFACE:
-            return {
-                # Claim that we are a current version
-                "VersionMajor": dbus.UInt32(0),
-                "VersionMinor": dbus.UInt32(8),
-                "VersionMicro": dbus.UInt32(9),
-                "BackendName": dbus.String("aptdaemon"),
-                "BackendDescription": dbus.String("Compatibility layer"),
-                "BackendAuthor": dbus.String(__author__),
-                "Groups": dbus.UInt64(self.groups),
-                "Provides": dbus.UInt64(self.provides),
-                "Filters": dbus.UInt64(self.filters),
-                "Roles": dbus.UInt64(self.roles),
-                "MimeTypes": dbus.Array(["application/x-deb"], signature="s"),
-                "Locked": dbus.Boolean(False),
-                "NetworkState": dbus.UInt32(self.netmon.state),
-                "DistroId": dbus.String(self._get_distro_id())}
-        else:
-            return {}
-
-    def _get_distro_id(self):
-        """Return information about the distibution."""
-        if self._distro_id is None:
-            distro, version, _codename = platform.dist()
-            self._distro_id = "%s;%s;%s" % (distro or "unknown",
-                                            version or "unknown",
-                                            NATIVE_ARCH)
-        return self._distro_id
-
-    def _on_network_state_changed(self, mon, state):
-        self.Changed()
-        self.PropertiesChanged(PACKAGEKIT_DBUS_INTERFACE,
-                               {"NetworkState": dbus.UInt32(state)}, [])
-
-    def _on_queue_changed(self, queue):
-        self.TransactionListChanged(self._get_transaction_list())
-        self._check_updates_changed()
-
-    def _get_transaction_list(self):
-        pk_transactions = []
-        for trans in self.queue.items:
-            # We currently only emit PackageKit transaction
-            #FIXME: Should we use MergedTransaction for all transactions and
-            #       ROLE_UNKOWN for aptdaemon only transactions?
-            try:
-                pk_transactions.append(trans.pktrans.tid)
-            except AttributeError:
-                pass
-        try:
-            pk_transactions.append(self.queue.worker.trans.pktrans.tid)
-        except AttributeError:
-            pass
-        return pk_transactions
-
-    def _on_transaction_done(self, worker, trans):
-        # If a cache modifing transaction is completed schedule an
-        # UpdatesChanged signal
-        if trans.role in (aptd_enums.ROLE_INSTALL_FILE,
-                          aptd_enums.ROLE_INSTALL_PACKAGES,
-                          aptd_enums.ROLE_REMOVE_PACKAGES,
-                          aptd_enums.ROLE_UPGRADE_PACKAGES,
-                          aptd_enums.ROLE_COMMIT_PACKAGES,
-                          aptd_enums.ROLE_UPGRADE_SYSTEM,
-                          aptd_enums.ROLE_FIX_BROKEN_DEPENDS):
-            self._updates_changed = True
-            self._check_updates_changed()
-        elif trans.role == aptd_enums.ROLE_UPDATE_CACHE:
-            self._updates_changed = True
-            self._check_updates_changed(timeout=30)
-
-    def _check_updates_changed(self, timeout=60):
-        """After the queue was processed schedule a delayed UpdatesChanged
-        signal if required.
-        """
-        if not self.queue.items and self._updates_changed:
-            if self._updates_changed_timeout_id:
-                # If we already have a scheduled UpdatesChanged signal
-                # delay it even further
-                pklog.debug("UpdatesChanged signal re-scheduled")
-                GLib.source_remove(self._updates_changed_timeout_id)
-            else:
-                pklog.debug("UpdatesChanged signal scheduled")
-            self._updates_changed_timeout_id = \
-                GLib.timeout_add_seconds(timeout,
-                                         self._delayed_updates_changed)
-
-    def _delayed_updates_changed(self):
-        """Emit the UpdatesChanged signal and clear the timeout."""
-        self.UpdatesChanged()
-        self._updates_changed_timeout_id = None
-        self._updates_changed = False
-        return False
-
-
-class MergedTransaction(core.Transaction):
-
-    """Overlay of an Aptdaemon transaction which also provides the
-    PackageKit object and its interfaces.
-    """
-
-    def __init__(self, pktrans, role, queue, connect=True,
-                 bus=None, packages=None, kwargs=None):
-        core.Transaction.__init__(self, pktrans.tid[1:], role, queue,
-                                  pktrans.pid, pktrans.uid,
-                                  pktrans.cmdline, pktrans.sender,
-                                  connect, bus, packages, kwargs)
-        self.pktrans = pktrans
-        self.run_time = 0
-
-    @inline_callbacks
-    def _run(self, sender):
-        """Run the transaction and convert exceptions to PackageKit ones."""
-        try:
-            yield core.Transaction._run(self, sender)
-        except (TransactionFailed, errors.NotAuthorizedError,
-                errors.AuthorizationFailed):
-            # It is sufficient for PackageKit if the exit state and error
-            # code of the transaction are set. So silently drop the execp
-            if self.error:
-                pass
-        except Exception as error:
-            raise error
-
-    @inline_callbacks
-    def _check_auth(self):
-        """Override the auth method to allow simulates without any
-        authorization.
-        """
-        if bitfield_contains(self.pktrans.flags,
-                             pk.TransactionFlagEnum.SIMULATE):
-            raise StopIteration
-        else:
-            yield core.Transaction._check_auth(self)
-
-    @inline_callbacks
-    def _check_simulated(self):
-        """Skip simulate calls for simulated transactions."""
-        if bitfield_contains(self.pktrans.flags,
-                             pk.TransactionFlagEnum.SIMULATE):
-            raise StopIteration
-        else:
-            yield core.Transaction._check_simulated(self)
-
-    def _set_status(self, enum):
-        core.Transaction._set_status(self, enum)
-        self.pktrans.status = get_pk_status_enum(enum)
-
-    status = property(core.Transaction._get_status, _set_status)
-
-    def _set_progress(self, percent):
-        core.Transaction._set_progress(self, percent)
-        self.pktrans.percentage = self._progress
-
-    progress = property(core.Transaction._get_progress, _set_progress)
-
-    def _set_progress_details(self, details):
-        core.Transaction._set_progress_details(self, details)
-        self.pktrans.download_size_remaing = int(details[3]) - int(details[2])
-        self.pktrans.speed = int(details[4])
-        self.pktrans.remaining_time = int(details[5])
-        self.pktrans.elapsed_time = int(time.time() - self.pktrans.start_time)
-
-    progress_details = property(core.Transaction._get_progress_details,
-                                _set_progress_details)
-
-    def _set_progress_package(self, progress):
-        core.Transaction._set_progress_package(self, progress)
-        pkg_name, enum = progress
-        # Ignore dpkg triggers
-        if enum == aptd_enums.PKG_RUNNING_TRIGGER or pkg_name == "dpkg-exec":
-            return
-        try:
-            id = self.pktrans.pkg_id_cache[pkg_name]
-        except KeyError:
-            id = get_pk_package_id(pkg_name)
-        self.emit_package(get_pk_package_enum(enum), id, "")
-
-    progress_package = property(core.Transaction._get_progress_package,
-                                _set_progress_package)
-
-    def _set_progress_download(self, progress_download):
-        core.Transaction._set_progress_download(self, progress_download)
-        prog_enum = progress_download[1]
-        prog_name = progress_download[2]
-        total_size = progress_download[3]
-        partial_size = progress_download[4]
-
-        try:
-            id = self.pktrans.pkg_id_cache[prog_name]
-        except KeyError:
-            return
-        self.pktrans.Package(pk.InfoEnum.DOWNLOADING, id, "")
-        if prog_enum == aptd_enums.DOWNLOAD_IDLE:
-            percentage = 0
-        elif prog_enum == aptd_enums.DOWNLOAD_FETCHING and total_size > 0:
-            percentage = partial_size * 100 / total_size
-        elif prog_enum == aptd_enums.DOWNLOAD_DONE:
-            percentage = 100
-        else:
-            # In the case of an error
-            percentage = 0
-        self.pktrans.ItemProgress(id, pk.InfoEnum.DOWNLOADING, percentage)
-
-    progress_download = property(core.Transaction._get_progress_download,
-                                 _set_progress_download)
-
-    def _set_exit(self, enum):
-        core.Transaction._set_exit(self, enum)
-        self.pktrans.exit = get_pk_exit_enum(enum)
-
-    exit = property(core.Transaction._get_exit, _set_exit)
-
-    def _set_error(self, excep):
-        core.Transaction._set_error(self, excep)
-        self.pktrans.ErrorCode(get_pk_error_enum(excep.code),
-                               self._error_property[1])
-
-    error = property(core.Transaction._get_error, _set_error)
-
-    def _remove_from_connection_no_raise(self):
-        core.Transaction._remove_from_connection_no_raise(self)
-        self.pktrans.Destroy()
-        try:
-            self.pktrans.remove_from_connection()
-        except LookupError as error:
-            pklog.debug("remove_from_connection() raised LookupError: %s",
-                        error)
-        finally:
-            self.pktrans.trans = None
-            self.pktrans = None
-        return False
-
-    def emit_details(self, package_id, license, group, detail, url, size):
-        self.pktrans.Details(package_id, license, group, detail, url, size)
-
-    def emit_files(self, id, file_list):
-        self.pktrans.Files(id, file_list)
-
-    def emit_package(self, info, id, summary):
-        if id.startswith("dpkg-exec;"):
-            # PackageKit would show a non existing package
-            pklog.debug("Don't emit Package() signal for the dpkg trigger")
-            return
-        self.pktrans.Package(info, id, summary)
-        self.pktrans.last_package = id
-
-    def emit_update_detail(self, package_id, updates, obsoletes, vendor_urls,
-                           bugzilla_urls, cve_urls, restart, update_text,
-                           changelog, state, issued, updated):
-        self.pktrans.UpdateDetail(package_id, updates, obsoletes, vendor_urls,
-                                  bugzilla_urls, cve_urls, restart,
-                                  update_text, changelog, state, issued,
-                                  updated)
-
-
-class PackageKitTransaction(core.DBusObject):
-
-    """Provides a PackageKit transaction object."""
-
-    def __init__(self, pid, uid, cmdline, queue, sender,
-                 connect=True, bus=None):
-        pklog.info("Initializing PackageKit transaction")
-        bus_name = None
-        bus_path = None
-        self.tid = "/%s" % uuid.uuid4().hex
-        if connect is True:
-            if bus is None:
-                bus = dbus.SystemBus()
-            self.bus = bus
-            bus_path = self.tid
-            bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, bus)
-        core.DBusObject.__init__(self, bus_name, bus_path)
-        self.queue = queue
-        self.hints = {}
-        self.start_time = time.time()
-        self._elapsed_time = dbus.UInt32(0)
-        self._remaining_time = dbus.UInt32(0)
-        self._download_size_remaining = dbus.UInt64(0)
-        self._speed = dbus.UInt32(0)
-        self._caller_active = True
-        self._allow_cancel = False
-        self._percentage = dbus.UInt32(0)
-        self._status = pk.StatusEnum.SETUP
-        self._last_package = ""
-        self.uid = dbus.UInt32(uid)
-        self.pid = pid
-        self.cmdline = cmdline
-        self.role = pk.RoleEnum.UNKNOWN
-        self.sender = sender
-        self.trans = None
-        self.flags = pk.TransactionFlagEnum.NONE
-        self.pkg_id_cache = {}
-
-    @property
-    def allow_cancel(self):
-        return self._allow_cancel
-
-    @allow_cancel.setter
-    def allow_cancel(self, value):
-        self._allow_cancel = dbus.Boolean(value)
-        self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                               {"AllowCancel": self._allow_cancel}, [])
-        self.Changed()
-
-    @property
-    def last_package(self):
-        return self._last_package
-
-    @last_package.setter
-    def last_package(self, value):
-        self._last_package = dbus.String(value)
-        self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                               {"LastPackage": self._last_package}, [])
-        self.Changed()
-
-    @property
-    def caller_active(self):
-        return self._caller_active
-
-    @caller_active.setter
-    def caller_active(self, value):
-        self._caller_active = dbus.Boolean(value)
-        self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                               {"CallerActive": self._caller_active}, [])
-        self.Changed()
-
-    @property
-    def percentage(self):
-        return self._percentage
-
-    @percentage.setter
-    def percentage(self, progress):
-        self._percentage = dbus.UInt32(progress)
-        self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                               {"Percentage": self._percentage}, [])
-        self.Changed()
-
-    @property
-    def status(self):
-        return self._status
-
-    @status.setter
-    def status(self, enum):
-        self._status = dbus.UInt32(enum)
-        self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                               {"Status": self._status}, [])
-        self.Changed()
-
-    @property
-    def elapsed_time(self):
-        return self._elapsed_time
-
-    @elapsed_time.setter
-    def elapsed_time(self, ela):
-        self._elpased_time = dbus.UInt32(ela)
-        self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                               {"ElapsedTime": self._elapsed_time}, [])
-        self.Changed()
-
-    @property
-    def remaining_time(self):
-        return self._remaining_time
-
-    @remaining_time.setter
-    def remaining_time(self, value):
-        self._remaining_time = dbus.UInt32(value)
-        self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                               {"RemainingTime": self._remaining_time}, [])
-        self.Changed()
-
-    @property
-    def download_size_remaining(self):
-        return self._download_size_remaining
-
-    @download_size_remaining.setter
-    def download_size_remaining(self, value):
-        self._download_size_remaining = dbus.UInt64(value)
-        self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                               {"DownloadSizeRemaining":
-                                self._download_size_remaining}, [])
-        self.Changed()
-
-    @property
-    def speed(self):
-        return self._speed
-
-    @speed.setter
-    def speed(self, speed):
-        self._speed = dbus.UInt32(speed)
-        self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                               {"Speed": self._speed}, [])
-        self.Changed()
-
-    @property
-    def exit(self):
-        return self._exit
-
-    @exit.setter
-    def exit(self, enum):
-        self._exit = enum
-        self.run_time = int((time.time() - self.start_time) * 1000)
-        # The time could go backwards ...
-        if self.run_time < 0:
-            self.run_time = 0
-        if enum == pk.ExitEnum.CANCELLED:
-            self.ErrorCode(pk.ErrorEnum.TRANSACTION_CANCELLED, "")
-        self.status = pk.StatusEnum.FINISHED
-        self.Finished(enum, self.run_time)
-
-    # SIGNALS
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         signature="osbuusus")
-    def Transaction(self, object_path, timespec, succeeded, role, duration,
-                    data, uid, cmdline):
-        """This signal is sent when more details are required about a
-        specific transaction.
-
-        :param object_path: The transaction ID of the old transaction.
-        :param timespec: The timespec of the old transaction in ISO8601 format.
-        :param succeeded: If the transaction succeeded.
-        :param role: The role enumerated type.
-        :param duration: The duration of the transaction in milliseconds.
-        :param data: Any data associated
-        :param uid: The user ID of the user that scheduled the action.
-        :param cmdline: The command line of the tool that scheduled the action,
-            e.g. /usr/bin/gpk-application.
-        """
-        pklog.debug("Emitting Transaction signal: %s, %s, %s, %s, %s, %s, "
-                    "%s, %s", object_path, timespec, succeeded,
-                    pk.role_enum_to_string(role), duration, data, uid,
-                    cmdline)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         signature="us")
-    def ErrorCode(self, code, details):
-        """This signal is used to report errors back to the session program.
-        Errors should only be send on fatal abort.
-
-        :param code: Enumerated type, e.g. no-network.
-        :param details: Long description or error, e.g. "failed to connect"
-
-        :type code: u
-        :type details: s
-        """
-        pklog.debug("Emitting ErrorCode signal: %s, %s",
-                    pk.error_enum_to_string(code), details)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         signature="")
-    def Changed(self):
-        """This signal is emitted when a property on the interface changes."""
-        pklog.debug("Emitting Changed signal")
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         signature="")
-    def Destroy(self):
-        """This signal is sent when the transaction has been destroyed
-        and is no longer available for use."""
-        pklog.debug("Emitting Destroy signal")
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         signature="uu")
-    def Finished(self, exit_enum, runtime):
-        """This signal is used to signal that the transaction has finished.
-        :param exit: The PkExitEnum describing the exit status of the
-            transaction.
-        :param runtime: The amount of time in milliseconds that the
-            transaction ran for.
-
-        :type exit: s
-        :type runtime: u
-        """
-        pklog.debug("Emitting Finished signal: %s, %s",
-                    pk.exit_enum_to_string(exit_enum), runtime)
-        pass
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         signature="ssusst")
-    def Details(self, package_id, license, group, detail, url, size):
-        """This signal allows the backend to convey more details about the
-        package.
-
-        :param package_id: The package ID
-
-        :param license:
-            The license string, e.g. GPLv2+ or BSD and (MPLv1.1 or GPLv2+).
-            Moredetails about the correct way to format licensing strings can
-            be found on the Fedora packaging wiki.
-        :param group:
-            The enumerated package group description
-        :param detail:
-            The multi-line package description. If formatting is required,
-            then markdown syntax should be used, e.g. This is **critically**
-            important
-        :param url:
-            The upstream project homepage
-        :param size:
-            The size of the package in bytes. This should be the size of the
-            entire package file, not the size of the files installed on the
-            system. If the package is not installed, and already downloaded
-            and present in the package manager cache, then this value should
-            be set to zero.
-        """
-        pklog.debug("Emitting Details signal for %s", package_id)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         signature="us")
-    def Message(self, kind, details):
-        """This signal is sent when the backend wants to send a message to
-        the session.
-
-        The message will be shown after the transaction has been completed.
-        """
-        pklog.debug("Emitting Message signal: %s, %s", kind, details)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         signature="sas")
-    def Files(self, package_id, file_list):
-        """This signal is used to push file lists from the backend to the
-        session.
-
-        :param package_id:
-            The Package ID that called the method.
-        :param file_list:
-            The file list
-        """
-        pklog.debug("Emitting Files signal: %s, %s", package_id, file_list)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         signature="suu")
-    def ItemProgress(self, package_id, status, percentage):
-        """This signal allows the backend to send information about
-        package or repository progress when using Simultanous mode.
-
-        :param package_id: The package ID
-        :param status:
-            The status enumerated value that is being completed
-        :param percentage:
-            The percentage of this action is completed
-        """
-        pklog.debug("Emitting ItemProgress signal for %s: %s, %s",
-                    package_id, pk.info_enum_to_string(status), percentage)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         signature="sasasasasasussuss")
-    def UpdateDetail(self, package_id, updates, obsoletes, vendor_urls,
-                     bugzilla_urls, cve_urls, restart, update_text, changelog,
-                     state, issued, updated):
-        """This signal is sent when more details are required about a
-        specific update.
-
-        :param package_id: The package ID
-        :param updates:
-            A list of package_id's that are to be updated.
-        :param obsoletes:
-            A list of package_id's that are to be obsoleted.
-        :param vendor_urls:
-            A URL with more details on the update, e.g. a page with more
-            information on the update. The format of this command should
-            be http://www.foo.org/page.html?4567;Update to SELinux
-        :param bugzilla_urls:
-            A bugzilla URL with more details on the update. If no URL is
-            available then this field should be left empty.
-        :param cve_urls:
-            A CVE URL with more details on the security advisory.
-        :param restart:
-            A valid restart type, e.g. system.
-        :param update_text:
-            The update text describing the update. If formatting is required,
-            then markdown syntax should be used, e.g. This is **critically**
-            important.
-        :param changelog:
-            The ChangeLog text describing the changes since the last version.
-        :param state:
-            The state of the update, e.g. stable or testing.
-        :param issued:
-            The ISO8601 encoded date that the update was issued.
-        :param updated:
-            The ISO8601 encoded date that the update was updated.
-        """
-        pklog.debug("Emitting UpdateDetail signal for %s", package_id)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         signature="uss")
-    def Package(self, info, package_id, summary):
-        """This signal allows the backend to communicate packages to the
-        session.
-
-        If updating, as packages are updated then emit them to the screen.
-        This allows a summary to be presented after the transaction.
-        When returning results from a search always return installed
-        before available for the same package name.
-
-        :param info: A valid info enumerated type
-        :param package_id: This identifier is of the form
-            name;version;arch;data in a single string and is meant to
-            represent a single package unique across all local and remote
-            data stores. For a remote, not-installed package the data
-            field should be set as the repository identifier or repository
-            name. The data field for an installed package must be prefixed
-            with installed as this is used to identify which packages are
-            installable or installed in the client tools. As a special
-            extension, if the package manager is able to track which
-            repository a package was originally installed from, then the data
-            field can be set to installed:REPO-NAME which allows the frontend
-            client to advise the user of the package origin. The data field
-            for a non-installed local package must be local as this signifies
-            a repository name is not available and that package resides
-            locally on the client system rather than in any specific
-            repository.
-        :param summary: The one line package summary, e.g. Clipart for
-            OpenOffice
-        """
-        pklog.debug("Emitting Package signal: %s, %s, %s'",
-                    pk.info_enum_to_string(info), package_id, summary[:10])
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         signature="sss")
-    def DistroUpgrade(self, distro_type, name, summary):
-        """This signal allows the backend to communicate distribution upgrades
-        to the session.
-        :param type: A valid upgrade string enumerated type, e.g. stable
-            or unstable
-        :param name: The short name of the distribution, e.g. Fedora Core
-            10 RC1
-        :param summary: The multi-line description of the release
-        """
-        pklog.debug("Emitting DistroUpgrade signal: %s, %s, %s",
-                    pk.distro_upgrade_enum_to_string(distro_type),
-                    name, summary)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         signature="us")
-    def RequireRestart(self, restart_type, package_id):
-        """This signal is sent when the session client should notify the user
-        that a restart is required to get all changes into effect.
-
-        :param package_id:
-            The Package ID of the package tiggering the restart
-        :param file_list:
-            One of system, application or session
-        """
-        pklog.debug("Emitting RequireRestart signal: %s, %s",
-                    pk.restart_enum_to_string(restart_type), package_id)
-
-    # METHODS
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         in_signature="as", out_signature="")
-    def SetHints(self, hints):
-        """This method allows the calling session to set transaction hints
-        for the package manager which can change as the transaction runs.
-
-        This method can be sent before the transaction has been run or
-        whilst it is running. There is no limit to the number of times
-        this method can be sent, although some backends may only use the
-        values that were set before the transaction was started.
-
-        Each parameter value is optional.
-
-        :param hints: The values as an array of strings, for example
-            ['locale=en_GB.utf8','interactive=false','cache-age=3600']
-        """
-        pklog.info("SetHints() was called: %s", get_string_from_array(hints))
-        for hint in hints:
-            key, value = hint.split("=", 1)
-            if key not in ["locale", "idle", "background", "interactive",
-                           "cache-age", "frontend-socket"]:
-                raise Exception("Invalid option %s" % key)
-            self.hints[key] = value
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="", out_signature="",
-                          sender_keyword="sender")
-    def Cancel(self, sender):
-        """This method cancels a transaction that is already running."""
-        if self.trans:
-            return self.trans._cancel(sender)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="tasbb", out_signature="",
-                          sender_keyword="sender")
-    def RemovePackages(self, flags, package_ids, allow_deps, autoremove,
-                       sender):
-        """This method removes packages from the local system.
-
-        This method typically emits Progress, Status and Error and Package.
-
-        Package enumerated types should be downloading, updating,
-        installing or removing.
-
-        :param flags: If the transaction should be simulated or prepared
-        :param package_ids: An array of package IDs.
-        :param allow_deps:
-            Either true or false. If true allow other packages to be removed
-            with the package, but false should cause the script to abort if
-            other packages are dependant on the package.
-        :param autoremove:
-            Either true or false. This option is only really interesting on
-            embedded devices with a limited amount of flash storage. It
-            suggests to the packagekit backend that dependencies installed at
-            the same time as the package should also be removed if they are not
-            required by anything else. For instance, if you install OpenOffice,
-            it might download libneon as a dependency. When auto_remove is set
-            to true, and you remove OpenOffice then libneon will also get
-            removed automatically.
-        """
-        pklog.info("RemovePackages() was called: %s, %s",
-                   get_string_from_flags(flags),
-                   get_string_from_array(package_ids))
-        return self._remove_packages(flags, package_ids, allow_deps,
-                                     autoremove, sender)
-
-    @inline_callbacks
-    def _remove_packages(self, flags, package_ids, allow_deps, autoremove,
-                         sender):
-        self.role = pk.RoleEnum.REMOVE_PACKAGES
-        self.flags = flags
-        self.trans = self._get_merged_trans(aptd_enums.ROLE_REMOVE_PACKAGES,
-                                            pkg_ids=package_ids,
-                                            pkg_type=aptd_enums.PKGS_REMOVE)
-        yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
-                                       "RemoveObsoletedDepends", autoremove,
-                                       sender)
-        #FIXME: Implement allow_deps
-        yield self.trans._run(sender)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="tas", out_signature="",
-                          sender_keyword="sender")
-    def UpdatePackages(self, flags, package_ids, sender):
-        """This method updates existing packages on the local system.
-
-        The installer should always update extra packages automatically
-        to fulfil dependencies.
-
-        This should allow an application to find out what package owns a
-        file on the system.
-
-        This method typically emits Progress, Status and Error and Package.
-
-        :param flags:
-            If the transaction is only allowed to install trusted packages.
-            Unsigned packages should not be installed if the flags
-            contains ONLY_TRUSED.
-            If this method is can only install trusted packages, and
-            the packages are unsigned, then the backend will send a
-            ErrorCode(missing-gpg-signature). On recieving this error, the
-            client may choose to retry with ONLY_TRUSTED set after
-            gaining further authentication.
-        : param package_ids: An array of package IDs.
-        """
-        pklog.info("UpdatePackages() was called: %s, %s",
-                   get_string_from_flags(flags),
-                   get_string_from_array(package_ids))
-        return self._update_packages(flags, package_ids, sender)
-
-    @inline_callbacks
-    def _update_packages(self, flags, package_ids, sender):
-        self.role = pk.RoleEnum.UPDATE_PACKAGES
-        self.flags = flags
-        self.trans = self._get_merged_trans(aptd_enums.ROLE_UPGRADE_PACKAGES,
-                                            pkg_ids=package_ids,
-                                            pkg_type=aptd_enums.PKGS_UPGRADE)
-        yield self.trans._set_property(
-            APTDAEMON_TRANSACTION_DBUS_INTERFACE,
-            "AllowUnauthenticated",
-            not bitfield_contains(flags,
-                                  pk.TransactionFlagEnum.ONLY_TRUSTED),
-            sender)
-        yield self.trans._run(sender)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="uas", out_signature="",
-                          sender_keyword="sender")
-    def InstallPackages(self, flags, package_ids, sender):
-        """This method installs new packages on the local system.
-
-        The installer should always install extra packages automatically
-        as the use could call GetDepends prior to the install if a
-        confirmation is required in the UI.
-
-        This method typically emits Progress, Status and Error and Package.
-
-        Package enumerated types should be downloading, updating,
-        installing or removing.
-
-        :param flags:
-            If the transaction is only allowed to install trusted packages.
-            Unsigned packages should not be installed if the flags
-            contains ONLY_TRUSED.
-            If this method is can only install trusted packages, and
-            the packages are unsigned, then the backend will send a
-            ErrorCode(missing-gpg-signature). On recieving this error, the
-            client may choose to retry with ONLY_TRUSTED set after
-            gaining further authentication.
-        : param package_ids: An array of package IDs.
-        """
-        pklog.info("InstallPackages() was called: %s, %s",
-                   get_string_from_flags(flags),
-                   get_string_from_array(package_ids))
-        return self._install_packages(flags, package_ids, sender)
-
-    @inline_callbacks
-    def _install_packages(self, flags, package_ids, sender):
-        self.role = pk.RoleEnum.INSTALL_PACKAGES
-        self.flags = flags
-        self.trans = self._get_merged_trans(aptd_enums.ROLE_INSTALL_PACKAGES,
-                                            pkg_ids=package_ids,
-                                            pkg_type=aptd_enums.PKGS_INSTALL)
-        yield self.trans._set_property(
-            APTDAEMON_TRANSACTION_DBUS_INTERFACE,
-            "AllowUnauthenticated",
-            not bitfield_contains(flags,
-                                  pk.TransactionFlagEnum.ONLY_TRUSTED),
-            sender)
-        yield self.trans._run(sender)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         in_signature="su", out_signature="",
-                         sender_keyword="sender")
-    def UpgradeSystem(self, distro_id, upgrade_kind, sender):
-        """This method updates existing packages on the local system.
-
-        The installer should always update extra packages automatically
-        to fulfil dependencies.
-
-        This should allow an application to find out what package owns a
-        file on the system.
-
-        This method typically emits Progress, Status and Error and Package.
-
-        :param distro_id: The distribution id to upgrade to, e.g. saucy
-        :param upgrade_kind:
-            The type of upgrade e.g. minimal, default or complete.
-            Minimal upgrades will download the smallest amount of data
-            before launching a installer.
-            The default is to download enough data to launch a full graphical
-            installer, but a complete upgrade will be required if there is no
-            internet access during install time.
-        """
-        pklog.info("UpgradeSystem() was called")
-        GLib.idle_add(self._fail_not_implemented)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="t", out_signature="",
-                          sender_keyword="sender")
-    def RepairSystem(self, flags, sender):
-        """This method recovers the package managment system from e.g.
-        unsatisified dependencies of installed packages.
-
-        :param flags:
-            If the transaction is only allowed to install trusted packages.
-            Unsigned packages should not be installed if the flags
-            contains ONLY_TRUSED.
-            If this method is can only install trusted packages, and
-            the packages are unsigned, then the backend will send a
-            ErrorCode(missing-gpg-signature). On recieving this error, the
-            client may choose to retry with ONLY_TRUSTED set after
-            gaining further authentication.
-        """
-        pklog.info("RepairSystem() was called")
-        return self._repair_system(flags, sender)
-
-    @inline_callbacks
-    def _repair_system(self, flags, sender):
-        self.role = pk.RoleEnum.REPAIR_SYSTEM
-        self.flags = flags
-        self.trans = self._get_merged_trans(aptd_enums.ROLE_FIX_BROKEN_DEPENDS)
-        yield self.trans._set_property(
-            APTDAEMON_TRANSACTION_DBUS_INTERFACE,
-            "AllowUnauthenticated",
-            not bitfield_contains(flags,
-                                  pk.TransactionFlagEnum.ONLY_TRUSTED),
-            sender)
-        yield self.trans._run(sender)
-
-    # pylint: disable-msg=C0103,C0322
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="b", out_signature="",
-                          sender_keyword="sender")
-    def RefreshCache(self, force, sender):
-        """This method should fetch updated meta-data for all enabled
-        repositories.
-
-        When fetching each software source, ensure to emit RepoDetail for
-        the current source to give the user interface some extra details.
-        Be sure to have the "enabled" field set to true, otherwise you
-        wouldn't be fetching that source.
-
-        This method typically emits Progress, Error and RepoDetail.
-
-        :param force: If the caches should be cleaned and reloaded even if
-            there is valid, up to date data.
-        """
-        pklog.info("RefreshCache() was called")
-        self.role = pk.RoleEnum.REFRESH_CACHE
-        return self._refresh_cache(force, sender)
-
-    @inline_callbacks
-    def _refresh_cache(self, force, sender):
-        self.trans = self._get_merged_trans(aptd_enums.ROLE_UPDATE_CACHE,
-                                            kwargs={"sources_list": None})
-        yield self.trans._run(sender)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="as", out_signature="",
-                          sender_keyword="sender")
-    def GetUpdateDetail(self, package_ids, sender):
-        """This method returns details about a specific update.
-
-        This method typically emits UpdateDetail and Error
-
-        :param package_ids: An array of package IDs.
-        """
-        pklog.info("GetUpdateDetail() was called")
-        self.role = pk.RoleEnum.GET_UPDATE_DETAIL
-        kwargs = {"package_ids": package_ids}
-        return self._run_query(kwargs, sender)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="t", out_signature="",
-                          sender_keyword="sender")
-    def GetUpdates(self, filter, sender):
-        """This method should return a list of packages that are installed
-        and are upgradable. It should only return the newest update for
-        each installed package.
-
-        This method typically emits Progress, Error and Package.
-
-        :param filter: A correct filter, e.g. none or installed;~devel
-        """
-        pklog.info("GetUpdates() was called")
-        self.role = pk.RoleEnum.GET_UPDATES
-        kwargs = {"filters": filter}
-        return self._run_query(kwargs, sender)
-
-    @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         in_signature="", out_signature="",
-                         sender_keyword="sender")
-    def GetDistroUpgrades(self, sender):
-        """This method should return a list of distribution upgrades that are
-        available. It should not return updates, only major upgrades.
-
-        This method typically emits DistroUpgrade, Error
-        """
-        pklog.info("GetDistroUpgrades() was called")
-        self.role = pk.RoleEnum.GET_DISTRO_UPGRADES
-        self.status = pk.StatusEnum.RUNNING
-        GLib.idle_add(defer_idle, self._get_distro_upgrades)
-
-    def _get_distro_upgrades(self):
-        #FIXME: Should go into the worker after the threading branch is merged
-        #       It allows to run a nested loop until the download is finished
-        self.allow_cancel = False
-        self.percentage = 101
-        self.status = pk.StatusEnum.DOWNLOAD_UPDATEINFO
-
-        if META_RELEASE_SUPPORT is False:
-            self.ErrorCode(pk.ErrorEnum.INTERNAL_ERROR,
-                           "Please make sure that update-manager-core is"
-                           "correctly installed.")
-            self.exit = pk.ExitEnum.FAILED
-            return
-
-        #FIXME Evil to start the download during init
-        meta_release = GMetaRelease()
-        meta_release.connect("download-done",
-                             self._on_distro_upgrade_download_done)
-
-    def _on_distro_upgrade_download_done(self, meta_release):
-        #FIXME: Add support for description
-        if meta_release.new_dist is not None:
-            self.DistroUpgrade("stable",
-                               "%s %s" % (meta_release.new_dist.name,
-                                          meta_release.new_dist.version),
-                               "The latest stable release")
-        self.exit = pk.ExitEnum.SUCCESS
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="tas", out_signature="",
-                          sender_keyword="sender")
-    def Resolve(self, filter, packages, sender):
-        """This method turns a single package name into a package_id suitable
-        for the other methods.
-
-        If the package is a fully formed package_id, then this should be
-        treated as an exact package match. This is useful to find the summary
-        or installed status of a package_id returned from other methods.
-
-        This method typically emits Error and Package.
-
-        Package enumerated types should be available or installed.
-
-        :param filter: A correct filter, e.g. none or installed;~devel
-        :param packages:
-            An array of package names, e.g. scribus-clipart. The package
-            names are case sensitive, so for instance: Resolve('Packagekit')
-            would not match PackageKit. As a special case, if Resolve() is
-            called with a name prefixed with @ then this should be treated as
-            a category, for example: @web-development. In this instance, a
-            meta-package should be emitted, for example:
-            web-development;;;meta with the correct installed status and
-            summary for the category.
-        """
-        pklog.info("Resolve() was called: %s", get_string_from_array(packages))
-        self.role = pk.RoleEnum.RESOLVE
-        kwargs = {"filters": filter, "packages": packages}
-        return self._run_query(kwargs, sender)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="t", out_signature="",
-                          sender_keyword="sender")
-    def GetPackages(self, filter, sender):
-        """This method returns all the packages without a search term.
-
-        This method typically emits Progress, Error and Package.
-
-        Package enumerated types should be available or installed.
-
-        :param filter: A correct filter, e.g. none or installed;~devel
-        """
-        pklog.info("GetPackages() was called")
-        self.role = pk.RoleEnum.GET_PACKAGES
-        kwargs = {"filters": filter}
-        return self._run_query(kwargs, sender)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="as", out_signature="",
-                          sender_keyword="sender")
-    def GetDetails(self, package_ids, sender):
-        """This method should return all the details about a specific
-        package_id.
-
-        This method typically emits Progress, Status and Error and Details.
-
-        :param package_ids: An array of package IDs.
-        """
-        pklog.info("GetDetails() was called")
-        self.role = pk.RoleEnum.GET_DETAILS
-        kwargs = {"package_ids": package_ids}
-        return self._run_query(kwargs, sender)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="as", out_signature="",
-                          sender_keyword="sender")
-    def GetFiles(self, package_ids, sender):
-        """This method should return the file list of the package_id.
-
-        This method typically emits Progress, Status and Error and Files.
-
-        :param package_ids: An array of package IDs.
-        """
-        pklog.info("GetFiles() was called")
-        self.role = pk.RoleEnum.GET_FILES
-        kwargs = {"package_ids": package_ids}
-        return self._run_query(kwargs, sender)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="tas", out_signature="",
-                          sender_keyword="sender")
-    def SearchFiles(self, filter, values, sender):
-        """This method searches for files on the local system and files in
-        available packages.
-
-        This should search for files. This should allow an application to
-        find out what package owns a file on the system.
-
-        This method typically emits Progress, Error and Package.
-
-        Package enumerated types should be available or installed.
-
-        :param filter: A correct filter, e.g. none or installed;~devel
-        :param values:
-            A filename or fully qualified path and filename on the system.
-            If the search term begins with a / it will be assumed the entire
-            path has been given and only packages that contain this exact
-            path and filename will be returned. If the search term does not
-            start with / then it should be treated as a single filename,
-            which can be in any directory. The search is case sensitive,
-            and should not be escaped or surrounded in quotes.
-        """
-        pklog.info("SearchFiles() was called")
-        self.role = pk.RoleEnum.SEARCH_FILE
-        kwargs = {"filters": filter,
-                  "values": values}
-        return self._run_query(kwargs, sender)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="tas", out_signature="",
-                          sender_keyword="sender")
-    def SearchDetails(self, filter, values, sender):
-        """This method allows deeper searching than SearchName().
-
-        Do not refresh the package cache. This should be fast. This is very
-        similar to search-name. This should search as much data as possible,
-        including, if possible repo names, package summaries, descriptions,
-        licenses and URLs.
-
-        Try to emit installed before available packages first, as it allows
-        the client program to perform the GUI filtering and matching whilst
-        the daemon is running the transaction.
-
-        If the backend includes installed and available versions of the same
-        package when searching then the available version will have to be
-        filtered in the backend.
-
-        This method typically emits Progress, Error and Package.
-
-        Package enumerated types should be available or installed.
-
-        :param filter: A correct filter, e.g. none or installed;~devel
-        :param values:
-            A single word search term with no wildcard chars. The search term
-            can contain many words separated by spaces. In this case, the
-            search operator is AND. For example, search of gnome power should
-            returns gnome-power-manager but not gnomesword or powertop.
-            The search should not be treated as case sensitive.
-        """
-        pklog.info("SearchDetails() was called")
-        self.role = pk.RoleEnum.SEARCH_DETAILS
-        kwargs = {"filters": filter,
-                  "values": values}
-        return self._run_query(kwargs, sender)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="tas", out_signature="",
-                          sender_keyword="sender")
-    def SearchGroups(self, filter, values, sender):
-        """This method returns packages from a given group enumerated type.
-
-        Do not refresh the package cache. This should be fast.
-
-        Try to emit installed before available packages first, as it
-        allows the client program to perform the GUI filtering and matching
-        whilst the daemon is running the transaction.
-
-        If the backend includes installed and available versions of the same
-        package when searching then the available version will have to be
-        filtered in the backend.
-
-        This method typically emits Progress, Error and Package.
-
-        Package enumerated types should be available or installed.
-
-        :param filter: A correct filter, e.g. none or installed;~devel
-        :param values:
-            An enumerated group type, or unknown. The search cannot contain
-            spaces. The following recommendations are made below: If the values
-            strings are prefixed with category: then the request is treated
-            as a 'category search', for example: category:web-development.
-            repo: then the request is treated as a 'repository search', for
-            example: repo:fedora-debuginfo. In this instance all packages that
-            were either installed from, or can be installed from the
-            fedora-debuginfo source would be returned.
-        """
-        pklog.info("SearchGroups() was called")
-        self.role = pk.RoleEnum.SEARCH_GROUP
-        kwargs = {"filters": filter,
-                  "values": values}
-        return self._run_query(kwargs, sender)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="tas", out_signature="",
-                          sender_keyword="sender")
-    def SearchNames(self, filter, values, sender):
-        """This method searches the package database by package name.
-
-        Try to emit installed before available packages first, as it
-        allows the client program to perform the GUI filtering and matching
-        whilst the daemon is running the transaction.
-
-        If the backend includes installed and available versions of the same
-        package when searching then the available version will have to be
-        filtered in the backend.
-
-        The search methods should return all results in all repositories.
-        This may mean that multiple versions of package are returned. If this
-        is not what is wanted by the client program, then the newest filter
-        should be used.
-
-        This method typically emits Progress, Error and Package.
-
-        Package enumerated types should be available or installed.
-
-        :param filter: A correct filter, e.g. none or installed;~devel
-        :param values:
-            A single word search term with no wildcard chars. The search term
-            can contain many words separated by spaces. In this case, the
-            search operator is AND. For example, search of gnome power should
-            returns gnome-power-manager but not gnomesword or powertop.
-            The search should not be treated as case sensitive.
-        """
-        pklog.info("SearchNames() was called")
-        self.role = pk.RoleEnum.SEARCH_NAME
-        kwargs = {"filters": filter,
-                  "values": values}
-        return self._run_query(kwargs, sender)
-
-    @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         in_signature="s", out_signature="",
-                         sender_keyword="sender")
-    def AcceptEula(self, eula_id, sender):
-        """This method allows the user to accept a end user licence agreement.
-
-        :param eula_id: A valid EULA ID
-        """
-        self.role = pk.RoleEnum.ACCEPT_EULA
-        GLib.idle_add(self._fail_not_implemented)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="bas", out_signature="",
-                          sender_keyword="sender")
-    def DownloadPackages(self, store_in_cache, package_ids, sender):
-        """This method downloads packages into a temporary directory.
-
-        This method should emit one Files signal for each package that
-        is downloaded, with the file list set as the name of the complete
-        downloaded file and directory, so for example:
-
-        DownloadPackages('hal;0.1.2;i386;fedora',
-        'hal-info;2009-09-07;no-arch;updates') should send two signals,
-        e.g. Files('hal;0.1.2;i386;fedora', '/tmp/hal-0.1.2.i386.rpm')
-        and Files('hal-info;2009-09-07;no-arch;updates',
-        '/tmp/hal-info-2009-09-07.noarch.rpm').
-
-        :param store_in_cache:
-            If the downloaded files should be stored in the system package
-            cache rather than copied into a newly created directory. See the
-            developer docs for more details on how this is supposed to work.
-        :param package_ids: An array of package IDs.
-        """
-        pklog.info("DownloadPackages() was called: %s",
-                   get_string_from_array(package_ids))
-        self.role = pk.RoleEnum.DOWNLOAD_PACKAGES
-        kwargs = {"store_in_cache": store_in_cache,
-                  "package_ids": package_ids}
-        return self._run_query(kwargs, sender)
-
-    @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         in_signature="u", out_signature="",
-                         sender_keyword="sender")
-    def GetOldTransactions(self, number, sender):
-        """This method allows a client to view details for old transactions.
-
-        :param number:
-            The number of past transactions, or 0 for all known transactions.
-        """
-        pklog.info("GetOldTransactions() was called: %s", str(number))
-        self.role = pk.RoleEnum.GET_OLD_TRANSACTIONS
-        GLib.idle_add(self._fail_not_implemented)
-
-    @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         in_signature="t", out_signature="",
-                         sender_keyword="sender")
-    def GetRepoList(self, filter, sender):
-        """This method returns the list of repositories used in the system.
-
-        This method should emit RepoDetail.
-
-        :param filter: A correct filter, e.g. none or installed;~devel
-        """
-        pklog.info("GetRepoList() was called")
-        self.role = pk.RoleEnum.GET_REPO_LIST
-        GLib.idle_add(self._fail_not_implemented)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="tas", out_signature="",
-                          sender_keyword="sender")
-    def InstallFiles(self, flags, full_paths, sender):
-        """This method installs local package files onto the local system.
-
-        The installer should always install extra dependant packages
-        automatically.
-
-        This method typically emits Progress, Status and Error and Package.
-
-        Package enumerated types should be downloading, updating, installing
-        or removing.
-
-        :param flags:
-            If the transaction is only allowed to install trusted packages.
-            Unsigned packages should not be installed if the flags
-            contains ONLY_TRUSED.
-            If this method is can only install trusted packages, and
-            the packages are unsigned, then the backend will send a
-            ErrorCode(missing-gpg-signature). On recieving this error, the
-            client may choose to retry with ONLY_TRUSTED set after
-            gaining further authentication.
-        :param full_paths: An array of full path and filenames to packages.
-        """
-        pklog.info("InstallFiles() was called: %s, %s",
-                   get_string_from_flags(flags),
-                   get_string_from_array(full_paths))
-        return self._install_files(flags, full_paths, sender)
-
-    @inline_callbacks
-    def _install_files(self, flags, full_paths, sender):
-        self.role = pk.RoleEnum.INSTALL_FILES
-        self.flags = flags
-        # Python-APT only supports installing one file
-        if len(full_paths) != 1:
-            self.ErrorCode(pk.ErrorEnum.NOT_SUPPORTED,
-                           "Only one package can be "
-                           "installed at the same time.")
-            self.exit = pk.ExitEnum.FAILED
-            raise StopIteration
-        path = full_paths[0]
-        if not os.path.abspath(path):
-            self.ErrorCode(pk.ErrorEnum.NOT_SUPPORTED,
-                           "Path is not absolute: %s")
-            self.exit = pk.ExitEnum.FAILED
-            raise StopIteration
-        if not os.path.isfile(path):
-            self.ErrorCode(pk.ErrorEnum.INVALID_PACKAGE_FILE,
-                           "File doesn't exist: %s" % path)
-            self.exit = pk.ExitEnum.FAILED
-            raise StopIteration
-
-        kwargs = {"path": path,
-                  "force": True}
-        self.trans = self._get_merged_trans(aptd_enums.ROLE_INSTALL_FILE,
-                                            kwargs=kwargs)
-        yield self.trans._run(sender)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="uss", out_signature="",
-                          sender_keyword="sender")
-    def InstallSignature(self, sig_type, key_id, package_id, sender):
-        """This method allows us to install new security keys.
-
-        :param sig_type: A key type, e.g. gpg
-        :param key_id: A key ID, e.g. BB7576AC
-        :param package_id:
-            A PackageID for the package that the user is trying to install
-            (ignored)
-        """
-        pklog.info("InstallSignature() was called: %s", str(key_id))
-        self.role = pk.RoleEnum.INSTALL_SIGNATURE
-        kwargs = {"sig_type": sig_type,
-                  "key_id": key_id,
-                  "package_id": package_id}
-        return self._run_query(kwargs, sender)
-
-    @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         in_signature="sss", out_signature="",
-                         sender_keyword="sender")
-    def RepoSetData(self, repo_id, parameter, value, sender):
-        """This method allows arbitary data to be passed to the repository
-        handler.
-
-        :param repo_id:
-            A repository identifier, e.g. fedora-development-debuginfo
-        :param parameter:
-            The backend specific value, e.g. set-download-url.
-        :param value:
-            The backend specific value, e.g. http://foo.bar.org/baz.
-        """
-        pklog.info("RepoSetData() was called: %s, %s, %s",
-                   str(repo_id), str(parameter), str(value))
-        self.role = pk.RoleEnum.REPO_SET_DATA
-        GLib.idle_add(self._fail_not_implemented)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="sb", out_signature="",
-                          sender_keyword="sender")
-    def RepoEnable(self, repo_id, enabled, sender):
-        """This method enables the repository specified.
-
-        :param repo_id:
-            A repository identifier, e.g. fedora-development-debuginfo or an
-            apt source ("deb http://... unstable main")
-        :param enabled: true if enabled, false if disabled.
-        """
-        pklog.info("RepoEnable() was called(): %s, %s",
-                   str(repo_id), str(enabled))
-        self.role = pk.RoleEnum.REPO_ENABLE
-        kwargs = {"repo_id": repo_id,
-                  "enabled": enabled}
-        return self._run_query(kwargs, sender)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="tsas", out_signature="",
-                          sender_keyword="sender")
-    def WhatProvides(self, filter, type, values, sender):
-        """This method returns packages that provide the supplied attributes.
-        This method is useful for finding out what package(s) provide a
-        modalias or GStreamer codec string.
-
-        This method typically emits Progress, Status and Error and Package.
-
-        Package enumerated types should be available or installed.
-
-        :param filter:
-            A correct filter, e.g. none or installed;~devel
-        :param type:
-            A PkProvideType, e.g. PK_PROVIDES_ENUM_CODEC.
-        :param values:
-            The data to send to the backend to get the packages. Note: This
-            is backend specific.
-        """
-        pklog.info("WhatProvides() was called")
-        self.role = pk.RoleEnum.WHAT_PROVIDES
-        kwargs = {"filters": filter,
-                  "provides_type": type,
-                  "values": values}
-        return self._run_query(kwargs, sender)
-
-    @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                         in_signature="", out_signature="",
-                         sender_keyword="sender")
-    def GetCategories(self, sender):
-        pklog.info("GetCategories() was called")
-        """This method return the collection categories"""
-        self.role = pk.RoleEnum.GET_CATEGORIES
-        GLib.idle_add(self._fail_not_implemented)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="tasb", out_signature="",
-                          sender_keyword="sender")
-    def GetRequires(self, filter, package_ids, recursive, sender):
-        """This method returns packages that depend on this package. This is
-        useful to know, as if package_id is being removed, we can warn the
-        user what else would be removed.
-
-        This method typically emits Progress, Status and Error and Package.
-
-        Package enumerated types should be available or installed.
-
-        :param filter: A correct filter, e.g. none or installed;~devel
-        :param package_ids: An array of package IDs.
-        :param recursive:
-            Either true or false. If yes then the requirements should be
-            returned for all packages returned. This means if
-            gnome-power-manager depends on NetworkManager and NetworkManager
-            depends on HAL, then GetRequires on HAL should return both
-            gnome-power-manager and NetworkManager.
-        """
-        pklog.info("GetRequires() was called")
-        self.role = pk.RoleEnum.GET_REQUIRES
-        kwargs = {"filters": filter,
-                  "package_ids": package_ids,
-                  "recursive": recursive}
-        return self._run_query(kwargs, sender)
-
-    @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
-                          in_signature="tasb", out_signature="",
-                          sender_keyword="sender")
-    def GetDepends(self, filter, package_ids, recursive, sender):
-        """This method returns packages that this package depends on.
-
-        This method typically emits Progress, Status and Error and Package.
-
-        Package enumerated types should be available or installed.
-
-        :param filter: A correct filter, e.g. none or installed;~devel
-        :param package_ids: An array of package IDs.
-        :param recursive:
-            Either true or false. If yes then the requirements should be
-            returned for all packages returned. This means if
-            gnome-power-manager depends on NetworkManager and NetworkManager
-            depends on HAL, then GetDepends on gnome-power-manager should
-            return both HAL and NetworkManager.
-        """
-        pklog.info("GetDepends() was called")
-        self.role = pk.RoleEnum.GET_DEPENDS
-        kwargs = {"filters": filter,
-                  "package_ids": package_ids,
-                  "recursive": recursive}
-        return self._run_query(kwargs, sender)
-
-    # HELPERS
-
-    def _fail_not_implemented(self):
-        self.ErrorCode(pk.ErrorEnum.NOT_SUPPORTED, "Unimplemented method")
-        self.exit = pk.ExitEnum.FAILED
-        return False
-
-    def _get_properties(self, iface):
-        """Helper to get the properties of a D-Bus interface."""
-        if iface == PACKAGEKIT_TRANS_DBUS_INTERFACE:
-            return {"Role": dbus.UInt32(self.role),
-                    "Status": dbus.UInt32(self.status),
-                    "LastPackage": dbus.String(self.last_package),
-                    "Uid": dbus.UInt32(self.uid),
-                    "Percentage": dbus.UInt32(self.percentage),
-                    "AllowCancel": dbus.Boolean(self.allow_cancel),
-                    "CallerActive": dbus.Boolean(self.caller_active),
-                    "ElapsedTime": dbus.UInt32(self.elapsed_time),
-                    "RemainingTime": dbus.UInt32(self.remaining_time),
-                    "DownloadSizeRemaining": dbus.UInt64(
-                        self.download_size_remaining),
-                    "TransactionFlags": dbus.UInt64(self.flags),
-                    "Speed": dbus.UInt32(self.speed)
-                    }
-        else:
-            return {}
-
-    @inline_callbacks
-    def _run_query(self, kwargs, sender):
-        self.trans = self._get_merged_trans(aptd_enums.ROLE_PK_QUERY,
-                                            kwargs=kwargs)
-        yield self.trans._run(sender)
-
-    def _get_merged_trans(self, role, pkg_ids=None, pkg_type=None,
-                          kwargs=None):
-        if pkg_ids:
-            packages = [[], [], [], [], [], []]
-            packages[pkg_type] = [get_aptd_package_id(pkg) for pkg in pkg_ids]
-        else:
-            packages = None
-        if self.trans:
-            raise Exception("%s: Transaction may only run once." %
-                            pk.ErrorEnum.TRANSACTION_FAILED)
-        trans = MergedTransaction(self, role, self.queue,
-                                  packages=packages, kwargs=kwargs)
-        try:
-            trans._set_locale(self.hints["locale"])
-        except (KeyError, ValueError):
-            # If the locale isn't vaild or supported a ValueError
-            # will be raised
-            pass
-        try:
-            trans._set_debconf(self.hints["frontend-socket"])
-        except KeyError:
-            pass
-        self.queue.limbo[trans.tid] = trans
-        return trans
-
-
-class PackageKitWorker(worker.AptWorker):
-
-    _plugins = None
-
-    """Process PackageKit Query transactions."""
-
-    def _process_transaction(self, trans):
-        if (hasattr(trans, "pktrans") and
-            bitfield_contains(trans.pktrans.flags,
-                              pk.TransactionFlagEnum.SIMULATE)):
-            self._simulate_and_emit_packages(trans)
-            return False
-        else:
-            return worker.AptWorker._process_transaction(self, trans)
-
-    def _simulate_and_emit_packages(self, trans):
-        trans.status = aptd_enums.STATUS_RUNNING
-
-        self._simulate(trans)
-
-        # The simulate method lets the transaction fail in the case of an
-        # error
-        if trans.exit == aptd_enums.EXIT_UNFINISHED:
-            # It is a little bit complicated to get the packages but avoids
-            # a larger refactoring of apt.AptWorker._simulate()
-            for pkg in trans.depends[aptd_enums.PKGS_INSTALL]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.INSTALLING)
-            for pkg in trans.depends[aptd_enums.PKGS_REINSTALL]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.REINSTALLING)
-            for pkg in trans.depends[aptd_enums.PKGS_REMOVE]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.REMOVING)
-            for pkg in trans.depends[aptd_enums.PKGS_PURGE]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.REMOVING)
-            for pkg in trans.depends[aptd_enums.PKGS_UPGRADE]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.UPDATING, force_candidate=True)
-            for pkg in trans.depends[aptd_enums.PKGS_DOWNGRADE]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.DOWNGRADING,
-                                   force_candidate=True)
-            for pkg in trans.depends[aptd_enums.PKGS_KEEP]:
-                self._emit_package(trans,
-                                   self._cache[self._split_package_id(pkg)[0]],
-                                   pk.InfoEnum.BLOCKED, force_candidate=True)
-            for pkg in trans.unauthenticated:
-                self._emit_package(trans, self._cache[pkg],
-                                   pk.InfoEnum.UNTRUSTED, force_candidate=True)
-            trans.status = aptd_enums.STATUS_FINISHED
-            trans.progress = 100
-            trans.exit = aptd_enums.EXIT_SUCCESS
-        tid = trans.tid[:]
-        self.trans = None
-        self.marked_tid = None
-        self._emit_transaction_done(trans)
-        pklog.info("Finished transaction %s", tid)
-
-    def query(self, trans):
-        """Run the worker"""
-        if trans.role != aptd_enums.ROLE_PK_QUERY:
-            raise TransactionFailed(aptd_enums.ERROR_UNKNOWN,
-                                    "The transaction doesn't seem to be "
-                                    "a query")
-        if trans.pktrans.role == pk.RoleEnum.RESOLVE:
-            self.resolve(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_UPDATES:
-            self.get_updates(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_UPDATE_DETAIL:
-            self.get_update_detail(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_PACKAGES:
-            self.get_packages(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_FILES:
-            self.get_files(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.SEARCH_NAME:
-            self.search_names(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.SEARCH_GROUP:
-            self.search_groups(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.SEARCH_DETAILS:
-            self.search_details(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.SEARCH_FILE:
-            self.search_files(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_DEPENDS:
-            self.get_depends(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_REQUIRES:
-            self.get_requires(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.GET_DETAILS:
-            self.get_details(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.DOWNLOAD_PACKAGES:
-            self.download_packages(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.WHAT_PROVIDES:
-            self.what_provides(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.REPO_ENABLE:
-            self.repo_enable(trans, **trans.kwargs)
-        elif trans.pktrans.role == pk.RoleEnum.INSTALL_SIGNATURE:
-            self.install_signature(trans, **trans.kwargs)
-        else:
-            raise TransactionFailed(aptd_enums.ERROR_UNKNOWN,
-                                    "Role %s isn't supported",
-                                    trans.pktrans.role)
-
-    def search_files(self, trans, filters, values):
-        """Implement org.freedesktop.PackageKit.Transaction.SearchFiles()
-
-        Works only for installed file if apt-file isn't installed.
-        """
-        trans.progress = 101
-
-        result_names = set()
-        # Optionally make use of apt-file's Contents cache to search for not
-        # installed files. But still search for installed files additionally
-        # to make sure that we provide up-to-date results
-        if (os.path.exists("/usr/bin/apt-file") and
-                not bitfield_contains(filters, pk.FilterEnum.INSTALLED)):
-            #FIXME: Make use of rapt-file on Debian if the network is available
-            #FIXME: Show a warning to the user if the apt-file cache is several
-            #       weeks old
-            pklog.debug("Using apt-file")
-            filenames_regex = []
-            for filename in values:
-                if filename.startswith("/"):
-                    pattern = "^%s$" % filename[1:].replace("/", "\/")
-                else:
-                    pattern = "\/%s$" % filename
-                filenames_regex.append(pattern)
-            cmd = ["/usr/bin/apt-file", "--regexp", "--non-interactive",
-                   "--package-only", "find", "|".join(filenames_regex)]
-            pklog.debug("Calling: %s" % cmd)
-            apt_file = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-                                        stderr=subprocess.PIPE)
-            stdout, stderr = apt_file.communicate()
-            if apt_file.returncode == 0:
-                #FIXME: Actually we should check if the file is part of the
-                #       candidate, e.g. if unstable and experimental are
-                #       enabled and a file would only be part of the
-                #       experimental version
-                result_names.update(stdout.split())
-                self._emit_visible_packages_by_name(trans, filters,
-                                                    result_names)
-            else:
-                raise TransactionFailed(aptd_enums.ERROR_INTERNAL_ERROR,
-                                        "%s %s" % (stdout, stderr))
-        # Search for installed files
-        filenames_regex = []
-        for filename in values:
-            if filename.startswith("/"):
-                pattern = "^%s$" % filename.replace("/", "\/")
-            else:
-                pattern = ".*\/%s$" % filename
-            filenames_regex.append(pattern)
-        files_pattern = re.compile("|".join(filenames_regex))
-        for pkg in self._iterate_packages():
-            if pkg.name in result_names:
-                continue
-            for installed_file in self._get_installed_files(pkg):
-                if files_pattern.match(installed_file):
-                    self._emit_visible_package(trans, filters, pkg)
-                    break
-
-    def search_groups(self, trans, filters, values):
-        """Implement org.freedesktop.PackageKit.Transaction.SearchGroups()"""
-        #FIXME: Handle repo and category search
-        trans.progress = 101
-
-        for pkg in self._iterate_packages():
-            group_str = pk.group_enum_to_string(self._get_package_group(pkg))
-            if group_str in values:
-                self._emit_visible_package(trans, filters, pkg)
-
-    def search_names(self, trans, filters, values):
-        """Implement org.freedesktop.PackageKit.Transaction.SearchNames()"""
-        def matches(searches, text):
-            for search in searches:
-                if not search in text:
-                    return False
-            return True
-        trans.progress = 101
-
-        for pkg_name in list(self._cache.keys()):
-            if matches(values, pkg_name):
-                self._emit_all_visible_pkg_versions(trans, filters,
-                                                    self._cache[pkg_name])
-
-    def search_details(self, trans, filters, values):
-        """Implement org.freedesktop.PackageKit.Transaction.SearchDetails()"""
-        trans.progress = 101
-
-        if XAPIAN_SUPPORT is 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(XAPIAN_DB)
-            parser = xapian.QueryParser()
-            parser.set_default_op(xapian.Query.OP_AND)
-            query = parser.parse_query(" ".join(values), search_flags)
-            enquire = xapian.Enquire(db)
-            enquire.set_query(query)
-            matches = enquire.get_mset(0, 1000)
-            for pkg_name in (match.document.get_data()
-                             for match in enquire.get_mset(0, 1000)):
-                if pkg_name in self._cache:
-                    self._emit_visible_package(trans, filters,
-                                               self._cache[pkg_name])
-        else:
-            def matches(searches, text):
-                for search in searches:
-                    if not search in text:
-                        return False
-                return True
-            pklog.debug("Performing apt cache based search")
-            values = [val.lower() for val in values]
-            for pkg in self._iterate_packages():
-                txt = pkg.name
-                try:
-                    txt += pkg.candidate.raw_description.lower()
-                    txt += pkg.candidate._translated_records.long_desc.lower()
-                except AttributeError:
-                    pass
-                if matches(values, txt):
-                    self._emit_visible_package(trans, filters, pkg)
-
-    def get_updates(self, trans, filters):
-        """Only report updates which can be installed safely: Which can depend
-        on the installation of additional packages but which don't require
-        the removal of already installed packages or block any other update.
-        """
-        def succeeds_security_update(pkg):
-            """
-            Return True if an update succeeds a previous security update
-
-            An example would be a package with version 1.1 in the security
-            archive and 1.1.1 in the archive of proposed updates or the
-            same version in both archives.
-            """
-            for version in pkg.versions:
-                # Only check versions between the installed and the candidate
-                if (pkg.installed and
-                    apt_pkg.version_compare(version.version,
-                                            pkg.installed.version) <= 0 and
-                    apt_pkg.version_compare(version.version,
-                                            pkg.candidate.version) > 0):
-                    continue
-                for origin in version.origins:
-                    if (origin.origin in ["Debian", "Ubuntu"] and
-                            (origin.archive.endswith("-security") or
-                             origin.label == "Debian-Security") and
-                            origin.trusted):
-                        return True
-            return False
-        #FIXME: Implment the basename filter
-        self.cancellable = False
-        self.progress = 101
-        # Start with a safe upgrade
-        try:
-            self._cache.upgrade(dist_upgrade=True)
-        except SystemError:
-            pass
-        for pkg in self._iterate_packages():
-            if not pkg.is_upgradable:
-                continue
-            # This may occur on pinned packages which have been updated to
-            # later version than the pinned one
-            if not pkg.candidate.origins:
-                continue
-            if not pkg.marked_upgrade:
-                #FIXME: Would be nice to all show why
-                self._emit_package(trans, pkg, pk.InfoEnum.BLOCKED,
-                                   force_candidate=True)
-                continue
-            # The update can be safely installed
-            info = pk.InfoEnum.NORMAL
-            # Detect the nature of the upgrade (e.g. security, enhancement)
-            candidate_origin = pkg.candidate.origins[0]
-            archive = candidate_origin.archive
-            origin = candidate_origin.origin
-            trusted = candidate_origin.trusted
-            label = candidate_origin.label
-            if origin in ["Debian", "Ubuntu"] and trusted is True:
-                if archive.endswith("-security") or label == "Debian-Security":
-                    info = pk.InfoEnum.SECURITY
-                elif succeeds_security_update(pkg):
-                    pklog.debug("Update of %s succeeds a security update. "
-                                "Raising its priority." % pkg.name)
-                    info = pk.InfoEnum.SECURITY
-                elif archive.endswith("-backports"):
-                    info = pk.InfoEnum.ENHANCEMENT
-                elif archive.endswith("-updates"):
-                    info = pk.InfoEnum.BUGFIX
-            if origin in ["Backports.org archive"] and trusted is True:
-                info = pk.InfoEnum.ENHANCEMENT
-            self._emit_package(trans, pkg, info, force_candidate=True)
-        self._emit_require_restart(trans)
-
-    def _emit_require_restart(self, trans):
-        """Emit RequireRestart if required."""
-        # Check for a system restart
-        if self.is_reboot_required():
-            trans.pktrans.RequireRestart(pk.RestartEnum.SYSTEM, "")
-
-    def get_update_detail(self, trans, package_ids):
-        """
-        Implement the {backend}-get-update-details functionality
-        """
-        def get_bug_urls(changelog):
-            """
-            Create a list of urls pointing to closed bugs in the changelog
-            """
-            urls = []
-            for r in re.findall(MATCH_BUG_CLOSES_DEBIAN, changelog,
-                                re.IGNORECASE | re.MULTILINE):
-                urls.extend([HREF_BUG_DEBIAN % bug for bug in
-                             re.findall(MATCH_BUG_NUMBERS, r)])
-            for r in re.findall(MATCH_BUG_CLOSES_UBUNTU, changelog,
-                                re.IGNORECASE | re.MULTILINE):
-                urls.extend([HREF_BUG_UBUNTU % bug for bug in
-                             re.findall(MATCH_BUG_NUMBERS, r)])
-            return urls
-
-        def get_cve_urls(changelog):
-            """
-            Create a list of urls pointing to cves referred in the changelog
-            """
-            return [HREF_CVE % c for c in re.findall(MATCH_CVE, changelog,
-                                                     re.MULTILINE)]
-
-        trans.progress = 0
-        trans.cancellable = False
-        trans.pktrans.status = pk.StatusEnum.DOWNLOAD_CHANGELOG
-        total = len(package_ids)
-        count = 1
-        old_locale = locale.getlocale(locale.LC_TIME)
-        locale.setlocale(locale.LC_TIME, "C")
-        for pkg_id in package_ids:
-            self._iterate_mainloop()
-            trans.progress = count * 100 / total
-            count += 1
-            pkg = self._get_package_by_id(pkg_id)
-            # FIXME add some real data
-            if pkg.installed.origins:
-                installed_origin = pkg.installed.origins[0].label
-                # APT returns a str with Python 2
-                if isinstance(installed_origin, bytes):
-                    installed_origin = installed_origin.decode("UTF-8")
-            else:
-                installed_origin = ""
-            updates = ["%s;%s;%s;%s" % (pkg.name, pkg.installed.version,
-                                        pkg.installed.architecture,
-                                        installed_origin)]
-            # Get the packages which will be replaced by the update
-            obsoletes = set()
-            if pkg.candidate:
-                for dep_group in pkg.candidate.get_dependencies("Replaces"):
-                    for dep in dep_group:
-                        try:
-                            obs = self._cache[dep.name]
-                        except KeyError:
-                            continue
-                        if not obs.installed:
-                            continue
-                        if dep.relation:
-                            cmp = apt_pkg.version_compare(
-                                obs.candidate.version,
-                                dep.version)
-                            # Same version
-                            if cmp == 0 and dep.relation in [">", "<"]:
-                                continue
-                            # Installed version higer
-                            elif cmp < 0 and dep.relation in ["<"]:
-                                continue
-                            # Installed version lower
-                            elif cmp > 0 and dep.relation in [">"]:
-                                continue
-                        obs_id = self._get_id_from_version(obs.installed)
-                        obsoletes.add(obs_id)
-            vendor_urls = []
-            restart = pk.RestartEnum.NONE
-            update_text = ""
-            state = pk.UpdateStateEnum.UNKNOWN
-            # FIXME: Add support for Ubuntu and a better one for Debian
-            if (pkg.candidate and pkg.candidate.origins[0].trusted and
-                    pkg.candidate.origins[0].label == "Debian"):
-                archive = pkg.candidate.origins[0].archive
-                if archive == "stable":
-                    state = pk.UpdateStateEnum.STABLE
-                elif archive == "testing":
-                    state = pk.UpdateStateEnum.TESTING
-                elif archive == "unstable":
-                    state = pk.UpdateStateEnum.UNSTABLE
-            issued = ""
-            updated = ""
-            #FIXME: make this more configurable. E.g. a dbus update requires
-            #       a reboot on Ubuntu but not on Debian
-            if (pkg.name.startswith("linux-image-") or
-                    pkg.name in ["libc6", "dbus"]):
-                restart == pk.RestartEnum.SYSTEM
-            changelog_dir = apt_pkg.config.find_dir("Dir::Cache::Changelogs")
-            if changelog_dir == "/":
-                changelog_dir = os.path.join(apt_pkg.config.find_dir("Dir::"
-                                                                     "Cache"),
-                                             "Changelogs")
-            filename = os.path.join(changelog_dir,
-                                    "%s_%s.gz" % (pkg.name,
-                                                  pkg.candidate.version))
-            changelog_raw = ""
-            if os.path.exists(filename):
-                pklog.debug("Reading changelog from cache")
-                changelog_file = gzip.open(filename, "rb")
-                try:
-                    changelog_raw = changelog_file.read().decode("UTF-8")
-                except:
-                    pass
-                finally:
-                    changelog_file.close()
-            if not changelog_raw:
-                pklog.debug("Downloading changelog")
-                changelog_raw = pkg.get_changelog()
-                # The internal download error string of python-apt ist not
-                # provided as unicode object
-                if not isinstance(changelog_raw, str):
-                    changelog_raw = changelog_raw.decode("UTF-8")
-                # Cache the fetched changelog
-                if not os.path.exists(changelog_dir):
-                    os.makedirs(changelog_dir)
-                # Remove old cached changelogs
-                pattern = os.path.join(changelog_dir, "%s_*" % pkg.name)
-                for old_changelog in glob.glob(pattern):
-                    os.remove(os.path.join(changelog_dir, old_changelog))
-                changelog_file = gzip.open(filename, mode="wb")
-                try:
-                    changelog_file.write(changelog_raw.encode("UTF-8"))
-                finally:
-                    changelog_file.close()
-            # Convert the changelog to markdown syntax
-            changelog = ""
-            for line in changelog_raw.split("\n"):
-                if line == "":
-                    changelog += " \n"
-                else:
-                    changelog += "    %s  \n" % line
-                if line.startswith(pkg.candidate.source_name):
-                    match = re.match(r"(?P<source>.+) \((?P<version>.*)\) "
-                                     "(?P<dist>.+); urgency=(?P<urgency>.+)",
-                                     line)
-                    update_text += "%s\n%s\n\n" % (match.group("version"),
-                                                   "=" *
-                                                   len(match.group("version")))
-                elif line.startswith("  "):
-                    #FIXME: The GNOME PackageKit markup parser doesn't support
-                    #       monospaced yet
-                    #update_text += "  %s  \n" % line
-                    update_text += "%s\n\n" % line
-                elif line.startswith(" --"):
-                    #FIXME: Add %z for the time zone - requires Python 2.6
-                    update_text += "  \n"
-                    match = re.match("^ -- (?P<maintainer>.+) (?P<mail><.+>)  "
-                                     "(?P<date>.+) (?P<offset>[-\+][0-9]+)$",
-                                     line)
-                    if not match:
-                        continue
-                    try:
-                        date = datetime.datetime.strptime(match.group("date"),
-                                                          "%a, %d %b %Y "
-                                                          "%H:%M:%S")
-                    except ValueError:
-                        continue
-                    issued = date.isoformat()
-                    if not updated:
-                        updated = date.isoformat()
-            if issued == updated:
-                updated = ""
-            bugzilla_urls = get_bug_urls(changelog)
-            cve_urls = get_cve_urls(changelog)
-            trans.emit_update_detail(pkg_id, updates, obsoletes, vendor_urls,
-                                     bugzilla_urls, cve_urls, restart,
-                                     update_text, changelog,
-                                     state, issued, updated)
-        locale.setlocale(locale.LC_TIME, old_locale)
-
-    def get_details(self, trans, package_ids):
-        """Implement org.freedesktop.PackageKit.Transaction.GetDetails()"""
-        trans.progress = 101
-
-        for pkg_id in package_ids:
-            version = self._get_version_by_id(pkg_id)
-            #FIXME: We need more fine grained license information!
-            origins = version.origins
-            if (origins and
-                    origins[0].component in ["main", "universe"] and
-                    origins[0].origin in ["Debian", "Ubuntu"]):
-                license = "free"
-            else:
-                license = "unknown"
-            group = self._get_package_group(version.package)
-            trans.emit_details(pkg_id, license, group, version.description,
-                               version.homepage, version.size)
-
-    def get_packages(self, trans, filters):
-        """Implement org.freedesktop.PackageKit.Transaction.GetPackages()"""
-        self.progress = 101
-
-        for pkg in self._iterate_packages():
-            if self._is_package_visible(pkg, filters):
-                self._emit_package(trans, pkg)
-
-    def resolve(self, trans, filters, packages):
-        """Implement org.freedesktop.PackageKit.Transaction.Resolve()"""
-        trans.status = aptd_enums.STATUS_QUERY
-        trans.progress = 101
-        self.cancellable = False
-
-        for name in packages:
-            try:
-                # Check if the name is a valid package id
-                version = self._get_version_by_id(name)
-            except ValueError:
-                pass
-            else:
-                if self._is_version_visible(version, filters):
-                    self._emit_pkg_version(trans, version)
-                continue
-            # The name seems to be a normal name
-            try:
-                pkg = self._cache[name]
-            except KeyError:
-                raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
-                                        "Package name %s could not be "
-                                        "resolved.", name)
-            else:
-                self._emit_all_visible_pkg_versions(trans, filters, pkg)
-
-    def get_depends(self, trans, filters, package_ids, recursive):
-        """Emit all dependencies of the given package ids.
-
-        Doesn't support recursive dependency resolution.
-        """
-        def emit_blocked_dependency(base_dependency, pkg=None,
-                                    filters=pk.FilterEnum.NONE):
-            """Send a blocked package signal for the given
-            apt.package.BaseDependency.
-            """
-            if pk.FilterEnum.INSTALLED in filters:
-                return
-            if pkg:
-                summary = pkg.candidate.summary
-                filters = bitfield_remove(filters, pk.FilterEnum.NOT_INSTALLED)
-                if not self._is_package_visible(pkg, filters):
-                    return
-            else:
-                summary = ""
-            if base_dependency.relation:
-                version = "%s%s" % (base_dependency.relation,
-                                    base_dependency.version)
-            else:
-                version = base_dependency.version
-            trans.emit_package("%s;%s;;" % (base_dependency.name, version),
-                               pk.InfoEnum.BLOCKED, summary)
-
-        def check_dependency(pkg, base_dep):
-            """Check if the given apt.package.Package can satisfy the
-            BaseDepenendcy and emit the corresponding package signals.
-            """
-            if not self._is_package_visible(pkg, filters):
-                return
-            if base_dep.version:
-                satisfied = False
-                # Sort the version list to check the installed
-                # and candidate before the other ones
-                ver_list = list(pkg.versions)
-                if pkg.installed:
-                    ver_list.remove(pkg.installed)
-                    ver_list.insert(0, pkg.installed)
-                if pkg.candidate:
-                    ver_list.remove(pkg.candidate)
-                    ver_list.insert(0, pkg.candidate)
-                for dep_ver in ver_list:
-                    if apt_pkg.check_dep(dep_ver.version,
-                                         base_dep.relation,
-                                         base_dep.version):
-                        self._emit_pkg_version(trans, dep_ver)
-                        satisfied = True
-                        break
-                if not satisfied:
-                    emit_blocked_dependency(base_dep, pkg, filters)
-            else:
-                self._emit_package(trans, pkg)
-
-        # Setup the transaction
-        self.status = aptd_enums.STATUS_RESOLVING_DEP
-        trans.progress = 101
-        self.cancellable = True
-
-        dependency_types = ["PreDepends", "Depends"]
-        if apt_pkg.config["APT::Install-Recommends"]:
-            dependency_types.append("Recommends")
-        for id in package_ids:
-            version = self._get_version_by_id(id)
-            for dependency in version.get_dependencies(*dependency_types):
-                # Walk through all or_dependencies
-                for base_dep in dependency.or_dependencies:
-                    if self._cache.is_virtual_package(base_dep.name):
-                        # Check each proivider of a virtual package
-                        for provider in self._cache.get_providing_packages(
-                                base_dep.name):
-                            check_dependency(provider, base_dep)
-                    elif base_dep.name in self._cache:
-                        check_dependency(self._cache[base_dep.name], base_dep)
-                    else:
-                        # The dependency does not exist
-                        emit_blocked_dependency(trans, base_dep,
-                                                filters=filters)
-
-    def get_requires(self, trans, filters, package_ids, recursive):
-        """Emit all packages which depend on the given ids.
-
-        Recursive searching is not supported.
-        """
-        self.status = aptd_enums.STATUS_RESOLVING_DEP
-        self.progress = 101
-        self.cancellable = True
-        for id in package_ids:
-            version = self._get_version_by_id(id)
-            for pkg in self._iterate_packages():
-                if not self._is_package_visible(pkg, filters):
-                    continue
-                if pkg.is_installed:
-                    pkg_ver = pkg.installed
-                elif pkg.candidate:
-                    pkg_ver = pkg.candidate
-                for dependency in pkg_ver.dependencies:
-                    satisfied = False
-                    for base_dep in dependency.or_dependencies:
-                        if (version.package.name == base_dep.name or
-                                base_dep.name in version.provides):
-                            satisfied = True
-                            break
-                    if satisfied:
-                        self._emit_package(trans, pkg)
-                        break
-
-    def download_packages(self, trans, store_in_cache, package_ids):
-        """Implement the DownloadPackages functionality.
-
-        The store_in_cache parameter gets ignored.
-        """
-        def get_download_details(ids):
-            """Calculate the start and end point of a package download
-            progress.
-            """
-            total = 0
-            downloaded = 0
-            versions = []
-            # Check if all ids are vaild and calculate the total download size
-            for id in ids:
-                pkg_ver = self._get_version_by_id(id)
-                if not pkg_ver.downloadable:
-                    raise TransactionFailed(
-                        aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED,
-                        "package %s isn't downloadable" % id)
-                total += pkg_ver.size
-                versions.append((id, pkg_ver))
-            for id, ver in versions:
-                start = downloaded * 100 / total
-                end = start + ver.size * 100 / total
-                yield id, ver, start, end
-                downloaded += ver.size
-        trans.status = aptd_enums.STATUS_DOWNLOADING
-        trans.cancellable = True
-        trans.progress = 10
-        # Check the destination directory
-        if store_in_cache:
-            dest = apt_pkg.config.find_dir("Dir::Cache::archives")
-        else:
-            dest = tempfile.mkdtemp(prefix="aptdaemon-download")
-        if not os.path.isdir(dest) or not os.access(dest, os.W_OK):
-            raise TransactionFailed(aptd_enums.ERROR_INTERNAL_ERROR,
-                                    "The directory '%s' is not writable" %
-                                    dest)
-        # Start the download
-        for id, ver, start, end in get_download_details(package_ids):
-            progress = DaemonAcquireProgress(trans, start, end)
-            self._emit_pkg_version(trans, ver, pk.InfoEnum.DOWNLOADING)
-            try:
-                ver.fetch_binary(dest, progress)
-            except Exception as error:
-                raise TransactionFailed(
-                    aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED, str(error))
-            else:
-                path = os.path.join(dest, os.path.basename(ver.filename))
-                trans.emit_files(id, [path])
-                self._emit_pkg_version(trans, ver, pk.InfoEnum.FINISHED)
-
-    def get_files(self, trans, package_ids):
-        """Emit the Files signal which includes the files included in a package
-        Apt only supports this for installed packages
-        """
-        for id in package_ids:
-            pkg = self._get_package_by_id(id)
-            trans.emit_files(id, self._get_installed_files(pkg))
-
-    def what_provides(self, trans, filters, provides_type, values):
-        """Emit all packages which provide the given type and search value."""
-        self._init_plugins()
-
-        supported_type = False
-        provides_type_str = pk.provides_enum_to_string(provides_type)
-
-        # run plugins
-        for plugin in self._plugins.get("what_provides", []):
-            pklog.debug("calling what_provides plugin %s %s",
-                        str(plugin), str(filters))
-            for search_item in values:
-                try:
-                    for package in plugin(self._cache, provides_type_str,
-                                          search_item):
-                        self._emit_visible_package(trans, filters, package)
-                    supported_type = True
-                except NotImplementedError:
-                    # keep supported_type as False
-                    pass
-
-        if not supported_type and provides_type != pk.ProvidesEnum.ANY:
-            # none of the plugins felt responsible for this type
-            raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
-                                    "Query type '%s' is not supported" %
-                                    pk.provides_enum_to_string(provides_type))
-
-    def repo_enable(self, trans, repo_id, enabled):
-        """Enable or disable a repository."""
-        if not enabled:
-            raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
-                                    "Disabling repositories is not "
-                                    "implemented")
-
-        fields = repo_id.split()
-        if len(fields) < 3 or fields[0] not in ('deb', 'deb-src'):
-            raise TransactionFailed(
-                aptd_enums.ERROR_NOT_SUPPORTED,
-                "Unknown repository ID format: %s" % repo_id)
-
-        self.add_repository(trans, fields[0], fields[1], fields[2],
-                            fields[3:], '', None)
-
-    def install_signature(self, trans, sig_type, key_id, package_id):
-        """Install an archive key."""
-        if sig_type != pk.SigTypeEnum.GPG:
-            raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
-                                    "Type %s is not supported" % sig_type)
-        try:
-            keyserver = os.environ["APTDAEMON_KEYSERVER"]
-        except KeyError:
-            if platform.dist()[0] == "Ubuntu":
-                keyserver = "hkp://keyserver.ubuntu.com:80"
-            else:
-                keyserver = "hkp://keys.gnupg.net"
-        self.add_vendor_key_from_keyserver(trans, key_id, keyserver)
-
-    # Helpers
-
-    def _get_id_from_version(self, version):
-        """Return the package id of an apt.package.Version instance."""
-        if version.origins:
-            origin = version.origins[0].label
-            # APT returns a str with Python 2
-            if isinstance(origin, bytes):
-                origin = origin.decode("UTF-8")
-        else:
-            origin = ""
-        if version.architecture in [NATIVE_ARCH, "all"]:
-            name = version.package.name
-        else:
-            name = version.package.name.split(":")[0]
-        id = "%s;%s;%s;%s" % (name, version.version,
-                              version.architecture, origin)
-        return id
-
-    def _emit_package(self, trans, pkg, info=None, force_candidate=False):
-        """
-        Send the Package signal for a given apt package
-        """
-        if (not pkg.is_installed or force_candidate) and pkg.candidate:
-            self._emit_pkg_version(trans, pkg.candidate, info)
-        elif pkg.is_installed:
-            self._emit_pkg_version(trans, pkg.installed, info)
-        else:
-            pklog.debug("Package %s hasn't got any version." % pkg.name)
-
-    def _emit_pkg_version(self, trans, version, info=None):
-        """Emit the Package signal of the given apt.package.Version."""
-        id = self._get_id_from_version(version)
-        section = version.section.split("/")[-1]
-        if not info:
-            if version == version.package.installed:
-                if section == "metapackages":
-                    info = pk.InfoEnum.COLLECTION_INSTALLED
-                else:
-                    info = pk.InfoEnum.INSTALLED
-            else:
-                if section == "metapackages":
-                    info = pk.InfoEnum.COLLECTION_AVAILABLE
-                else:
-                    info = pk.InfoEnum.AVAILABLE
-        trans.emit_package(info, id, version.summary)
-
-    def _emit_all_visible_pkg_versions(self, trans, filters, pkg):
-        """Emit all available versions of a package."""
-        for version in pkg.versions:
-            if self._is_version_visible(version, filters):
-                self._emit_pkg_version(trans, version)
-
-    def _emit_visible_package(self, trans, filters, pkg, info=None):
-        """
-        Filter and emit a package
-        """
-        if self._is_package_visible(pkg, filters):
-            self._emit_package(trans, pkg, info)
-
-    def _emit_visible_packages(self, trans, filters, pkgs, info=None):
-        """
-        Filter and emit packages
-        """
-        for pkg in pkgs:
-            if self._is_package_visible(pkg, filters):
-                self._emit_package(trans, pkg, info)
-
-    def _emit_visible_packages_by_name(self, trans, filters, pkgs, info=None):
-        """
-        Find the packages with the given namens. Afterwards filter and emit
-        them
-        """
-        for name in pkgs:
-            if (name in self._cache and
-                    self._is_package_visible(self._cache[name], filters)):
-                self._emit_package(trans, self._cache[name], info)
-
-    def _is_version_visible(self, version, filters):
-        """Return True if the package version is matched by the given
-        filters.
-        """
-        if filters == pk.FilterEnum.NONE:
-            return True
-        if (bitfield_contains(filters, pk.FilterEnum.NEWEST) and
-                version.package.candidate != version):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.INSTALLED) and
-                version.package.installed != version):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_INSTALLED) and
-                version.package.installed == version):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.SUPPORTED) and
-                not self._is_package_supported(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_SUPPORTED) and
-                self._is_package_supported(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.FREE) and
-                not self._is_version_free(version)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_FREE) and
-                self._is_version_free(version)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.GUI) and
-                not self._has_package_gui(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_GUI) and
-                self._has_package_gui(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.COLLECTIONS) and
-                not self._is_package_collection(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_COLLECTIONS) and
-                self._is_package_collection(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.DEVELOPMENT) and
-                not self._is_package_devel(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_DEVELOPMENT) and
-                self._is_package_devel(version.package)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.ARCH) and
-                not version.architecture in [NATIVE_ARCH, "all"]):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_ARCH) and
-                version.architecture in [NATIVE_ARCH, "all"]):
-            return False
-        return True
-
-    def _is_package_visible(self, pkg, filters):
-        """Return True if the package is matched by the given filters."""
-        if filters == pk.FilterEnum.NONE:
-            return True
-        if (bitfield_contains(filters, pk.FilterEnum.INSTALLED) and
-                not pkg.is_installed):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_INSTALLED) and
-                pkg.is_installed):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.SUPPORTED) and
-                not self._is_package_supported(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_SUPPORTED) and
-                self._is_package_supported(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.FREE) and
-                not self._is_package_free(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_FREE) and
-                self._is_package_free(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.GUI) and
-                not self._has_package_gui(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_GUI) and
-                self._has_package_gui(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.COLLECTIONS) and
-                not self._is_package_collection(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_COLLECTIONS) and
-                self._is_package_collection(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.DEVELOPMENT) and
-                not self._is_package_devel(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_DEVELOPMENT) and
-                self._is_package_devel(pkg)):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.ARCH) and
-                ":" in pkg.name):
-            return False
-        if (bitfield_contains(filters, pk.FilterEnum.NOT_ARCH) and
-                not ":" in pkg.name):
-            return False
-        return True
-
-    def _is_package_free(self, pkg):
-        """Return True if we can be sure that the package's license is a
-        free one
-        """
-        if not pkg.candidate:
-            return False
-        return self._is_version_free(pkg.candidate)
-
-    def _is_version_free(self, version):
-        """Return True if we can be sure that the package version has got
-        a free license.
-        """
-        origins = version.origins
-        return (origins and
-                ((origins[0].origin == "Ubuntu" and
-                  origins[0].component in ["main", "universe"]) or
-                 (origins[0].origin == "Debian" and
-                  origins[0].component == "main")) and
-                origins[0].trusted)
-
-    def _is_package_collection(self, pkg):
-        """Return True if the package is a metapackge
-        """
-        section = pkg.section.split("/")[-1]
-        return section == "metapackages"
-
-    def _has_package_gui(self, pkg):
-        #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 _is_package_devel(self, pkg):
-        return (pkg.name.endswith("-dev") or pkg.name.endswith("-dbg") or
-                pkg.section.split('/')[-1].lower() in ['devel', 'libdevel'])
-
-    def _is_package_supported(self, pkg):
-        if not pkg.candidate:
-            return False
-        origins = pkg.candidate.origins
-        return (origins and
-                ((origins[0].origin == "Ubuntu" and
-                  origins[0].component in ["main", "restricted"]) or
-                 (origins[0].origin == "Debian" and
-                  origins[0].component == "main")) and
-                origins[0].trusted)
-
-    def _get_package_by_id(self, id):
-        """Return the apt.package.Package corresponding to the given
-        package id.
-
-        If the package isn't available error out.
-        """
-        version = self._get_version_by_id(id)
-        return version.package
-
-    def _get_version_by_id(self, id):
-        """Return the apt.package.Version corresponding to the given
-        package id.
-
-        If the version isn't available error out.
-        """
-        name, version_string, arch, data = id.split(";", 4)
-        if arch and not arch in [NATIVE_ARCH, "all"]:
-            name += ":%s" % arch
-        try:
-            pkg = self._cache[name]
-        except KeyError:
-            raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
-                                    "There isn't any package named %s",
-                                    name)
-        try:
-            version = pkg.versions[version_string]
-        except:
-            raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
-                                    "Verion %s doesn't exist",
-                                    version_string)
-        if version.architecture != arch:
-            raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
-                                    "Version %s of %s isn't available "
-                                    "for architecture %s",
-                                    pkg.name, version.version, arch)
-        return version
-
-    def _get_installed_files(self, pkg):
-        """
-        Return the list of unicode names of the files which have
-        been installed by the package
-
-        This method should be obsolete by the
-        apt.package.Package.installedFiles attribute as soon as the
-        consolidate branch of python-apt gets merged
-        """
-        path = os.path.join(apt_pkg.config["Dir"],
-                            "var/lib/dpkg/info/%s.list" % pkg.name)
-        try:
-            with open(path, 'rb') as f:
-                files = f.read().decode('UTF-8').split("\n")
-        except IOError:
-            return []
-        return files
-
-    def _get_package_group(self, pkg):
-        """
-        Return the packagekit group corresponding to the package's section
-        """
-        section = pkg.section.split("/")[-1]
-        if section in SECTION_GROUP_MAP:
-            return SECTION_GROUP_MAP[section]
-        else:
-            pklog.warn("Unkown package section %s of %s" % (pkg.section,
-                                                            pkg.name))
-            return pk.GroupEnum.UNKNOWN
-
-    def _init_plugins(self):
-        """Initialize PackageKit apt backend plugins.
-        Do nothing if plugins are already initialized.
-        """
-        if self._plugins is not None:
-            return
-
-        if not pkg_resources:
-            return
-
-        self._plugins = {}  # plugin_name -> [plugin_fn1, ...]
-
-        # just look in standard Python paths for now
-        dists, errors = pkg_resources.working_set.find_plugins(
-            pkg_resources.Environment())
-        for dist in dists:
-            pkg_resources.working_set.add(dist)
-        for plugin_name in ["what_provides"]:
-            for entry_point in pkg_resources.iter_entry_points(
-                    "packagekit.apt.plugins", plugin_name):
-                try:
-                    plugin = entry_point.load()
-                except Exception as e:
-                    pklog.warning("Failed to load %s from plugin %s: %s" % (
-                        plugin_name, str(entry_point.dist), str(e)))
-                    continue
-                pklog.debug("Loaded %s from plugin %s" % (
-                    plugin_name, str(entry_point.dist)))
-                self._plugins.setdefault(plugin_name, []).append(plugin)
-
-    def _apply_changes(self, trans, fetch_range=(15, 50),
-                       install_range=(50, 90)):
-        """Apply changes and emit RequireRestart accordingly."""
-        if hasattr(trans, "pktrans"):
-            # Cache the ids of the to be changed packages, since we will
-            # only get the package name during download/install time
-            for pkg in self._cache.get_changes():
-                if pkg.marked_delete or pkg.marked_reinstall:
-                    pkg_id = self._get_id_from_version(pkg.installed)
-                else:
-                    pkg_id = self._get_id_from_version(pkg.candidate)
-                trans.pktrans.pkg_id_cache[pkg.name] = pkg_id
-
-        worker.AptWorker._apply_changes(self, trans, fetch_range,
-                                        install_range)
-
-        if (hasattr(trans, "pktrans") and
-            (trans.role == aptd_enums.ROLE_UPGRADE_SYSTEM or
-             trans.packages[aptd_enums.PKGS_UPGRADE] or
-             trans.depends[aptd_enums.PKGS_UPGRADE])):
-            self._emit_require_restart(trans)
-
-
-if META_RELEASE_SUPPORT:
-
-    class GMetaRelease(GObject.GObject, MetaReleaseCore):
-
-        __gsignals__ = {"download-done": (GObject.SignalFlags.RUN_FIRST,
-                                          None,
-                                          ())}
-
-        def __init__(self):
-            GObject.GObject.__init__(self)
-            MetaReleaseCore.__init__(self, False, False)
-
-        def download(self):
-            MetaReleaseCore.download(self)
-            self.emit("download-done")
-
-
-def get_pk_exit_enum(enum):
-    try:
-        return MAP_EXIT_ENUM[enum]
-    except KeyError:
-        return pk.ExitEnum.UNKNOWN
-
-
-def get_pk_status_enum(enum):
-    try:
-        return MAP_STATUS_ENUM[enum]
-    except KeyError:
-        return pk.StatusEnum.UNKNOWN
-
-
-def get_pk_package_enum(enum):
-    try:
-        return MAP_PACKAGE_ENUM[enum]
-    except KeyError:
-        return pk.InfoEnum.UNKNOWN
-
-
-def get_pk_error_enum(enum):
-    try:
-        return MAP_ERROR_ENUM[enum]
-    except KeyError:
-        return pk.ErrorEnum.UNKNOWN
-
-
-def get_aptd_package_id(pk_id):
-    """Convert a PackageKit Package ID to the apt syntax.
-    e.g. xterm;235;i386;installed to xterm:i386=235
-    """
-    name, version, arch, data = pk_id.split(";")
-    id = name
-    if arch != NATIVE_ARCH and arch != "all":
-        id += ":%s" % arch
-    if version:
-        id += "=%s" % version
-    return id
-
-
-def get_pk_package_id(pk_id, data=""):
-    """Convert an AptDaemon package ID to the PackageKit syntax.
-    e.g. xterm:i368=235; to xterm;235;i386;installed
-    """
-    #FIXME add arch support
-    name, version, release = worker.AptWorker._split_package_id(pk_id)
-    try:
-        name, arch = name.split(":", 1)
-    except ValueError:
-        arch = ""
-    if version is None:
-        version = ""
-    if release is None:
-        release = ""
-    return "%s;%s;%s;%s" % (name, version, arch, data or release)
-
-
-def defer_idle(func, *args):
-    func(*args)
-    return False
-
-
-def bitfield_summarize(*enums):
-    """Return the bitfield with the given PackageKit enums."""
-    field = 0
-    for enum in enums:
-        field |= 2 ** int(enum)
-    return field
-
-
-def bitfield_add(field, enum):
-    """Add a PackageKit enum to a given field"""
-    field |= 2 ** int(enum)
-    return field
-
-
-def bitfield_remove(field, enum):
-    """Remove a PackageKit enum to a given field"""
-    field = field ^ 2 ** int(enum)
-    return field
-
-
-def bitfield_contains(field, enum):
-    """Return True if a bitfield contains the given PackageKit enum"""
-    return field & 2 ** int(enum)
-
-
-def get_string_from_flags(flags):
-    """Return a human readable string of the applied transaction flags."""
-    ret = ""
-    if flags == pk.TransactionFlagEnum.NONE:
-        return "simulate"
-    if bitfield_contains(flags, pk.TransactionFlagEnum.SIMULATE):
-        ret += " simulate"
-    if bitfield_contains(flags, pk.TransactionFlagEnum.ONLY_DOWNLOAD):
-        ret += " only-download"
-    if bitfield_contains(flags, pk.TransactionFlagEnum.ONLY_TRUSTED):
-        ret += " only-trusted"
-    return ret.strip()
-
-
-def get_string_from_array(array):
-    """Convert a DBus Array to a human readable format"""
-    return [str(value) for value in array]
-
-
-# vim: ts=4 et sts=4
diff -pruN 1.1.1-4/.pc/dbus_timeout.patch/aptdaemon/client.py 1.1.1+bzr982-0ubuntu14/.pc/dbus_timeout.patch/aptdaemon/client.py
--- 1.1.1-4/.pc/dbus_timeout.patch/aptdaemon/client.py	2013-03-11 06:00:59.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/.pc/dbus_timeout.patch/aptdaemon/client.py	2014-08-21 12:59:23.000000000 +0000
@@ -33,17 +33,10 @@ import weakref
 import sys
 
 import dbus
-import dbus.glib
 import dbus.mainloop.glib
 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
-if 'gobject' in sys.modules and sys.modules['gobject'] is not None:
-    import gobject as GObject
-    GLib = GObject
-    _GObject = GObject.GObject
-else:
-    from gi.repository import GObject, GLib
-    _GObject = GObject.Object
+from gi.repository import GObject, GLib
 
 from . import enums
 from . import debconf
@@ -54,7 +47,7 @@ from .errors import convert_dbus_excepti
 __all__ = ("AptTransaction", "AptClient", "get_transaction", "get_aptdaemon")
 
 
-class AptTransaction(_GObject):
+class AptTransaction(GObject.Object):
 
     """Represents an aptdaemon transaction.
 
@@ -503,7 +496,7 @@ class AptTransaction(_GObject):
         try:
             return AptTransaction._tid_cache[tid]
         except KeyError:
-            value = _GObject.__new__(cls, tid, *args, **kwargs)
+            value = GObject.Object.__new__(cls, tid, *args, **kwargs)
             AptTransaction._tid_cache[tid] = value
             return value
 
@@ -683,9 +676,9 @@ class AptTransaction(_GObject):
                                reply_handler=sync_properties,
                                error_handler=error_handler)
         else:
-            properties = self._proxy.GetAll("org.debian.apt.transaction",
-                                            dbus_interface=
-                                            dbus.PROPERTIES_IFACE)
+            properties = self._proxy.GetAll(
+                "org.debian.apt.transaction",
+                dbus_interface=dbus.PROPERTIES_IFACE)
             sync_properties(properties)
 
     @deferable
@@ -937,7 +930,7 @@ class AptTransaction(_GObject):
     def set_terminal(self, ttyname, reply_handler=None, error_handler=None):
         """Allow to set a controlling terminal for the underlying dpkg call.
 
-        See the source code of gtkwidgets.AptTerminal or console.ConsoleClient
+        See the source code of gtk3widgets.AptTerminal or console.ConsoleClient
         as example.
 
         >>> master, slave = pty.openpty()
@@ -1272,7 +1265,7 @@ class AptClient(object):
         """
         # Root is not allowed to access FUSE file systems. So copy files
         # to the local system.
-        #FIXME: the locally cached one should be removed afterwards
+        # FIXME: the locally cached one should be removed afterwards
         home = os.getenv("HOME", None)
         if home and path.startswith(os.path.join(home, ".gvfs")):
             shutil.copy(path, "/tmp")
@@ -1594,7 +1587,7 @@ class AptClient(object):
             context = GLib.main_context_default()
             while not hasattr(deferred, "result"):
                 context.iteration(True)
-           # If there has been an error in the helper raise it
+            # If there has been an error in the helper raise it
             if isinstance(deferred.result, defer.DeferredException):
                 deferred.result.raise_exception()
             trans = deferred.result
@@ -1672,6 +1665,18 @@ def get_transaction(tid, bus=None, reply
         return trans
 
 
+def get_size_string(bytes):
+    """Returns a human friendly string for a given byte size.
+
+    Note: The bytes are skipped from the returned unit: 1024 returns 1K
+    """
+    for unit in ["", "K", "M", "G"]:
+        if bytes < 1024.0:
+            return "%3.1f%s" % (bytes, unit)
+        bytes /= 1024.0
+    return "%3.1f%s" % (bytes, "T")
+
+
 def get_aptdaemon(bus=None):
     """Get the daemon D-Bus interface.
 
diff -pruN 1.1.1-4/.pc/dbus_timeout.patch/aptdaemon/core.py 1.1.1+bzr982-0ubuntu14/.pc/dbus_timeout.patch/aptdaemon/core.py
--- 1.1.1-4/.pc/dbus_timeout.patch/aptdaemon/core.py	2013-08-11 19:07:59.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/.pc/dbus_timeout.patch/aptdaemon/core.py	2014-08-21 12:59:23.000000000 +0000
@@ -53,9 +53,6 @@ from gi.repository import GObject, GLib
 import dbus.exceptions
 import dbus.service
 import dbus.mainloop.glib
-import dbus.glib
-import apt_pkg
-import apt.auth
 
 from .config import ConfigWriter
 from . import errors
@@ -63,10 +60,10 @@ from . import enums
 from defer import inline_callbacks, return_value, Deferred
 from defer.utils import dbus_deferred_method
 from . import policykit1
-from .worker import (
-    AptWorker,
-    DummyWorker,
-    trans_only_installs_pkgs_from_high_trust_repos)
+from .utils import split_package_id
+from .worker import DummyWorker
+from .worker.aptworker import (AptWorker,
+                               trans_only_installs_pkgs_from_high_trust_repos)
 from .loop import mainloop
 from .logger import ColoredFormatter
 
@@ -130,7 +127,7 @@ _console_formatter = ColoredFormatter("%
                                       "%T")
 _console_handler.setFormatter(_console_formatter)
 log.addHandler(_console_handler)
-#FIXME: Use LoggerAdapter (requires Python 2.6)
+# FIXME: Use LoggerAdapter (requires Python 2.6)
 log_trans = logging.getLogger("AptDaemon.Trans")
 
 # Required for translations from APT
@@ -139,27 +136,12 @@ try:
 except locale.Error:
     log.warning("Failed to unset LC_ALL. Translations are not available.")
 
-_POPCON_PATH = "/etc/popularity-contest.conf"
-_POPCON_DEFAULT = """# Config file for Debian's popularity-contest package.
-#
-# To change this file, use:
-#        dpkg-reconfigure popularity-contest
-#
-# You can also edit it by hand, if you so choose.
-#
-# See /usr/share/popularity-contest/default.conf for more info
-# on the options.
-MY_HOSTID="%(host_id)s"
-PARTICIPATE="%(participate)s"
-USE_HTTP="yes"
-"""
-
 
 def _excepthook(exc_type, exc_obj, exc_tb, apport_excepthook):
     """Handle exceptions of aptdaemon and avoid tiggering apport crash
-    reports for valid DBusExceptions that are send to the client.
+    reports for valid DBusExceptions that are sent to the client.
     """
-    # apport registers is own excepthook as sys.excepthook. So we have to
+    # apport registers it's own excepthook as sys.excepthook. So we have to
     # send exceptions that we don't want to be tracked to Python's
     # internal excepthook directly
     if issubclass(exc_type, errors.AptDaemonError):
@@ -857,7 +839,7 @@ class Transaction(DBusObject):
         Keyword arguments:
         url -- the URL of the proxy server, e.g. http://proxy:8080
         """
-        if url != "" and (not url.startswith("http://") or not ":" in url):
+        if url != "" and (not url.startswith("http://") or ":" not in url):
             raise errors.InvalidProxyError(url)
         action = policykit1.PK_ACTION_SET_PROXY
         yield policykit1.check_authorization_by_name(sender, action,
@@ -941,7 +923,7 @@ class Transaction(DBusObject):
     @inline_callbacks
     def _check_simulated(self):
         # Simulate the new transaction if this has not been done before:
-        #FIXME: Compare the simulated timestamp with the time stamp of
+        # FIXME: Compare the simulated timestamp with the time stamp of
         #       the status and re-simulate the transaction
         if self.simulated is None:
             # If there isn't any transaction on the queue we send an early
@@ -1361,7 +1343,7 @@ class TransactionQueue(GObject.GObject):
 
     def _on_transaction_done(self, worker, trans):
         """Mark the last item as done and request a new item."""
-        #FIXME: Check if the transaction failed because of a broken system or
+        # FIXME: Check if the transaction failed because of a broken system or
         #       if dpkg journal is dirty. If so allready queued transactions
         #       except the repair transactions should be removed from the queue
         if trans.exit in [enums.EXIT_FAILED, enums.EXIT_CANCELLED]:
@@ -1420,8 +1402,8 @@ class AptDaemon(DBusObject):
         """
         log.info("Initializing daemon")
         # glib does not support SIGQUIT
-        #GLib.unix_signal_add_full(
-        #    GLib.PRIORITY_HIGH, signal.SIGQUIT, self._sigquit, None)
+        # GLib.unix_signal_add_full(
+        #     GLib.PRIORITY_HIGH, signal.SIGQUIT, self._sigquit, None)
         GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM,
                              self._sigquit, None)
         # Decrease the priority of the daemon to avoid blocking UI
@@ -1443,7 +1425,7 @@ class AptDaemon(DBusObject):
                 if self.options.replace is False:
                     log.critical("Another daemon is already running")
                     sys.exit(1)
-                log.warn("Replacing already running daemon")
+                log.warning("Replacing already running daemon")
                 the_other_guy = bus.get_object(APTDAEMON_DBUS_SERVICE,
                                                APTDAEMON_DBUS_PATH)
                 the_other_guy.Quit(dbus_interface=APTDAEMON_DBUS_INTERFACE,
@@ -1461,12 +1443,13 @@ class AptDaemon(DBusObject):
         else:
             load_plugins = not options.disable_plugins
             try:
+                from .worker.pkworker import AptPackageKitWorker
                 from . import pkcompat
             except ImportError:
                 self.worker = AptWorker(options.chroot, load_plugins)
             else:
-                self.worker = pkcompat.PackageKitWorker(options.chroot,
-                                                        load_plugins)
+                self.worker = AptPackageKitWorker(options.chroot,
+                                                  load_plugins)
         self.queue = TransactionQueue(self.worker)
         self.queue.connect("queue-changed", self._on_queue_changed)
         # keep state of the last information about reboot required
@@ -1474,7 +1457,7 @@ class AptDaemon(DBusObject):
         try:
             self.packagekit = pkcompat.PackageKit(self.queue, connect, bus)
         except dbus.exceptions.NameExistsException:
-            log.warn("PackageKit is already running")
+            log.warning("PackageKit is already running")
         except NameError:
             pass
         log.debug("Daemon was initialized")
@@ -1704,7 +1687,7 @@ class AptDaemon(DBusObject):
         :returns: The D-Bus path of the new transaction object which
             performs this action.
         """
-        #FIXME: take sha1 or md5 cash into accout to allow selecting a version
+        # FIXME: take sha1 or md5 cash into accout to allow selecting a version
         #       or an origin different from the candidate
         log.info("CommitPackages() was called: %s, %s, %s, %s, %s, %s",
                  install, reinstall, remove, purge, upgrade, downgrade)
@@ -1865,8 +1848,8 @@ class AptDaemon(DBusObject):
             performs this action.
         """
         log.info("InstallFile() was called: %s" % path)
-        #FIXME: Perform some checks
-        #FIXME: Should we already extract the package name here?
+        # FIXME: Perform some checks
+        # FIXME: Should we already extract the package name here?
         return self._create_trans(enums.ROLE_INSTALL_FILE,
                                   sender, kwargs={"path": path,
                                                   "force": force})
@@ -1997,7 +1980,7 @@ class AptDaemon(DBusObject):
         action = policykit1.PK_ACTION_GET_TRUSTED_VENDOR_KEYS
         yield policykit1.check_authorization_by_name(sender, action,
                                                      bus=self.bus)
-        fingerprints = [key.keyid for key in apt.auth.list_keys()]
+        fingerprints = self.worker.get_trusted_vendor_keys()
         return_value(fingerprints)
 
     # pylint: disable-msg=C0103,C0322
@@ -2062,20 +2045,15 @@ class AptDaemon(DBusObject):
                                                      bus=self.bus)
         if iface == APTDAEMON_DBUS_INTERFACE:
             if name == "PopConParticipation":
-                self._set_popcon_participation(value)
+                self.worker.set_config(name, dbus.Boolean(value))
             elif name == "AutoUpdateInterval":
-                self._set_apt_config("APT::Periodic::Update-Package-Lists",
-                                     dbus.Int32(value), "10periodic")
+                self.worker.set_config(name, dbus.Int32(value), "10periodic")
             elif name == "AutoDownload":
-                self._set_apt_config("APT::Periodic::"
-                                     "Download-Upgradeable-Packages",
-                                     dbus.Boolean(value), "10periodic")
+                self.worker.set_config(name, dbus.Boolean(value), "10periodic")
             elif name == "AutoCleanInterval":
-                self._set_apt_config("APT::Periodic::AutocleanInterval",
-                                     dbus.Int32(value), "10periodic")
+                self.worker.set_config(name, dbus.Int32(value), "10periodic")
             elif name == "UnattendedUpgrade":
-                self._set_apt_config("APT::Periodic::Unattended-Upgrade",
-                                     dbus.Boolean(value), "10periodic")
+                self.worker.set_config(name, dbus.Boolean(value), "10periodic")
             else:
                 raise dbus.exceptions.DBusException("Unknown or read only "
                                                     "property: %s" % name)
@@ -2088,7 +2066,7 @@ class AptDaemon(DBusObject):
         exception.
         """
         for fullname in pkg_names:
-            name, version, release = AptWorker._split_package_id(fullname)
+            name, version, release = split_package_id(fullname)
             if not re.match(REGEX_VALID_PACKAGENAME, name):
                 raise errors.AptDaemonError("%s isn't a valid package name" %
                                             name)
@@ -2101,72 +2079,22 @@ class AptDaemon(DBusObject):
                 raise errors.AptDaemonError("%s isn't a valid release" %
                                             release)
 
-    def _set_apt_config(self, option, key, filename):
-        cw = ConfigWriter()
-        cw.set_value(option, key, filename)
-        apt_pkg.init_config()
-
-    def _set_popcon_participation(self, participate):
-        if participate:
-            value = "yes"
-        else:
-            value = "no"
-        if os.path.exists(_POPCON_PATH):
-            # read the current config and replace the corresponding settings
-            # FIXME: Check if the config file is a valid bash script and
-            #        contains the host_id
-            with open(_POPCON_PATH) as conf_file:
-                old_config = conf_file.read()
-            config = re.sub(r'(PARTICIPATE=*)(".+?")',
-                            '\\1"%s"' % value,
-                            old_config)
-        else:
-            # create a new popcon config file
-            m = md5()
-            m.update(open("/dev/urandom", "r").read(1024))
-            config = _POPCON_DEFAULT % {"host_id": m.hexdigest(),
-                                        "participate": value}
-
-        with open(_POPCON_PATH, "w") as conf_file:
-            conf_file.write(config)
-
-    def _get_popcon_participation(self):
-        #FIXME: Use a script to evaluate the configuration:
-        #       #!/bin/sh
-        #       . /etc/popularitiy-contest.conf
-        #       . /usr/share/popularitiy-contest/default.conf
-        #       echo $PARTICIAPTE $HOST_ID
-        if os.path.exists(_POPCON_PATH):
-            with open(_POPCON_PATH) as conf_file:
-                config = conf_file.read()
-            match = re.match("\nPARTICIPATE=\"(yes|no)\"", config)
-            if match and match[0] == "yes":
-                return True
-        return False
-
     def _get_properties(self, iface):
         """Helper get the properties of a D-Bus interface."""
         if iface == APTDAEMON_DBUS_INTERFACE:
-            return {"AutoUpdateInterval": dbus.Int32(
-                apt_pkg.config.find_i("APT::Periodic::"
-                                      "Update-Package-Lists",
-                                      0)),
-                    "AutoDownload": dbus.Boolean(
-                        apt_pkg.config.find_b("APT::Periodic::"
-                                              "Download-Upgradeable-Packages",
-                                              False)),
-                    "AutoCleanInterval": dbus.Int32(
-                        apt_pkg.config.find_i("APT::Periodic::"
-                                              "AutocleanInterval",
-                                              0)),
-                    "UnattendedUpgrade": dbus.Int32(
-                        apt_pkg.config.find_b("APT::Periodic::"
-                                              "Unattended-Upgrade",
-                                              False)),
-                    "PopConParticipation": dbus.Boolean(
-                        self._get_popcon_participation()),
-                    "RebootRequired": dbus.Boolean(
-                        self.worker.is_reboot_required())}
+            return {
+                "AutoUpdateInterval": dbus.Int32(
+                    self.worker.get_config("AutoUpdateInterval")),
+                "AutoDownload": dbus.Boolean(
+                    self.worker.get_config("AutoDownload")),
+                "AutoCleanInterval": dbus.Int32(
+                    self.worker.get_config("AutoCleanInterval")),
+                "UnattendedUpgrade": dbus.Int32(
+                    self.worker.get_config("UnattendedUpgrade")),
+                "PopConParticipation": dbus.Boolean(
+                    self.worker.get_config("PopConParticipation")),
+                "RebootRequired": dbus.Boolean(
+                    self.worker.is_reboot_required())}
         else:
             return {}
 
diff -pruN 1.1.1-4/.pc/fix-configparser.patch/aptdaemon/config.py 1.1.1+bzr982-0ubuntu14/.pc/fix-configparser.patch/aptdaemon/config.py
--- 1.1.1-4/.pc/fix-configparser.patch/aptdaemon/config.py	2013-03-11 06:00:59.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/.pc/fix-configparser.patch/aptdaemon/config.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,242 +0,0 @@
-"""Handling configuration files."""
-#Copyright (C) 2010 Sebastian Heinlein <sevel@glatzor.de>
-#
-#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.
-
-__author__ = "Sebastian Heinlein <devel@glatzor.de>"
-
-__all__ = ("ConfigWriter",)
-
-import logging
-import os
-
-import apt_pkg
-
-log = logging.getLogger("AptDaemon.ConfigWriter")
-
-
-class Value(object):
-
-    """Represents a value with position information.
-
-    .. attribute:: string
-        The value string.
-
-    .. attribute:: line
-        The line number of the configuration file in which the value is set.
-
-    .. attribute:: start
-        The position in the line at which the value starts.
-
-    .. attribute:: end
-        The position in the line at which the value ends.
-
-    .. attribute:: quotes
-        The outer qoutes of the value: ' or "
-    """
-
-    def __init__(self, line, start, quotes):
-        self.string = ""
-        self.start = start
-        self.end = None
-        self.line = line
-        self.quotes = quotes
-
-    def __cmp__(self, other):
-        return self.string == other
-
-    def __repr__(self):
-        return "Value: '%s' (line %s: %s to %s)" % (self.string, self.line,
-                                                    self.start, self.end)
-
-
-class ConfigWriter(object):
-
-    """Modifies apt configuration files."""
-
-    def parse(self, lines):
-        """Parse an ISC based apt configuration.
-
-        :param lines: The list of lines of a configuration file.
-
-        :returns: Dictionary of key, values found in the parsed configuration.
-        """
-        options = {}
-        in_comment = False
-        in_value = False
-        prev_char = None
-        option = []
-        value = None
-        option_name = ""
-        value_list = []
-        in_brackets = True
-        level = 0
-        for line_no, line in enumerate(lines):
-            for char_no, char in enumerate(line):
-                if not in_comment and char == "*" and prev_char == "/":
-                    in_comment = True
-                    prev_char = ""
-                    continue
-                elif in_comment and char == "/" and prev_char == "*":
-                    # A multiline comment was closed
-                    in_comment = False
-                    prev_char = ""
-                    option_name = option_name[:-1]
-                    continue
-                elif in_comment:
-                    # We ignore the content of multiline comments
-                    pass
-                elif not in_value and char == "/" and prev_char == "/":
-                    # In the case of a line comment continue processing
-                    # the next line
-                    prev_char = ""
-                    option_name = option_name[:-1]
-                    break
-                elif char in "'\"":
-                    if in_value and value.quotes == char:
-                        value.end = char_no
-                        in_value = not in_value
-                    elif not value:
-                        value = Value(line_no, char_no, char)
-                        in_value = not in_value
-                    else:
-                        value.string += char
-                elif in_value:
-                    value.string += char
-                elif option_name and char == ":" and prev_char == ":":
-                    option.append(option_name[:-1])
-                    option_name = ""
-                elif char.isalpha() or char in "/-:._+":
-                    option_name += char.lower()
-                elif char == ";":
-                    if in_brackets:
-                        value_list.append(value)
-                        value = None
-                        continue
-                    if value_list:
-                        log.debug("Found %s \"%s\"", "::".join(option),
-                                  value_list)
-                        options["::".join(option)] = value_list
-                        value_list = []
-                    elif value:
-                        log.debug("Found %s \"%s\"", "::".join(option), value)
-                        options["::".join(option)] = value
-                    else:
-                        log.debug("Skipping empty key %s", "::".join(option))
-                    value = None
-                    if level > 0:
-                        option.pop()
-                    else:
-                        option = []
-                elif char == "}":
-                    level -= 1
-                    in_brackets = False
-                elif char == "{":
-                    level += 1
-                    if option_name:
-                        option.append(option_name)
-                        option_name = ""
-                    in_brackets = True
-                elif char in "\t\n ":
-                    if option_name:
-                        option.append(option_name)
-                        option_name = ""
-                        in_brackets = False
-                else:
-                    raise ValueError("Unknown char '%s' in line: '%s'" %
-                                     (char, line))
-                prev_char = char
-        return options
-
-    def set_value(self, option, value, defaultfile):
-        """Change the value of an option in the configuration.
-
-        :param option: The name of the option, e.g.
-            'apt::periodic::AutoCleanInterval'.
-        :param value: The value of the option. Will be converted to string.
-        :param defaultfile: The filename of the ``/etc/apt/apt.conf.d``
-            configuration snippet in which the option should be set.
-            If the value is overriden by a later configuration file snippet
-            it will be disabled in the corresponding configuration file.
-        """
-        #FIXME: Support value lists
-        # Convert the value to string
-        if value is True:
-            value = "true"
-        elif value is False:
-            value = "false"
-        else:
-            value = str(value)
-        # Check all configuration file snippets
-        etc_parts = os.path.join(apt_pkg.config.find_dir("Dir::Etc"),
-                                 apt_pkg.config.find_dir("Dir::Etc::Parts"))
-        for filename in os.listdir(etc_parts):
-            if filename < defaultfile:
-                continue
-            with open(os.path.join(etc_parts, filename)) as fd:
-                lines = fd.readlines()
-            config = self.parse(lines)
-            try:
-                val = config[option.lower()]
-            except KeyError:
-                if filename == defaultfile:
-                    lines.append("%s '%s';\n" % (option, value))
-                else:
-                    continue
-            else:
-                # Check if the value needs to be changed at all
-                if ((value == "true" and
-                        val.string.lower() in ["yes", "with", "on",
-                                               "enable"]) or
-                        (value == "false" and
-                         val.string.lower() in ["no", "without", "off",
-                                                "disable"]) or
-                        (str(value) == val.string)):
-                    continue
-                if filename == defaultfile:
-                    line = lines[val.line]
-                    new_line = line[:val.start + 1]
-                    new_line += value
-                    new_line += line[val.end:]
-                    lines[val.line] = new_line
-                else:
-                    # Comment out existing values instead in non default
-                    # configuration files
-                    #FIXME Quite dangerous for brackets
-                    lines[val.line] = "// %s" % lines[val.line]
-            with open(os.path.join(etc_parts, filename), "w") as fd:
-                log.debug("Writting %s", filename)
-                fd.writelines(lines)
-        if not os.path.exists(os.path.join(etc_parts, defaultfile)):
-            with open(os.path.join(etc_parts, defaultfile), "w") as fd:
-                log.debug("Writting %s", filename)
-                line = "%s '%s';\n" % (option, value)
-                fd.write(line)
-
-
-def main():
-    apt_pkg.init_config()
-    cw = ConfigWriter()
-    for filename in sorted(os.listdir("/etc/apt/apt.conf.d/")):
-        lines = open("/etc/apt/apt.conf.d/%s" % filename).readlines()
-        cw.parse(lines)
-    print((cw.set_value("huhu::abc", "lumpi", "10glatzor")))
-
-if __name__ == "__main__":
-    main()
-
-# vim:ts=4:sw=4:et
diff -pruN 1.1.1-4/.pc/fix-configparser.patch/tests/test_configparser.py 1.1.1+bzr982-0ubuntu14/.pc/fix-configparser.patch/tests/test_configparser.py
--- 1.1.1-4/.pc/fix-configparser.patch/tests/test_configparser.py	2013-03-11 06:00:59.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/.pc/fix-configparser.patch/tests/test_configparser.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,100 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""Provides unit tests for the APT configuration file parser"""
-# Copyright (C) 2010 Sebastian Heinlein <devel@glatzor.de>
-#
-# 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.
-# Licensed under the GNU General Public License Version 2
-
-__author__ = "Sebastian Heinlein <devel@glatzor.de>"
-
-import os
-import sys
-import unittest
-
-import apt_pkg
-
-from aptdaemon.config import ConfigWriter
-
-
-class ConfigurationParserTestCase(unittest.TestCase):
-
-    """Test suite for the configuration parser."""
-
-    def setUp(self):
-        self.parser = ConfigWriter()
-
-    def test_comment_in_value(self):
-        """ ensure that comment strings in values are parsed correctly """
-        s = """// Server information for apt-changelog
-        APT {
-         Changelogs {
-          Server "http://changelogs.ubuntu.com/changelogs";
-         }
-        }
-        """
-        cf = self.parser.parse(s.split("\n"))
-        self.assertEqual(cf["apt::changelogs::server"].string,
-                         "http://changelogs.ubuntu.com/changelogs")
-
-    def test_multi_line_comments(self):
-        s = """/*
- * APT configuration file for Zope Debian packages.
- */
-
-DPkg {
-    Post-Invoke {"which dzhandle";};
-}
-        """
-        cf = self.parser.parse(s.split("\n"))
-        self.assertEqual(cf["dpkg::post-invoke"][0].string, "which dzhandle")
-
-    def test_(self):
-        config = {}
-        config_check = {}
-
-        for filename in os.listdir("/etc/apt/apt.conf.d"):
-            path = "/etc/apt/apt.conf.d/%s" % filename
-            config_apt = apt_pkg.Configuration()
-            with open(path, "r") as fd:
-                apt_pkg.read_config_file(config_apt, path)
-                config = self.parser.parse(fd.readlines())
-            for key in config_apt.keys():
-                if key.endswith("::"):
-                    key = key[:-2]
-                    value_list_apt = config_apt.value_list(key)
-                    if value_list_apt:
-                        value_list = [val.string for val in
-                                      config[key.lower()]]
-                        self.assertTrue(value_list_apt == value_list,
-                                        "%s: %s != %s" % (key, value_list_apt,
-                                                          value_list))
-                else:
-                    value_apt = config_apt[key]
-                    if value_apt:
-                        self.assertTrue(
-                            value_apt == config[key.lower()].string)
-
-
-@unittest.skipIf(sys.version_info.major < 3, "Only Python3")
-def setUp():
-    pass
-
-if __name__ == "__main__":
-    unittest.main()
-
-# vim: ts=4 et sts=4
diff -pruN 1.1.1-4/.pc/fix-ftbs.patch/aptdaemon/gtk3widgets.py 1.1.1+bzr982-0ubuntu14/.pc/fix-ftbs.patch/aptdaemon/gtk3widgets.py
--- 1.1.1-4/.pc/fix-ftbs.patch/aptdaemon/gtk3widgets.py	2015-10-12 18:06:09.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/.pc/fix-ftbs.patch/aptdaemon/gtk3widgets.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,1192 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""
-This module provides widgets to use aptdaemon in a GTK application.
-"""
-# Copyright (C) 2008-2009 Sebastian Heinlein <devel@glatzor.de>
-#
-# 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.
-
-__author__ = "Sebastian Heinlein <devel@glatzor.de>"
-
-__all__ = ("AptConfigFileConflictDialog", "AptCancelButton",
-           "AptConfirmDialog",
-           "AptProgressDialog", "AptTerminalExpander", "AptStatusIcon",
-           "AptRoleIcon", "AptStatusAnimation", "AptRoleLabel",
-           "AptStatusLabel", "AptMediumRequiredDialog", "AptMessageDialog",
-           "AptErrorDialog", "AptProgressBar", "DiffView",
-           "AptTerminal"
-           )
-
-import difflib
-import gettext
-import os
-import pty
-import re
-
-import apt_pkg
-from gi.repository import GObject
-from gi.repository import GLib
-from gi.repository import Gdk
-from gi.repository import Gtk
-from gi.repository import Pango
-from gi.repository import Vte
-
-from .enums import *
-from defer import inline_callbacks
-from defer.utils import deferable
-
-_ = lambda msg: gettext.dgettext("aptdaemon", msg)
-
-(COLUMN_ID,
- COLUMN_PACKAGE) = list(range(2))
-
-
-class AptStatusIcon(Gtk.Image):
-    """
-    Provides a Gtk.Image which shows an icon representing the status of a
-    aptdaemon transaction
-    """
-    def __init__(self, transaction=None, size=Gtk.IconSize.DIALOG):
-        Gtk.Image.__init__(self)
-        # note: icon_size is a property which you can't set with GTK 2, so use
-        # a different name
-        self._icon_size = size
-        self.icon_name = None
-        self._signals = []
-        self.set_alignment(0, 0)
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect to the given transaction"""
-        for sig in self._signals:
-            GLib.source_remove(sig)
-        self._signals = []
-        self._signals.append(transaction.connect("status-changed",
-                                                 self._on_status_changed))
-
-    def set_icon_size(self, size):
-        """Set the icon size to gtk stock icon size value"""
-        self._icon_size = size
-
-    def _on_status_changed(self, transaction, status):
-        """Set the status icon according to the changed status"""
-        icon_name = get_status_icon_name_from_enum(status)
-        if icon_name is None:
-            icon_name = Gtk.STOCK_MISSING_IMAGE
-        if icon_name != self.icon_name:
-            self.set_from_icon_name(icon_name, self._icon_size)
-            self.icon_name = icon_name
-
-
-class AptRoleIcon(AptStatusIcon):
-    """
-    Provides a Gtk.Image which shows an icon representing the role of an
-    aptdaemon transaction
-    """
-    def set_transaction(self, transaction):
-        for sig in self._signals:
-            GLib.source_remove(sig)
-        self._signals = []
-        self._signals.append(transaction.connect("role-changed",
-                                                 self._on_role_changed))
-        self._on_role_changed(transaction, transaction.role)
-
-    def _on_role_changed(self, transaction, role_enum):
-        """Show an icon representing the role"""
-        icon_name = get_role_icon_name_from_enum(role_enum)
-        if icon_name is None:
-            icon_name = Gtk.STOCK_MISSING_IMAGE
-        if icon_name != self.icon_name:
-            self.set_from_icon_name(icon_name, self._icon_size)
-            self.icon_name = icon_name
-
-
-class AptStatusAnimation(AptStatusIcon):
-    """
-    Provides a Gtk.Image which shows an animation representing the
-    transaction status
-    """
-    def __init__(self, transaction=None, size=Gtk.IconSize.DIALOG):
-        AptStatusIcon.__init__(self, transaction, size)
-        self.animation = []
-        self.ticker = 0
-        self.frame_counter = 0
-        self.iter = 0
-        name = get_status_animation_name_from_enum(STATUS_WAITING)
-        fallback = get_status_icon_name_from_enum(STATUS_WAITING)
-        self.set_animation(name, fallback)
-
-    def set_animation(self, name, fallback=None, size=None):
-        """Show and start the animation of the given name and size"""
-        if name == self.icon_name:
-            return
-        if size is not None:
-            self._icon_size = size
-        self.stop_animation()
-        animation = []
-        (width, height) = Gtk.icon_size_lookup(self._icon_size)
-        theme = Gtk.IconTheme.get_default()
-        if name is not None and theme.has_icon(name):
-            pixbuf = theme.load_icon(name, width, 0)
-            rows = pixbuf.get_height() / height
-            cols = pixbuf.get_width() / width
-            for r in range(rows):
-                for c in range(cols):
-                    animation.append(pixbuf.subpixbuf(c * width, r * height,
-                                                      width, height))
-            if len(animation) > 0:
-                self.animation = animation
-                self.iter = 0
-                self.set_from_pixbuf(self.animation[0])
-                self.start_animation()
-            else:
-                self.set_from_pixbuf(pixbuf)
-            self.icon_name = name
-        elif fallback is not None and theme.has_icon(fallback):
-            self.set_from_icon_name(fallback, self._icon_size)
-            self.icon_name = fallback
-        else:
-            self.set_from_icon_name(Gtk.STOCK_MISSING_IMAGE)
-
-    def start_animation(self):
-        """Start the animation"""
-        if self.ticker == 0:
-            self.ticker = GLib.timeout_add(200, self._advance)
-
-    def stop_animation(self):
-        """Stop the animation"""
-        if self.ticker != 0:
-            GLib.source_remove(self.ticker)
-            self.ticker = 0
-
-    def _advance(self):
-        """
-        Show the next frame of the animation and stop the animation if the
-        widget is no longer visible
-        """
-        if self.get_property("visible") is False:
-            self.ticker = 0
-            return False
-        self.iter = self.iter + 1
-        if self.iter >= len(self.animation):
-            self.iter = 0
-        self.set_from_pixbuf(self.animation[self.iter])
-        return True
-
-    def _on_status_changed(self, transaction, status):
-        """
-        Set the animation according to the changed status
-        """
-        name = get_status_animation_name_from_enum(status)
-        fallback = get_status_icon_name_from_enum(status)
-        self.set_animation(name, fallback)
-
-
-class AptRoleLabel(Gtk.Label):
-    """
-    Status label for the running aptdaemon transaction
-    """
-    def __init__(self, transaction=None):
-        GtkLabel.__init__(self)
-        self.set_alignment(0, 0)
-        self.set_ellipsize(Pango.EllipsizeMode.END)
-        self.set_max_width_chars(15)
-        self._signals = []
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect the status label to the given aptdaemon transaction"""
-        for sig in self._signals:
-            GLib.source_remove(sig)
-        self._signals = []
-        self._on_role_changed(transaction, transaction.role)
-        self._signals.append(transaction.connect("role-changed",
-                                                 self._on_role_changed))
-
-    def _on_role_changed(self, transaction, role):
-        """Set the role text."""
-        self.set_markup(get_role_localised_present_from_enum(role))
-
-
-class AptStatusLabel(Gtk.Label):
-    """
-    Status label for the running aptdaemon transaction
-    """
-    def __init__(self, transaction=None):
-        Gtk.Label.__init__(self)
-        self.set_alignment(0, 0)
-        self.set_ellipsize(Pango.EllipsizeMode.END)
-        self.set_max_width_chars(15)
-        self._signals = []
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect the status label to the given aptdaemon transaction"""
-        for sig in self._signals:
-            GLib.source_remove(sig)
-        self._signals = []
-        self._signals.append(
-            transaction.connect("status-changed", self._on_status_changed))
-        self._signals.append(
-            transaction.connect("status-details-changed",
-                                self._on_status_details_changed))
-
-    def _on_status_changed(self, transaction, status):
-        """Set the status text according to the changed status"""
-        self.set_markup(get_status_string_from_enum(status))
-
-    def _on_status_details_changed(self, transaction, text):
-        """Set the status text to the one reported by apt"""
-        self.set_markup(text)
-
-
-class AptProgressBar(Gtk.ProgressBar):
-    """
-    Provides a Gtk.Progress which represents the progress of an aptdaemon
-    transactions
-    """
-    def __init__(self, transaction=None):
-        Gtk.ProgressBar.__init__(self)
-        self.set_ellipsize(Pango.EllipsizeMode.END)
-        self.set_text(" ")
-        self.set_pulse_step(0.05)
-        self._signals = []
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect the progress bar to the given aptdaemon transaction"""
-        for sig in self._signals:
-            GLib.source_remove(sig)
-        self._signals = []
-        self._signals.append(
-            transaction.connect("finished", self._on_finished))
-        self._signals.append(
-            transaction.connect("progress-changed", self._on_progress_changed))
-        self._signals.append(transaction.connect("progress-details-changed",
-                                                 self._on_progress_details))
-
-    def _on_progress_changed(self, transaction, progress):
-        """
-        Update the progress according to the latest progress information
-        """
-        if progress > 100:
-            self.pulse()
-        else:
-            self.set_fraction(progress / 100.0)
-
-    def _on_progress_details(self, transaction, items_done, items_total,
-                             bytes_done, bytes_total, speed, eta):
-        """
-        Update the progress bar text according to the latest progress details
-        """
-        if items_total == 0 and bytes_total == 0:
-            self.set_text(" ")
-            return
-        if speed != 0:
-            self.set_text(_("Downloaded %sB of %sB at %sB/s") %
-                          (apt_pkg.size_to_str(bytes_done),
-                           apt_pkg.size_to_str(bytes_total),
-                           apt_pkg.size_to_str(speed)))
-        else:
-            self.set_text(_("Downloaded %sB of %sB") %
-                          (apt_pkg.size_to_str(bytes_done),
-                           apt_pkg.size_to_str(bytes_total)))
-
-    def _on_finished(self, transaction, exit):
-        """Set the progress to 100% when the transaction is complete"""
-        self.set_fraction(1)
-
-
-class AptDetailsExpander(Gtk.Expander):
-
-    def __init__(self, transaction=None, terminal=True):
-        Gtk.Expander.__init__(self, label=_("Details"))
-        self.show_terminal = terminal
-        self._signals = []
-        self.set_sensitive(False)
-        self.set_expanded(False)
-        if self.show_terminal:
-            self.terminal = AptTerminal()
-        else:
-            self.terminal = None
-        self.download_view = AptDownloadsView()
-        self.download_scrolled = Gtk.ScrolledWindow()
-        self.download_scrolled.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
-        self.download_scrolled.set_policy(Gtk.PolicyType.NEVER,
-                                          Gtk.PolicyType.AUTOMATIC)
-        self.download_scrolled.add(self.download_view)
-        hbox = Gtk.HBox()
-        hbox.pack_start(self.download_scrolled, True, True, 0)
-        if self.terminal:
-            hbox.pack_start(self.terminal, True, True, 0)
-        self.add(hbox)
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect the status label to the given aptdaemon transaction"""
-        for sig in self._signals:
-            GLib.source_remove(sig)
-        self._signals.append(
-            transaction.connect("status-changed", self._on_status_changed))
-        self._signals.append(
-            transaction.connect("terminal-attached-changed",
-                                self._on_terminal_attached_changed))
-        if self.terminal:
-            self.terminal.set_transaction(transaction)
-        self.download_view.set_transaction(transaction)
-
-    def _on_status_changed(self, trans, status):
-        if status in (STATUS_DOWNLOADING, STATUS_DOWNLOADING_REPO):
-            self.set_sensitive(True)
-            self.download_scrolled.show()
-            if self.terminal:
-                self.terminal.hide()
-        elif status == STATUS_COMMITTING:
-            self.download_scrolled.hide()
-            if self.terminal:
-                self.terminal.show()
-                self.set_sensitive(True)
-            else:
-                self.set_expanded(False)
-                self.set_sensitive(False)
-        else:
-            self.download_scrolled.hide()
-            if self.terminal:
-                self.terminal.hide()
-            self.set_sensitive(False)
-            self.set_expanded(False)
-
-    def _on_terminal_attached_changed(self, transaction, attached):
-        """Connect the terminal to the pty device"""
-        if attached and self.terminal:
-            self.set_sensitive(True)
-
-
-class AptTerminal(Vte.Terminal):
-
-    def __init__(self, transaction=None):
-        Vte.Terminal.__init__(self)
-        self._signals = []
-        self._master, self._slave = pty.openpty()
-        self._ttyname = os.ttyname(self._slave)
-        self.set_size(80, 24)
-        self.set_pty_object(Vte.Pty.new_foreign(self._master))
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect the status label to the given aptdaemon transaction"""
-        for sig in self._signals:
-            GLib.source_remove(sig)
-        self._signals.append(
-            transaction.connect("terminal-attached-changed",
-                                self._on_terminal_attached_changed))
-        self._transaction = transaction
-        self._transaction.set_terminal(self._ttyname)
-
-    def _on_terminal_attached_changed(self, transaction, attached):
-        """Show the terminal"""
-        self.set_sensitive(attached)
-
-
-class AptCancelButton(Gtk.Button):
-    """
-    Provides a Gtk.Button which allows to cancel a running aptdaemon
-    transaction
-    """
-    def __init__(self, transaction=None):
-        Gtk.Button.__init__(self)
-        self.set_use_stock(True)
-        self.set_label(Gtk.STOCK_CANCEL)
-        self.set_sensitive(True)
-        self._signals = []
-        if transaction is not None:
-            self.set_transaction(transaction)
-
-    def set_transaction(self, transaction):
-        """Connect the status label to the given aptdaemon transaction"""
-        for sig in self._signals:
-            GLib.source_remove(sig)
-        self._signals = []
-        self._signals.append(
-            transaction.connect("finished", self._on_finished))
-        self._signals.append(
-            transaction.connect("cancellable-changed",
-                                self._on_cancellable_changed))
-        self.connect("clicked", self._on_clicked, transaction)
-
-    def _on_cancellable_changed(self, transaction, cancellable):
-        """
-        Enable the button if cancel is allowed and disable it in the other case
-        """
-        self.set_sensitive(cancellable)
-
-    def _on_finished(self, transaction, status):
-        self.set_sensitive(False)
-
-    def _on_clicked(self, button, transaction):
-        transaction.cancel()
-        self.set_sensitive(False)
-
-
-class AptDownloadsView(Gtk.TreeView):
-
-    """A Gtk.TreeView which displays the progress and status of each dowload
-    of a transaction.
-    """
-
-    COL_TEXT, COL_PROGRESS, COL_URI = list(range(3))
-
-    def __init__(self, transaction=None):
-        Gtk.TreeView.__init__(self)
-        model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_INT,
-                              GObject.TYPE_STRING)
-        self.set_model(model)
-        self.props.headers_visible = False
-        self.set_rules_hint(True)
-        self._download_map = {}
-        self._signals = []
-        if transaction is not None:
-            self.set_transaction(transaction)
-        cell_uri = Gtk.CellRendererText()
-        cell_uri.props.ellipsize = Pango.EllipsizeMode.END
-        column_download = Gtk.TreeViewColumn(_("File"))
-        column_download.pack_start(cell_uri, True)
-        column_download.add_attribute(cell_uri, "markup", self.COL_TEXT)
-        cell_progress = Gtk.CellRendererProgress()
-        #TRANSLATORS: header of the progress download column
-        column_progress = Gtk.TreeViewColumn(_("%"))
-        column_progress.pack_start(cell_progress, True)
-        column_progress.set_cell_data_func(cell_progress, self._data_progress,
-                                           None)
-        self.append_column(column_progress)
-        self.append_column(column_download)
-        self.set_tooltip_column(self.COL_URI)
-
-    def set_transaction(self, transaction):
-        """Connect the download view to the given aptdaemon transaction"""
-        for sig in self._signals:
-            GLib.source_remove(sig)
-        self._signals = []
-        self._signals.append(transaction.connect("progress-download-changed",
-                                                 self._on_download_changed))
-
-    def _on_download_changed(self, transaction, uri, status, desc, full_size,
-                             downloaded, message):
-        """Callback for a changed download progress."""
-        try:
-            progress = int(downloaded * 100 / full_size)
-        except ZeroDivisionError:
-            progress = -1
-        if status == DOWNLOAD_DONE:
-            progress = 100
-        if progress > 100:
-            progress = 100
-        text = desc[:]
-        text += "\n<small>"
-        #TRANSLATORS: %s is the full size in Bytes, e.g. 198M
-        if status == DOWNLOAD_FETCHING:
-            text += (_("Downloaded %sB of %sB") %
-                     (apt_pkg.size_to_str(downloaded),
-                     apt_pkg.size_to_str(full_size)))
-        elif status == DOWNLOAD_DONE:
-            if full_size != 0:
-                text += _("Downloaded %sB") % apt_pkg.size_to_str(full_size)
-            else:
-                text += _("Downloaded")
-        else:
-            text += get_download_status_from_enum(status)
-        text += "</small>"
-        model = self.get_model()
-        try:
-            iter = self._download_map[uri]
-        except KeyError:
-            # we we haven't seen the uri yet, add it now
-            iter = model.append((text, progress, uri))
-            self._download_map[uri] = iter
-            # and update the adj if needed
-            adj = self.get_vadjustment()
-            # this may be None (LP: #1024590)
-            if adj:
-                is_scrolled_down = (
-                    adj.get_value() + adj.get_page_size() == adj.get_upper())
-                if is_scrolled_down:
-                    # If the treeview was scrolled to the end, do this again
-                    # after appending a new item
-                    self.scroll_to_cell(
-                        model.get_path(iter), None, False, False, False)
-        else:
-            model.set_value(iter, self.COL_TEXT, text)
-            model.set_value(iter, self.COL_PROGRESS, progress)
-
-    def _data_progress(self, column, cell, model, iter, data):
-        progress = model.get_value(iter, self.COL_PROGRESS)
-        if progress == -1:
-            cell.props.pulse = progress
-        else:
-            cell.props.value = progress
-
-
-class AptProgressDialog(Gtk.Dialog):
-    """
-    Complete progress dialog for long taking aptdaemon transactions, which
-    features a progress bar, cancel button, status icon and label
-    """
-
-    __gsignals__ = {"finished": (GObject.SIGNAL_RUN_FIRST,
-                                 GObject.TYPE_NONE, ())}
-
-    def __init__(self, transaction=None, parent=None, terminal=True,
-                 debconf=True):
-        Gtk.Dialog.__init__(self, parent=parent)
-        self._expanded_size = None
-        self.debconf = debconf
-        # Setup the dialog
-        self.set_border_width(6)
-        self.set_resizable(False)
-        self.get_content_area().set_spacing(6)
-        # Setup the cancel button
-        self.button_cancel = AptCancelButton(transaction)
-        self.get_action_area().pack_start(self.button_cancel, False, False, 0)
-        # Setup the status icon, label and progressbar
-        hbox = Gtk.HBox()
-        hbox.set_spacing(12)
-        hbox.set_border_width(6)
-        self.icon = AptRoleIcon()
-        hbox.pack_start(self.icon, False, True, 0)
-        vbox = Gtk.VBox()
-        vbox.set_spacing(12)
-        self.label_role = Gtk.Label()
-        self.label_role.set_alignment(0, 0)
-        vbox.pack_start(self.label_role, False, True, 0)
-        vbox_progress = Gtk.VBox()
-        vbox_progress.set_spacing(6)
-        self.progress = AptProgressBar()
-        vbox_progress.pack_start(self.progress, False, True, 0)
-        self.label = AptStatusLabel()
-        self.label._on_status_changed(None, STATUS_WAITING)
-        vbox_progress.pack_start(self.label, False, True, 0)
-        vbox.pack_start(vbox_progress, False, True, 0)
-        hbox.pack_start(vbox, True, True, 0)
-        self.expander = AptDetailsExpander(terminal=terminal)
-        self.expander.connect("notify::expanded", self._on_expanded)
-        vbox.pack_start(self.expander, True, True, 0)
-        self.get_content_area().pack_start(hbox, True, True, 0)
-        self._transaction = None
-        self._signals = []
-        self.set_title("")
-        self.realize()
-        self.progress.set_size_request(350, -1)
-        functions = Gdk.WMFunction.MOVE | Gdk.WMFunction.RESIZE
-        try:
-            self.get_window().set_functions(functions)
-        except TypeError:
-            # workaround for older and broken GTK typelibs
-            self.get_window().set_functions(Gdk.WMFunction(functions))
-        if transaction is not None:
-            self.set_transaction(transaction)
-        # catch ESC and behave as if cancel was clicked
-        self.connect("delete-event", self._on_dialog_delete_event)
-
-    def _on_dialog_delete_event(self, dialog, event):
-        self.button_cancel.clicked()
-        return True
-
-    def _on_expanded(self, expander, param):
-        # Make the dialog resizable if the expander is expanded
-        # try to restore a previous size
-        if not expander.get_expanded():
-            self._expanded_size = (self.expander.terminal.get_visible(),
-                                   self.get_size())
-            self.set_resizable(False)
-        elif self._expanded_size:
-            self.set_resizable(True)
-            term_visible, (stored_width, stored_height) = self._expanded_size
-            # Check if the stored size was for the download details or
-            # the terminal widget
-            if term_visible != self.expander.terminal.get_visible():
-                # The stored size was for the download details, so we need
-                # get a new size for the terminal widget
-                self._resize_to_show_details()
-            else:
-                self.resize(stored_width, stored_height)
-        else:
-            self.set_resizable(True)
-            self._resize_to_show_details()
-
-    def _resize_to_show_details(self):
-        """Resize the window to show the expanded details.
-
-        Unfortunately the expander only expands to the preferred size of the
-        child widget (e.g showing all 80x24 chars of the Vte terminal) if
-        the window is rendered the first time and the terminal is also visible.
-        If the expander is expanded afterwards the window won't change its
-        size anymore. So we have to do this manually. See LP#840942
-        """
-        win_width, win_height = self.get_size()
-        exp_width = self.expander.get_allocation().width
-        exp_height = self.expander.get_allocation().height
-        if self.expander.terminal.get_visible():
-            terminal_width = self.expander.terminal.get_char_width() * 80
-            terminal_height = self.expander.terminal.get_char_height() * 24
-            self.resize(terminal_width - exp_width + win_width,
-                        terminal_height - exp_height + win_height)
-        else:
-            self.resize(win_width + 100, win_height + 200)
-
-    def _on_status_changed(self, trans, status):
-        # Also resize the window if we switch from download details to
-        # the terminal window
-        if (status == STATUS_COMMITTING and
-                self.expander.terminal.get_visible()):
-            self._resize_to_show_details()
-
-    @deferable
-    def run(self, attach=False, close_on_finished=True, show_error=True,
-            reply_handler=None, error_handler=None):
-        """Run the transaction and show the progress in the dialog.
-
-        Keyword arguments:
-        attach -- do not start the transaction but instead only monitor
-                  an already running one
-        close_on_finished -- if the dialog should be closed when the
-                  transaction is complete
-        show_error -- show a dialog with the error message
-        """
-        return self._run(attach, close_on_finished, show_error,
-                         reply_handler, error_handler)
-
-    @inline_callbacks
-    def _run(self, attach, close_on_finished, show_error,
-             reply_handler, error_handler):
-        try:
-            sig = self._transaction.connect("finished", self._on_finished,
-                                            close_on_finished, show_error)
-            self._signals.append(sig)
-            if attach:
-                yield self._transaction.sync()
-            else:
-                if self.debconf:
-                    yield self._transaction.set_debconf_frontend("gnome")
-                yield self._transaction.run()
-            self.show_all()
-        except Exception as error:
-            if error_handler:
-                error_handler(error)
-            else:
-                raise
-        else:
-            if reply_handler:
-                reply_handler()
-
-    def _on_role_changed(self, transaction, role_enum):
-        """Show the role of the transaction in the dialog interface"""
-        role = get_role_localised_present_from_enum(role_enum)
-        self.set_title(role)
-        self.label_role.set_markup("<big><b>%s</b></big>" % role)
-
-    def set_transaction(self, transaction):
-        """Connect the dialog to the given aptdaemon transaction"""
-        for sig in self._signals:
-            GLib.source_remove(sig)
-        self._signals = []
-        self._signals.append(
-            transaction.connect_after("status-changed",
-                                      self._on_status_changed))
-        self._signals.append(transaction.connect("role-changed",
-                                                 self._on_role_changed))
-        self._signals.append(transaction.connect("medium-required",
-                                                 self._on_medium_required))
-        self._signals.append(transaction.connect("config-file-conflict",
-                             self._on_config_file_conflict))
-        self._on_role_changed(transaction, transaction.role)
-        self.progress.set_transaction(transaction)
-        self.icon.set_transaction(transaction)
-        self.label.set_transaction(transaction)
-        self.expander.set_transaction(transaction)
-        self._transaction = transaction
-
-    def _on_medium_required(self, transaction, medium, drive):
-        dialog = AptMediumRequiredDialog(medium, drive, self)
-        res = dialog.run()
-        dialog.hide()
-        if res == Gtk.ResponseType.OK:
-            self._transaction.provide_medium(medium)
-        else:
-            self._transaction.cancel()
-
-    def _on_config_file_conflict(self, transaction, old, new):
-        dialog = AptConfigFileConflictDialog(old, new, self)
-        res = dialog.run()
-        dialog.hide()
-        if res == Gtk.ResponseType.YES:
-            self._transaction.resolve_config_file_conflict(old, "replace")
-        else:
-            self._transaction.resolve_config_file_conflict(old, "keep")
-
-    def _on_finished(self, transaction, status, close, show_error):
-        if close:
-            self.hide()
-        if status == EXIT_FAILED and show_error:
-            err_dia = AptErrorDialog(self._transaction.error, self)
-            err_dia.run()
-            err_dia.hide()
-        self.emit("finished")
-
-
-class _ExpandableDialog(Gtk.Dialog):
-
-    """Dialog with an expander."""
-
-    def __init__(self, parent=None, stock_type=None, expanded_child=None,
-                 expander_label=None, title=None, message=None, buttons=None):
-        """Return an _AptDaemonDialog instance.
-
-        Keyword arguments:
-        parent -- set the dialog transient for the given Gtk.Window
-        stock_type -- type of the Dialog, defaults to Gtk.STOCK_DIALOG_QUESTION
-        expanded_child -- Widget which should be expanded
-        expander_label -- label for the expander
-        title -- a news header like title of the dialog
-        message -- the message which should be shown in the dialog
-        buttons -- tuple containing button text/reponse id pairs, defaults
-                   to a close button
-        """
-        if not buttons:
-            buttons = (Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
-        Gtk.Dialog.__init__(self, parent=parent)
-        self.set_title("")
-        self.add_buttons(*buttons)
-        self.set_resizable(False)
-        self.set_border_width(6)
-        self.get_content_area().set_spacing(12)
-        if not stock_type:
-            stock_type = Gtk.STOCK_DIALOG_QUESTION
-        icon = Gtk.Image.new_from_stock(stock_type, Gtk.IconSize.DIALOG)
-        icon.set_alignment(0, 0)
-        hbox_base = Gtk.HBox()
-        hbox_base.set_spacing(12)
-        hbox_base.set_border_width(6)
-        vbox_left = Gtk.VBox()
-        vbox_left.set_spacing(12)
-        hbox_base.pack_start(icon, False, True, 0)
-        hbox_base.pack_start(vbox_left, True, True, 0)
-        self.label = Gtk.Label()
-        self.label.set_selectable(True)
-        self.label.set_alignment(0, 0)
-        self.label.set_line_wrap(True)
-        vbox_left.pack_start(self.label, False, True, 0)
-        self.get_content_area().pack_start(hbox_base, True, True, 0)
-        # The expander widget
-        self.expander = Gtk.Expander(label=expander_label)
-        self.expander.set_spacing(6)
-        self.expander.set_use_underline(True)
-        self.expander.connect("notify::expanded", self._on_expanded)
-        self._expanded_size = None
-        vbox_left.pack_start(self.expander, True, True, 0)
-        # Set some initial data
-        text = ""
-        if title:
-            text = "<b><big>%s</big></b>" % title
-        if message:
-            if text:
-                text += "\n\n"
-            text += message
-        self.label.set_markup(text)
-        if expanded_child:
-            self.expander.add(expanded_child)
-        else:
-            self.expander.set_sensitive(False)
-
-    def _on_expanded(self, expander, param):
-        if expander.get_expanded():
-            self.set_resizable(True)
-            if self._expanded_size:
-                # Workaround a random crash during progress dialog expanding
-                # It seems that either the gtk.Window.get_size() method
-                # doesn't always return a tuple or that the
-                # gtk.Window.set_size() method doesn't correctly handle *
-                # arguments correctly, see LP#898851
-                try:
-                    self.resize(self._expanded_size[0], self._expanded_size[1])
-                except (IndexError, TypeError):
-                    pass
-        else:
-            self._expanded_size = self.get_size()
-            self.set_resizable(False)
-
-
-class AptMediumRequiredDialog(Gtk.MessageDialog):
-
-    """Dialog to ask for medium change."""
-
-    def __init__(self, medium, drive, parent=None):
-        Gtk.MessageDialog.__init__(self, parent=parent,
-                                   type=Gtk.MessageType.INFO)
-        #TRANSLATORS: %s represents the name of a CD or DVD
-        text = _("CD/DVD '%s' is required") % medium
-        #TRANSLATORS: %s is the name of the CD/DVD drive
-        desc = _("Please insert the above CD/DVD into the drive '%s' to "
-                 "install software packages from it.") % drive
-        self.set_markup("<big><b>%s</b></big>\n\n%s" % (text, desc))
-        self.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
-                         _("C_ontinue"), Gtk.ResponseType.OK)
-        self.set_default_response(Gtk.ResponseType.OK)
-
-
-class AptConfirmDialog(Gtk.Dialog):
-
-    """Dialog to confirm the changes that would be required by a
-    transaction.
-    """
-
-    def __init__(self, trans, cache=None, parent=None):
-        """Return an AptConfirmDialog instance.
-
-        Keyword arguments:
-        trans -- the transaction of which the dependencies should be shown
-        cache -- an optional apt.cache.Cache() instance to provide more details
-                 about packages
-        parent -- set the dialog transient for the given Gtk.Window
-        """
-        Gtk.Dialog.__init__(self, parent=parent)
-        self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
-        self.add_button(_("C_ontinue"), Gtk.ResponseType.OK)
-        self.cache = cache
-        self.trans = trans
-        if isinstance(parent, Gdk.Window):
-            self.realize()
-            self.window.set_transient_for(parent)
-        else:
-            self.set_transient_for(parent)
-        self.set_resizable(True)
-        self.set_border_width(6)
-        self.get_content_area().set_spacing(12)
-        icon = Gtk.Image.new_from_stock(Gtk.STOCK_DIALOG_QUESTION,
-                                        Gtk.IconSize.DIALOG)
-        icon.set_alignment(0, 0)
-        hbox_base = Gtk.HBox()
-        hbox_base.set_spacing(12)
-        hbox_base.set_border_width(6)
-        vbox_left = Gtk.VBox()
-        vbox_left.set_spacing(12)
-        hbox_base.pack_start(icon, False, True, 0)
-        hbox_base.pack_start(vbox_left, True, True, 0)
-        self.label = Gtk.Label()
-        self.label.set_selectable(True)
-        self.label.set_alignment(0, 0)
-        vbox_left.pack_start(self.label, False, True, 0)
-        self.get_content_area().pack_start(hbox_base, True, True, 0)
-        self.treestore = Gtk.TreeStore(GObject.TYPE_STRING)
-        self.treeview = Gtk.TreeView.new_with_model(self.treestore)
-        self.treeview.set_headers_visible(False)
-        self.treeview.set_rules_hint(True)
-        self.column = Gtk.TreeViewColumn()
-        self.treeview.append_column(self.column)
-        cell_icon = Gtk.CellRendererPixbuf()
-        self.column.pack_start(cell_icon, False)
-        self.column.set_cell_data_func(cell_icon, self.render_package_icon,
-                                       None)
-        cell_desc = Gtk.CellRendererText()
-        self.column.pack_start(cell_desc, True)
-        self.column.set_cell_data_func(cell_desc, self.render_package_desc,
-                                       None)
-        self.scrolled = Gtk.ScrolledWindow()
-        self.scrolled.set_policy(Gtk.PolicyType.AUTOMATIC,
-                                 Gtk.PolicyType.AUTOMATIC)
-        self.scrolled.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
-        self.scrolled.add(self.treeview)
-        vbox_left.pack_start(self.scrolled, True, True, 0)
-        self.set_default_response(Gtk.ResponseType.CANCEL)
-
-    def _show_changes(self):
-        """Show a message and the dependencies in the dialog."""
-        self.treestore.clear()
-        for index, msg in enumerate([_("Install"),
-                                     _("Reinstall"),
-                                     _("Remove"),
-                                     _("Purge"),
-                                     _("Upgrade"),
-                                     _("Downgrade"),
-                                     _("Skip upgrade")]):
-            if self.trans.dependencies[index]:
-                piter = self.treestore.append(None, ["<b>%s</b>" % msg])
-                for pkg in self.trans.dependencies[index]:
-                    for object in self.map_package(pkg):
-                        self.treestore.append(piter, [str(object)])
-        # If there is only one type of changes (e.g. only installs) expand the
-        # tree
-        #FIXME: adapt the title and message accordingly
-        #FIXME: Should we have different modes? Only show dependencies, only
-        #       initial packages or both?
-        msg = _("Please take a look at the list of changes below.")
-        if len(self.treestore) == 1:
-            filtered_store = self.treestore.filter_new(
-                Gtk.TreePath.new_first())
-            self.treeview.expand_all()
-            self.treeview.set_model(filtered_store)
-            self.treeview.set_show_expanders(False)
-            if self.trans.dependencies[PKGS_INSTALL]:
-                title = _("Additional software has to be installed")
-            elif self.trans.dependencies[PKGS_REINSTALL]:
-                title = _("Additional software has to be re-installed")
-            elif self.trans.dependencies[PKGS_REMOVE]:
-                title = _("Additional software has to be removed")
-            elif self.trans.dependencies[PKGS_PURGE]:
-                title = _("Additional software has to be purged")
-            elif self.trans.dependencies[PKGS_UPGRADE]:
-                title = _("Additional software has to be upgraded")
-            elif self.trans.dependencies[PKGS_DOWNGRADE]:
-                title = _("Additional software has to be downgraded")
-            elif self.trans.dependencies[PKGS_KEEP]:
-                title = _("Updates will be skipped")
-            if len(filtered_store) < 6:
-                self.set_resizable(False)
-                self.scrolled.set_policy(Gtk.PolicyType.AUTOMATIC,
-                                         Gtk.PolicyType.NEVER)
-            else:
-                self.treeview.set_size_request(350, 200)
-        else:
-            title = _("Additional changes are required")
-            self.treeview.set_size_request(350, 200)
-            self.treeview.collapse_all()
-        if self.trans.download:
-            msg += "\n"
-            msg += (_("%sB will be downloaded in total.") %
-                    apt_pkg.size_to_str(self.trans.download))
-        if self.trans.space < 0:
-            msg += "\n"
-            msg += (_("%sB of disk space will be freed.") %
-                    apt_pkg.size_to_str(self.trans.space))
-        elif self.trans.space > 0:
-            msg += "\n"
-            msg += (_("%sB more disk space will be used.") %
-                    apt_pkg.size_to_str(self.trans.space))
-        self.label.set_markup("<b><big>%s</big></b>\n\n%s" % (title, msg))
-
-    def map_package(self, pkg):
-        """Map a package to a different object type, e.g. applications
-        and return a list of those.
-
-        By default return the package itself inside a list.
-
-        Override this method if you don't want to store package names
-        in the treeview.
-        """
-        return [pkg]
-
-    def render_package_icon(self, column, cell, model, iter, data):
-        """Data func for the Gtk.CellRendererPixbuf which shows the package.
-
-        Override this method if you want to show custom icons for
-        a package or map it to applications.
-        """
-        path = model.get_path(iter)
-        if path.get_depth() == 0:
-            cell.props.visible = False
-        else:
-            cell.props.visible = True
-        cell.props.icon_name = "applications-other"
-
-    def render_package_desc(self, column, cell, model, iter, data):
-        """Data func for the Gtk.CellRendererText which shows the package.
-
-        Override this method if you want to show more information about
-        a package or map it to applications.
-        """
-        value = model.get_value(iter, 0)
-        if not value:
-            return
-        try:
-            pkg_name, pkg_version = value.split("=")[0:2]
-        except ValueError:
-            pkg_name = value
-            pkg_version = None
-        try:
-            if pkg_version:
-                text = "%s (%s)\n<small>%s</small>" % (
-                    pkg_name, pkg_version, self.cache[pkg_name].summary)
-            else:
-                text = "%s\n<small>%s</small>" % (
-                    pkg_name, self.cache[pkg_name].summary)
-        except (KeyError, TypeError):
-            if pkg_version:
-                text = "%s (%s)" % (pkg_name, pkg_version)
-            else:
-                text = "%s" % pkg_name
-        cell.set_property("markup", text)
-
-    def run(self):
-        self._show_changes()
-        self.show_all()
-        return Gtk.Dialog.run(self)
-
-
-class AptConfigFileConflictDialog(_ExpandableDialog):
-
-    """Dialog to resolve conflicts between local and shipped
-    configuration files.
-    """
-
-    def __init__(self, from_path, to_path, parent=None):
-        self.from_path = from_path
-        self.to_path = to_path
-        #TRANSLATORS: %s is a file path
-        title = _("Replace your changes in '%s' with a later version of "
-                  "the configuration file?") % from_path
-        msg = _("If you don't know why the file is there already, it is "
-                "usually safe to replace it.")
-        scrolled = Gtk.ScrolledWindow()
-        scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
-        scrolled.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
-        self.diffview = DiffView()
-        self.diffview.set_size_request(-1, 200)
-        scrolled.add(self.diffview)
-        _ExpandableDialog.__init__(self, parent=parent,
-                                   expander_label=_("_Changes"),
-                                   expanded_child=scrolled,
-                                   title=title, message=msg,
-                                   buttons=(_("_Keep"), Gtk.ResponseType.NO,
-                                            _("_Replace"),
-                                            Gtk.ResponseType.YES))
-        self.set_default_response(Gtk.ResponseType.YES)
-
-    def run(self):
-        self.show_all()
-        self.diffview.show_diff(self.from_path, self.to_path)
-        return _ExpandableDialog.run(self)
-
-
-REGEX_RANGE = "^@@ \-(?P<from_start>[0-9]+)(?:,(?P<from_context>[0-9]+))? " \
-              "\+(?P<to_start>[0-9]+)(?:,(?P<to_context>[0-9]+))? @@"
-
-
-class DiffView(Gtk.TextView):
-
-    """Shows the difference between two files."""
-
-    ELLIPSIS = "[…]\n"
-
-    def __init__(self):
-        self.textbuffer = Gtk.TextBuffer()
-        Gtk.TextView.__init__(self, buffer=self.textbuffer)
-        self.set_property("editable", False)
-        self.set_cursor_visible(False)
-        tags = self.textbuffer.get_tag_table()
-        #FIXME: How to get better colors?
-        tag_default = Gtk.TextTag.new("default")
-        tag_default.set_properties(font="Mono")
-        tags.add(tag_default)
-        tag_add = Gtk.TextTag.new("add")
-        tag_add.set_properties(font="Mono",
-                               background='#8ae234')
-        tags.add(tag_add)
-        tag_remove = Gtk.TextTag.new("remove")
-        tag_remove.set_properties(font="Mono",
-                                  background='#ef2929')
-        tags.add(tag_remove)
-        tag_num = Gtk.TextTag.new("number")
-        tag_num.set_properties(font="Mono",
-                               background='#eee')
-        tags.add(tag_num)
-
-    def show_diff(self, from_path, to_path):
-        """Show the difference between two files."""
-        #FIXME: Use gio
-        try:
-            with open(from_path) as fp:
-                from_lines = fp.readlines()
-            with open(to_path) as fp:
-                to_lines = fp.readlines()
-        except IOError:
-            return
-
-        # helper function to work around current un-introspectability of
-        # varargs methods like insert_with_tags_by_name()
-        def insert_tagged_text(iter, text, tag):
-            #self.textbuffer.insert_with_tags_by_name(iter, text, tag)
-            offset = iter.get_offset()
-            self.textbuffer.insert(iter, text)
-            self.textbuffer.apply_tag_by_name(
-                tag, self.textbuffer.get_iter_at_offset(offset), iter)
-
-        line_number = 0
-        iter = self.textbuffer.get_start_iter()
-        for line in difflib.unified_diff(from_lines, to_lines, lineterm=""):
-            if line.startswith("@@"):
-                match = re.match(REGEX_RANGE, line)
-                if not match:
-                    continue
-                line_number = int(match.group("from_start"))
-                if line_number > 1:
-                    insert_tagged_text(iter, self.ELLIPSIS, "default")
-            elif line.startswith("---") or line.startswith("+++"):
-                continue
-            elif line.startswith(" "):
-                line_number += 1
-                insert_tagged_text(iter, str(line_number), "number")
-                insert_tagged_text(iter, line, "default")
-            elif line.startswith("-"):
-                line_number += 1
-                insert_tagged_text(iter, str(line_number), "number")
-                insert_tagged_text(iter, line, "remove")
-            elif line.startswith("+"):
-                spaces = " " * len(str(line_number))
-                insert_tagged_text(iter, spaces, "number")
-                insert_tagged_text(iter, line, "add")
-
-
-class _DetailsExpanderMessageDialog(_ExpandableDialog):
-    """
-    Common base class for Apt*Dialog
-    """
-    def __init__(self, text, desc, type, details=None, parent=None):
-        scrolled = Gtk.ScrolledWindow()
-        scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
-        scrolled.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
-        textview = Gtk.TextView()
-        textview.set_wrap_mode(Gtk.WrapMode.WORD)
-        buffer = textview.get_buffer()
-        scrolled.add(textview)
-        #TRANSLATORS: expander label in the error dialog
-        _ExpandableDialog.__init__(self, parent=parent,
-                                   expander_label=_("_Details"),
-                                   expanded_child=scrolled,
-                                   title=text, message=desc,
-                                   stock_type=type)
-        self.show_all()
-        if details:
-            buffer.insert_at_cursor(details)
-        else:
-            self.expander.set_visible(False)
-
-
-class AptErrorDialog(_DetailsExpanderMessageDialog):
-    """
-    Dialog for aptdaemon errors with details in an expandable text view
-    """
-    def __init__(self, error=None, parent=None):
-        text = get_error_string_from_enum(error.code)
-        desc = get_error_description_from_enum(error.code)
-        _DetailsExpanderMessageDialog.__init__(
-            self, text, desc, Gtk.STOCK_DIALOG_ERROR, error.details, parent)
diff -pruN 1.1.1-4/.pc/fix-high-trust-pkcompat.diff/aptdaemon/worker/aptworker.py 1.1.1+bzr982-0ubuntu14/.pc/fix-high-trust-pkcompat.diff/aptdaemon/worker/aptworker.py
--- 1.1.1-4/.pc/fix-high-trust-pkcompat.diff/aptdaemon/worker/aptworker.py	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/.pc/fix-high-trust-pkcompat.diff/aptdaemon/worker/aptworker.py	2014-06-26 07:13:49.000000000 +0000
@@ -0,0 +1,1509 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""Provides AptWorker which processes transactions."""
+# Copyright (C) 2008-2009 Sebastian Heinlein <devel@glatzor.de>
+#
+# 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
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+__author__ = "Sebastian Heinlein <devel@glatzor.de>"
+
+__all__ = ("AptWorker")
+
+import contextlib
+import errno
+import glob
+import logging
+import netrc
+import os
+import re
+import shutil
+import stat
+import sys
+import tempfile
+import time
+import traceback
+try:
+    from urllib.parse import urlsplit, urlunsplit
+except ImportError:
+    from urlparse import urlsplit, urlunsplit
+
+try:
+    from configparser import ConfigParser
+except ImportError:
+    from ConfigParser import ConfigParser
+
+import apt
+import apt.auth
+import apt.cache
+import apt.debfile
+import apt_pkg
+import aptsources
+import aptsources.distro
+from aptsources.sourceslist import SourcesList
+from gi.repository import GObject, GLib
+
+from . import BaseWorker
+from ..enums import *
+from ..errors import *
+from .. import lock
+from ..progress import (
+    DaemonOpenProgress,
+    DaemonInstallProgress,
+    DaemonAcquireProgress,
+    DaemonAcquireRepoProgress,
+    DaemonDpkgInstallProgress,
+    DaemonDpkgReconfigureProgress,
+    DaemonDpkgRecoverProgress,
+    DaemonLintianProgress,
+    DaemonForkProgress)
+
+log = logging.getLogger("AptDaemon.Worker")
+
+# Just required to detect translatable strings. The translation is done by
+# core.Transaction.gettext
+_ = lambda s: s
+
+_POPCON_PATH = "/etc/popularity-contest.conf"
+_POPCON_DEFAULT = """# Config file for Debian's popularity-contest package.
+#
+# To change this file, use:
+#        dpkg-reconfigure popularity-contest
+#
+# You can also edit it by hand, if you so choose.
+#
+# See /usr/share/popularity-contest/default.conf for more info
+# on the options.
+MY_HOSTID="%(host_id)s"
+PARTICIPATE="%(participate)s"
+USE_HTTP="yes"
+"""
+
+
+def trans_only_installs_pkgs_from_high_trust_repos(trans,
+                                                   whitelist=set()):
+    """Return True if this transaction only touches packages in the
+    aptdaemon repoisotry high trust repository whitelist
+    """
+    # the transaction *must* be simulated before
+    if not trans.simulated:
+        return False
+    # we never allow unauthenticated ones
+    if trans.unauthenticated:
+        return False
+    # paranoia: wrong role
+    if trans.role not in (ROLE_INSTALL_PACKAGES, ROLE_COMMIT_PACKAGES):
+        return False
+    # if there is anything touched that is not a install bail out
+    for enum in (PKGS_REINSTALL, PKGS_REMOVE, PKGS_PURGE, PKGS_DOWNGRADE,
+                 PKGS_UPGRADE):
+        if trans.packages[enum]:
+            return False
+    # paranoia(2): we must want to install something
+    if not trans.packages[PKGS_INSTALL]:
+        return False
+    # if the install packages matches the whitelisted set we are good
+    return set(trans.packages[PKGS_INSTALL]) == set(trans.high_trust_packages)
+
+
+def read_high_trust_repository_dir(whitelist_cfg_d):
+    """Return a set of (origin, component, pkgname-regexp) from a
+    high-trust-repository-whitelist.d directory
+    """
+    whitelist = set()
+    for path in glob.glob(os.path.join(whitelist_cfg_d, "*.cfg")):
+        whitelist |= _read_high_trust_repository_whitelist_file(path)
+    return whitelist
+
+
+def _read_high_trust_repository_whitelist_file(path):
+    """Read a individual high-trust-repository whitelist file and return
+       a set of tuples (origin, component, pkgname-regexp)
+    """
+    parser = ConfigParser()
+    whitelist = set()
+    try:
+        parser.read(path)
+    except Exception as e:
+        log.error("Failed to read repository whitelist '%s' (%s)" % (path, e))
+        return whitelist
+    for section in parser.sections():
+        origin = parser.get(section, "origin")
+        component = parser.get(section, "component")
+        pkgnames = parser.get(section, "pkgnames")
+        whitelist.add((origin, component, pkgnames))
+    return whitelist
+
+
+class AptWorker(BaseWorker):
+
+    """Worker which processes transactions from the queue."""
+
+    NATIVE_ARCH = apt_pkg.get_architectures()[0]
+
+    # the basedir under which license keys can be stored
+    LICENSE_KEY_ROOTDIR = "/opt/"
+
+    def __init__(self, chroot=None, load_plugins=True):
+        """Initialize a new AptWorker instance."""
+        BaseWorker.__init__(self, chroot, load_plugins)
+        self._cache = None
+
+        # Change to a given chroot
+        if self.chroot:
+            apt_conf_file = os.path.join(chroot, "etc/apt/apt.conf")
+            if os.path.exists(apt_conf_file):
+                apt_pkg.read_config_file(apt_pkg.config, apt_conf_file)
+            apt_conf_dir = os.path.join(chroot, "etc/apt/apt.conf.d")
+            if os.path.isdir(apt_conf_dir):
+                apt_pkg.read_config_dir(apt_pkg.config, apt_conf_dir)
+            apt_pkg.config["Dir"] = chroot
+            apt_pkg.config["Dir::State::Status"] = os.path.join(
+                chroot, "var/lib/dpkg/status")
+            apt_pkg.config.clear("DPkg::Post-Invoke")
+            apt_pkg.config.clear("DPkg::Options")
+            apt_pkg.config["DPkg::Options::"] = "--root=%s" % chroot
+            apt_pkg.config["DPkg::Options::"] = ("--log=%s/var/log/dpkg.log" %
+                                                 chroot)
+            status_file = apt_pkg.config.find_file("Dir::State::status")
+            lock.status_lock.path = os.path.join(os.path.dirname(status_file),
+                                                 "lock")
+            archives_dir = apt_pkg.config.find_dir("Dir::Cache::Archives")
+            lock.archive_lock.path = os.path.join(archives_dir, "lock")
+            lists_dir = apt_pkg.config.find_dir("Dir::State::lists")
+            lock.lists_lock.path = os.path.join(lists_dir, "lock")
+            apt_pkg.init_system()
+
+        # a set of tuples of the type (origin, component, pkgname-regexp)
+        # that on install will trigger a different kind of polkit
+        # authentication request (see LP: #1035207), useful for e.g.
+        # webapps/company repos
+        self._high_trust_repositories = read_high_trust_repository_dir(
+            os.path.join(apt_pkg.config.find_dir("Dir"),
+                         "etc/aptdaemon/high-trust-repository-whitelist.d"))
+        log.debug(
+            "using high-trust whitelist: '%s'" % self._high_trust_repositories)
+
+        self._status_orig = apt_pkg.config.find_file("Dir::State::status")
+        self._status_frozen = None
+        if load_plugins:
+            self._load_plugins(["modify_cache_after", "modify_cache_before",
+                                "get_license_key"])
+
+    def _call_plugins(self, name, resolver=None):
+        """Call all plugins of a given type."""
+        if not resolver:
+            # If the resolver of the original task isn't available we create
+            # a new one and protect the already marked changes
+            resolver = apt.cache.ProblemResolver(self._cache)
+            for pkg in self._cache.get_changes():
+                resolver.clear(pkg)
+                resolver.protect(pkg)
+                if pkg.marked_delete:
+                    resolver.remove(pkg)
+        if name not in self.plugins:
+            log.debug("There isn't any registered %s plugin" % name)
+            return False
+        for plugin in self.plugins[name]:
+            log.debug("Calling %s plugin: %s", name, plugin)
+            try:
+                plugin(resolver, self._cache)
+            except Exception as error:
+                log.critical("Failed to call %s plugin:\n%s" % (plugin, error))
+        return True
+
+    def _run_transaction(self, trans):
+        """Run the worker"""
+        try:
+            lock.wait_for_lock(trans)
+            # Prepare the package cache
+            if (trans.role == ROLE_FIX_INCOMPLETE_INSTALL or
+                    not self.is_dpkg_journal_clean()):
+                self.fix_incomplete_install(trans)
+            # Process transaction which don't require a cache
+            if trans.role == ROLE_ADD_VENDOR_KEY_FILE:
+                self.add_vendor_key_from_file(trans, **trans.kwargs)
+            elif trans.role == ROLE_ADD_VENDOR_KEY_FROM_KEYSERVER:
+                self.add_vendor_key_from_keyserver(trans, **trans.kwargs)
+            elif trans.role == ROLE_REMOVE_VENDOR_KEY:
+                self.remove_vendor_key(trans, **trans.kwargs)
+            elif trans.role == ROLE_ADD_REPOSITORY:
+                self.add_repository(trans, **trans.kwargs)
+            elif trans.role == ROLE_ENABLE_DISTRO_COMP:
+                self.enable_distro_comp(trans, **trans.kwargs)
+            elif trans.role == ROLE_RECONFIGURE:
+                self.reconfigure(trans, trans.packages[PKGS_REINSTALL],
+                                 **trans.kwargs)
+            elif trans.role == ROLE_CLEAN:
+                self.clean(trans)
+            # Check if the transaction has been just simulated. So we could
+            # skip marking the changes a second time.
+            elif (trans.role in (ROLE_REMOVE_PACKAGES, ROLE_INSTALL_PACKAGES,
+                                 ROLE_UPGRADE_PACKAGES, ROLE_COMMIT_PACKAGES,
+                                 ROLE_UPGRADE_SYSTEM,
+                                 ROLE_FIX_BROKEN_DEPENDS) and
+                  self.marked_tid == trans.tid):
+                self._apply_changes(trans)
+                trans.exit = EXIT_SUCCESS
+                return False
+            else:
+                self._open_cache(trans)
+            # Process transaction which can handle a broken dep cache
+            if trans.role == ROLE_FIX_BROKEN_DEPENDS:
+                self.fix_broken_depends(trans)
+            elif trans.role == ROLE_UPDATE_CACHE:
+                self.update_cache(trans, **trans.kwargs)
+            # Process the transactions which require a consistent cache
+            elif trans.role == ROLE_ADD_LICENSE_KEY:
+                self.add_license_key(trans, **trans.kwargs)
+            elif self._cache and self._cache.broken_count:
+                raise TransactionFailed(ERROR_CACHE_BROKEN,
+                                        self._get_broken_details(trans))
+            if trans.role == ROLE_PK_QUERY:
+                self.query(trans)
+            elif trans.role == ROLE_INSTALL_FILE:
+                self.install_file(trans, **trans.kwargs)
+            elif trans.role in [ROLE_REMOVE_PACKAGES, ROLE_INSTALL_PACKAGES,
+                                ROLE_UPGRADE_PACKAGES, ROLE_COMMIT_PACKAGES]:
+                self.commit_packages(trans, *trans.packages)
+            elif trans.role == ROLE_UPGRADE_SYSTEM:
+                self.upgrade_system(trans, **trans.kwargs)
+        finally:
+            lock.release()
+
+    def commit_packages(self, trans, install, reinstall, remove, purge,
+                        upgrade, downgrade, simulate=False):
+        """Perform a complex package operation.
+
+        Keyword arguments:
+        trans - the transaction
+        install - list of package names to install
+        reinstall - list of package names to reinstall
+        remove - list of package names to remove
+        purge - list of package names to purge including configuration files
+        upgrade - list of package names to upgrade
+        downgrade - list of package names to upgrade
+        simulate -- if True the changes won't be applied
+        """
+        log.info("Committing packages: %s, %s, %s, %s, %s, %s",
+                 install, reinstall, remove, purge, upgrade, downgrade)
+        with self._cache.actiongroup():
+            resolver = apt.cache.ProblemResolver(self._cache)
+            self._mark_packages_for_installation(install, resolver)
+            self._mark_packages_for_installation(reinstall, resolver,
+                                                 reinstall=True)
+            self._mark_packages_for_removal(remove, resolver)
+            self._mark_packages_for_removal(purge, resolver, purge=True)
+            self._mark_packages_for_upgrade(upgrade, resolver)
+            self._mark_packages_for_downgrade(downgrade, resolver)
+            self._resolve_depends(trans, resolver)
+        self._check_obsoleted_dependencies(trans, resolver)
+        if not simulate:
+            self._apply_changes(trans)
+
+    def _resolve_depends(self, trans, resolver):
+        """Resolve the dependencies using the given ProblemResolver."""
+        self._call_plugins("modify_cache_before", resolver)
+        resolver.install_protect()
+        try:
+            resolver.resolve()
+        except SystemError:
+            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED,
+                                    self._get_broken_details(trans, now=False))
+        if self._call_plugins("modify_cache_after", resolver):
+            try:
+                resolver.resolve()
+            except SystemError:
+                details = self._get_broken_details(trans, now=False)
+                raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED, details)
+
+    def _get_high_trust_packages(self):
+        """ Return a list of packages that come from a high-trust repo """
+        def _in_high_trust_repository(pkgname, pkgorigin):
+            for origin, component, regexp in self._high_trust_repositories:
+                if (origin == pkgorigin.origin and
+                        component == pkgorigin.component and
+                        re.match(regexp, pkgname)):
+                    return True
+            return False
+        # loop
+        from_high_trust_repo = []
+        for pkg in self._cache.get_changes():
+            if pkg.marked_install:
+                for origin in pkg.candidate.origins:
+                    if _in_high_trust_repository(pkg.name, origin):
+                        from_high_trust_repo.append(pkg.name)
+                        break
+        return from_high_trust_repo
+
+    def _get_unauthenticated(self):
+        """Return a list of unauthenticated package names """
+        unauthenticated = []
+        for pkg in self._cache.get_changes():
+            if (pkg.marked_install or
+                    pkg.marked_downgrade or
+                    pkg.marked_upgrade or
+                    pkg.marked_reinstall):
+                trusted = False
+                for origin in pkg.candidate.origins:
+                    trusted |= origin.trusted
+                if not trusted:
+                    unauthenticated.append(pkg.name)
+        return unauthenticated
+
+    def _mark_packages_for_installation(self, packages, resolver,
+                                        reinstall=False):
+        """Mark packages for installation."""
+        for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
+                                           for pkg in packages]:
+            try:
+                pkg = self._cache[pkg_name]
+            except KeyError:
+                raise TransactionFailed(ERROR_NO_PACKAGE,
+                                        _("Package %s isn't available"),
+                                        pkg_name)
+            if reinstall:
+                if not pkg.is_installed:
+                    raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
+                                            _("Package %s isn't installed"),
+                                            pkg.name)
+                if pkg_ver and pkg.installed.version != pkg_ver:
+                    raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
+                                            _("The version %s of %s isn't "
+                                              "installed"),
+                                            pkg_ver, pkg_name)
+            else:
+                # Fail if the user requests to install the same version
+                # of an already installed package.
+                if (pkg.is_installed and
+                    # Compare version numbers
+                    pkg_ver and pkg_ver == pkg.installed.version and
+                    # Optionally compare the origin if specified
+                    (not pkg_rel or
+                     pkg_rel in [origin.archive for
+                                 origin in pkg.installed.origins])):
+                        raise TransactionFailed(
+                            ERROR_PACKAGE_ALREADY_INSTALLED,
+                            _("Package %s is already installed"), pkg_name)
+            pkg.mark_install(False, True, True)
+            resolver.clear(pkg)
+            resolver.protect(pkg)
+            if pkg_ver:
+                try:
+                    pkg.candidate = pkg.versions[pkg_ver]
+                except KeyError:
+                    raise TransactionFailed(ERROR_NO_PACKAGE,
+                                            _("The version %s of %s isn't "
+                                              "available."), pkg_ver, pkg_name)
+            elif pkg_rel:
+                self._set_candidate_release(pkg, pkg_rel)
+
+    def enable_distro_comp(self, trans, component):
+        """Enable given component in the sources list.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        component -- a component, e.g. main or universe
+        """
+        trans.progress = 101
+        trans.status = STATUS_COMMITTING
+        old_umask = os.umask(0o022)
+        try:
+            sourceslist = SourcesList()
+            distro = aptsources.distro.get_distro()
+            distro.get_sources(sourceslist)
+            distro.enable_component(component)
+            sourceslist.save()
+        finally:
+            os.umask(old_umask)
+
+    def add_repository(self, trans, src_type, uri, dist, comps, comment,
+                       sourcesfile):
+        """Add given repository to the sources list.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        src_type -- the type of the entry (deb, deb-src)
+        uri -- the main repository uri (e.g. http://archive.ubuntu.com/ubuntu)
+        dist -- the distribution to use (e.g. karmic, "/")
+        comps -- a (possible empty) list of components (main, restricted)
+        comment -- an (optional) comment
+        sourcesfile -- an (optinal) filename in sources.list.d
+        """
+        trans.progress = 101
+        trans.status = STATUS_COMMITTING
+
+        if sourcesfile:
+            if not sourcesfile.endswith(".list"):
+                sourcesfile += ".list"
+            dir = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
+            sourcesfile = os.path.join(dir, os.path.basename(sourcesfile))
+        else:
+            sourcesfile = None
+        # Store any private login information in a separate auth.conf file
+        if re.match("(http|https|ftp)://\S+?:\S+?@\S+", uri):
+            uri = self._store_and_strip_password_from_uri(uri)
+            auth_conf_path = apt_pkg.config.find_file("Dir::etc::netrc")
+            if not comment:
+                comment = "credentials stored in %s" % auth_conf_path
+            else:
+                comment += "; credentials stored in %s" % auth_conf_path
+        try:
+            sources = SourcesList()
+            entry = sources.add(src_type, uri, dist, comps, comment,
+                                file=sourcesfile)
+            if entry.invalid:
+                # FIXME: Introduce new error codes
+                raise RepositoryInvalidError()
+        except:
+            log.exception("adding repository")
+            raise
+        else:
+            sources.save()
+
+    def _store_and_strip_password_from_uri(self, uri, auth_conf_path=None):
+        """Extract the credentials from an URI. Store the password in
+        auth.conf and return the URI without any password information.
+        """
+        try:
+            res = urlsplit(uri)
+        except ValueError as error:
+            log.warning("Failed to urlsplit '%s'", error)
+            return uri
+        netloc_public = res.netloc.replace("%s:%s@" % (res.username,
+                                                       res.password),
+                                           "")
+        machine = netloc_public + res.path
+        # find auth.conf
+        if auth_conf_path is None:
+            auth_conf_path = apt_pkg.config.find_file("Dir::etc::netrc")
+
+        # read all "machine"s from the auth.conf "netrc" file
+        netrc_hosts = {}
+        netrc_hosts_as_text = ""
+        if os.path.exists(auth_conf_path):
+                netrc_hosts = netrc.netrc(auth_conf_path).hosts
+                with open(auth_conf_path, "rb") as f:
+                    netrc_hosts_as_text = f.read().decode("UTF-8")
+
+        # the new entry
+        new_netrc_entry = "\nmachine %s login %s password %s\n" % (
+            machine, res.username, res.password)
+        # if there is the same machine already defined, update it
+        # using a regexp this will ensure order/comments remain
+        if machine in netrc_hosts:
+            sub_regexp = r'machine\s+%s\s+login\s+%s\s+password\s+%s' % (
+                re.escape(machine),
+                re.escape(netrc_hosts[machine][0]),
+                re.escape(netrc_hosts[machine][2]))
+            replacement = 'machine %s login %s password %s' % (
+                machine, res.username, res.password)
+            # this may happen if e.g. the order is unexpected
+            if not re.search(sub_regexp, netrc_hosts_as_text):
+                log.warning("can not replace existing netrc entry for '%s' "
+                            "prepending it instead" % machine)
+                netrc_hosts_as_text = new_netrc_entry + netrc_hosts_as_text
+            else:
+                netrc_hosts_as_text = re.sub(
+                    sub_regexp, replacement, netrc_hosts_as_text)
+        else:
+            netrc_hosts_as_text += new_netrc_entry
+
+        # keep permssion bits of the file
+        mode = 0o640
+        try:
+            mode = os.stat(auth_conf_path)[stat.ST_MODE]
+        except OSError as e:
+            if e.errno != errno.ENOENT:
+                raise
+        # write out, tmp file first plus rename to be atomic
+        try:
+            auth_conf_tmp = tempfile.NamedTemporaryFile(
+                dir=os.path.dirname(auth_conf_path),
+                prefix=os.path.basename(auth_conf_path),
+                delete=False)
+            auth_conf_tmp.write(netrc_hosts_as_text.encode('UTF-8'))
+            auth_conf_tmp.close()
+            os.rename(auth_conf_tmp.name, auth_conf_path)
+            # and restore permissions (or set default ones)
+            os.chmod(auth_conf_path, mode)
+        except OSError as error:
+            log.warning("Failed to write auth.conf: '%s'" % error)
+
+        # Return URI without user/pass
+        return urlunsplit((res.scheme, netloc_public, res.path, res.query,
+                           res.fragment))
+
+    def add_vendor_key_from_keyserver(self, trans, keyid, keyserver):
+        """Add the signing key from the given (keyid, keyserver) to the
+        trusted vendors.
+
+        Keyword argument:
+        trans -- the corresponding transaction
+        keyid - the keyid of the key (e.g. 0x0EB12F05)
+        keyserver - the keyserver (e.g. keyserver.ubuntu.com)
+        """
+        log.info("Adding vendor key from keyserver: %s %s", keyid, keyserver)
+        # Perform some sanity checks
+        try:
+            res = urlsplit(keyserver)
+        except ValueError:
+            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
+                                    # TRANSLATORS: %s is the URL of GnuPG
+                                    #             keyserver
+                                    _("The keyserver URL is invalid: %s"),
+                                    keyserver)
+        if res.scheme not in ["hkp", "ldap", "ldaps", "http", "https"]:
+            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
+                                    # TRANSLATORS: %s is the URL of GnuPG
+                                    #             keyserver
+                                    _("Invalid protocol of the server: %s"),
+                                    keyserver)
+        try:
+            int(keyid, 16)
+        except ValueError:
+            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
+                                    # TRANSLATORS: %s is the id of a GnuPG key
+                                    #             e.g. E08ADE95
+                                    _("Invalid key id: %s"), keyid)
+        trans.status = STATUS_DOWNLOADING
+        trans.progress = 101
+        with DaemonForkProgress(trans) as progress:
+            progress.run(apt.auth.add_key_from_keyserver, keyid, keyserver)
+        if progress._child_exit != 0:
+            # TRANSLATORS: The first %s is the key id and the second the server
+            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
+                                    _("Failed to download and install the key "
+                                      "%s from %s:\n%s"),
+                                    keyid, keyserver, progress.output)
+
+    def add_vendor_key_from_file(self, trans, path):
+        """Add the signing key from the given file to the trusted vendors.
+
+        Keyword argument:
+        path -- absolute path to the key file
+        """
+        log.info("Adding vendor key from file: %s", path)
+        trans.progress = 101
+        trans.status = STATUS_COMMITTING
+        with DaemonForkProgress(trans) as progress:
+            progress.run(apt.auth.add_key_from_file, path)
+        if progress._child_exit != 0:
+            raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
+                                    _("Key file %s couldn't be installed: %s"),
+                                    path, progress.output)
+
+    def remove_vendor_key(self, trans, fingerprint):
+        """Remove repository key.
+
+        Keyword argument:
+        trans -- the corresponding transaction
+        fingerprint -- fingerprint of the key to remove
+        """
+        log.info("Removing vendor key: %s", fingerprint)
+        trans.progress = 101
+        trans.status = STATUS_COMMITTING
+        try:
+            int(fingerprint, 16)
+        except ValueError:
+            raise TransactionFailed(ERROR_KEY_NOT_REMOVED,
+                                    # TRANSLATORS: %s is the id of a GnuPG key
+                                    #             e.g. E08ADE95
+                                    _("Invalid key id: %s"), fingerprint)
+        with DaemonForkProgress(trans) as progress:
+            progress.run(apt.auth.remove_key, fingerprint)
+        if progress._child_exit != 0:
+            raise TransactionFailed(ERROR_KEY_NOT_REMOVED,
+                                    _("Key with fingerprint %s couldn't be "
+                                      "removed: %s"),
+                                    fingerprint, progress.output)
+
+    def install_file(self, trans, path, force, simulate=False):
+        """Install local package file.
+
+        Keyword argument:
+        trans -- the corresponding transaction
+        path -- absolute path to the package file
+        force -- if installing an invalid package is allowed
+        simulate -- if True the changes won't be committed but the debfile
+                    instance will be returned
+        """
+        log.info("Installing local package file: %s", path)
+        # Check if the dpkg can be installed at all
+        trans.status = STATUS_RESOLVING_DEP
+        deb = self._check_deb_file(trans, path, force)
+        # Check for required changes and apply them before
+        (install, remove, unauth) = deb.required_changes
+        self._call_plugins("modify_cache_after")
+        if simulate:
+            return deb
+        with self._frozen_status():
+            if len(install) > 0 or len(remove) > 0:
+                self._apply_changes(trans, fetch_range=(15, 33),
+                                    install_range=(34, 63))
+            # Install the dpkg file
+            deb_progress = DaemonDpkgInstallProgress(trans, begin=64, end=95)
+            res = deb.install(deb_progress)
+            trans.output += deb_progress.output
+            if res:
+                raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
+                                        trans.output)
+
+    def _mark_packages_for_removal(self, packages, resolver, purge=False):
+        """Mark packages for installation."""
+        for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
+                                           for pkg in packages]:
+            try:
+                pkg = self._cache[pkg_name]
+            except KeyError:
+                raise TransactionFailed(ERROR_NO_PACKAGE,
+                                        _("Package %s isn't available"),
+                                        pkg_name)
+            if not pkg.is_installed and not pkg.installed_files:
+                raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
+                                        _("Package %s isn't installed"),
+                                        pkg_name)
+            if pkg.essential is True:
+                raise TransactionFailed(ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE,
+                                        _("Package %s cannot be removed."),
+                                        pkg_name)
+            if pkg_ver and pkg.installed != pkg_ver:
+                raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
+                                        _("The version %s of %s is not "
+                                          "installed"), pkg_ver, pkg_name)
+            pkg.mark_delete(False, purge)
+            resolver.clear(pkg)
+            resolver.protect(pkg)
+            resolver.remove(pkg)
+
+    def _check_obsoleted_dependencies(self, trans, resolver=None):
+        """Mark obsoleted dependencies of to be removed packages
+        for removal.
+        """
+        if not trans.remove_obsoleted_depends:
+            return
+        if not resolver:
+            resolver = apt.cache.ProblemResolver(self._cache)
+        installed_deps = set()
+        with self._cache.actiongroup():
+            for pkg in self._cache.get_changes():
+                if pkg.marked_delete:
+                    installed_deps = self._installed_dependencies(
+                        pkg.name, installed_deps)
+            for dep_name in installed_deps:
+                if dep_name in self._cache:
+                    pkg = self._cache[dep_name]
+                    if pkg.is_installed and pkg.is_auto_removable:
+                        pkg.mark_delete(False)
+            # do an additional resolver run to ensure that the autoremove
+            # never leaves the cache in an inconsistent state, see bug
+            # LP: #659111 for the rational, essentially this may happen
+            # if a package is marked install during problem resolving but
+            # is later no longer required. the resolver deals with that
+            self._resolve_depends(trans, resolver)
+
+    def _installed_dependencies(self, pkg_name, all_deps=None):
+        """Recursively return all installed dependencies of a given package."""
+        # FIXME: Should be part of python-apt, since it makes use of non-public
+        #       API. Perhaps by adding a recursive argument to
+        #       apt.package.Version.get_dependencies()
+        if not all_deps:
+            all_deps = set()
+        if pkg_name not in self._cache:
+            return all_deps
+        cur = self._cache[pkg_name]._pkg.current_ver
+        if not cur:
+            return all_deps
+        for sec in ("PreDepends", "Depends", "Recommends"):
+            try:
+                for dep in cur.depends_list[sec]:
+                    dep_name = dep[0].target_pkg.name
+                    if dep_name not in all_deps:
+                        all_deps.add(dep_name)
+                        all_deps |= self._installed_dependencies(dep_name,
+                                                                 all_deps)
+            except KeyError:
+                pass
+        return all_deps
+
+    def _mark_packages_for_downgrade(self, packages, resolver):
+        """Mark packages for downgrade."""
+        for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
+                                           for pkg in packages]:
+            try:
+                pkg = self._cache[pkg_name]
+            except KeyError:
+                raise TransactionFailed(ERROR_NO_PACKAGE,
+                                        _("Package %s isn't available"),
+                                        pkg_name)
+            if not pkg.is_installed:
+                raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
+                                        _("Package %s isn't installed"),
+                                        pkg_name)
+            auto = pkg.is_auto_installed
+            pkg.mark_install(False, True, True)
+            pkg.mark_auto(auto)
+            resolver.clear(pkg)
+            resolver.protect(pkg)
+            if pkg_ver:
+                if pkg.installed and pkg.installed.version < pkg_ver:
+                    # FIXME: We need a new error enum
+                    raise TransactionFailed(ERROR_NO_PACKAGE,
+                                            _("The former version %s of %s "
+                                              "is already installed"),
+                                            pkg.installed.version, pkg.name)
+                elif pkg.installed and pkg.installed.version == pkg_ver:
+                    raise TransactionFailed(ERROR_PACKAGE_ALREADY_INSTALLED,
+                                            _("The version %s of %s "
+                                              "is already installed"),
+                                            pkg.installed.version, pkg.name)
+                try:
+                    pkg.candidate = pkg.versions[pkg_ver]
+                except KeyError:
+                    raise TransactionFailed(ERROR_NO_PACKAGE,
+                                            _("The version %s of %s isn't "
+                                              "available"), pkg_ver, pkg_name)
+            else:
+                raise TransactionFailed(ERROR_NO_PACKAGE,
+                                        _("You need to specify a version to "
+                                          "downgrade %s to"),
+                                        pkg_name)
+
+    def _mark_packages_for_upgrade(self, packages, resolver):
+        """Mark packages for upgrade."""
+        for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
+                                           for pkg in packages]:
+            try:
+                pkg = self._cache[pkg_name]
+            except KeyError:
+                raise TransactionFailed(ERROR_NO_PACKAGE,
+                                        _("Package %s isn't available"),
+                                        pkg_name)
+            if not pkg.is_installed:
+                raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
+                                        _("Package %s isn't installed"),
+                                        pkg_name)
+            auto = pkg.is_auto_installed
+            pkg.mark_install(False, True, True)
+            pkg.mark_auto(auto)
+            resolver.clear(pkg)
+            resolver.protect(pkg)
+            if pkg_ver:
+                if (pkg.installed and
+                    apt_pkg.version_compare(pkg.installed.version,
+                                            pkg_ver) == 1):
+                    raise TransactionFailed(ERROR_PACKAGE_UPTODATE,
+                                            _("The later version %s of %s "
+                                              "is already installed"),
+                                            pkg.installed.version, pkg.name)
+                elif (pkg.installed and
+                      apt_pkg.version_compare(pkg.installed.version,
+                                              pkg_ver) == 0):
+                    raise TransactionFailed(ERROR_PACKAGE_UPTODATE,
+                                            _("The version %s of %s "
+                                              "is already installed"),
+                                            pkg.installed.version, pkg.name)
+                try:
+                    pkg.candidate = pkg.versions[pkg_ver]
+                except KeyError:
+                    raise TransactionFailed(ERROR_NO_PACKAGE,
+                                            _("The version %s of %s isn't "
+                                              "available."), pkg_ver, pkg_name)
+
+            elif pkg_rel:
+                self._set_candidate_release(pkg, pkg_rel)
+
+    @staticmethod
+    def _set_candidate_release(pkg, release):
+        """Set the candidate of a package to the one from the given release."""
+        # FIXME: Should be moved to python-apt
+        # Check if the package is provided in the release
+        for version in pkg.versions:
+            if [origin for origin in version.origins
+                    if origin.archive == release]:
+                break
+        else:
+            raise TransactionFailed(ERROR_NO_PACKAGE,
+                                    _("The package %s isn't available in "
+                                      "the %s release."), pkg.name, release)
+        pkg._pcache.cache_pre_change()
+        pkg._pcache._depcache.set_candidate_release(pkg._pkg, version._cand,
+                                                    release)
+        pkg._pcache.cache_post_change()
+
+    def update_cache(self, trans, sources_list):
+        """Update the cache.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        sources_list -- only update the repositories found in the sources.list
+                        snippet by the given file name.
+        """
+
+        def compare_pathes(first, second):
+            """Small helper to compare two pathes."""
+            return os.path.normpath(first) == os.path.normpath(second)
+
+        log.info("Updating cache")
+
+        progress = DaemonAcquireRepoProgress(trans, begin=10, end=90)
+        if sources_list and not sources_list.startswith("/"):
+            dir = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
+            sources_list = os.path.join(dir, sources_list)
+        if sources_list:
+            # For security reasons (LP #722228) we only allow files inside
+            # sources.list.d as basedir
+            basedir = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
+            system_sources = apt_pkg.config.find_file("Dir::Etc::sourcelist")
+            if "/" in sources_list:
+                sources_list = os.path.abspath(sources_list)
+                # Check if the sources_list snippet is in the sourceparts
+                # directory
+                common_prefix = os.path.commonprefix([sources_list, basedir])
+                if not (compare_pathes(common_prefix, basedir) or
+                        compare_pathes(sources_list, system_sources)):
+                    raise AptDaemonError("Only alternative sources.list files "
+                                         "inside '%s' are allowed (not '%s')" %
+                                         (basedir, sources_list))
+            else:
+                sources_list = os.path.join(basedir, sources_list)
+        try:
+            self._cache.update(progress, sources_list=sources_list)
+        except apt.cache.FetchFailedException as error:
+            # ListUpdate() method of apt handles a cancelled operation
+            # as a failed one, see LP #162441
+            if trans.cancelled:
+                raise TransactionCancelled()
+            else:
+                raise TransactionFailed(ERROR_REPO_DOWNLOAD_FAILED,
+                                        str(error))
+        except apt.cache.FetchCancelledException:
+            raise TransactionCancelled()
+        except apt.cache.LockFailedException:
+            raise TransactionFailed(ERROR_NO_LOCK)
+        self._open_cache(trans, begin=91, end=95)
+
+    def upgrade_system(self, trans, safe_mode=True, simulate=False):
+        """Upgrade the system.
+
+        Keyword argument:
+        trans -- the corresponding transaction
+        safe_mode -- if additional software should be installed or removed to
+                     satisfy the dependencies the an updates
+        simulate -- if the changes should not be applied
+        """
+        log.info("Upgrade system with safe mode: %s" % safe_mode)
+        trans.status = STATUS_RESOLVING_DEP
+        # FIXME: What to do if already uptotdate? Add error code?
+        self._call_plugins("modify_cache_before")
+        try:
+            self._cache.upgrade(dist_upgrade=not safe_mode)
+        except SystemError as excep:
+            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED, str(excep))
+        self._call_plugins("modify_cache_after")
+        self._check_obsoleted_dependencies(trans)
+        if not simulate:
+            self._apply_changes(trans)
+
+    def fix_incomplete_install(self, trans):
+        """Run dpkg --configure -a to recover from a failed installation.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        """
+        log.info("Fixing incomplete installs")
+        trans.status = STATUS_CLEANING_UP
+        with self._frozen_status():
+            with DaemonDpkgRecoverProgress(trans) as progress:
+                progress.run()
+        trans.output += progress.output
+        if progress._child_exit != 0:
+            raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
+                                    trans.output)
+
+    def reconfigure(self, trans, packages, priority):
+        """Run dpkg-reconfigure to reconfigure installed packages.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        packages -- list of packages to reconfigure
+        priority -- the lowest priority of question which should be asked
+        """
+        log.info("Reconfiguring packages")
+        with self._frozen_status():
+            with DaemonDpkgReconfigureProgress(trans) as progress:
+                progress.run(packages, priority)
+        trans.output += progress.output
+        if progress._child_exit != 0:
+            raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
+                                    trans.output)
+
+    def fix_broken_depends(self, trans, simulate=False):
+        """Try to fix broken dependencies.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        simualte -- if the changes should not be applied
+        """
+        log.info("Fixing broken depends")
+        trans.status = STATUS_RESOLVING_DEP
+        try:
+            self._cache._depcache.fix_broken()
+        except SystemError:
+            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED,
+                                    self._get_broken_details(trans))
+        if not simulate:
+            self._apply_changes(trans)
+
+    def _open_cache(self, trans, begin=1, end=5, quiet=False, status=None):
+        """Open the APT cache.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        start -- the begin of the progress range
+        end -- the end of the the progress range
+        quiet -- if True do no report any progress
+        status -- an alternative dpkg status file
+        """
+        self.marked_tid = None
+        trans.status = STATUS_LOADING_CACHE
+        if not status:
+            status = self._status_orig
+        apt_pkg.config.set("Dir::State::status", status)
+        apt_pkg.init_system()
+        progress = DaemonOpenProgress(trans, begin=begin, end=end,
+                                      quiet=quiet)
+        try:
+            if not isinstance(self._cache, apt.cache.Cache):
+                self._cache = apt.cache.Cache(progress)
+            else:
+                self._cache.open(progress)
+        except SystemError as excep:
+            raise TransactionFailed(ERROR_NO_CACHE, str(excep))
+
+    def is_dpkg_journal_clean(self):
+        """Return False if there are traces of incomplete dpkg status
+        updates."""
+        status_updates = os.path.join(os.path.dirname(self._status_orig),
+                                      "updates/")
+        for dentry in os.listdir(status_updates):
+            if dentry.isdigit():
+                return False
+        return True
+
+    def _apply_changes(self, trans, fetch_range=(15, 50),
+                       install_range=(50, 90)):
+        """Apply previously marked changes to the system.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        fetch_range -- tuple containing the start and end point of the
+                       download progress
+        install_range -- tuple containing the start and end point of the
+                         install progress
+        """
+        changes = self._cache.get_changes()
+        if not changes:
+            return
+        # Do not allow to remove essential packages
+        for pkg in changes:
+            if pkg.marked_delete and (pkg.essential is True or
+                                      (pkg.installed and
+                                       pkg.installed.priority == "required") or
+                                      pkg.name == "aptdaemon"):
+                raise TransactionFailed(ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE,
+                                        _("Package %s cannot be removed"),
+                                        pkg.name)
+        # Check if any of the cache changes get installed from an
+        # unauthenticated repository""
+        if not trans.allow_unauthenticated and trans.unauthenticated:
+            raise TransactionFailed(ERROR_PACKAGE_UNAUTHENTICATED,
+                                    " ".join(sorted(trans.unauthenticated)))
+        if trans.cancelled:
+            raise TransactionCancelled()
+        trans.cancellable = False
+        fetch_progress = DaemonAcquireProgress(trans, begin=fetch_range[0],
+                                               end=fetch_range[1])
+        inst_progress = DaemonInstallProgress(trans, begin=install_range[0],
+                                              end=install_range[1])
+        with self._frozen_status():
+            try:
+                self._cache.commit(fetch_progress, inst_progress)
+            except apt.cache.FetchFailedException as error:
+                raise TransactionFailed(ERROR_PACKAGE_DOWNLOAD_FAILED,
+                                        str(error))
+            except apt.cache.FetchCancelledException:
+                raise TransactionCancelled()
+            except SystemError as excep:
+                # Run dpkg --configure -a to recover from a failed transaction
+                trans.status = STATUS_CLEANING_UP
+                with DaemonDpkgRecoverProgress(trans, begin=90, end=95) as pro:
+                    pro.run()
+                output = inst_progress.output + pro.output
+                trans.output += output
+                raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
+                                        "%s: %s" % (excep, trans.output))
+            else:
+                trans.output += inst_progress.output
+
+    @contextlib.contextmanager
+    def _frozen_status(self):
+        """Freeze the status file to allow simulate operations during
+        a dpkg call."""
+        frozen_dir = tempfile.mkdtemp(prefix="aptdaemon-frozen-status")
+        shutil.copy(self._status_orig, frozen_dir)
+        self._status_frozen = os.path.join(frozen_dir, "status")
+        try:
+            yield
+        finally:
+            shutil.rmtree(frozen_dir)
+            self._status_frozen = None
+
+    def query(self, trans):
+        """Process a PackageKit query transaction."""
+        raise NotImplementedError
+
+    def _simulate_transaction(self, trans):
+        depends = [[], [], [], [], [], [], []]
+        unauthenticated = []
+        high_trust_packages = []
+        skip_pkgs = []
+        size = 0
+        installs = reinstalls = removals = purges = upgrades = upgradables = \
+            downgrades = []
+
+        # Only handle transaction which change packages
+        # FIXME: Add support for ROLE_FIX_INCOMPLETE_INSTALL
+        if trans.role not in [ROLE_INSTALL_PACKAGES, ROLE_UPGRADE_PACKAGES,
+                              ROLE_UPGRADE_SYSTEM, ROLE_REMOVE_PACKAGES,
+                              ROLE_COMMIT_PACKAGES, ROLE_INSTALL_FILE,
+                              ROLE_FIX_BROKEN_DEPENDS]:
+            return depends, 0, 0, [], []
+
+        # If a transaction is currently running use the former status file
+        if self._status_frozen:
+            status_path = self._status_frozen
+        else:
+            status_path = self._status_orig
+        self._open_cache(trans, quiet=True, status=status_path)
+        if trans.role == ROLE_FIX_BROKEN_DEPENDS:
+            self.fix_broken_depends(trans, simulate=True)
+        elif self._cache.broken_count:
+            raise TransactionFailed(ERROR_CACHE_BROKEN,
+                                    self._get_broken_details(trans))
+        elif trans.role == ROLE_UPGRADE_SYSTEM:
+            for pkg in self._iterate_packages():
+                if pkg.is_upgradable:
+                    upgradables.append(pkg)
+            self.upgrade_system(trans, simulate=True, **trans.kwargs)
+        elif trans.role == ROLE_INSTALL_FILE:
+            deb = self.install_file(trans, simulate=True, **trans.kwargs)
+            skip_pkgs.append(deb.pkgname)
+            try:
+                # Sometimes a thousands comma is used in packages
+                # See LP #656633
+                size = int(deb["Installed-Size"].replace(",", "")) * 1024
+                # Some packages ship really large install sizes e.g.
+                # openvpn access server, see LP #758837
+                if size > sys.maxsize:
+                    raise OverflowError("Size is too large: %s Bytes" % size)
+            except (KeyError, AttributeError, ValueError, OverflowError):
+                if not trans.kwargs["force"]:
+                    msg = trans.gettext("The package doesn't provide a "
+                                        "valid Installed-Size control "
+                                        "field. See Debian Policy 5.6.20.")
+                    raise TransactionFailed(ERROR_INVALID_PACKAGE_FILE, msg)
+            try:
+                pkg = self._cache[deb.pkgname]
+            except KeyError:
+                trans.packages = [[deb.pkgname], [], [], [], [], []]
+            else:
+                if pkg.is_installed:
+                    # if we failed to get the size from the deb file do nor
+                    # try to get the delta
+                    if size != 0:
+                        size -= pkg.installed.installed_size
+                    trans.packages = [[], [deb.pkgname], [], [], [], []]
+                else:
+                    trans.packages = [[deb.pkgname], [], [], [], [], []]
+        else:
+            # FIXME: ugly code to get the names of the packages
+            (installs, reinstalls, removals, purges,
+             upgrades, downgrades) = [[re.split("(=|/)", entry, 1)[0]
+                                       for entry in lst]
+                                      for lst in trans.packages]
+            self.commit_packages(trans, *trans.packages, simulate=True)
+
+        changes = self._cache.get_changes()
+        changes_names = []
+        # get the additional dependencies
+        for pkg in changes:
+            if (pkg.marked_upgrade and pkg.is_installed and
+                    pkg.name not in upgrades):
+                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
+                depends[PKGS_UPGRADE].append(pkg_str)
+            elif pkg.marked_reinstall and pkg.name not in reinstalls:
+                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
+                depends[PKGS_REINSTALL].append(pkg_str)
+            elif pkg.marked_downgrade and pkg.name not in downgrades:
+                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
+                depends[PKGS_DOWNGRADE].append(pkg_str)
+            elif pkg.marked_install and pkg.name not in installs:
+                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
+                depends[PKGS_INSTALL].append(pkg_str)
+            elif pkg.marked_delete and pkg.name not in removals:
+                pkg_str = "%s=%s" % (pkg.name, pkg.installed.version)
+                depends[PKGS_REMOVE].append(pkg_str)
+            # FIXME: add support for purges
+            changes_names.append(pkg.name)
+        # get the unauthenticated packages
+        unauthenticated = self._get_unauthenticated()
+        high_trust_packages = self._get_high_trust_packages()
+        # Check for skipped upgrades
+        for pkg in upgradables:
+            if pkg.marked_keep:
+                pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
+                depends[PKGS_KEEP].append(pkg_str)
+
+        # apt.cache.Cache.required_download requires a clean cache. Under some
+        # strange circumstances it can fail (most likely an interrupted
+        # debconf question), see LP#659438
+        # Running dpkg --configure -a fixes the situation
+        try:
+            required_download = self._cache.required_download
+        except SystemError as error:
+            raise TransactionFailed(ERROR_INCOMPLETE_INSTALL, str(error))
+
+        required_space = size + self._cache.required_space
+
+        return (depends, required_download, required_space, unauthenticated,
+                high_trust_packages)
+
+    def _check_deb_file(self, trans, path, force):
+        """Perform some basic checks for the Debian package.
+
+        :param trans: The transaction instance.
+
+        :returns: An apt.debfile.Debfile instance.
+        """
+        if not os.path.isfile(path):
+            raise TransactionFailed(ERROR_UNREADABLE_PACKAGE_FILE, path)
+        if not force and os.path.isfile("/usr/bin/lintian"):
+            with DaemonLintianProgress(trans) as progress:
+                progress.run(path)
+            # FIXME: Add an error to catch return state 2 (failure)
+            if progress._child_exit != 0:
+                raise TransactionFailed(ERROR_INVALID_PACKAGE_FILE,
+                                        "Lintian check results for %s:"
+                                        "\n%s" % (path, progress.output))
+        try:
+            deb = apt.debfile.DebPackage(path, self._cache)
+        except IOError:
+            raise TransactionFailed(ERROR_UNREADABLE_PACKAGE_FILE, path)
+        except Exception as error:
+            raise TransactionFailed(ERROR_INVALID_PACKAGE_FILE, str(error))
+        try:
+            ret = deb.check()
+        except Exception as error:
+            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED, str(error))
+        if not ret:
+            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED,
+                                    deb._failure_string)
+        return deb
+
+    def clean(self, trans):
+        """Clean the download directories.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        """
+        # FIXME: Use pkgAcquire.Clean(). Currently not part of python-apt.
+        trans.status = STATUS_CLEANING_UP
+        archive_path = apt_pkg.config.find_dir("Dir::Cache::archives")
+        for dir in [archive_path, os.path.join(archive_path, "partial")]:
+            for filename in os.listdir(dir):
+                if filename == "lock":
+                    continue
+                path = os.path.join(dir, filename)
+                if os.path.isfile(path):
+                    log.debug("Removing file %s", path)
+                    os.remove(path)
+
+    def add_license_key(self, trans, pkg_name, json_token, server_name):
+        """Add a license key data to the given package.
+
+        Keyword arguemnts:
+        trans -- the coresponding transaction
+        pkg_name -- the name of the corresponding package
+        json_token -- the oauth token as json
+        server_name -- the server to use (ubuntu-production, ubuntu-staging)
+        """
+        # set transaction state to downloading
+        trans.status = STATUS_DOWNLOADING
+        try:
+            license_key, license_key_path = (
+                self.plugins["get_license_key"][0](trans.uid, pkg_name,
+                                                   json_token, server_name))
+        except Exception as error:
+            logging.exception("get_license_key plugin failed")
+            raise TransactionFailed(ERROR_LICENSE_KEY_DOWNLOAD_FAILED,
+                                    str(error))
+        # ensure stuff is good
+        if not license_key_path or not license_key:
+            raise TransactionFailed(ERROR_LICENSE_KEY_DOWNLOAD_FAILED,
+                                    _("The license key is empty"))
+
+        # add license key if we have one
+        self._add_license_key_to_system(pkg_name, license_key,
+                                        license_key_path)
+
+    def _add_license_key_to_system(self, pkg_name, license_key,
+                                   license_key_path):
+        # fixup path
+        license_key_path = os.path.join(apt_pkg.config.find_dir("Dir"),
+                                        license_key_path.lstrip("/"))
+
+        # Check content of the key
+        if (license_key.strip().startswith("#!") or
+                license_key.startswith("\x7fELF")):
+            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
+                                    _("The license key is not allowed to "
+                                      "contain executable code."))
+        # Check the path of the license
+        license_key_path = os.path.normpath(license_key_path)
+        license_key_path_rootdir = os.path.join(
+            apt_pkg.config["Dir"], self.LICENSE_KEY_ROOTDIR.lstrip("/"),
+            pkg_name)
+        if not license_key_path.startswith(license_key_path_rootdir):
+            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
+                                    _("The license key path %s is invalid"),
+                                    license_key_path)
+        if os.path.lexists(license_key_path):
+            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
+                                    _("The license key already exists: %s"),
+                                    license_key_path)
+        # Symlink attacks!
+        if os.path.realpath(license_key_path) != license_key_path:
+            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
+                                    _("The location of the license key is "
+                                      "unsecure since it contains symbolic "
+                                      "links. The path %s maps to %s"),
+                                    license_key_path,
+                                    os.path.realpath(license_key_path))
+        # Check if the directory already exists
+        if not os.path.isdir(os.path.dirname(license_key_path)):
+            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
+                                    _("The directory where to install the key "
+                                      "to doesn't exist yet: %s"),
+                                    license_key_path)
+        # write it
+        log.info("Writing license key to '%s'" % license_key_path)
+        old_umask = os.umask(18)
+        try:
+            with open(license_key_path, "w") as license_file:
+                license_file.write(license_key)
+        except IOError:
+            raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
+                                    _("Failed to write key file to: %s"),
+                                    license_key_path)
+        finally:
+            os.umask(old_umask)
+
+    def _iterate_mainloop(self):
+        """Process pending actions on the main loop."""
+        while GLib.main_context_default().pending():
+            GLib.main_context_default().iteration()
+
+    def _iterate_packages(self, interval=1000):
+        """Itarte von the packages of the cache and iterate on the
+        GObject main loop time for more responsiveness.
+
+        Keyword arguments:
+        interval - the number of packages after which we iterate on the
+            mainloop
+        """
+        for enum, pkg in enumerate(self._cache):
+            if not enum % interval:
+                self._iterate_mainloop()
+            yield pkg
+
+    def _get_broken_details(self, trans, now=True):
+        """Return a message which provides debugging information about
+        broken packages.
+
+        This method is basically a Python implementation of apt-get.cc's
+        ShowBroken.
+
+        Keyword arguments:
+        trans -- the corresponding transaction
+        now -- if we check currently broken dependecies or the installation
+               candidate
+        """
+        msg = trans.gettext("The following packages have unmet dependencies:")
+        msg += "\n\n"
+        for pkg in self._cache:
+            if not ((now and pkg.is_now_broken) or
+                    (not now and pkg.is_inst_broken)):
+                continue
+            msg += "%s: " % pkg.name
+            if now:
+                version = pkg.installed
+            else:
+                version = pkg.candidate
+            indent = " " * (len(pkg.name) + 2)
+            dep_msg = ""
+            for dep in version.dependencies:
+                or_msg = ""
+                for base_dep in dep.or_dependencies:
+                    if or_msg:
+                        or_msg += "or\n"
+                        or_msg += indent
+                    # Check if it's an important dependency
+                    # See apt-pkg/depcache.cc IsImportantDep
+                    # See apt-pkg/pkgcache.cc IsCritical()
+                    if not (base_dep.rawtype in ["Depends", "PreDepends",
+                                                 "Obsoletes", "DpkgBreaks",
+                                                 "Conflicts"] or
+                            (apt_pkg.config.find_b("APT::Install-Recommends",
+                                                   False) and
+                            base_dep.rawtype == "Recommends") or
+                            (apt_pkg.config.find_b("APT::Install-Suggests",
+                                                   False) and
+                             base_dep.rawtype == "Suggests")):
+                        continue
+                    # Get the version of the target package
+                    try:
+                        pkg_dep = self._cache[base_dep.name]
+                    except KeyError:
+                        dep_version = None
+                    else:
+                        if now:
+                            dep_version = pkg_dep.installed
+                        else:
+                            dep_version = pkg_dep.candidate
+                    # We only want to display dependencies which cannot
+                    # be satisfied
+                    if dep_version and not apt_pkg.check_dep(base_dep.version,
+                                                             base_dep.relation,
+                                                             version.version):
+                        break
+                    or_msg = "%s: %s " % (base_dep.rawtype, base_dep.name)
+                    if base_dep.version:
+                        or_msg += "(%s %s) " % (base_dep.relation,
+                                                base_dep.version)
+                    if self._cache.is_virtual_package(base_dep.name):
+                        or_msg += trans.gettext("but it is a virtual package")
+                    elif not dep_version:
+                        if now:
+                            or_msg += trans.gettext("but it is not installed")
+                        else:
+                            or_msg += trans.gettext("but it is not going to "
+                                                    "be installed")
+                    elif now:
+                        # TRANSLATORS: %s is a version number
+                        or_msg += (trans.gettext("but %s is installed") %
+                                   dep_version.version)
+                    else:
+                        # TRANSLATORS: %s is a version number
+                        or_msg += (trans.gettext("but %s is to be installed") %
+                                   dep_version.version)
+                else:
+                    # Only append an or-group if at least one of the
+                    # dependencies cannot be satisfied
+                    if dep_msg:
+                        dep_msg += indent
+                    dep_msg += or_msg
+                    dep_msg += "\n"
+            msg += dep_msg
+        return msg
+
+    def is_reboot_required(self):
+        """If a reboot is required to get all changes into effect."""
+        return os.path.exists(os.path.join(apt_pkg.config.find_dir("Dir"),
+                                           "var/run/reboot-required"))
+
+    def set_config(self, option, value, filename=None):
+        """Write a configuration value to file."""
+        if option in ["AutoUpdateInterval", "AutoDownload",
+                      "AutoCleanInterval", "UnattendedUpgrade"]:
+            self._set_apt_config(option, value, filename)
+        elif option == "PopConParticipation":
+            self._set_popcon_pariticipation(value)
+
+    def _set_apt_config(self, option, value, filename):
+        config_writer = ConfigWriter()
+        cw.set_value(option, value, filename)
+        apt_pkg.init_config()
+
+    def _set_popcon_participation(self, participate):
+        if participate in [True, 1, "yes"]:
+            value = "yes"
+        else:
+            value = "no"
+        if os.path.exists(_POPCON_PATH):
+            # read the current config and replace the corresponding settings
+            # FIXME: Check if the config file is a valid bash script and
+            #        contains the host_id
+            with open(_POPCON_PATH) as conf_file:
+                old_config = conf_file.read()
+            config = re.sub(r'(PARTICIPATE=*)(".+?")',
+                            '\\1"%s"' % value,
+                            old_config)
+        else:
+            # create a new popcon config file
+            m = md5()
+            m.update(open("/dev/urandom", "r").read(1024))
+            config = _POPCON_DEFAULT % {"host_id": m.hexdigest(),
+                                        "participate": value}
+
+        with open(_POPCON_PATH, "w") as conf_file:
+            conf_file.write(config)
+
+    def get_config(self, option):
+        """Return a configuration value."""
+        if option == "AutoUpdateInterval":
+            key = "APT::Periodic::Update-Package-Lists"
+            return apt_pkg.config.find_i(key, 0)
+        elif option == "AutoDownload":
+            key = "APT::Periodic::Download-Upgradeable-Packages"
+            return apt_pkg.config.find_b(key, False)
+        elif option == "AutoCleanInterval":
+            key = "APT::Periodic::AutocleanInterval"
+            return apt_pkg.config.find_i(key, 0)
+        elif option == "UnattendedUpgrade":
+            key = "APT::Periodic::Unattended-Upgrade",
+            return apt_pkg.config.find_b(key, False)
+        elif option == "GetPopconParticipation":
+            return self._get_popcon_pariticipation()
+
+    def _get_popcon_participation(self):
+        # FIXME: Use a script to evaluate the configuration:
+        #       #!/bin/sh
+        #       . /etc/popularitiy-contest.conf
+        #       . /usr/share/popularitiy-contest/default.conf
+        #       echo $PARTICIAPTE $HOST_ID
+        if os.path.exists(_POPCON_PATH):
+            with open(_POPCON_PATH) as conf_file:
+                config = conf_file.read()
+            match = re.match("\nPARTICIPATE=\"(yes|no)\"", config)
+            if match and match[0] == "yes":
+                return True
+        return False
+
+    def get_trusted_vendor_keys(self):
+        """Return a list of trusted GPG keys."""
+        return [key.keyid for key in apt.auth.list_keys()]
+
+
+# vim:ts=4:sw=4:et
diff -pruN 1.1.1-4/.pc/fix-high-trust-pkcompat.diff/aptdaemon/worker.py 1.1.1+bzr982-0ubuntu14/.pc/fix-high-trust-pkcompat.diff/aptdaemon/worker.py
--- 1.1.1-4/.pc/fix-high-trust-pkcompat.diff/aptdaemon/worker.py	2013-08-11 19:05:47.000000000 +0000
+++ 1.1.1+bzr982-0ubuntu14/.pc/fix-high-trust-pkcompat.diff/aptdaemon/worker.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,1659 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""Provides AptWorker which processes transactions."""
-# Copyright (C) 2008-2009 Sebastian Heinlein <devel@glatzor.de>
-#
-# 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
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-__author__ = "Sebastian Heinlein <devel@glatzor.de>"
-
-__all__ = ("AptWorker", "DummyWorker")
-
-import contextlib
-import errno
-import glob
-import logging
-import netrc
-import os
-import re
-import shutil
-import stat
-import sys
-import tempfile
-import time
-import traceback
-try:
-    from urllib.parse import urlsplit, urlunsplit
-except ImportError:
-    from urlparse import urlsplit, urlunsplit
-
-try:
-    from configparser import ConfigParser
-except ImportError:
-    from ConfigParser import ConfigParser
-
-import apt
-import apt.auth
-import apt.cache
-import apt.debfile
-import apt_pkg
-import aptsources
-import aptsources.distro
-from aptsources.sourceslist import SourcesList
-from gi.repository import GObject, GLib
-import pkg_resources
-
-from .enums import *
-from .errors import *
-from . import lock
-from .progress import (
-    DaemonOpenProgress,
-    DaemonInstallProgress,
-    DaemonAcquireProgress,
-    DaemonAcquireRepoProgress,
-    DaemonDpkgInstallProgress,
-    DaemonDpkgReconfigureProgress,
-    DaemonDpkgRecoverProgress,
-    DaemonLintianProgress,
-    DaemonForkProgress)
-
-log = logging.getLogger("AptDaemon.Worker")
-
-# Just required to detect translatable strings. The translation is done by
-# core.Transaction.gettext
-_ = lambda s: s
-
-
-def trans_only_installs_pkgs_from_high_trust_repos(trans,
-                                                   whitelist=set()):
-    """Return True if this transaction only touches packages in the
-    aptdaemon repoisotry high trust repository whitelist
-    """
-    # the transaction *must* be simulated before
-    if not trans.simulated:
-        return False
-    # we never allow unauthenticated ones
-    if trans.unauthenticated:
-        return False
-    # paranoia: wrong role
-    if not trans.role in (ROLE_INSTALL_PACKAGES, ROLE_COMMIT_PACKAGES):
-        return False
-    # if there is anything touched that is not a install bail out
-    for enum in (PKGS_REINSTALL, PKGS_REMOVE, PKGS_PURGE, PKGS_DOWNGRADE,
-                 PKGS_UPGRADE):
-        if trans.packages[enum]:
-            return False
-    # paranoia(2): we must want to install something
-    if not trans.packages[PKGS_INSTALL]:
-        return False
-    # if the install packages matches the whitelisted set we are good
-    return set(trans.packages[PKGS_INSTALL]) == set(trans.high_trust_packages)
-
-
-def read_high_trust_repository_dir(whitelist_cfg_d):
-    """Return a set of (origin, component, pkgname-regexp) from a
-    high-trust-repository-whitelist.d directory
-    """
-    whitelist = set()
-    for path in glob.glob(os.path.join(whitelist_cfg_d, "*.cfg")):
-        whitelist |= _read_high_trust_repository_whitelist_file(path)
-    return whitelist
-
-
-def _read_high_trust_repository_whitelist_file(path):
-    """Read a individual high-trust-repository whitelist file and return
-       a set of tuples (origin, component, pkgname-regexp)
-    """
-    parser = ConfigParser()
-    whitelist = set()
-    try:
-        parser.read(path)
-    except Exception as e:
-        log.error("Failed to read repository whitelist '%s' (%s)" % (path, e))
-        return whitelist
-    for section in parser.sections():
-        origin = parser.get(section, "origin")
-        component = parser.get(section, "component")
-        pkgnames = parser.get(section, "pkgnames")
-        whitelist.add((origin, component, pkgnames))
-    return whitelist
-
-
-class AptWorker(GObject.GObject):
-
-    """Worker which processes transactions from the queue."""
-
-    __gsignals__ = {"transaction-done": (GObject.SignalFlags.RUN_FIRST,
-                                         None,
-                                         (GObject.TYPE_PYOBJECT,)),
-                    "transaction-simulated": (GObject.SignalFlags.RUN_FIRST,
-                                              None,
-                                              (GObject.TYPE_PYOBJECT,))}
-
-    # the basedir under which license keys can be stored
-    LICENSE_KEY_ROOTDIR = "/opt/"
-
-    def __init__(self, chroot=None, load_plugins=True):
-        """Initialize a new AptWorker instance."""
-        GObject.GObject.__init__(self)
-        self.trans = None
-        self.last_action_timestamp = time.time()
-        self._cache = None
-        # Store the the tid of the transaction whose changes are currently
-        # marked in the cache
-        self.marked_tid = None
-
-        # Change to a given chroot
-        if chroot:
-            apt_conf_file = os.path.join(chroot, "etc/apt/apt.conf")
-            if os.path.exists(apt_conf_file):
-                apt_pkg.read_config_file(apt_pkg.config, apt_conf_file)
-            apt_conf_dir = os.path.join(chroot, "etc/apt/apt.conf.d")
-            if os.path.isdir(apt_conf_dir):
-                apt_pkg.read_config_dir(apt_pkg.config, apt_conf_dir)
-            apt_pkg.config["Dir"] = chroot
-            apt_pkg.config["Dir::State::Status"] = os.path.join(
-                chroot, "var/lib/dpkg/status")
-            apt_pkg.config.clear("DPkg::Post-Invoke")
-            apt_pkg.config.clear("DPkg::Options")
-            apt_pkg.config["DPkg::Options::"] = "--root=%s" % chroot
-            apt_pkg.config["DPkg::Options::"] = ("--log=%s/var/log/dpkg.log" %
-                                                 chroot)
-            status_file = apt_pkg.config.find_file("Dir::State::status")
-            lock.status_lock.path = os.path.join(os.path.dirname(status_file),
-                                                 "lock")
-            archives_dir = apt_pkg.config.find_dir("Dir::Cache::Archives")
-            lock.archive_lock.path = os.path.join(archives_dir, "lock")
-            lists_dir = apt_pkg.config.find_dir("Dir::State::lists")
-            lock.lists_lock.path = os.path.join(lists_dir, "lock")
-            apt_pkg.init_system()
-
-        # a set of tuples of the type (origin, component, pkgname-regexp)
-        # that on install will trigger a different kind of polkit
-        # authentication request (see LP: #1035207), useful for e.g.
-        # webapps/company repos
-        self._high_trust_repositories = read_high_trust_repository_dir(
-            os.path.join(apt_pkg.config.find_dir("Dir"),
-                         "etc/aptdaemon/high-trust-repository-whitelist.d"))
-        log.debug(
-            "using high-trust whitelist: '%s'" % self._high_trust_repositories)
-
-        self._status_orig = apt_pkg.config.find_file("Dir::State::status")
-        self._status_frozen = None
-        self.plugins = {}
-        if load_plugins:
-            self._load_plugins()
-
-    def _load_plugins(self):
-        """Load the plugins from setuptools' entry points."""
-        plugin_dirs = [os.path.join(os.path.dirname(__file__), "plugins")]
-        env = pkg_resources.Environment(plugin_dirs)
-        dists, errors = pkg_resources.working_set.find_plugins(env)
-        for dist in dists:
-            pkg_resources.working_set.add(dist)
-        for name in ["modify_cache_after", "modify_cache_before",
-                     "get_license_key"]:
-            for ept in pkg_resources.iter_entry_points("aptdaemon.plugins",
-                                                       name):
-                try:
-                    self.plugins.setdefault(name, []).append(ept.load())
-                except:
-                    log.critical("Failed to load %s plugin: "
-                                 "%s" % (name, ept.dist))
-                else:
-                    log.debug("Loaded %s plugin: %s", name, ept.dist)
-
-    def _call_plugins(self, name, resolver=None):
-        """Call all plugins of a given type."""
-        if not resolver:
-            # If the resolver of the original task isn't available we create
-            # a new one and protect the already marked changes
-            resolver = apt.cache.ProblemResolver(self._cache)
-            for pkg in self._cache.get_changes():
-                resolver.clear(pkg)
-                resolver.protect(pkg)
-                if pkg.marked_delete:
-                    resolver.remove(pkg)
-        if not name in self.plugins:
-            log.debug("There isn't any registered %s plugin" % name)
-            return False
-        for plugin in self.plugins[name]:
-            log.debug("Calling %s plugin: %s", name, plugin)
-            try:
-                plugin(resolver, self._cache)
-            except Exception as error:
-                log.critical("Failed to call %s plugin:\n%s" % (plugin, error))
-        return True
-
-    def run(self, transaction):
-        """Process the given transaction in the background.
-
-        Keyword argument:
-        transaction -- core.Transcation instance to run
-        """
-        log.info("Processing transaction %s", transaction.tid)
-        if self.trans:
-            raise Exception("There is already a running transaction")
-        self.trans = transaction
-        GLib.idle_add(self._process_transaction, transaction)
-
-    def _emit_transaction_simulated(self, trans):
-        """Emit the transaction-simulated signal.
-
-        Keyword argument:
-        trans -- the simulated transaction
-        """
-        log.debug("Emitting transaction-simulated: %s", trans.tid)
-        self.emit("transaction-simulated", trans)
-
-    def _emit_transaction_done(self, trans):
-        """Emit the transaction-done signal.
-
-        Keyword argument:
-        trans -- the finished transaction
-        """
-        log.debug("Emitting transaction-done: %s", trans.tid)
-        self.emit("transaction-done", trans)
-
-    def _process_transaction(self, trans):
-        """Run the worker"""
-        self.last_action_timestamp = time.time()
-        trans.status = STATUS_RUNNING
-        trans.progress = 11
-        try:
-            lock.wait_for_lock(trans)
-            # Prepare the package cache
-            if (trans.role == ROLE_FIX_INCOMPLETE_INSTALL or
-                    not self.is_dpkg_journal_clean()):
-                self.fix_incomplete_install(trans)
-            # Process transaction which don't require a cache
-            if trans.role == ROLE_ADD_VENDOR_KEY_FILE:
-                self.add_vendor_key_from_file(trans, **trans.kwargs)
-            elif trans.role == ROLE_ADD_VENDOR_KEY_FROM_KEYSERVER:
-                self.add_vendor_key_from_keyserver(trans, **trans.kwargs)
-            elif trans.role == ROLE_REMOVE_VENDOR_KEY:
-                self.remove_vendor_key(trans, **trans.kwargs)
-            elif trans.role == ROLE_ADD_REPOSITORY:
-                self.add_repository(trans, **trans.kwargs)
-            elif trans.role == ROLE_ENABLE_DISTRO_COMP:
-                self.enable_distro_comp(trans, **trans.kwargs)
-            elif trans.role == ROLE_RECONFIGURE:
-                self.reconfigure(trans, trans.packages[PKGS_REINSTALL],
-                                 **trans.kwargs)
-            elif trans.role == ROLE_CLEAN:
-                self.clean(trans)
-            # Check if the transaction has been just simulated. So we could
-            # skip marking the changes a second time.
-            elif (trans.role in (ROLE_REMOVE_PACKAGES, ROLE_INSTALL_PACKAGES,
-                                 ROLE_UPGRADE_PACKAGES, ROLE_COMMIT_PACKAGES,
-                                 ROLE_UPGRADE_SYSTEM,
-                                 ROLE_FIX_BROKEN_DEPENDS) and
-                  self.marked_tid == trans.tid):
-                self._apply_changes(trans)
-                trans.exit = EXIT_SUCCESS
-                return False
-            else:
-                self._open_cache(trans)
-            # Process transaction which can handle a broken dep cache
-            if trans.role == ROLE_FIX_BROKEN_DEPENDS:
-                self.fix_broken_depends(trans)
-            elif trans.role == ROLE_UPDATE_CACHE:
-                self.update_cache(trans, **trans.kwargs)
-            # Process the transactions which require a consistent cache
-            elif trans.role == ROLE_ADD_LICENSE_KEY:
-                self.add_license_key(trans, **trans.kwargs)
-            elif self._cache and self._cache.broken_count:
-                raise TransactionFailed(ERROR_CACHE_BROKEN,
-                                        self._get_broken_details(trans))
-            if trans.role == ROLE_PK_QUERY:
-                self.query(trans)
-            elif trans.role == ROLE_INSTALL_FILE:
-                self.install_file(trans, **trans.kwargs)
-            elif trans.role in [ROLE_REMOVE_PACKAGES, ROLE_INSTALL_PACKAGES,
-                                ROLE_UPGRADE_PACKAGES, ROLE_COMMIT_PACKAGES]:
-                self.commit_packages(trans, *trans.packages)
-            elif trans.role == ROLE_UPGRADE_SYSTEM:
-                self.upgrade_system(trans, **trans.kwargs)
-        except TransactionCancelled:
-            trans.exit = EXIT_CANCELLED
-        except TransactionFailed as excep:
-            trans.error = excep
-            trans.exit = EXIT_FAILED
-        except (KeyboardInterrupt, SystemExit):
-            trans.exit = EXIT_CANCELLED
-        except Exception as excep:
-            tbk = traceback.format_exc()
-            trans.error = TransactionFailed(ERROR_UNKNOWN, tbk)
-            trans.exit = EXIT_FAILED
-            try:
-                from . import crash
-            except ImportError:
-                pass
-            else:
-                crash.create_report("%s: %s" % (type(excep), str(excep)),
-                                    tbk, trans)
-        else:
-            trans.exit = EXIT_SUCCESS
-        finally:
-            trans.progress = 100
-            self.last_action_timestamp = time.time()
-            tid = trans.tid[:]
-            self.trans = None
-            self.marked_tid = None
-            self._emit_transaction_done(trans)
-            lock.release()
-            log.info("Finished transaction %s", tid)
-        return False
-
-    def commit_packages(self, trans, install, reinstall, remove, purge,
-                        upgrade, downgrade, simulate=False):
-        """Perform a complex package operation.
-
-        Keyword arguments:
-        trans - the transaction
-        install - list of package names to install
-        reinstall - list of package names to reinstall
-        remove - list of package names to remove
-        purge - list of package names to purge including configuration files
-        upgrade - list of package names to upgrade
-        downgrade - list of package names to upgrade
-        simulate -- if True the changes won't be applied
-        """
-        log.info("Committing packages: %s, %s, %s, %s, %s, %s",
-                 install, reinstall, remove, purge, upgrade, downgrade)
-        with self._cache.actiongroup():
-            resolver = apt.cache.ProblemResolver(self._cache)
-            self._mark_packages_for_installation(install, resolver)
-            self._mark_packages_for_installation(reinstall, resolver,
-                                                 reinstall=True)
-            self._mark_packages_for_removal(remove, resolver)
-            self._mark_packages_for_removal(purge, resolver, purge=True)
-            self._mark_packages_for_upgrade(upgrade, resolver)
-            self._mark_packages_for_downgrade(downgrade, resolver)
-            self._resolve_depends(trans, resolver)
-        self._check_obsoleted_dependencies(trans, resolver)
-        if not simulate:
-            self._apply_changes(trans)
-
-    def _resolve_depends(self, trans, resolver):
-        """Resolve the dependencies using the given ProblemResolver."""
-        self._call_plugins("modify_cache_before", resolver)
-        resolver.install_protect()
-        try:
-            resolver.resolve()
-        except SystemError:
-            raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED,
-                                    self._get_broken_details(trans, now=False))
-        if self._call_plugins("modify_cache_after", resolver):
-            try:
-                resolver.resolve()
-            except SystemError:
-                details = self._get_broken_details(trans, now=False)
-                raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED, details)
-
-    @staticmethod
-    def _split_package_id(package):
-        """Return the name, the version number and the release of the
-        specified package."""
-        if "=" in package:
-            name, version = package.split("=", 1)
-            release = None
-        elif "/" in package:
-            name, release = package.split("/", 1)
-            version = None
-        else:
-            name = package
-            version = release = None
-        return name, version, release
-
-    def _get_high_trust_packages(self):
-        """ Return a list of packages that come from a high-trust repo """
-        def _in_high_trust_repository(pkgname, pkgorigin):
-            for origin, component, regexp in self._high_trust_repositories:
-                if (origin == pkgorigin.origin and
-                        component == pkgorigin.component and
-                        re.match(regexp, pkgname)):
-                    return True
-            return False
-        # loop
-        from_high_trust_repo = []
-        for pkg in self._cache.get_changes():
-            if pkg.marked_install:
-                for origin in pkg.candidate.origins:
-                    if _in_high_trust_repository(pkg.name, origin):
-                        from_high_trust_repo.append(pkg.name)
-                        break
-        return from_high_trust_repo
-
-    def _get_unauthenticated(self):
-        """Return a list of unauthenticated package names """
-        unauthenticated = []
-        for pkg in self._cache.get_changes():
-            if (pkg.marked_install or
-                    pkg.marked_downgrade or
-                    pkg.marked_upgrade or
-                    pkg.marked_reinstall):
-                trusted = False
-                for origin in pkg.candidate.origins:
-                    trusted |= origin.trusted
-                if not trusted:
-                    unauthenticated.append(pkg.name)
-        return unauthenticated
-
-    def _mark_packages_for_installation(self, packages, resolver,
-                                        reinstall=False):
-        """Mark packages for installation."""
-        for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
-                                           for pkg in packages]:
-            try:
-                pkg = self._cache[pkg_name]
-            except KeyError:
-                raise TransactionFailed(ERROR_NO_PACKAGE,
-                                        _("Package %s isn't available"),
-                                        pkg_name)
-            if reinstall:
-                if not pkg.is_installed:
-                    raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
-                                            _("Package %s isn't installed"),
-                                            pkg.name)
-                if pkg_ver and pkg.installed.version != pkg_ver:
-                    raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
-                                            _("The version %s of %s isn't "
-                                              "installed"),
-                                            pkg_ver, pkg_name)
-            else:
-                # Fail if the user requests to install the same version
-                # of an already installed package.
-                if (pkg.is_installed and
-                    # Compare version numbers
-                    pkg_ver and pkg_ver == pkg.installed.version and
-                    # Optionally compare the origin if specified
-                    (not pkg_rel or
-                     pkg_rel in [origin.archive for
-                                 origin in pkg.installed.origins])):
-                        raise TransactionFailed(
-                            ERROR_PACKAGE_ALREADY_INSTALLED,
-                            _("Package %s is already installed"), pkg_name)
-            pkg.mark_install(False, True, True)
-            resolver.clear(pkg)
-            resolver.protect(pkg)
-            if pkg_ver:
-                try:
-                    pkg.candidate = pkg.versions[pkg_ver]
-                except KeyError:
-                    raise TransactionFailed(ERROR_NO_PACKAGE,
-                                            _("The version %s of %s isn't "
-                                              "available."), pkg_ver, pkg_name)
-            elif pkg_rel:
-                self._set_candidate_release(pkg, pkg_rel)
-
-    def enable_distro_comp(self, trans, component):
-        """Enable given component in the sources list.
-
-        Keyword arguments:
-        trans -- the corresponding transaction
-        component -- a component, e.g. main or universe
-        """
-        trans.progress = 101
-        trans.status = STATUS_COMMITTING
-        old_umask = os.umask(0o022)
-        try:
-            sourceslist = SourcesList()
-            distro = aptsources.distro.get_distro()
-            distro.get_sources(sourceslist)
-            distro.enable_component(component)
-            sourceslist.save()
-        finally:
-            os.umask(old_umask)
-
-    def add_repository(self, trans, src_type, uri, dist, comps, comment,
-                       sourcesfile):
-        """Add given repository to the sources list.
-
-        Keyword arguments:
-        trans -- the corresponding transaction
-        src_type -- the type of the entry (deb, deb-src)
-        uri -- the main repository uri (e.g. http://archive.ubuntu.com/ubuntu)
-        dist -- the distribution to use (e.g. karmic, "/")
-        comps -- a (possible empty) list of components (main, restricted)
-        comment -- an (optional) comment
-        sourcesfile -- an (optinal) filename in sources.list.d
-        """
-        trans.progress = 101
-        trans.status = STATUS_COMMITTING
-
-        if sourcesfile:
-            if not sourcesfile.endswith(".list"):
-                sourcesfile += ".list"
-            dir = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
-            sourcesfile = os.path.join(dir, os.path.basename(sourcesfile))
-        else:
-            sourcesfile = None
-        # Store any private login information in a separate auth.conf file
-        if re.match("(http|https|ftp)://\S+?:\S+?@\S+", uri):
-            uri = self._store_and_strip_password_from_uri(uri)
-            auth_conf_path = apt_pkg.config.find_file("Dir::etc::netrc")
-            if not comment:
-                comment = "credentials stored in %s" % auth_conf_path
-            else:
-                comment += "; credentials stored in %s" % auth_conf_path
-        try:
-            sources = SourcesList()
-            entry = sources.add(src_type, uri, dist, comps, comment,
-                                file=sourcesfile)
-            if entry.invalid:
-                #FIXME: Introduce new error codes
-                raise RepositoryInvalidError()
-        except:
-            log.exception("adding repository")
-            raise
-        else:
-            sources.save()
-
-    def _store_and_strip_password_from_uri(self, uri, auth_conf_path=None):
-        """Extract the credentials from an URI. Store the password in
-        auth.conf and return the URI without any password information.
-        """
-        try:
-            res = urlsplit(uri)
-        except ValueError as error:
-            log.warn("Failed to urlsplit '%s'", error)
-            return uri
-        netloc_public = res.netloc.replace("%s:%s@" % (res.username,
-                                                       res.password),
-                                           "")
-        machine = netloc_public + res.path
-        # find auth.conf
-        if auth_conf_path is None:
-            auth_conf_path = apt_pkg.config.find_file("Dir::etc::netrc")
-
-        # read all "machine"s from the auth.conf "netrc" file
-        netrc_hosts = {}
-        netrc_hosts_as_text = ""
-        if os.path.exists(auth_conf_path):
-                netrc_hosts = netrc.netrc(auth_conf_path).hosts
-                with open(auth_conf_path, "rb") as f:
-                    netrc_hosts_as_text = f.read().decode("UTF-8")
-
-        # the new entry
-        new_netrc_entry = "\nmachine %s login %s password %s\n" % (
-            machine, res.username, res.password)
-        # if there is the same machine already defined, update it
-        # using a regexp this will ensure order/comments remain
-        if machine in netrc_hosts:
-            sub_regexp = r'machine\s+%s\s+login\s+%s\s+password\s+%s' % (
-                re.escape(machine),
-                re.escape(netrc_hosts[machine][0]),
-                re.escape(netrc_hosts[machine][2]))
-            replacement = 'machine %s login %s password %s' % (
-                machine, res.username, res.password)
-            # this may happen if e.g. the order is unexpected
-            if not re.search(sub_regexp, netrc_hosts_as_text):
-                log.warn("can not replace existing netrc entry for '%s' "
-                         "prepending it instead" % machine)
-                netrc_hosts_as_text = new_netrc_entry + netrc_hosts_as_text
-            else:
-                netrc_hosts_as_text = re.sub(
-                    sub_regexp, replacement, netrc_hosts_as_text)
-        else:
-            netrc_hosts_as_text += new_netrc_entry
-
-        # keep permssion bits of the file
-        mode = 0o640
-        try:
-            mode = os.stat(auth_conf_path)[stat.ST_MODE]
-        except OSError as e:
-            if e.errno != errno.ENO