From ecb2afe33e70b66af8e95d79afc6470e5ad3ce16 Mon Sep 17 00:00:00 2001
From: Jonathan Kang <jonathan121537@gmail.com>
Date: Wed, 3 Aug 2016 15:17:18 +0800
Subject: [PATCH] Revert "Move the D-Bus interface to gnome-software" and "Remove unused functionality"

This reverts commit 0780f7987f0dc9a0021207ea22e9b032be6b27e1 and 52b1ece4d58f407436bd74aceeca9da607c701eb

---
 configure.ac                               |    5 +
 data/Makefile.am                           |    9 +
 data/gpk-dbus-service.desktop.in           |   10 +
 data/org.freedesktop.PackageKit.service.in |    4 +
 docs/Makefile.am                           |    1 +
 docs/dbus/.gitignore                       |    3 +
 docs/dbus/Makefile.am                      |   17 +
 docs/dbus/dbus-introspect-docs.dtd         |   32 +
 docs/dbus/spec-to-docbook.xsl              |  436 ++++
 man/Makefile.am                            |    4 +
 man/gpk-dbus-service.sgml                  |   77 +
 man/gpk-install-local-file.sgml            |   77 +
 po/POTFILES.in                             |    7 +
 src/Makefile.am                            |   97 +
 src/gpk-animated-icon.c                    |  307 +++
 src/gpk-animated-icon.h                    |   72 +
 src/gpk-application.c                      |    6 +-
 src/gpk-common.c                           |   47 +
 src/gpk-common.h                           |    5 +
 src/gpk-dbus-service.c                     |  184 ++
 src/gpk-dbus-task.c                        | 3273 ++++++++++++++++++++++++++++
 src/gpk-dbus-task.h                        |  161 ++
 src/gpk-dbus.c                             |  590 +++++
 src/gpk-dbus.h                             |  124 ++
 src/gpk-enum.c                             |  139 +-
 src/gpk-enum.h                             |    8 +
 src/gpk-error.c                            |    2 +-
 src/gpk-error.h                            |    5 +
 src/gpk-gnome.c                            |   49 +
 src/gpk-gnome.h                            |   33 +
 src/gpk-helper-chooser.c                   |  348 +++
 src/gpk-helper-chooser.h                   |   65 +
 src/gpk-helper-run.c                       |  392 ++++
 src/gpk-helper-run.h                       |   61 +
 src/gpk-install-local-file.c               |  139 ++
 src/gpk-language.c                         |  196 ++
 src/gpk-language.h                         |   60 +
 src/gpk-log.c                              |    1 +
 src/gpk-marshal.list                       |    3 +
 src/gpk-modal-dialog.c                     |  861 ++++++++
 src/gpk-modal-dialog.h                     |  127 ++
 src/gpk-prefs.c                            |    1 +
 src/gpk-self-test.c                        |  219 ++
 src/gpk-session.c                          |  361 +++
 src/gpk-session.h                          |   69 +
 src/gpk-task.c                             |    1 +
 src/gpk-update-viewer.c                    |   12 +-
 src/gpk-vendor.c                           |  159 ++
 src/gpk-vendor.h                           |   70 +
 src/gpk-x11.c                              |  250 +++
 src/gpk-x11.h                              |   63 +
 src/org.freedesktop.PackageKit.xml         |  506 +++++
 53 files changed, 9754 insertions(+), 4 deletions(-)
 create mode 100644 data/gpk-dbus-service.desktop.in
 create mode 100644 data/org.freedesktop.PackageKit.service.in
 create mode 100644 docs/dbus/.gitignore
 create mode 100644 docs/dbus/Makefile.am
 create mode 100644 docs/dbus/dbus-introspect-docs.dtd
 create mode 100644 docs/dbus/spec-to-docbook.xsl
 create mode 100644 man/gpk-dbus-service.sgml
 create mode 100644 man/gpk-install-local-file.sgml
 create mode 100644 src/gpk-animated-icon.c
 create mode 100644 src/gpk-animated-icon.h
 create mode 100644 src/gpk-dbus-service.c
 create mode 100644 src/gpk-dbus-task.c
 create mode 100644 src/gpk-dbus-task.h
 create mode 100644 src/gpk-dbus.c
 create mode 100644 src/gpk-dbus.h
 create mode 100644 src/gpk-gnome.c
 create mode 100644 src/gpk-gnome.h
 create mode 100644 src/gpk-helper-chooser.c
 create mode 100644 src/gpk-helper-chooser.h
 create mode 100644 src/gpk-helper-run.c
 create mode 100644 src/gpk-helper-run.h
 create mode 100644 src/gpk-install-local-file.c
 create mode 100644 src/gpk-language.c
 create mode 100644 src/gpk-language.h
 create mode 100644 src/gpk-marshal.list
 create mode 100644 src/gpk-modal-dialog.c
 create mode 100644 src/gpk-modal-dialog.h
 create mode 100644 src/gpk-session.c
 create mode 100644 src/gpk-session.h
 create mode 100644 src/gpk-vendor.c
 create mode 100644 src/gpk-vendor.h
 create mode 100644 src/gpk-x11.c
 create mode 100644 src/gpk-x11.h
 create mode 100644 src/org.freedesktop.PackageKit.xml

Index: gnome-packagekit-3.20.0/configure.ac
===================================================================
--- gnome-packagekit-3.20.0.orig/configure.ac
+++ gnome-packagekit-3.20.0/configure.ac
@@ -92,6 +92,10 @@ PKG_CHECK_MODULES(GLIB, \
  gobject-2.0
  gio-2.0 >= 2.25.9
  gio-unix-2.0)
+PKG_CHECK_MODULES(DBUS, \
+ dbus-glib-1 >= 0.73 \
+ dbus-1 >= 1.1.2 \
+ gthread-2.0)
 PKG_CHECK_MODULES(GTK, \
  gtk+-3.0 >= 3.15.3 gdk-3.0 fontconfig)
 PKG_CHECK_MODULES(CANBERRA, libcanberra-gtk3 >= 0.10)
@@ -203,6 +207,7 @@ po/Makefile.in
 data/Makefile
 data/appdata/Makefile
 docs/Makefile
+docs/dbus/Makefile
 data/icons/Makefile
 data/icons/16x16/Makefile
 data/icons/22x22/Makefile
Index: gnome-packagekit-3.20.0/data/Makefile.am
===================================================================
--- gnome-packagekit-3.20.0.orig/data/Makefile.am
+++ gnome-packagekit-3.20.0/data/Makefile.am
@@ -9,6 +9,7 @@ dist_migration_DATA = org.gnome.packagek
 desktopdir = $(datadir)/applications
 desktop_in_files =					\
 	gpk-install-local-file.desktop.in		\
+	gpk-dbus-service.desktop.in			\
 	gpk-prefs.desktop.in				\
 	gpk-application.desktop.in			\
 	gpk-update-viewer.desktop.in			\
@@ -30,6 +31,13 @@ pkgdata_DATA =						\
 	gpk-client.ui					\
 	$(NULL)
 
+servicedir = $(datadir)/dbus-1/services
+service_in_files = org.freedesktop.PackageKit.service.in
+service_DATA = $(service_in_files:.service.in=.service)
+
+$(service_DATA): $(service_in_files) Makefile
+	@sed -e "s|\@servicedir\@|$(bindir)|" $< > $@
+
 @GSETTINGS_RULES@
 gsettings_SCHEMAS = org.gnome.packagekit.gschema.xml
 
@@ -48,6 +56,7 @@ DISTCLEANFILES =					\
 	gpk-prefs.desktop				\
 	gpk-update-viewer.desktop			\
 	gpk-install-local-file.desktop			\
+	gpk-dbus-service.desktop			\
 	gpk-log.desktop					\
 	gpk-application.desktop				\
 	org.freedesktop.PackageKit.service		\
Index: gnome-packagekit-3.20.0/data/gpk-dbus-service.desktop.in
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/data/gpk-dbus-service.desktop.in
@@ -0,0 +1,10 @@
+[Desktop Entry]
+_Name=Software Install
+_Comment=Install selected software on the system
+Categories=System;
+Exec=gpk-dbus-service
+Terminal=false
+Type=Application
+Icon=system-software-install
+StartupNotify=true
+NoDisplay=true
Index: gnome-packagekit-3.20.0/data/org.freedesktop.PackageKit.service.in
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/data/org.freedesktop.PackageKit.service.in
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=org.freedesktop.PackageKit
+Exec=@servicedir@/gpk-dbus-service
+
Index: gnome-packagekit-3.20.0/docs/Makefile.am
===================================================================
--- gnome-packagekit-3.20.0.orig/docs/Makefile.am
+++ gnome-packagekit-3.20.0/docs/Makefile.am
@@ -1 +1,2 @@
+SUBDIRS = dbus
 
Index: gnome-packagekit-3.20.0/docs/dbus/.gitignore
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/docs/dbus/.gitignore
@@ -0,0 +1,3 @@
+*.ref.xml
+*.html
+
Index: gnome-packagekit-3.20.0/docs/dbus/Makefile.am
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/docs/dbus/Makefile.am
@@ -0,0 +1,17 @@
+
+if ENABLE_GTK_DOC
+
+all : org.freedesktop.PackageKit.ref.xml
+
+org.freedesktop.PackageKit.ref.xml : $(top_srcdir)/src/org.freedesktop.PackageKit.xml $(top_srcdir)/docs/dbus/spec-to-docbook.xsl
+	echo "<?xml version=\"1.0\"?>""<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.1.2//EN\" \"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd\">" > $@
+	$(XSLTPROC) $(top_srcdir)/docs/dbus/spec-to-docbook.xsl $< | tail -n +2 >> $@
+
+#$(top_srcdir)/docs/dbus/spec-to-docbook $(top_srcdir)/src/org.freedesktop.PackageKit.xml
+
+endif
+
+EXTRA_DIST = spec-to-docbook.xsl dbus-introspect-docs.dtd
+
+clean-local :
+	rm -f *~ *.ref.xml
Index: gnome-packagekit-3.20.0/docs/dbus/dbus-introspect-docs.dtd
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/docs/dbus/dbus-introspect-docs.dtd
@@ -0,0 +1,32 @@
+<!-- DTD for D-Bus Introspection Documentation -->
+
+<!ELEMENT doc (summary?,description?,errors?,permission?,since?,deprecated,seealso?)>
+
+<!ELEMENT summary (#PCDATA|ref)*>
+<!ELEMENT description (#PCDATA|para|example)*>
+<!ELEMENT errors (error)*>
+<!ELEMENT permission (#PCDATA|ref|para)*>
+<!ELEMENT since EMPTY>
+<!ATTLIST since version CDATA #REQUIRED>
+<!ELEMENT deprecated (#PCDATA|ref)>
+<!ATTLIST deprecated version CDATA #REQUIRED>
+<!ATTLIST deprecated instead CDATA #REQUIRED>
+<!ELEMENT seealso (ref+)>
+
+<!ELEMENT error (#PCDATA|para)*>
+<!ATTLIST error name CDATA #REQUIRED>
+<!ELEMENT para (#PCDATA|example|code|list|ref)*>
+<!ELEMENT example (#PCDATA|para|code|ref)*>
+<!ATTLIST language (c|glib|python|shell) #REQUIRED>
+<!ATTLIST title CDATA #IMPLIED>
+<!ELEMENT list (listheader?, item*)>
+<!ATTLIST list type (bullet|number|table) #REQUIRED>
+<!ELEMENT item (term|definition)*>
+<!ELEMENT term (#PCDATA|ref)*>
+<!ELEMENT definition (#PCDATA|para)*>
+
+<!ELEMENT code (#PCDATA)>
+<!ATTLIST code lang CDATA #IMPLIED>
+<!ELEMENT ref CDATA>
+<!ATTLIST ref type (parameter|arg|signal|method|interface) #REQUIRED>
+<!ATTLIST ref to CDATA #REQUIRED>
Index: gnome-packagekit-3.20.0/docs/dbus/spec-to-docbook.xsl
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/docs/dbus/spec-to-docbook.xsl
@@ -0,0 +1,436 @@
+<?xml version='1.0'?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"
+  exclude-result-prefixes="doc">
+<!--
+     Convert D-Bus Glib xml into DocBook refentries
+     Copyright (C) 2007 William Jon McCann
+     License: GPL
+-->
+<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
+
+<xsl:template match="/">
+
+<xsl:variable name="interface" select="//interface/@name"/>
+<xsl:variable name="basename">
+  <xsl:call-template name="interface-basename">
+    <xsl:with-param name="str" select="$interface"/>
+  </xsl:call-template>
+</xsl:variable>
+
+<refentry><xsl:attribute name="id"><xsl:value-of select="$basename"/></xsl:attribute>
+  <refmeta>
+    <refentrytitle role="top_of_page"><xsl:value-of select="//interface/@name"/></refentrytitle>
+  </refmeta>
+
+  <refnamediv>
+    <refname><xsl:value-of select="//interface/@name"/></refname>
+    <refpurpose><xsl:value-of select="$basename"/> interface</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv role="synopsis">
+    <title role="synopsis.title">Methods</title>
+    <synopsis>
+  <xsl:call-template name="methods-synopsis">
+    <xsl:with-param name="basename" select="$basename"/>
+  </xsl:call-template>
+    </synopsis>
+  </refsynopsisdiv>
+
+  <refsect1 role="signal_proto">
+    <title role="signal_proto.title">Signals</title>
+    <synopsis>
+  <xsl:call-template name="signals-synopsis">
+    <xsl:with-param name="basename" select="$basename"/>
+  </xsl:call-template>
+    </synopsis>
+  </refsect1>
+
+  <refsect1 role="impl_interfaces">
+    <title role="impl_interfaces.title">Implemented Interfaces</title>
+    <para>
+    <xsl:value-of select="$interface"/> implements
+    org.freedesktop.DBus.Introspectable,
+    org.freedesktop.DBus.Properties
+    </para>
+  </refsect1>
+
+  <refsect1 role="properties">
+    <title role="properties.title">Properties</title>
+    <synopsis>
+  <xsl:call-template name="properties-synopsis">
+    <xsl:with-param name="basename" select="$basename"/>
+  </xsl:call-template>
+    </synopsis>
+  </refsect1>
+
+  <refsect1 role="desc">
+    <title role="desc.title">Description</title>
+    <para>
+      <xsl:apply-templates select="//interface/doc:doc"/>
+    </para>
+  </refsect1>
+
+  <refsect1 role="details">
+    <title role="details.title">Details</title>
+    <xsl:call-template name="method-details">
+      <xsl:with-param name="basename" select="$basename"/>
+    </xsl:call-template>
+  </refsect1>
+
+  <refsect1 role="signals">
+    <title role="signals.title">Signal Details</title>
+    <xsl:call-template name="signal-details">
+      <xsl:with-param name="basename" select="$basename"/>
+    </xsl:call-template>
+  </refsect1>
+
+  <refsect1 role="property_details">
+    <title role="property_details.title">Property Details</title>
+    <xsl:call-template name="property-details">
+      <xsl:with-param name="basename" select="$basename"/>
+    </xsl:call-template>
+  </refsect1>
+
+</refentry>
+</xsl:template>
+
+
+<xsl:template name="property-doc">
+  <xsl:apply-templates select="doc:doc/doc:description"/>
+
+  <variablelist role="params">
+    <xsl:for-each select="arg">
+<varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term>
+<listitem><simpara><xsl:value-of select="doc:doc/doc:summary"/></simpara></listitem>
+</varlistentry>
+    </xsl:for-each>
+  </variablelist>
+
+  <xsl:apply-templates select="doc:doc/doc:since"/>
+  <xsl:apply-templates select="doc:doc/doc:deprecated"/>
+  <xsl:apply-templates select="doc:doc/doc:permission"/>
+  <xsl:apply-templates select="doc:doc/doc:seealso"/>
+</xsl:template>
+
+
+<xsl:template name="property-details">
+  <xsl:param name="basename"/>
+  <xsl:variable name="longest">
+    <xsl:call-template name="find-longest">
+      <xsl:with-param name="set" select="@name"/>
+    </xsl:call-template>
+  </xsl:variable>
+  <xsl:for-each select="///property">
+  <refsect2>
+    <title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>:<xsl:value-of select="@name"/></xsl:attribute></anchor>The "<xsl:value-of select="@name"/>" property</title>
+<indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm>
+<programlisting>'<xsl:value-of select="@name"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="2"/></xsl:call-template>
+<xsl:call-template name="property-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/></xsl:call-template></programlisting>
+  </refsect2>
+
+  <xsl:call-template name="property-doc"/>
+
+  </xsl:for-each>
+</xsl:template>
+
+<xsl:template name="signal-doc">
+  <xsl:apply-templates select="doc:doc/doc:description"/>
+
+  <variablelist role="params">
+    <xsl:for-each select="arg">
+<varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term>
+<listitem><simpara><xsl:value-of select="doc:doc/doc:summary"/></simpara></listitem>
+</varlistentry>
+    </xsl:for-each>
+  </variablelist>
+
+  <xsl:apply-templates select="doc:doc/doc:since"/>
+  <xsl:apply-templates select="doc:doc/doc:deprecated"/>
+  <xsl:apply-templates select="doc:doc/doc:permission"/>
+  <xsl:apply-templates select="doc:doc/doc:seealso"/>
+</xsl:template>
+
+<xsl:template name="signal-details">
+  <xsl:param name="basename"/>
+  <xsl:variable name="longest">
+    <xsl:call-template name="find-longest">
+      <xsl:with-param name="set" select="@name"/>
+    </xsl:call-template>
+  </xsl:variable>
+  <xsl:for-each select="///signal">
+  <refsect2>
+    <title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>::<xsl:value-of select="@name"/></xsl:attribute></anchor>The <xsl:value-of select="@name"/> signal</title>
+<indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm>
+<programlisting><xsl:value-of select="@name"/> (<xsl:call-template name="signal-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/><xsl:with-param name="prefix" select="."/></xsl:call-template>)</programlisting>
+  </refsect2>
+
+  <xsl:call-template name="signal-doc"/>
+
+  </xsl:for-each>
+</xsl:template>
+
+<xsl:template match="doc:code">
+<programlisting>
+<xsl:apply-templates />
+</programlisting>
+</xsl:template>
+
+<xsl:template match="doc:summary">
+<!-- by default don't display -->
+</xsl:template>
+
+<xsl:template match="doc:example">
+<informalexample>
+<xsl:apply-templates />
+</informalexample>
+</xsl:template>
+
+<xsl:template match="doc:para">
+<para>
+<xsl:apply-templates />
+</para>
+</xsl:template>
+
+<xsl:template match="doc:description">
+<xsl:apply-templates />
+</xsl:template>
+
+<xsl:template match="doc:since">
+<para role="since">Since <xsl:value-of select="@version"/>
+</para>
+</xsl:template>
+
+<xsl:template match="doc:deprecated">
+  <xsl:variable name="name" select="../../@name"/>
+  <xsl:variable name="parent">
+    <xsl:call-template name="interface-basename">
+      <xsl:with-param name="str" select="../../../@name"/>/>
+    </xsl:call-template>
+  </xsl:variable>
+
+  <xsl:variable name="type" select="name(../..)"/>
+
+  <para role="deprecated">
+  <warning><para><literal><xsl:value-of select="$name"/></literal> is deprecated since version <xsl:value-of select="@version"/> and should not be used in newly-written code. Use
+
+  <xsl:variable name="to">
+  <xsl:choose>
+    <xsl:when test="contains($type,'property')">
+      <xsl:value-of select="$parent"/>:<xsl:value-of select="@instead"/>
+    </xsl:when>
+    <xsl:when test="contains($type,'signal')">
+      <xsl:value-of select="$parent"/>::<xsl:value-of select="@instead"/>
+    </xsl:when>
+    <xsl:when test="contains($type,'method')">
+      <xsl:value-of select="$parent"/>.<xsl:value-of select="@instead"/>
+    </xsl:when>
+    <xsl:when test="contains($type,'interface')">
+      <xsl:value-of select="@instead"/>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:value-of select="@instead"/>
+    </xsl:otherwise>
+  </xsl:choose>
+  </xsl:variable>
+
+  <xsl:call-template name="create-link">
+    <xsl:with-param name="type" select="$type"/>
+    <xsl:with-param name="to" select="$to"/>
+    <xsl:with-param name="val" select="@instead"/>
+  </xsl:call-template>
+instead.</para></warning>
+</para>
+</xsl:template>
+
+<xsl:template match="doc:permission">
+<para role="permission">
+<xsl:apply-templates />
+</para>
+</xsl:template>
+
+<xsl:template match="doc:seealso">
+<para>
+See also:
+<xsl:apply-templates />
+
+</para>
+</xsl:template>
+
+<xsl:template name="create-link">
+  <xsl:param name="type"/>
+  <xsl:param name="to"/>
+  <xsl:param name="val"/>
+
+  <xsl:choose>
+    <xsl:when test="contains($type,'property')">
+      <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><literal><xsl:value-of select="$val"/></literal></link>
+    </xsl:when>
+    <xsl:when test="contains($type,'signal')">
+      <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><literal><xsl:value-of select="$val"/></literal></link>
+    </xsl:when>
+    <xsl:when test="contains($type,'method')">
+      <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><function><xsl:value-of select="$val"/></function></link>
+    </xsl:when>
+    <xsl:when test="contains($type,'interface')">
+      <link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><xsl:value-of select="$val"/></link>
+    </xsl:when>
+  </xsl:choose>
+</xsl:template>
+
+<xsl:template match="doc:ref">
+  <xsl:call-template name="create-link">
+    <xsl:with-param name="type" select="@type"/>
+    <xsl:with-param name="to" select="@to"/>
+    <xsl:with-param name="val" select="."/>
+  </xsl:call-template>
+</xsl:template>
+
+<xsl:template name="method-doc">
+  <xsl:apply-templates select="doc:doc/doc:description"/>
+
+  <variablelist role="params">
+    <xsl:for-each select="arg">
+<varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term>
+<listitem><simpara><xsl:value-of select="doc:doc/doc:summary"/></simpara></listitem>
+</varlistentry>
+    </xsl:for-each>
+  </variablelist>
+
+  <xsl:apply-templates select="doc:doc/doc:since"/>
+  <xsl:apply-templates select="doc:doc/doc:deprecated"/>
+  <xsl:apply-templates select="doc:doc/doc:permission"/>
+  <xsl:apply-templates select="doc:doc/doc:seealso"/>
+</xsl:template>
+
+<xsl:template name="method-details">
+  <xsl:param name="basename"/>
+  <xsl:variable name="longest">
+    <xsl:call-template name="find-longest">
+      <xsl:with-param name="set" select="@name"/>
+    </xsl:call-template>
+  </xsl:variable>
+  <xsl:for-each select="///method">
+    <refsect2>
+    <title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>.<xsl:value-of select="@name"/></xsl:attribute></anchor><xsl:value-of select="@name"/> ()</title>
+<indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm>
+<programlisting><xsl:value-of select="@name"/> (<xsl:call-template name="method-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/><xsl:with-param name="prefix" select="."/></xsl:call-template>)</programlisting>
+    </refsect2>
+
+    <xsl:call-template name="method-doc"/>
+
+  </xsl:for-each>
+</xsl:template>
+
+
+<xsl:template name="properties-synopsis">
+  <xsl:param name="basename"/>
+  <xsl:variable name="longest">
+    <xsl:call-template name="find-longest">
+      <xsl:with-param name="set" select="///property/@name"/>
+    </xsl:call-template>
+  </xsl:variable>
+  <xsl:for-each select="///property">
+<link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>:<xsl:value-of select="@name"/></xsl:attribute>'<xsl:value-of select="@name"/>'</link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template> <xsl:call-template name="property-args"><xsl:with-param name="indent" select="$longest + 2"/></xsl:call-template>
+</xsl:for-each>
+</xsl:template>
+
+
+<xsl:template name="signals-synopsis">
+  <xsl:param name="basename"/>
+  <xsl:variable name="longest">
+    <xsl:call-template name="find-longest">
+      <xsl:with-param name="set" select="///signal/@name"/>
+    </xsl:call-template>
+  </xsl:variable>
+  <xsl:for-each select="///signal">
+<link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>::<xsl:value-of select="@name"/></xsl:attribute><xsl:value-of select="@name"/></link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template>(<xsl:call-template name="signal-args"><xsl:with-param name="indent" select="$longest + 2"/><xsl:with-param name="prefix" select="///signal"/></xsl:call-template>)
+</xsl:for-each>
+</xsl:template>
+
+
+<xsl:template name="methods-synopsis">
+  <xsl:param name="basename"/>
+  <xsl:variable name="longest">
+    <xsl:call-template name="find-longest">
+      <xsl:with-param name="set" select="///method/@name"/>
+    </xsl:call-template>
+  </xsl:variable>
+  <xsl:for-each select="///method">
+<link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>.<xsl:value-of select="@name"/></xsl:attribute><xsl:value-of select="@name"/></link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template>(<xsl:call-template name="method-args"><xsl:with-param name="indent" select="$longest + 2"/><xsl:with-param name="prefix" select="///method"/></xsl:call-template>)
+</xsl:for-each>
+</xsl:template>
+
+
+<xsl:template name="method-args"><xsl:param name="indent"/><xsl:param name="prefix"/><xsl:variable name="longest"><xsl:call-template name="find-longest"><xsl:with-param name="set" select="$prefix/arg/@type"/></xsl:call-template></xsl:variable><xsl:for-each select="arg"><xsl:value-of select="@direction"/>
+<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="4 - string-length(@direction)"/></xsl:call-template>'<xsl:value-of select="@type"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@type) + 1"/></xsl:call-template>
+<xsl:value-of select="@name"/><xsl:if test="not(position() = last())">,
+<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$indent"/></xsl:call-template></xsl:if>
+</xsl:for-each>
+</xsl:template>
+
+
+<xsl:template name="signal-args"><xsl:param name="indent"/><xsl:param name="prefix"/><xsl:variable name="longest"><xsl:call-template name="find-longest"><xsl:with-param name="set" select="$prefix/arg/@type"/></xsl:call-template></xsl:variable><xsl:for-each select="arg">'<xsl:value-of select="@type"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@type) + 1"/></xsl:call-template>
+<xsl:value-of select="@name"/><xsl:if test="not(position() = last())">,
+<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$indent"/></xsl:call-template></xsl:if>
+</xsl:for-each>
+</xsl:template>
+
+
+<xsl:template name="property-args"><xsl:param name="indent"/>
+<xsl:value-of select="@access"/><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="9 - string-length(@access) + 1"/></xsl:call-template>'<xsl:value-of select="@type"/>'
+</xsl:template>
+
+
+<xsl:template name="pad-spaces">
+  <xsl:param name="width"/>
+  <xsl:variable name="spaces" xml:space="preserve">                                                                        </xsl:variable>
+  <xsl:value-of select="substring($spaces,1,$width)"/>
+</xsl:template>
+
+
+<xsl:template name="find-longest">
+  <xsl:param name="set"/>
+  <xsl:param name="index" select="1"/>
+  <xsl:param name="longest" select="0"/>
+
+  <xsl:choose>
+    <xsl:when test="$index > count($set)">
+      <!--finished looking-->
+      <xsl:value-of select="$longest"/>
+    </xsl:when>
+    <xsl:when test="string-length($set[$index])>$longest">
+      <!--found new longest-->
+      <xsl:call-template name="find-longest">
+        <xsl:with-param name="set" select="$set"/>
+        <xsl:with-param name="index" select="$index + 1"/>
+        <xsl:with-param name="longest" select="string-length($set[$index])"/>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      <!--this isn't any longer-->
+      <xsl:call-template name="find-longest">
+        <xsl:with-param name="set" select="$set"/>
+        <xsl:with-param name="index" select="$index + 1"/>
+        <xsl:with-param name="longest" select="$longest"/>
+      </xsl:call-template>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+
+<xsl:template name="interface-basename">
+  <xsl:param name="str"/>
+  <xsl:choose>
+    <xsl:when test="contains($str,'.')">
+      <xsl:call-template name="interface-basename">
+	<xsl:with-param name="str" select="substring-after($str,'.')"/>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:value-of select="$str"/>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
Index: gnome-packagekit-3.20.0/man/Makefile.am
===================================================================
--- gnome-packagekit-3.20.0.orig/man/Makefile.am
+++ gnome-packagekit-3.20.0/man/Makefile.am
@@ -1,5 +1,7 @@
 EXTRA_DIST =						\
 	gpk-application.sgml				\
+	gpk-dbus-service.sgml				\
+	gpk-install-local-file.sgml			\
 	gpk-log.sgml					\
 	gpk-prefs.sgml					\
 	gpk-update-viewer.sgml
@@ -7,6 +9,8 @@ EXTRA_DIST =						\
 if HAVE_DOCBOOK2MAN
 man_MANS =						\
 	gpk-application.1				\
+	gpk-dbus-service.1				\
+	gpk-install-local-file.1			\
 	gpk-log.1					\
 	gpk-prefs.1					\
 	gpk-update-viewer.1
Index: gnome-packagekit-3.20.0/man/gpk-dbus-service.sgml
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/man/gpk-dbus-service.sgml
@@ -0,0 +1,77 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
+  <!-- Please adjust the date whenever revising the manpage. -->
+  <!ENTITY date        "<date>11 April,2008</date>">
+  <!ENTITY package     "gpk-dbus-service">
+  <!ENTITY gnu         "<acronym>GNU</acronym>">
+  <!ENTITY gpl         "&gnu; <acronym>GPL</acronym>">
+]>
+
+<refentry>
+  <refentryinfo>
+    <address>
+      <email>richard@hughsie.com</email>;
+    </address>
+    <author>
+      <firstname>Richard</firstname>
+      <surname>Hughes</surname>
+    </author>
+    <copyright>
+      <year>2008-2013</year>
+      <holder>Richard Hughes</holder>
+    </copyright>
+    &date;
+  </refentryinfo>
+  <refmeta>
+    <refentrytitle>gpk-dbus-service</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+  <refnamediv>
+    <refname>&package;</refname>
+    <refpurpose>GNOME PackageKit Session Service</refpurpose>
+  </refnamediv>
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>&package;</command>
+      <arg><option>--verbose</option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+  <refsect1>
+    <title>DESCRIPTION</title>
+    <para>
+      This manual page documents briefly the <command>&package;</command> command.
+    </para>
+    <para>
+      <command>&package;</command> provides the PackageKit D-Bus session API in GNOME.
+    </para>
+  </refsect1>
+  <refsect1>
+    <title>SEE ALSO</title>
+    <para>gpk-update-viewer (1).</para>
+    <para>gpk-application (2).</para>
+    <para>gpk-log (3).</para>
+    <para>gpk-install-catalog (4).</para>
+  </refsect1>
+  <refsect1>
+    <title>AUTHOR</title>
+    <para>This manual page was written by Richard Hughes <email>richard@hughsie.com</email>.
+    </para>
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
+
Index: gnome-packagekit-3.20.0/man/gpk-install-local-file.sgml
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/man/gpk-install-local-file.sgml
@@ -0,0 +1,77 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
+  <!-- Please adjust the date whenever revising the manpage. -->
+  <!ENTITY date        "<date>11 April,2008</date>">
+  <!ENTITY package     "gpk-install-local-file">
+  <!ENTITY gnu         "<acronym>GNU</acronym>">
+  <!ENTITY gpl         "&gnu; <acronym>GPL</acronym>">
+]>
+
+<refentry>
+  <refentryinfo>
+    <address>
+      <email>richard@hughsie.com</email>;
+    </address>
+    <author>
+      <firstname>Richard</firstname>
+      <surname>Hughes</surname>
+    </author>
+    <copyright>
+      <year>2008-2013</year>
+      <holder>Richard Hughes</holder>
+    </copyright>
+    &date;
+  </refentryinfo>
+  <refmeta>
+    <refentrytitle>gpk-install-local-file</refentrytitle>
+    <manvolnum>1</manvolnum>
+  </refmeta>
+  <refnamediv>
+    <refname>&package;</refname>
+    <refpurpose>GNOME PackageKit Local File Helper</refpurpose>
+  </refnamediv>
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>&package;</command>
+      <arg><option>--verbose</option></arg>
+      <arg><option>filename</option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+  <refsect1>
+    <title>DESCRIPTION</title>
+    <para>
+      This manual page documents briefly the <command>&package;</command> command.
+    </para>
+    <para>
+      <command>&package;</command> allows you to install a local package file such as an
+      rpm or deb file.
+    </para>
+  </refsect1>
+  <refsect1>
+    <title>SEE ALSO</title>
+    <para>gpk-install-package-name (1).</para>
+    <para>gpk-install-provide-file (2).</para>
+  </refsect1>
+  <refsect1>
+    <title>AUTHOR</title>
+    <para>This manual page was written by Richard Hughes <email>richard@hughsie.com</email>.
+    </para>
+  </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:2
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:nil
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+-->
+
Index: gnome-packagekit-3.20.0/po/POTFILES.in
===================================================================
--- gnome-packagekit-3.20.0.orig/po/POTFILES.in
+++ gnome-packagekit-3.20.0/po/POTFILES.in
@@ -6,6 +6,7 @@ data/appdata/gpk-update-viewer.appdata.x
 data/gpk-application.desktop.in
 [type: gettext/glade]data/gpk-application.ui
 [type: gettext/glade]data/gpk-client.ui
+data/gpk-dbus-service.desktop.in
 [type: gettext/glade]data/gpk-error.ui
 [type: gettext/glade]data/gpk-eula.ui
 data/gpk-install-local-file.desktop.in
@@ -19,11 +20,17 @@ data/gpk-update-viewer.desktop.in
 data/org.gnome.packagekit.gschema.xml
 src/gpk-application.c
 src/gpk-common.c
+src/gpk-dbus-service.c
+src/gpk-dbus-task.c
 src/gpk-debug.c
 src/gpk-dialog.c
 src/gpk-enum.c
 src/gpk-error.c
+src/gpk-helper-chooser.c
+src/gpk-helper-run.c
+src/gpk-install-local-file.c
 src/gpk-log.c
+src/gpk-modal-dialog.c
 src/gpk-prefs.c
 src/gpk-task.c
 src/gpk-update-viewer.c
Index: gnome-packagekit-3.20.0/src/Makefile.am
===================================================================
--- gnome-packagekit-3.20.0.orig/src/Makefile.am
+++ gnome-packagekit-3.20.0/src/Makefile.am
@@ -7,6 +7,7 @@ AM_CPPFLAGS =						\
 	$(GLIB_CFLAGS)					\
 	$(GIO_CFLAGS)					\
 	$(GTK_CFLAGS)					\
+	$(DBUS_CFLAGS)					\
 	$(NOTIFY_CFLAGS)				\
 	$(PACKAGEKIT_CFLAGS)				\
 	$(GUDEV_CFLAGS)					\
@@ -30,8 +31,10 @@ AM_CPPFLAGS =						\
 bin_PROGRAMS =						\
 	gpk-application					\
 	gpk-prefs					\
+	gpk-install-local-file				\
 	gpk-update-viewer				\
 	gpk-log						\
+	gpk-dbus-service				\
 	$(NULL)
 
 noinst_LIBRARIES = libgpkshared.a
@@ -44,8 +47,28 @@ libgpkshared_a_SOURCES =				\
 	gpk-debug.h					\
 	gpk-enum.c					\
 	gpk-enum.h					\
+	gpk-x11.c					\
+	gpk-x11.h					\
+	gpk-session.c					\
+	gpk-session.h					\
 	gpk-dialog.c					\
 	gpk-dialog.h					\
+	gpk-marshal.c					\
+	gpk-marshal.h					\
+	gpk-animated-icon.c				\
+	gpk-animated-icon.h				\
+	gpk-vendor.c					\
+	gpk-vendor.h					\
+	gpk-language.c					\
+	gpk-language.h					\
+	gpk-modal-dialog.c				\
+	gpk-modal-dialog.h				\
+	gpk-helper-run.c				\
+	gpk-helper-run.h				\
+	gpk-helper-chooser.c				\
+	gpk-helper-chooser.h				\
+	gpk-gnome.c					\
+	gpk-gnome.h					\
 	gpk-common.c					\
 	gpk-common.h					\
 	gpk-task.c					\
@@ -63,6 +86,7 @@ endif
 shared_LIBS =						\
 	$(GLIB_LIBS)					\
 	$(GIO_LIBS)					\
+	$(DBUS_LIBS)					\
 	$(GTK_LIBS)					\
 	$(GUDEV_LIBS)					\
 	$(NOTIFY_LIBS)					\
@@ -70,6 +94,29 @@ shared_LIBS =						\
 	$(PACKAGEKIT_LIBS)				\
 	$(GNOME_MENUS_LIBS)				\
 	$(CANBERRA_LIBS)				\
+	$(X11_LIBS)					\
+	$(NULL)
+
+gpk_install_local_file_SOURCES =			\
+	gpk-install-local-file.c			\
+	$(NULL)
+
+gpk_install_local_file_LDADD =				\
+	libgpkshared.a					\
+	$(shared_LIBS)					\
+	$(NULL)
+
+gpk_dbus_service_SOURCES =				\
+	gpk-dbus-service.c				\
+	gpk-dbus.c					\
+	gpk-dbus.h					\
+	gpk-dbus-task.c					\
+	gpk-dbus-task.h					\
+	$(NULL)
+
+gpk_dbus_service_LDADD =				\
+	libgpkshared.a					\
+	$(shared_LIBS)					\
 	$(NULL)
 
 gpk_application_SOURCES =				\
@@ -84,6 +131,8 @@ gpk_application_LDADD =					\
 gpk_prefs_SOURCES =					\
 	gpk-debug.h					\
 	gpk-debug.c					\
+	gpk-animated-icon.c				\
+	gpk-animated-icon.h				\
 	gpk-enum.c					\
 	gpk-enum.h					\
 	gpk-common.c					\
@@ -122,6 +171,26 @@ gpk_log_LDADD =						\
 	$(shared_LIBS)					\
 	$(NULL)
 
+BUILT_SOURCES = 					\
+	gpk-marshal.c					\
+	gpk-marshal.h					\
+	org.freedesktop.PackageKit.h			\
+	$(NULL)
+
+gpk-marshal.c: gpk-marshal.list
+	echo "#include \"gpk-marshal.h\"" > $@ && \
+	glib-genmarshal $< --prefix=gpk_marshal --body >> $@
+
+gpk-marshal.h: gpk-marshal.list
+	glib-genmarshal $< --prefix=gpk_marshal --header > $@
+
+org.freedesktop.PackageKit.h: org.freedesktop.PackageKit.xml
+	$(LIBTOOL) --mode=execute dbus-binding-tool	\
+		--prefix=gpk_dbus			\
+		--mode=glib-server			\
+		--output=org.freedesktop.PackageKit.h	\
+		$(srcdir)/org.freedesktop.PackageKit.xml
+
 if EGG_BUILD_TESTS
 
 check_PROGRAMS =					\
@@ -144,8 +213,30 @@ gpk_self_test_SOURCES =					\
 	gpk-common.h					\
 	gpk-error.c					\
 	gpk-error.h					\
+	gpk-dbus.c					\
+	gpk-dbus.h					\
+	gpk-dbus-task.c					\
+	gpk-dbus-task.h					\
+	gpk-x11.c					\
+	gpk-x11.h					\
 	gpk-task.c					\
 	gpk-task.h					\
+	gpk-language.c					\
+	gpk-language.h					\
+	gpk-modal-dialog.c				\
+	gpk-modal-dialog.h				\
+	gpk-animated-icon.c				\
+	gpk-animated-icon.h				\
+	gpk-gnome.c					\
+	gpk-gnome.h					\
+	gpk-vendor.c					\
+	gpk-vendor.h					\
+	gpk-helper-run.c				\
+	gpk-helper-run.h				\
+	gpk-helper-chooser.c				\
+	gpk-helper-chooser.h				\
+	gpk-marshal.c					\
+	gpk-marshal.h					\
 	gpk-dialog.c					\
 	gpk-dialog.h					\
 	$(NULL)
@@ -160,8 +251,14 @@ gpk_self_test_CFLAGS = $(AM_CFLAGS)
 TESTS = gpk-self-test
 endif
 
+EXTRA_DIST =						\
+	gpk-marshal.list				\
+	org.freedesktop.PackageKit.xml			\
+	$(NULL)
+
 clean-local:
 	rm -f *~
+	rm -f gpk-marshal.c gpk-marshal.h
 	rm -f *.out
 	rm -f *.gcda
 	rm -f *.gcno
Index: gnome-packagekit-3.20.0/src/gpk-animated-icon.c
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-animated-icon.c
@@ -0,0 +1,307 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <packagekit-glib2/packagekit.h>
+
+#include "egg-string.h"
+
+#include "gpk-animated-icon.h"
+
+G_DEFINE_TYPE (GpkAnimatedIcon, gpk_animated_icon, GTK_TYPE_IMAGE)
+
+static gpointer parent_class = NULL;
+
+/**
+ * gpk_animated_icon_free_pixbufs:
+ **/
+static gboolean
+gpk_animated_icon_free_pixbufs (GpkAnimatedIcon *icon)
+{
+	guint i;
+
+	g_return_val_if_fail (GPK_IS_ANIMATED_ICON (icon), FALSE);
+
+	/* none loaded */
+	if (icon->frames == NULL) {
+		g_debug ("nothing to free");
+		return FALSE;
+	}
+
+	/* free each frame */
+	for (i=0; i<icon->number_frames; i++)
+		g_object_unref (icon->frames[i]);
+	g_free (icon->frames);
+	icon->frames = NULL;
+	return TRUE;
+}
+
+/**
+ * gpk_animated_icon_set_icon_name:
+ **/
+gboolean
+gpk_animated_icon_set_icon_name (GpkAnimatedIcon *icon, GtkIconSize size, const gchar *name)
+{
+	g_return_val_if_fail (GPK_IS_ANIMATED_ICON (icon), FALSE);
+	g_return_val_if_fail (name != NULL, FALSE);
+
+	/* stop existing animation */
+	gpk_animated_icon_enable_animation (icon, FALSE);
+
+	/* set static image */
+	gtk_image_set_from_icon_name (GTK_IMAGE (icon), name, size);
+	return TRUE;
+}
+
+/**
+ * gpk_animated_icon_set_filename_tile:
+ **/
+gboolean
+gpk_animated_icon_set_filename_tile (GpkAnimatedIcon *icon, GtkIconSize size, const gchar *name)
+{
+	gboolean ret;
+	gint w, h;
+	gint rows, cols;
+	gint r, c, i;
+	GdkPixbuf *pixbuf;
+
+	g_return_val_if_fail (GPK_IS_ANIMATED_ICON (icon), FALSE);
+	g_return_val_if_fail (name != NULL, FALSE);
+
+	/* have we already set the same icon */
+	if (g_strcmp0 (icon->filename, name) == 0) {
+		g_debug ("already set the same icon name %s, ignoring", name);
+		return FALSE;
+	}
+
+	/* stop existing animation */
+	gpk_animated_icon_enable_animation (icon, FALSE);
+
+	/* save new value */
+	g_free (icon->filename);
+	icon->filename = g_strdup (name);
+
+	/* do we need to unload */
+	if (icon->frames != NULL) {
+		gpk_animated_icon_free_pixbufs (icon);
+	}
+
+	g_debug ("loading from %s", name);
+	ret = gtk_icon_size_lookup (size, &w, &h);
+	if (!ret) {
+		g_warning ("Can't get icon size info");
+		return FALSE;
+	}
+
+	pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), name, w, 0, NULL);
+	/* can't load from gnome-icon-theme */
+	if (pixbuf == NULL) {
+		g_debug ("can't load animation %s", name);
+		return FALSE;
+	}
+
+	/* silly hack until we get some metadata */
+	if (g_strcmp0 (name, "process-working") == 0) {
+		w = gdk_pixbuf_get_width (pixbuf) / 8;
+		h = gdk_pixbuf_get_height (pixbuf) / 4;
+	}
+
+	/* we failed to get a valid pixbuf */
+	if (w == 0 || h == 0) {
+		g_object_unref (pixbuf);
+		return FALSE;
+	}
+
+	cols = gdk_pixbuf_get_width (pixbuf) / w;
+	rows = gdk_pixbuf_get_height (pixbuf) / h;
+
+	icon->frame_counter = 0;
+	icon->number_frames = rows * cols;
+	icon->frames = g_new (GdkPixbuf*, icon->number_frames);
+
+	for (i = 0, r = 0; r < rows; r++)
+		for (c = 0; c < cols; c++, i++) {
+		icon->frames[i] = gdk_pixbuf_new_subpixbuf (pixbuf, c * w, r * h, w, h);
+	}
+
+	g_object_unref (pixbuf);
+
+	/* enable new animation */
+	gpk_animated_icon_enable_animation (icon, TRUE);
+
+	return TRUE;
+}
+
+/**
+ * gpk_animated_icon_visible_notify_cb:
+ **/
+static void
+gpk_animated_icon_visible_notify_cb (GObject *object, GParamSpec *param, GpkAnimatedIcon *icon)
+{
+	gboolean ret;
+	g_object_get (object, "visible", &ret, NULL);
+	if (!ret && icon->animation_id != 0) {
+		g_debug ("disabling animation as hidden");
+		gpk_animated_icon_enable_animation (icon, FALSE);
+	}
+}
+
+/**
+ * gpk_animated_icon_update:
+ **/
+static gboolean
+gpk_animated_icon_update (GpkAnimatedIcon *icon)
+{
+	static guint rate_limit = 0;
+
+	/* debug so we can catch polling */
+	if (rate_limit++ % 20 == 0)
+		g_debug ("polling check");
+
+	/* have we loaded a file */
+	if (icon->frames == NULL) {
+		g_warning ("no frames to process");
+		icon->animation_id = 0;
+		return FALSE;
+	}
+
+	/* set new */
+	gtk_image_set_from_pixbuf (GTK_IMAGE (icon), icon->frames[icon->frame_counter]);
+
+	/* advance counter, wrapping around */
+	icon->frame_counter = (icon->frame_counter + 1) % icon->number_frames;
+
+	return TRUE;
+}
+
+/**
+ * gpk_animated_icon_set_frame_delay:
+ **/
+gboolean
+gpk_animated_icon_set_frame_delay (GpkAnimatedIcon *icon, guint delay_ms)
+{
+	g_return_val_if_fail (GPK_IS_ANIMATED_ICON (icon), FALSE);
+
+	g_debug ("frame delay set to %ims", delay_ms);
+	icon->frame_delay = delay_ms;
+
+	/* do we have to change a running icon? */
+	if (icon->animation_id != 0) {
+		g_source_remove (icon->animation_id);
+		icon->animation_id = g_timeout_add (icon->frame_delay, (GSourceFunc) gpk_animated_icon_update, icon);
+		g_source_set_name_by_id (icon->animation_id, "[GpkAnimatedIcon] update from delay change");
+	}
+
+	return TRUE;
+}
+
+/**
+ * gpk_animated_icon_enable_animation:
+ **/
+gboolean
+gpk_animated_icon_enable_animation (GpkAnimatedIcon *icon, gboolean enabled)
+{
+	g_return_val_if_fail (GPK_IS_ANIMATED_ICON (icon), FALSE);
+
+	if (!enabled) {
+		if (icon->animation_id == 0) {
+			g_debug ("ignoring stop on stopped icon");
+			return FALSE;
+		}
+
+		g_source_remove (icon->animation_id);
+		icon->animation_id = 0;
+		return TRUE;
+	}
+
+	/* don't double queue */
+	if (icon->animation_id != 0) {
+		g_debug ("ignoring start on started icon");
+		return FALSE;
+	}
+
+	/* start */
+	icon->frame_counter = 0;
+	icon->animation_id = g_timeout_add (icon->frame_delay, (GSourceFunc) gpk_animated_icon_update, icon);
+	g_source_set_name_by_id (icon->animation_id, "[GpkAnimatedIcon] start update");
+	gpk_animated_icon_update (icon);
+	return TRUE;
+}
+
+/**
+ * gpk_animated_icon_destroy:
+ * @object: The object to destroy
+ **/
+static void
+gpk_animated_icon_destroy (GtkWidget *object)
+{
+	GpkAnimatedIcon *icon;
+	icon = GPK_ANIMATED_ICON (object);
+
+	/* avoid going pop after unref when spinning */
+	if (icon->animation_id != 0) {
+		g_source_remove (icon->animation_id);
+	}
+	g_free (icon->filename);
+	icon->filename = NULL;
+	gpk_animated_icon_free_pixbufs (icon);
+
+	GTK_WIDGET_CLASS (parent_class)->destroy (object);
+}
+
+static void
+gpk_animated_icon_class_init (GpkAnimatedIconClass *class)
+{
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+	widget_class->destroy = gpk_animated_icon_destroy;
+	parent_class = g_type_class_peek_parent (class);
+}
+
+/**
+ * gpk_animated_icon_init:
+ **/
+static void
+gpk_animated_icon_init (GpkAnimatedIcon *icon)
+{
+	g_return_if_fail (GPK_IS_ANIMATED_ICON (icon));
+	icon->frames = NULL;
+	icon->filename = NULL;
+	icon->animation_id = 0;
+	icon->frame_counter = 0;
+	icon->number_frames = 0;
+	icon->frame_delay = 200;
+
+	/* disable polling if we are hidden */
+	g_signal_connect (GTK_WIDGET (icon), "notify::visible", G_CALLBACK (gpk_animated_icon_visible_notify_cb), icon);
+}
+
+/**
+ * gpk_animated_icon_new:
+ **/
+GtkWidget *
+gpk_animated_icon_new (void)
+{
+	return g_object_new (GPK_TYPE_ANIMATED_ICON, NULL);
+}
Index: gnome-packagekit-3.20.0/src/gpk-animated-icon.h
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-animated-icon.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#ifndef GPK_ANIMATED_ICON_H
+#define GPK_ANIMATED_ICON_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#define GPK_TYPE_ANIMATED_ICON			(gpk_animated_icon_get_type())
+#define GPK_ANIMATED_ICON(obj)			(G_TYPE_CHECK_INSTANCE_CAST((obj), GPK_TYPE_ANIMATED_ICON, GpkAnimatedIcon))
+#define GPK_ANIMATED_ICON_CLASS(cls)		(G_TYPE_CHECK_CLASS_CAST((cls), GPK_TYPE_ANIMATED_ICON, GpkAnimatedIconClass))
+#define GPK_IS_ANIMATED_ICON(obj)		(G_TYPE_CHECK_INSTANCE_TYPE((obj), GPK_TYPE_ANIMATED_ICON))
+#define GPK_IS_ANIMATED_ICON_CLASS(cls)		(G_TYPE_CHECK_CLASS_TYPE((cls), GPK_TYPE_ANIMATED_ICON))
+#define GPK_ANIMATED_ICON_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), GPK_TYPE_ANIMATED_ICON, GpkAnimatedIconClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GpkAnimatedIcon			GpkAnimatedIcon;
+typedef struct _GpkAnimatedIconClass		GpkAnimatedIconClass;
+
+struct _GpkAnimatedIcon
+{
+	GtkImage		 parent;
+	gchar			*filename;
+	guint			 animation_id;
+	guint			 frame_counter;
+	guint			 number_frames;
+	guint			 frame_delay;
+	GdkPixbuf		**frames;
+};
+
+struct _GpkAnimatedIconClass
+{
+	GtkImageClass		 parent_class;
+};
+
+GType		 gpk_animated_icon_get_type		(void);
+GtkWidget	*gpk_animated_icon_new			(void);
+gboolean	 gpk_animated_icon_set_filename_tile	(GpkAnimatedIcon	*icon,
+							 GtkIconSize		 size,
+							 const gchar		*name);
+gboolean	 gpk_animated_icon_set_icon_name	(GpkAnimatedIcon	*icon,
+							 GtkIconSize		 size,
+							 const gchar		*name);
+gboolean	 gpk_animated_icon_set_frame_delay	(GpkAnimatedIcon	*icon,
+							 guint			 delay_ms);
+gboolean	 gpk_animated_icon_enable_animation	(GpkAnimatedIcon	*icon,
+							 gboolean		 enabled);
+
+G_END_DECLS
+
+#endif /* GPK_ANIMATED_ICON_H */
+
Index: gnome-packagekit-3.20.0/src/gpk-application.c
===================================================================
--- gnome-packagekit-3.20.0.orig/src/gpk-application.c
+++ gnome-packagekit-3.20.0/src/gpk-application.c
@@ -21,6 +21,7 @@
 
 #include "config.h"
 
+#include <dbus/dbus-glib.h>
 #include <errno.h>
 #include <gdk/gdkkeysyms.h>
 #include <gdk/gdkx.h>
@@ -42,6 +43,8 @@
 #include "gpk-dialog.h"
 #include "gpk-enum.h"
 #include "gpk-error.h"
+#include "gpk-gnome.h"
+#include "gpk-helper-run.h"
 #include "gpk-task.h"
 #include "gpk-debug.h"
 
@@ -505,7 +508,7 @@ out:
 static void
 gpk_application_menu_homepage_cb (GtkAction *action, GpkApplicationPrivate *priv)
 {
-	gtk_show_uri (NULL, priv->homepage_url, GDK_CURRENT_TIME, NULL);
+	gpk_gnome_open (priv->homepage_url);
 }
 
 /**
@@ -3433,6 +3436,7 @@ main (int argc, char *argv[])
 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 	textdomain (GETTEXT_PACKAGE);
 
+	dbus_g_thread_init ();
 	gtk_init (&argc, &argv);
 
 	context = g_option_context_new (NULL);
Index: gnome-packagekit-3.20.0/src/gpk-common.c
===================================================================
--- gnome-packagekit-3.20.0.orig/src/gpk-common.c
+++ gnome-packagekit-3.20.0/src/gpk-common.c
@@ -49,6 +49,21 @@
 /* static, so local to process */
 static gboolean small_form_factor_mode = FALSE;
 
+gchar **
+pk_package_array_to_strv (GPtrArray *array)
+{
+	PkPackage *item;
+	gchar **results;
+	guint i;
+
+	results = g_new0 (gchar *, array->len+1);
+	for (i=0; i<array->len; i++) {
+		item = g_ptr_array_index (array, i);
+		results[i] = g_strdup (pk_package_get_id (item));
+	}
+	return results;
+}
+
 /**
  * pk_strv_to_ptr_array:
  * @array: the gchar** array of strings
@@ -320,6 +335,38 @@ out:
 }
 
 /**
+ * gpk_set_animated_icon_from_status:
+ **/
+gboolean
+gpk_set_animated_icon_from_status (GpkAnimatedIcon *icon, PkStatusEnum status, GtkIconSize size)
+{
+	const gchar *name = NULL;
+	guint delay = 0;
+
+	/* see if there is an animation */
+	name = gpk_status_enum_to_animation (status);
+
+	/* get the timing */
+	if (g_str_has_prefix (name, "pk-action-"))
+		delay = 150;
+	else if (g_str_has_prefix (name, "process-working"))
+		delay = 50;
+
+	/* animate or set static */
+	if (delay != 0) {
+		gpk_animated_icon_set_frame_delay (icon, delay);
+		gpk_animated_icon_set_filename_tile (icon, size, name);
+	} else {
+		gpk_animated_icon_set_icon_name (icon, size, name);
+	}
+
+	/* stop spinning */
+	if (status == PK_STATUS_ENUM_FINISHED)
+		gpk_animated_icon_enable_animation (icon, FALSE);
+	return TRUE;
+}
+
+/**
  * gpk_time_to_imprecise_string:
  * @time_secs: The time value to convert in seconds
  *
Index: gnome-packagekit-3.20.0/src/gpk-common.h
===================================================================
--- gnome-packagekit-3.20.0.orig/src/gpk-common.h
+++ gnome-packagekit-3.20.0/src/gpk-common.h
@@ -26,6 +26,7 @@
 #include <gtk/gtk.h>
 #include <packagekit-glib2/packagekit.h>
 
+#include "gpk-animated-icon.h"
 #include "gpk-enum.h"
 
 G_BEGIN_DECLS
@@ -69,6 +70,9 @@ gchar		*gpk_time_to_localised_string		(g
 gchar		*gpk_time_to_imprecise_string		(guint		 time_secs);
 gboolean	 gpk_check_privileged_user		(const gchar	*application_name,
 							 gboolean	 show_ui);
+gboolean	 gpk_set_animated_icon_from_status	(GpkAnimatedIcon *icon,
+							 PkStatusEnum	 status,
+							 GtkIconSize	 size);
 gchar		*gpk_strv_join_locale			(gchar		**array);
 GtkEntryCompletion *gpk_package_entry_completion_new	(void);
 gboolean	 gpk_window_set_size_request		(GtkWindow	*window,
@@ -78,6 +82,7 @@ gboolean	 gpk_window_set_parent_xid		(Gt
 							 guint32	 xid);
 GPtrArray	*pk_strv_to_ptr_array			(gchar		**array)
 							 G_GNUC_WARN_UNUSED_RESULT;
+gchar		**pk_package_array_to_strv		(GPtrArray	*array);
 
 G_END_DECLS
 
Index: gnome-packagekit-3.20.0/src/gpk-dbus-service.c
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-dbus-service.c
@@ -0,0 +1,184 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007-2009 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <dbus/dbus-glib.h>
+#include <gtk/gtk.h>
+#include <locale.h>
+#include <libnotify/notify.h>
+#include <packagekit-glib2/packagekit.h>
+
+#include "gpk-common.h"
+#include "gpk-dbus.h"
+#include "gpk-debug.h"
+
+#include "org.freedesktop.PackageKit.h"
+
+static GMainLoop *loop = NULL;
+
+#define GPK_SESSION_IDLE_EXIT	60 /* seconds */
+
+/**
+ * gpk_dbus_service_object_register:
+ * @connection: What we want to register to
+ * @object: The GObject we want to register
+ *
+ * Return value: success
+ **/
+static gboolean
+gpk_dbus_service_object_register (DBusGConnection *connection, GObject *object)
+{
+	DBusGProxy *bus_proxy = NULL;
+	GError *error = NULL;
+	guint request_name_result;
+	gboolean ret;
+
+	/* connect to the bus */
+	bus_proxy = dbus_g_proxy_new_for_name (connection, DBUS_SERVICE_DBUS,
+					       DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
+
+	/* get our name */
+	ret = dbus_g_proxy_call (bus_proxy, "RequestName", &error,
+				 G_TYPE_STRING, PK_DBUS_SERVICE,
+				 G_TYPE_UINT, DBUS_NAME_FLAG_ALLOW_REPLACEMENT |
+					      DBUS_NAME_FLAG_REPLACE_EXISTING |
+					      DBUS_NAME_FLAG_DO_NOT_QUEUE,
+				 G_TYPE_INVALID,
+				 G_TYPE_UINT, &request_name_result,
+				 G_TYPE_INVALID);
+	if (!ret) {
+		/* abort as the D-Bus method failed */
+		g_warning ("RequestName failed: %s", error->message);
+		g_error_free (error);
+		return FALSE;
+	}
+
+	/* free the bus_proxy */
+	g_object_unref (G_OBJECT (bus_proxy));
+
+	/* already running */
+	if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+		return FALSE;
+
+	dbus_g_object_type_install_info (GPK_TYPE_DBUS, &dbus_glib_gpk_dbus_object_info);
+	dbus_g_error_domain_register (GPK_DBUS_ERROR, NULL, GPK_DBUS_TYPE_ERROR);
+	dbus_g_connection_register_g_object (connection, PK_DBUS_PATH, object);
+
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_service_check_idle_cb:
+ **/
+static gboolean
+gpk_dbus_service_check_idle_cb (GpkDbus *dbus)
+{
+	guint idle;
+
+	/* get the idle time */
+	idle = gpk_dbus_get_idle_time (dbus);
+	if (idle > GPK_SESSION_IDLE_EXIT) {
+		g_debug ("exiting loop as idle");
+		g_main_loop_quit (loop);
+		return FALSE;
+	}
+	/* continue to poll */
+	return TRUE;
+}
+
+/**
+ * main:
+ **/
+int
+main (int argc, char *argv[])
+{
+	gboolean no_timed_exit = FALSE;
+	GpkDbus *dbus = NULL;
+	GOptionContext *context;
+	GError *error = NULL;
+	gboolean ret;
+	guint retval = 0;
+	DBusGConnection *connection;
+	guint timer_id = 0;
+
+	const GOptionEntry options[] = {
+		{ "no-timed-exit", '\0', 0, G_OPTION_ARG_NONE, &no_timed_exit,
+		  _("Do not exit after the request has been processed"), NULL },
+		{ NULL}
+	};
+
+	setlocale (LC_ALL, "");
+
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+	textdomain (GETTEXT_PACKAGE);
+
+	dbus_g_thread_init ();
+	notify_init (_("Software Install"));
+
+	/* TRANSLATORS: program name, a session wide daemon to watch for updates and changing system state */
+	g_set_application_name (_("Software Install"));
+	context = g_option_context_new (NULL);
+	g_option_context_set_summary (context, _("Session D-Bus service for PackageKit"));
+	g_option_context_add_main_entries (context, options, NULL);
+	g_option_context_add_group (context, gpk_debug_get_option_group ());
+	g_option_context_add_group (context, gtk_get_option_group (TRUE));
+	g_option_context_parse (context, &argc, &argv, NULL);
+	g_option_context_free (context);
+
+	gtk_init (&argc, &argv);
+
+	/* create new objects */
+	dbus = gpk_dbus_new ();
+	loop = g_main_loop_new (NULL, FALSE);
+
+	/* get the bus */
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+	if (error) {
+		g_warning ("%s", error->message);
+		g_error_free (error);
+		retval = 1;
+		goto out;
+	}
+
+	/* try to register */
+	ret = gpk_dbus_service_object_register (connection, G_OBJECT (dbus));
+	if (!ret) {
+		g_warning ("failed to replace running instance.");
+		retval = 1;
+		goto out;
+	}
+
+	/* only timeout if we have specified iton the command line */
+	if (!no_timed_exit) {
+		timer_id = g_timeout_add_seconds (5, (GSourceFunc) gpk_dbus_service_check_idle_cb, dbus);
+		g_source_set_name_by_id (timer_id, "[GpkDbusService] timed exit");
+	}
+
+	/* wait */
+	g_main_loop_run (loop);
+out:
+	g_main_loop_unref (loop);
+	g_object_unref (dbus);
+	return retval;
+}
Index: gnome-packagekit-3.20.0/src/gpk-dbus-task.c
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-dbus-task.c
@@ -0,0 +1,3273 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+#include <string.h>
+#include <glib/gi18n.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+
+#include <fontconfig/fontconfig.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <libnotify/notify.h>
+#include <packagekit-glib2/packagekit.h>
+
+#include "egg-string.h"
+
+#include "gpk-common.h"
+#include "gpk-dbus.h"
+#include "gpk-dbus-task.h"
+#include "gpk-dialog.h"
+#include "gpk-enum.h"
+#include "gpk-error.h"
+#include "gpk-gnome.h"
+#include "gpk-helper-chooser.h"
+#include "gpk-helper-run.h"
+#include "gpk-language.h"
+#include "gpk-modal-dialog.h"
+#include "gpk-task.h"
+#include "gpk-vendor.h"
+#include "gpk-x11.h"
+
+static void gpk_dbus_task_finalize (GObject *object);
+static void gpk_dbus_task_progress_cb (PkProgress *progress, PkProgressType type, GpkDbusTask *dtask);
+
+#define GPK_DBUS_TASK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_DBUS_TASK, GpkDbusTaskPrivate))
+#define GPK_DBUS_TASK_FINISHED_AUTOCLOSE_DELAY	10 /* seconds */
+
+/**
+ * GpkDbusTaskPrivate:
+ *
+ * Private #GpkDbusTask data
+ **/
+struct _GpkDbusTaskPrivate
+{
+	GdkWindow		*parent_window;
+	GSettings		*settings;
+	PkTask			*task;
+	PkControl		*control;
+	PkExitEnum		 exit;
+	PkBitfield		 roles;
+	GpkLanguage		*language;
+	GpkModalDialog		*dialog;
+	GpkVendor		*vendor;
+	gboolean		 show_confirm_search;
+	gboolean		 show_confirm_deps;
+	gboolean		 show_confirm_install;
+	gboolean		 show_progress;
+	gboolean		 show_finished;
+	gboolean		 show_warning;
+	guint			 timestamp;
+	gchar			*parent_title;
+	gchar			*parent_icon_name;
+	gchar			*exec;
+	PkError			*cached_error_code;
+	gint			 timeout;
+	GpkHelperRun		*helper_run;
+	GpkHelperChooser	*helper_chooser;
+	DBusGMethodInvocation	*context;
+	gchar			**package_ids;
+	gchar			**files;
+	GCancellable		*cancellable;
+	GpkDbusTaskFinishedCb	 finished_cb;
+	gpointer		 finished_userdata;
+};
+
+G_DEFINE_TYPE (GpkDbusTask, gpk_dbus_task, G_TYPE_OBJECT)
+
+/**
+ * gpk_dbus_task_set_interaction:
+ **/
+gboolean
+gpk_dbus_task_set_interaction (GpkDbusTask *dtask, PkBitfield interact)
+{
+	g_return_val_if_fail (GPK_IS_DBUS_TASK (dtask), FALSE);
+
+	dtask->priv->show_confirm_search = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_CONFIRM_SEARCH);
+	dtask->priv->show_confirm_deps = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_CONFIRM_DEPS);
+	dtask->priv->show_confirm_install = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_CONFIRM_INSTALL);
+	dtask->priv->show_progress = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_PROGRESS);
+	dtask->priv->show_finished = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_FINISHED);
+	dtask->priv->show_warning = pk_bitfield_contain (interact, GPK_CLIENT_INTERACT_WARNING);
+
+	/* debug */
+	g_debug ("confirm_search:%i, confirm_deps:%i, confirm_install:%i, progress:%i, finished:%i, warning:%i",
+		   dtask->priv->show_confirm_search, dtask->priv->show_confirm_deps,
+		   dtask->priv->show_confirm_install, dtask->priv->show_progress,
+		   dtask->priv->show_finished, dtask->priv->show_warning);
+
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_set_context:
+ **/
+gboolean
+gpk_dbus_task_set_context (GpkDbusTask *dtask, DBusGMethodInvocation *context)
+{
+	g_return_val_if_fail (GPK_IS_DBUS_TASK (dtask), FALSE);
+	g_return_val_if_fail (context != NULL, FALSE);
+
+	dtask->priv->context = context;
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_set_xid:
+ **/
+gboolean
+gpk_dbus_task_set_xid (GpkDbusTask *dtask, guint32 xid)
+{
+	GdkDisplay *display;
+	g_return_val_if_fail (GPK_IS_DBUS_TASK (dtask), FALSE);
+
+	display = gdk_display_get_default ();
+	dtask->priv->parent_window = gdk_x11_window_foreign_new_for_display (display, xid);
+	g_debug ("parent_window=%p", dtask->priv->parent_window);
+	gpk_modal_dialog_set_parent (dtask->priv->dialog, dtask->priv->parent_window);
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_set_timestamp:
+ **/
+gboolean
+gpk_dbus_task_set_timestamp (GpkDbusTask *dtask, guint32 timestamp)
+{
+	g_return_val_if_fail (GPK_IS_DBUS_TASK (dtask), FALSE);
+	dtask->priv->timestamp = timestamp;
+	return TRUE;
+}
+
+static void gpk_dbus_task_install_package_ids (GpkDbusTask *dtask);
+
+/**
+ * gpk_dbus_task_dbus_return_error:
+ **/
+static void
+gpk_dbus_task_dbus_return_error (GpkDbusTask *dtask, const GError *error)
+{
+	g_return_if_fail (error != NULL);
+
+	/* already sent or never setup */
+	if (dtask->priv->context == NULL) {
+		g_error ("context does not exist, cannot return: %s", error->message);
+		goto out;
+	}
+
+	/* send error */
+	g_debug ("sending async return error in response to %p: %s", dtask->priv->context, error->message);
+	dbus_g_method_return_error (dtask->priv->context, error);
+
+	/* set context NULL just in case we try to repeat */
+	dtask->priv->context = NULL;
+
+	/* do the finish callback */
+	if (dtask->priv->finished_cb)
+		dtask->priv->finished_cb (dtask, dtask->priv->finished_userdata);
+out:
+	/* we can't touch dtask now, as it might have been unreffed in the finished callback */
+	return;
+}
+
+/**
+ * gpk_dbus_task_dbus_return_value:
+ **/
+static void
+gpk_dbus_task_dbus_return_value (GpkDbusTask *dtask, gboolean ret)
+{
+	/* already sent or never setup */
+	if (dtask->priv->context == NULL) {
+		g_error ("context does not exist, cannot return %i", ret);
+		goto out;
+	}
+
+	/* send error */
+	g_debug ("sending async return in response to %p: %i", dtask->priv->context, ret);
+	dbus_g_method_return (dtask->priv->context, ret);
+
+	/* set context NULL just in case we try to repeat */
+	dtask->priv->context = NULL;
+
+	/* do the finish callback */
+	if (dtask->priv->finished_cb)
+		dtask->priv->finished_cb (dtask, dtask->priv->finished_userdata);
+out:
+	/* we can't touch dtask now, as it might have been unreffed in the finished callback */
+	return;
+}
+
+/**
+ * gpk_dbus_task_chooser_event_cb:
+ **/
+static void
+gpk_dbus_task_chooser_event_cb (GpkHelperChooser *helper_chooser, GtkResponseType type, const gchar *package_id, GpkDbusTask *dtask)
+{
+	GError *error_dbus = NULL;
+
+	/* selected nothing */
+	if (type != GTK_RESPONSE_YES || package_id == NULL) {
+
+		/* failed */
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not choose anything to install");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+
+		if (dtask->priv->show_warning) {
+			gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+			/* TRANSLATORS: we failed to install */
+			gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to install software"));
+			/* TRANSLATORS: we didn't select any applications that were returned */
+			gpk_modal_dialog_set_message (dtask->priv->dialog, _("No applications were chosen to be installed"));
+			gpk_modal_dialog_present (dtask->priv->dialog);
+			gpk_modal_dialog_run (dtask->priv->dialog);
+		}
+		goto out;
+	}
+
+	/* install this specific package */
+	dtask->priv->package_ids = pk_package_ids_from_id (package_id);
+
+	/* install these packages with deps */
+	gpk_dbus_task_install_package_ids (dtask);
+out:
+	return;
+}
+
+/**
+ * gpk_dbus_task_libnotify_cb:
+ **/
+static void
+gpk_dbus_task_libnotify_cb (NotifyNotification *notification, gchar *action, gpointer data)
+{
+	GpkDbusTask *task = GPK_DBUS_TASK (data);
+	gchar *details;
+
+	if (task->priv->cached_error_code == NULL) {
+		g_warning ("called show error with no error!");
+		return;
+	}
+	if (g_strcmp0 (action, "show-error-details") == 0) {
+		details = g_markup_escape_text (pk_error_get_details (task->priv->cached_error_code), -1);
+		/* TRANSLATORS: detailed text about the error */
+		gpk_error_dialog (_("Error details"), _("Package Manager error details"), details);
+		g_free (details);
+	} else {
+		g_warning ("unknown action id: %s", action);
+	}
+}
+
+/**
+ * gpk_dbus_task_error_msg:
+ **/
+static void
+gpk_dbus_task_error_msg (GpkDbusTask *dtask, const gchar *title, GError *error)
+{
+	GtkWindow *window;
+	/* TRANSLATORS: default fallback error -- this should never happen */
+	const gchar *message = _("Unknown error. Please refer to the detailed report and report in your distribution bug tracker.");
+	const gchar *details = NULL;
+
+	if (!dtask->priv->show_warning)
+		return;
+
+	/* setup UI */
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+
+	/* print a proper error if we have it */
+	if (error != NULL) {
+		if (error->domain == GPK_DBUS_ERROR) {
+			message = gpk_error_enum_to_localised_message (error->code);
+		}
+	}
+
+	/* it's a normal UI, not a backtrace so keep in the UI */
+	if (details == NULL) {
+		gpk_modal_dialog_set_title (dtask->priv->dialog, title);
+		gpk_modal_dialog_set_message (dtask->priv->dialog, message);
+		gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp);
+		gpk_modal_dialog_run (dtask->priv->dialog);
+		return;
+	}
+
+	/* hide the main window */
+	window = gpk_modal_dialog_get_window (dtask->priv->dialog);
+	gpk_error_dialog_modal_with_time (window, title, message, details, dtask->priv->timestamp);
+}
+
+/**
+ * gpk_dbus_task_handle_error:
+ **/
+static void
+gpk_dbus_task_handle_error (GpkDbusTask *dtask, PkError *error_code)
+{
+	gboolean ret;
+	GError *error = NULL;
+	const gchar *title;
+	const gchar *message;
+	NotifyNotification *notification;
+	GtkWidget *widget;
+
+	/* ignore some errors */
+	if (pk_error_get_code (error_code) == PK_ERROR_ENUM_NO_LICENSE_AGREEMENT ||
+	    pk_error_get_code (error_code) == PK_ERROR_ENUM_PROCESS_KILL ||
+	    pk_error_get_code (error_code) == PK_ERROR_ENUM_TRANSACTION_CANCELLED) {
+		g_warning ("ignoring %s", pk_error_enum_to_string (pk_error_get_code (error_code)));
+	}
+
+	g_debug ("code was %s", pk_error_enum_to_string (pk_error_get_code (error_code)));
+
+	/* use a modal dialog if showing progress, else use libnotify */
+	title = gpk_error_enum_to_localised_text (pk_error_get_code (error_code));
+	message = gpk_error_enum_to_localised_message (pk_error_get_code (error_code));
+	if (dtask->priv->show_progress) {
+		widget = GTK_WIDGET (gpk_modal_dialog_get_window (dtask->priv->dialog));
+		gpk_error_dialog_modal (GTK_WINDOW (widget), title, message, pk_error_get_details (error_code));
+		return;
+	}
+
+	/* save this globally */
+	if (dtask->priv->cached_error_code != NULL)
+		g_object_unref (dtask->priv->cached_error_code);
+	dtask->priv->cached_error_code = g_object_ref (error_code);
+
+	/* do the bubble */
+	notification = notify_notification_new (title, message, NULL);
+	notify_notification_set_hint_string (notification, "desktop-entry", "gpk-application");
+	notify_notification_set_timeout (notification, 15000);
+	notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW);
+	notify_notification_add_action (notification, "show-error-details",
+					/* TRANSLATORS: button: show details about the error */
+					_("Show details"), gpk_dbus_task_libnotify_cb, dtask, NULL);
+	ret = notify_notification_show (notification, &error);
+	if (!ret) {
+		g_warning ("error: %s", error->message);
+		g_error_free (error);
+	}
+}
+
+/**
+ * gpk_dbus_task_get_code_from_gerror:
+ **/
+static gint
+gpk_dbus_task_get_code_from_gerror (const GError *error)
+{
+	gint code = PK_ERROR_ENUM_INTERNAL_ERROR;
+
+	/* already correct */
+	if (error->domain == GPK_DBUS_ERROR) {
+		code = error->code;
+		goto out;
+	}
+
+	/* not recognized */
+	if (error->domain != PK_CLIENT_ERROR) {
+		g_warning ("Not a PkClientError error code");
+		goto out;
+	}
+
+	/* PkError codes */
+	if (error->code > 0xff) {
+		code = error->code - 0xff;
+		goto out;
+	}
+
+	/* map return codes to PkError codes */
+	switch (error->code) {
+	case PK_CLIENT_ERROR_NO_TID:
+	case PK_CLIENT_ERROR_ALREADY_TID:
+	case PK_CLIENT_ERROR_ROLE_UNKNOWN:
+	case PK_CLIENT_ERROR_CANNOT_START_DAEMON:
+	case PK_CLIENT_ERROR_NOT_SUPPORTED:
+		code = PK_ERROR_ENUM_INTERNAL_ERROR;
+		break;
+	case PK_CLIENT_ERROR_INVALID_INPUT:
+	case PK_CLIENT_ERROR_INVALID_FILE:
+	case PK_CLIENT_ERROR_FAILED:
+		code = PK_ERROR_ENUM_UNKNOWN;
+		break;
+	case PK_CLIENT_ERROR_DECLINED_SIMULATION:
+		code = PK_ERROR_ENUM_TRANSACTION_CANCELLED;
+		break;
+	case PK_CLIENT_ERROR_FAILED_AUTH:
+		code = PK_ERROR_ENUM_NOT_AUTHORIZED;
+		break;
+	default:
+		break;
+	}
+out:
+	return code;
+}
+
+/**
+ * gpk_dbus_task_get_code_from_pkerror:
+ **/
+static gint
+gpk_dbus_task_get_code_from_pkerror (PkError *error_code)
+{
+	gint code = PK_ERROR_ENUM_UNKNOWN;
+
+	switch (pk_error_get_code (error_code)) {
+	case PK_ERROR_ENUM_TRANSACTION_CANCELLED:
+		code = PK_ERROR_ENUM_TRANSACTION_CANCELLED;
+		break;
+	default:
+		break;
+	}
+	return code;
+}
+
+/**
+ * gpk_dbus_task_install_packages_cb:
+ **/
+static void
+gpk_dbus_task_install_packages_cb (PkTask *task, GAsyncResult *res, GpkDbusTask *dtask)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	PkResults *results = NULL;
+	PkError *error_code = NULL;
+
+	/* get the results */
+	results = pk_task_generic_finish (task, res, &error);
+	if (results == NULL) {
+		/* TRANSLATORS: error: failed to install, detailed error follows */
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "%s", error->message);
+		gpk_dbus_task_error_msg (dtask, _("Failed to install software"), error_dbus);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* check error code */
+	error_code = pk_results_get_error_code (results);
+	if (error_code != NULL) {
+		g_warning ("failed to install package: %s, %s", pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code));
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "%s", pk_error_get_details (error_code));
+		gpk_dbus_task_handle_error (dtask, error_code);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* we're done */
+	gpk_dbus_task_dbus_return_value (dtask, TRUE);
+out:
+	if (error_code != NULL)
+		g_object_unref (error_code);
+	if (results != NULL)
+		g_object_unref (results);
+}
+
+/**
+ * gpk_dbus_task_install_package_ids:
+ * @task: a valid #GpkDbusTask instance
+ **/
+static void
+gpk_dbus_task_install_package_ids (GpkDbusTask *dtask)
+{
+	GtkWindow *window;
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING);
+	/* TRANSLATORS: title: installing packages */
+	gpk_modal_dialog_set_title (dtask->priv->dialog, _("Installing packages"));
+	if (dtask->priv->show_progress)
+		gpk_modal_dialog_present (dtask->priv->dialog);
+
+	/* ensure parent is set */
+	window = gpk_modal_dialog_get_window (dtask->priv->dialog);
+	gpk_task_set_parent_window (GPK_TASK (dtask->priv->task), window);
+
+	/* install async */
+	pk_task_install_packages_async (dtask->priv->task, dtask->priv->package_ids, NULL,
+					(PkProgressCallback) gpk_dbus_task_progress_cb, dtask,
+					(GAsyncReadyCallback) gpk_dbus_task_install_packages_cb, dtask);
+}
+
+/**
+ * gpk_dbus_task_set_status:
+ **/
+static gboolean
+gpk_dbus_task_set_status (GpkDbusTask *dtask, PkStatusEnum status)
+{
+	g_return_val_if_fail (GPK_IS_DBUS_TASK (dtask), FALSE);
+
+	/* do we force progress? */
+	if (!dtask->priv->show_progress) {
+		if (status == PK_STATUS_ENUM_DOWNLOAD_REPOSITORY ||
+		    status == PK_STATUS_ENUM_DOWNLOAD_PACKAGELIST ||
+		    status == PK_STATUS_ENUM_DOWNLOAD_FILELIST ||
+		    status == PK_STATUS_ENUM_DOWNLOAD_CHANGELOG ||
+		    status == PK_STATUS_ENUM_DOWNLOAD_GROUP ||
+		    status == PK_STATUS_ENUM_DOWNLOAD_UPDATEINFO ||
+		    status == PK_STATUS_ENUM_REFRESH_CACHE) {
+			gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+			gpk_modal_dialog_present_with_time (dtask->priv->dialog, 0);
+		}
+	}
+
+	/* ignore */
+	if (!dtask->priv->show_progress) {
+		g_warning ("not showing progress");
+		return FALSE;
+	}
+
+	/* set icon */
+	gpk_modal_dialog_set_image_status (dtask->priv->dialog, status);
+
+	/* set label */
+	gpk_modal_dialog_set_title (dtask->priv->dialog, gpk_status_enum_to_localised_text (status));
+
+	/* spin */
+	if (status == PK_STATUS_ENUM_WAIT)
+		gpk_modal_dialog_set_percentage (dtask->priv->dialog, -1);
+
+	/* do visual stuff when finished */
+	if (status == PK_STATUS_ENUM_FINISHED) {
+		/* make insensitive */
+		gpk_modal_dialog_set_allow_cancel (dtask->priv->dialog, FALSE);
+
+		/* stop spinning */
+		gpk_modal_dialog_set_percentage (dtask->priv->dialog, 100);
+	}
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_button_close_cb:
+ **/
+static void
+gpk_dbus_task_button_close_cb (GtkWidget *widget, GpkDbusTask *dtask)
+{
+	/* close, don't abort */
+	gpk_modal_dialog_close (dtask->priv->dialog);
+}
+
+/**
+ * gpk_dbus_task_button_cancel_cb:
+ **/
+static void
+gpk_dbus_task_button_cancel_cb (GtkWidget *widget, GpkDbusTask *dtask)
+{
+	/* we might have a transaction running */
+	g_cancellable_cancel (dtask->priv->cancellable);
+}
+
+/**
+ * gpk_dbus_task_install_files_cb:
+ **/
+static void
+gpk_dbus_task_install_files_cb (PkTask *task, GAsyncResult *res, GpkDbusTask *dtask)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	PkResults *results = NULL;
+	guint length;
+	const gchar *title;
+	PkError *error_code = NULL;
+
+	/* get the results */
+	results = pk_task_generic_finish (task, res, &error);
+	if (results == NULL) {
+		/* TRANSLATORS: error: failed to install, detailed error follows */
+		length = g_strv_length (dtask->priv->files);
+		title = ngettext ("Failed to install file", "Failed to install files", length);
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "%s", error->message);
+		gpk_dbus_task_error_msg (dtask, title, error_dbus);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* check error code */
+	error_code = pk_results_get_error_code (results);
+	if (error_code != NULL) {
+		g_warning ("failed to install file: %s, %s",
+			     pk_error_enum_to_string (pk_error_get_code (error_code)),
+			     pk_error_get_details (error_code));
+		gpk_dbus_task_handle_error (dtask, error_code);
+		error_dbus = g_error_new (GPK_DBUS_ERROR,
+					  gpk_dbus_task_get_code_from_pkerror (error_code),
+					  "failed to install file: %s",
+					  pk_error_get_details (error_code));
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* we're done */
+	gpk_dbus_task_dbus_return_value (dtask, TRUE);
+out:
+	if (error_code != NULL)
+		g_object_unref (error_code);
+	if (results != NULL)
+		g_object_unref (results);
+}
+
+/**
+ * gpk_dbus_task_ptr_array_to_bullets:
+ *
+ * splits the strings up nicely
+ *
+ * Return value: a newly allocated string
+ **/
+static gchar *
+gpk_dbus_task_ptr_array_to_bullets (GPtrArray *array, const gchar *prefix)
+{
+	GString *string;
+	guint i;
+	gchar *text;
+
+	/* don't use a bullet for one item */
+	if (array->len == 1) {
+		if (prefix != NULL)
+			return g_strdup_printf ("%s\n\n%s", prefix, (const gchar *) g_ptr_array_index (array, 0));
+		else
+			return g_strdup (g_ptr_array_index (array, 0));
+	}
+
+	string = g_string_new (prefix);
+	if (prefix != NULL)
+		g_string_append (string, "\n\n");
+
+	/* prefix with bullet and suffix with newline */
+	for (i=0; i<array->len; i++) {
+		text = (gchar *) g_ptr_array_index (array, i);
+		g_string_append_printf (string, "• %s\n", text);
+	}
+
+	/* remove last \n */
+	g_string_set_size (string, string->len - 1);
+
+	text = g_string_free (string, FALSE);
+	return text;
+}
+
+/**
+ * gpk_dbus_task_install_package_files_verify:
+ *
+ * Allow the user to confirm the action
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+static gboolean
+gpk_dbus_task_install_package_files_verify (GpkDbusTask *dtask, GPtrArray *array, GError **error)
+{
+	GtkResponseType button;
+	const gchar *title;
+	gchar *message;
+	gboolean ret = TRUE;
+
+	/* TRANSLATORS: title: confirm the user want's to install a local file */
+	title = ngettext ("Do you want to install this file?",
+			  "Do you want to install these files?", array->len);
+	message = gpk_dbus_task_ptr_array_to_bullets (array, NULL);
+
+	/* show UI */
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, 0);
+	gpk_modal_dialog_set_title (dtask->priv->dialog, title);
+	gpk_modal_dialog_set_message (dtask->priv->dialog, message);
+	/* TRANSLATORS: title: installing local files */
+	gpk_modal_dialog_set_action (dtask->priv->dialog, _("Install"));
+	gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp);
+	button = gpk_modal_dialog_run (dtask->priv->dialog);
+	g_free (message);
+
+	/* did we click no or exit the window? */
+	if (button != GTK_RESPONSE_OK) {
+		g_set_error_literal (error, GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "Aborted");
+		ret = FALSE;
+		goto out;
+	}
+out:
+	return ret;
+}
+
+/**
+ * gpk_dbus_task_confirm_action:
+ * @task: a valid #GpkDbusTask instance
+ **/
+static gboolean
+gpk_dbus_task_confirm_action (GpkDbusTask *dtask, const gchar *title, const gchar *message, const gchar *action)
+{
+	GtkResponseType button;
+
+	/* check the user wanted to call this method */
+	if (!dtask->priv->show_confirm_search)
+		return TRUE;
+
+	/* setup UI */
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, 0);
+	gpk_modal_dialog_set_action (dtask->priv->dialog, action);
+
+	/* set icon */
+	if (dtask->priv->parent_icon_name != NULL)
+		gpk_modal_dialog_set_image (dtask->priv->dialog, dtask->priv->parent_icon_name);
+	else
+		gpk_modal_dialog_set_image (dtask->priv->dialog, "emblem-system");
+
+	gpk_modal_dialog_set_title (dtask->priv->dialog, title);
+	gpk_modal_dialog_set_message (dtask->priv->dialog, message);
+	gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp);
+	button = gpk_modal_dialog_run (dtask->priv->dialog);
+
+	/* close, we're going to fail the method */
+	if (button != GTK_RESPONSE_OK) {
+		gpk_modal_dialog_close (dtask->priv->dialog);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_progress_cb:
+ **/
+static void
+gpk_dbus_task_progress_cb (PkProgress *progress, PkProgressType type, GpkDbusTask *dtask)
+{
+	gboolean allow_cancel;
+	gint percentage;
+	guint remaining_time;
+	PkStatusEnum status;
+	gchar *package_id = NULL;
+	gchar *text;
+
+	/* optimise */
+	if (!dtask->priv->show_progress)
+		goto out;
+
+	g_object_get (progress,
+		      "allow-cancel", &allow_cancel,
+		      "percentage", &percentage,
+		      "remaining-time", &remaining_time,
+		      "status", &status,
+		      "package-id", &package_id,
+		      NULL);
+
+	if (type == PK_PROGRESS_TYPE_PACKAGE_ID) {
+		g_debug ("_package");
+	} else if (type == PK_PROGRESS_TYPE_PERCENTAGE) {
+		gpk_modal_dialog_set_percentage (dtask->priv->dialog, percentage);
+	} else if (type == PK_PROGRESS_TYPE_ALLOW_CANCEL) {
+		gpk_modal_dialog_set_allow_cancel (dtask->priv->dialog, allow_cancel);
+	} else if (type == PK_PROGRESS_TYPE_STATUS) {
+		gpk_dbus_task_set_status (dtask, status);
+
+		if (status == PK_STATUS_ENUM_FINISHED) {
+			/* stop spinning */
+			gpk_modal_dialog_set_percentage (dtask->priv->dialog, 100);
+		}
+	} else if (type == PK_PROGRESS_TYPE_REMAINING_TIME) {
+		gpk_modal_dialog_set_remaining (dtask->priv->dialog, remaining_time);
+	} else if (type == PK_PROGRESS_TYPE_PACKAGE_ID) {
+		text = gpk_package_id_format_twoline (NULL, package_id, NULL); //TODO: need summary
+		gpk_modal_dialog_set_message (dtask->priv->dialog, text);
+		g_free (text);
+	}
+out:
+	g_free (package_id);
+}
+
+/**
+ * gpk_dbus_task_is_installed_resolve_cb:
+ **/
+static void
+gpk_dbus_task_is_installed_resolve_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	PkResults *results = NULL;
+	GPtrArray *array = NULL;
+	gboolean ret;
+	PkError *error_code = NULL;
+
+	/* get the results */
+	results = pk_client_generic_finish (client, res, &error);
+	if (results == NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to resolve: %s", error->message);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_warning ("failed to resolve: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* check error code */
+	error_code = pk_results_get_error_code (results);
+	if (error_code != NULL) {
+		g_warning ("failed to resolve: %s, %s", pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code));
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to resolve: %s", pk_error_get_details (error_code));
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* get results */
+	array = pk_results_get_package_array (results);
+	ret = (array->len > 0);
+	gpk_dbus_task_dbus_return_value (dtask, ret);
+out:
+	if (error_code != NULL)
+		g_object_unref (error_code);
+	if (array != NULL)
+		g_ptr_array_unref (array);
+	if (results != NULL)
+		g_object_unref (results);
+}
+
+/**
+ * gpk_dbus_task_is_installed:
+ **/
+void
+gpk_dbus_task_is_installed (GpkDbusTask *dtask, const gchar *package_name, GpkDbusTaskFinishedCb finished_cb, gpointer userdata)
+{
+	gchar **package_names = NULL;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (dtask));
+	g_return_if_fail (package_name != NULL);
+
+	/* save callback information */
+	dtask->priv->finished_cb = finished_cb;
+	dtask->priv->finished_userdata = userdata;
+
+	/* get the package list for the installed packages */
+	package_names = g_strsplit (package_name, "|", 1);
+	pk_client_resolve_async (PK_CLIENT(dtask->priv->task), pk_bitfield_value (PK_FILTER_ENUM_INSTALLED), package_names, NULL,
+				 (PkProgressCallback) gpk_dbus_task_progress_cb, dtask,
+				 (GAsyncReadyCallback) gpk_dbus_task_is_installed_resolve_cb, dtask);
+	g_strfreev (package_names);
+}
+
+/**
+ * gpk_dbus_task_search_file_search_file_cb:
+ **/
+static void
+gpk_dbus_task_search_file_search_file_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	PkResults *results = NULL;
+	GPtrArray *array = NULL;
+	PkError *error_code = NULL;
+	gchar **split = NULL;
+	PkPackage *item;
+	PkInfoEnum info;
+	gchar *package_id = NULL;
+
+	/* get the results */
+	results = pk_client_generic_finish (client, res, &error);
+	if (results == NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to search file: %s", error->message);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_warning ("failed to resolve: %s", error->message);
+		g_error_free (error);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* check error code */
+	error_code = pk_results_get_error_code (results);
+	if (error_code != NULL) {
+		g_warning ("failed to resolve: %s, %s", pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code));
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to search file: %s", pk_error_get_details (error_code));
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* get results */
+	array = pk_results_get_package_array (results);
+	if (array->len == 0) {
+		g_warning ("no packages");
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_UNKNOWN, "failed to find any packages");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* get first item */
+	item = g_ptr_array_index (array, 0);
+	g_object_get (item,
+		      "info", &info,
+		      "package-id", &package_id,
+		      NULL);
+	split = pk_package_id_split (package_id);
+
+	/* send error */
+	g_debug ("sending async return in response to %p", dtask->priv->context);
+	dbus_g_method_return (dtask->priv->context, (info == PK_INFO_ENUM_INSTALLED), split[PK_PACKAGE_ID_NAME]);
+
+	/* set context NULL just in case we try to repeat */
+	dtask->priv->context = NULL;
+out:
+	g_free (package_id);
+	g_strfreev (split);
+	if (error_code != NULL)
+		g_object_unref (error_code);
+	if (array != NULL)
+		g_ptr_array_unref (array);
+	if (results != NULL)
+		g_object_unref (results);
+}
+
+/**
+ * gpk_dbus_task_search_file:
+ **/
+void
+gpk_dbus_task_search_file (GpkDbusTask *dtask, const gchar *search_file, GpkDbusTaskFinishedCb finished_cb, gpointer userdata)
+{
+	gchar **values = NULL;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (dtask));
+	g_return_if_fail (search_file != NULL);
+
+	/* save callback information */
+	dtask->priv->finished_cb = finished_cb;
+	dtask->priv->finished_userdata = userdata;
+
+	/* get the package list for the installed packages */
+	g_debug ("package_name=%s", search_file);
+	values = g_strsplit (search_file, "&", -1);
+	pk_client_search_files_async (PK_CLIENT(dtask->priv->task), pk_bitfield_value (PK_FILTER_ENUM_NEWEST), values, NULL,
+				     (PkProgressCallback) gpk_dbus_task_progress_cb, dtask,
+				     (GAsyncReadyCallback) gpk_dbus_task_search_file_search_file_cb, dtask);
+	g_strfreev (values);
+}
+
+/**
+ * gpk_dbus_task_install_package_files:
+ * @task: a valid #GpkDbusTask instance
+ * @file_rel: a file such as <literal>./hal-devel-0.10.0.rpm</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a file locally, and get the deps from the repositories.
+ * This is useful for double clicking on a .rpm or .deb file.
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_package_files (GpkDbusTask *dtask, gchar **files_rel, GpkDbusTaskFinishedCb finished_cb, gpointer userdata)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	gboolean ret;
+	GPtrArray *array_basename;
+	GPtrArray *array;
+	guint len;
+	guint i;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (dtask));
+	g_return_if_fail (files_rel != NULL);
+
+	/* save callback information */
+	dtask->priv->finished_cb = finished_cb;
+	dtask->priv->finished_userdata = userdata;
+
+	/* only show the basenames */
+	array = g_ptr_array_new_with_free_func (g_free);
+	array_basename = g_ptr_array_new_with_free_func (g_free);
+	for (i = 0; files_rel[i] != NULL; i++) {
+		g_ptr_array_add (array, g_strdup (files_rel[i]));
+		g_ptr_array_add (array_basename, g_path_get_basename (files_rel[i]));
+	}
+
+	/* check the user wanted to call this method */
+	if (dtask->priv->show_confirm_search) {
+		ret = gpk_dbus_task_install_package_files_verify (dtask, array_basename, &error);
+		if (!ret) {
+			error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to verify files: %s", error->message);
+			gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+			g_error_free (error);
+			g_error_free (error_dbus);
+			goto out;
+		}
+	}
+
+	/* check for deps */
+	dtask->priv->files = pk_ptr_array_to_strv (array);
+
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	len = g_strv_length (dtask->priv->files);
+	/* TRANSLATORS: title: installing a local file */
+	gpk_modal_dialog_set_title (dtask->priv->dialog, ngettext ("Install local file", "Install local files", len));
+	if (dtask->priv->show_progress)
+		gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp);
+
+	/* install async */
+	pk_task_install_files_async (dtask->priv->task, dtask->priv->files, NULL,
+				     (PkProgressCallback) gpk_dbus_task_progress_cb, dtask,
+				     (GAsyncReadyCallback) gpk_dbus_task_install_files_cb, dtask);
+
+	/* wait for async reply */
+out:
+	g_ptr_array_unref (array);
+	g_ptr_array_unref (array_basename);
+}
+
+/**
+ * gpk_dbus_task_install_package_names_resolve_cb:
+ **/
+static void
+gpk_dbus_task_install_package_names_resolve_cb (PkTask *task, GAsyncResult *res, GpkDbusTask *dtask, GpkDbusTaskFinishedCb finished_cb, gpointer userdata)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	PkResults *results = NULL;
+	GPtrArray *array = NULL;
+	PkError *error_code = NULL;
+	gchar *package_id = NULL;
+	gchar *title;
+	gchar *info_url;
+	PkPackage *item;
+	GtkResponseType button;
+	guint i;
+	gboolean already_installed = FALSE;
+	PkInfoEnum info;
+	gchar *package_id_tmp = NULL;
+
+	/* get the results */
+	results = pk_task_generic_finish (task, res, &error);
+	if (results == NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to resolve: %s", error->message);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* check error code */
+	error_code = pk_results_get_error_code (results);
+	if (error_code != NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to resolve: %s", pk_error_get_details (error_code));
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* found nothing? */
+	array = pk_results_get_package_array (results);
+	if (array->len == 0) {
+		if (!dtask->priv->show_warning) {
+			/* TRANSLATORS: couldn't resolve name to package */
+			title = g_strdup_printf (_("Could not find packages"));
+			info_url = gpk_vendor_get_not_found_url (dtask->priv->vendor, GPK_VENDOR_URL_TYPE_DEFAULT);
+			/* only show the "more info" button if there is a valid link */
+			if (info_url != NULL)
+				gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION);
+			else
+				gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+			gpk_modal_dialog_set_title (dtask->priv->dialog, title);
+			/* TRANSLATORS: message: could not find */
+			gpk_modal_dialog_set_message (dtask->priv->dialog, _("The packages could not be found in any package source"));
+			/* TRANSLATORS: button: a link to the help file */
+			gpk_modal_dialog_set_action (dtask->priv->dialog, _("More information"));
+			gpk_modal_dialog_present (dtask->priv->dialog);
+			button = gpk_modal_dialog_run (dtask->priv->dialog);
+			if (button == GTK_RESPONSE_OK)
+				gpk_gnome_open (info_url);
+			g_free (info_url);
+			g_free (title);
+		}
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "no package found");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* see what we've got already */
+	for (i=0; i<array->len; i++) {
+		item = g_ptr_array_index (array, i);
+		g_object_get (item,
+			      "info", &info,
+			      "package-id", &package_id_tmp,
+			      NULL);
+		if (info == PK_INFO_ENUM_INSTALLED) {
+			already_installed = TRUE;
+		} else if (info == PK_INFO_ENUM_AVAILABLE) {
+			g_debug ("package '%s' resolved", package_id_tmp);
+			package_id = g_strdup (package_id_tmp);
+			//TODO: we need to list these in a gpk-dbus_task-chooser
+		}
+		g_free (package_id_tmp);
+	}
+
+	/* already installed? */
+	if (already_installed) {
+		if (dtask->priv->show_warning) {
+			gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_FINISHED, 0);
+			/* TRANSLATORS: title: package is already installed */
+			gpk_modal_dialog_set_title (dtask->priv->dialog,
+						    ngettext ("The package is already installed",
+							      "The packages are already installed",
+							      g_strv_length (dtask->priv->package_ids)));
+			/* TRANSLATORS: message: package is already installed */
+			gpk_modal_dialog_set_message (dtask->priv->dialog, _("Nothing to do."));
+			gpk_modal_dialog_present (dtask->priv->dialog);
+			gpk_modal_dialog_run (dtask->priv->dialog);
+		}
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_UNKNOWN, "package already found");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* got junk? */
+	if (package_id == NULL) {
+		if (dtask->priv->show_warning) {
+			gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+			/* TRANSLATORS: failed to install, shouldn't be shown */
+			gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to install package"));
+			/* TRANSLATORS: the search gave us the wrong result. internal error. barf. */
+			gpk_modal_dialog_set_message (dtask->priv->dialog, _("Incorrect response from search"));
+			gpk_modal_dialog_present (dtask->priv->dialog);
+			gpk_modal_dialog_run (dtask->priv->dialog);
+		}
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_UNKNOWN, "incorrect response from search");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* convert to data */
+	dtask->priv->package_ids = pk_package_array_to_strv (array);
+
+	/* install these packages with deps */
+	gpk_dbus_task_install_package_ids (dtask);
+out:
+	g_free (package_id);
+	if (error_code != NULL)
+		g_object_unref (error_code);
+	if (array != NULL)
+		g_ptr_array_unref (array);
+	if (results != NULL)
+		g_object_unref (results);
+}
+
+/**
+ * gpk_dbus_task_install_package_names:
+ * @task: a valid #GpkDbusTask instance
+ * @package: a pakage name such as <literal>hal-info</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a package of the newest and most correct version.
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_package_names (GpkDbusTask *dtask, gchar **packages, GpkDbusTaskFinishedCb finished_cb, gpointer userdata)
+{
+	gboolean ret;
+	GError *error_dbus = NULL;
+	gchar *message;
+	gchar *text;
+	guint len;
+	guint i;
+	GString *string;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (dtask));
+	g_return_if_fail (packages != NULL);
+
+	/* save callback information */
+	dtask->priv->finished_cb = finished_cb;
+	dtask->priv->finished_userdata = userdata;
+
+	/* optional */
+	if (!dtask->priv->show_confirm_install) {
+		g_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	string = g_string_new ("");
+	len = g_strv_length (packages);
+	if (len == 0) {
+		gpk_dbus_task_dbus_return_value (dtask, TRUE);
+		goto out;
+	}
+
+	/* don't use a bullet for one item */
+	if (len == 1) {
+		g_string_append_printf (string, "%s\n", packages[0]);
+	} else {
+		for (i=0; i<len; i++)
+			g_string_append_printf (string, "• %s\n", packages[i]);
+	}
+	/* display messagebox  */
+	text = g_string_free (string, FALSE);
+
+	/* check user wanted operation */
+	message = g_strdup_printf ("%s\n\n%s\n%s",
+				   /* TRANSLATORS: a program needs a package, for instance openoffice-clipart */
+				   ngettext ("An additional package is required:", "Additional packages are required:", len),
+				   text,
+				   /* TRANSLATORS: ask the user if it's okay to search */
+				   ngettext ("Do you want to search for and install this package now?", "Do you want to search for and install these packages now?", len));
+	g_free (text);
+
+	/* make title using application name */
+	if (dtask->priv->parent_title != NULL) {
+		/* TRANSLATORS: string is a program name, e.g. "Movie Player" */
+		text = g_strdup_printf (ngettext ("%s wants to install a package", "%s wants to install packages", len), dtask->priv->parent_title);
+	} else {
+		/* TRANSLATORS: a random program which we can't get the name wants to do something */
+		text = g_strdup (ngettext ("A program wants to install a package", "A program wants to install packages", len));
+	}
+
+	/* TRANSLATORS: button: confirm to search for packages */
+	ret = gpk_dbus_task_confirm_action (dtask, text, message, _("Install"));
+	g_free (text);
+	g_free (message);
+	if (!ret) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+skip_checks:
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	/* TRANSLATORS: title, searching */
+	gpk_modal_dialog_set_title (dtask->priv->dialog, _("Searching for packages"));
+	gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT);
+	if (dtask->priv->show_progress)
+		gpk_modal_dialog_present (dtask->priv->dialog);
+
+	/* find out if we can find a package */
+	pk_client_resolve_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, -1), packages, NULL,
+			         (PkProgressCallback) gpk_dbus_task_progress_cb, dtask,
+				 (GAsyncReadyCallback) gpk_dbus_task_install_package_names_resolve_cb, dtask);
+
+	/* wait for async reply */
+out:
+	return;
+}
+
+/**
+ * gpk_dbus_task_install_provide_files_search_file_cb:
+ **/
+static void
+gpk_dbus_task_install_provide_files_search_file_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	PkResults *results = NULL;
+	GPtrArray *array = NULL;
+	PkError *error_code = NULL;
+	gchar *info_url;
+	PkPackage *item;
+	GtkResponseType button;
+	guint i;
+	gboolean already_installed = FALSE;
+	gchar *text;
+	gchar **split;
+	PkInfoEnum info;
+	gchar *package_id = NULL;
+	gchar *package_id_tmp = NULL;
+
+	/* get the results */
+	results = pk_client_generic_finish (client, res, &error);
+	if (results == NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to resolve: %s", error->message);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* check error code */
+	error_code = pk_results_get_error_code (results);
+	if (error_code != NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to resolve: %s", pk_error_get_details (error_code));
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* get results */
+	array = pk_results_get_package_array (results);
+
+	/* found nothing? */
+	if (array->len == 0) {
+		if (dtask->priv->show_warning) {
+			info_url = gpk_vendor_get_not_found_url (dtask->priv->vendor, GPK_VENDOR_URL_TYPE_DEFAULT);
+			/* only show the "more info" button if there is a valid link */
+			if (info_url != NULL)
+				gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION);
+			else
+				gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+			/* TRANSLATORS: failed to fild the package for thefile */
+			gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to find package"));
+			/* TRANSLATORS: nothing found */
+			gpk_modal_dialog_set_message (dtask->priv->dialog, _("The file could not be found in any packages"));
+			/* TRANSLATORS: button: show the user a button to get more help finding stuff */
+			gpk_modal_dialog_set_action (dtask->priv->dialog, _("More information"));
+			gpk_modal_dialog_present (dtask->priv->dialog);
+			button = gpk_modal_dialog_run (dtask->priv->dialog);
+			if (button == GTK_RESPONSE_OK)
+				gpk_gnome_open (info_url);
+			g_free (info_url);
+		}
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "no files found");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* see what we've got already */
+	for (i=0; i<array->len; i++) {
+		item = g_ptr_array_index (array, i);
+		g_object_get (item,
+			      "info", &info,
+			      "package-id", &package_id_tmp,
+			      NULL);
+		if (info == PK_INFO_ENUM_INSTALLED) {
+			already_installed = TRUE;
+			package_id = g_strdup (package_id_tmp);
+		} else if (info == PK_INFO_ENUM_AVAILABLE) {
+			g_debug ("package '%s' resolved to:", package_id_tmp);
+			package_id = g_strdup (package_id_tmp);
+		}
+		g_free (package_id_tmp);
+	}
+
+	/* already installed? */
+	if (already_installed) {
+		if (dtask->priv->show_warning) {
+			split = pk_package_id_split (package_id);
+			/* TRANSLATORS: we've already got a package that provides this file */
+			text = g_strdup_printf (_("The %s package already provides this file"), split[PK_PACKAGE_ID_NAME]);
+			gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+			/* TRANSLATORS: title */
+			gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to install file"));
+			gpk_modal_dialog_set_message (dtask->priv->dialog, text);
+			gpk_modal_dialog_present (dtask->priv->dialog);
+			gpk_modal_dialog_run (dtask->priv->dialog);
+			g_free (text);
+			g_strfreev (split);
+		}
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_UNKNOWN, "already provided");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* convert to data */
+	dtask->priv->package_ids = pk_package_ids_from_id (package_id);
+
+	/* install these packages with deps */
+	gpk_dbus_task_install_package_ids (dtask);
+out:
+	g_free (package_id);
+	if (error_code != NULL)
+		g_object_unref (error_code);
+	if (array != NULL)
+		g_ptr_array_unref (array);
+	if (results != NULL)
+		g_object_unref (results);
+}
+
+/**
+ * gpk_dbus_task_install_provide_files:
+ * @task: a valid #GpkDbusTask instance
+ * @full_path: a file path name such as <literal>/usr/sbin/packagekitd</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a package which provides a file on the system.
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_provide_files (GpkDbusTask *dtask, gchar **full_paths, GpkDbusTaskFinishedCb finished_cb, gpointer userdata)
+{
+	gboolean ret;
+	GError *error_dbus = NULL;
+	guint len;
+	guint i;
+	gchar *text;
+	gchar *message;
+	GString *string;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (dtask));
+	g_return_if_fail (full_paths != NULL);
+
+	/* save callback information */
+	dtask->priv->finished_cb = finished_cb;
+	dtask->priv->finished_userdata = userdata;
+
+	/* optional */
+	if (!dtask->priv->show_confirm_search) {
+		g_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	string = g_string_new ("");
+	len = g_strv_length (full_paths);
+
+	/* don't use a bullet for one item */
+	if (len == 1) {
+		g_string_append_printf (string, "%s\n", full_paths[0]);
+	} else {
+		for (i=0; i<len; i++)
+			g_string_append_printf (string, "• %s\n", full_paths[i]);
+	}
+	/* display messagebox  */
+	text = g_string_free (string, FALSE);
+
+	/* check user wanted operation */
+	message = g_strdup_printf ("%s\n\n%s\n\n%s",
+				   /* TRANSLATORS: a program wants to install a file, e.g. /lib/moo.so */
+				   ngettext ("The following file is required:", "The following files are required:", len),
+				   text,
+				   /* TRANSLATORS: confirm with the user */
+				   ngettext ("Do you want to search for this file now?", "Do you want to search for these files now?", len));
+
+	/* make title using application name */
+	if (dtask->priv->parent_title != NULL) {
+		/* TRANSLATORS: string is a program name, e.g. "Movie Player" */
+		text = g_strdup_printf (ngettext ("%s wants to install a file", "%s wants to install files", len), dtask->priv->parent_title);
+	} else {
+		/* TRANSLATORS: a random program which we can't get the name wants to do something */
+		text = g_strdup (ngettext ("A program wants to install a file", "A program wants to install files", len));
+	}
+
+	/* TRANSLATORS: button: confirm to search for packages */
+	ret = gpk_dbus_task_confirm_action (dtask, text, message, _("Install"));
+	g_free (text);
+	g_free (message);
+	if (!ret) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+skip_checks:
+	/* TRANSLATORS: searching for the package that provides the file */
+	gpk_modal_dialog_set_title (dtask->priv->dialog, _("Searching for file"));
+	gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT);
+
+	/* do search */
+	pk_client_search_files_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, -1), full_paths, NULL,
+			             (PkProgressCallback) gpk_dbus_task_progress_cb, dtask,
+				     (GAsyncReadyCallback) gpk_dbus_task_install_provide_files_search_file_cb, dtask);
+
+	/* wait for async reply */
+out:
+	return;
+}
+
+/**
+ * gpk_dbus_task_install_gstreamer_resources_confirm:
+ **/
+static gboolean
+gpk_dbus_task_install_gstreamer_resources_confirm (GpkDbusTask *dtask, gchar **codec_names)
+{
+	guint i;
+	guint len;
+	const gchar *text;
+	gchar **parts;
+	gboolean ret;
+	GString *string;
+	gchar *title;
+	gchar *message;
+	gboolean is_decoder = FALSE;
+	gboolean is_encoder = FALSE;
+
+	len = g_strv_length (codec_names);
+
+	/* find out what type of request this is */
+	for (i=0; i<len; i++) {
+		parts = g_strsplit (codec_names[i], "|", 2);
+		if (g_strstr_len (parts[1], -1, "(decoder") != NULL)
+			is_decoder = TRUE;
+		if (g_strstr_len (parts[1], -1, "(encoder") != NULL)
+			is_encoder = TRUE;
+		g_strfreev (parts);
+	}
+
+	/* TRANSLATORS: we are listing the plugins in a box */
+	text = ngettext ("The following plugin is required:", "The following plugins are required:", len);
+	string = g_string_new ("");
+	g_string_append_printf (string, "%s\n\n", text);
+
+	/* don't use a bullet for one item */
+	if (len == 1) {
+		parts = g_strsplit (codec_names[0], "|", 2);
+		g_string_append_printf (string, "%s\n", parts[0]);
+		g_strfreev (parts);
+	} else {
+		for (i=0; i<len; i++) {
+			parts = g_strsplit (codec_names[i], "|", 2);
+			g_string_append_printf (string, "• %s\n", parts[0]);
+			g_strfreev (parts);
+		}
+	}
+
+	/* TRANSLATORS: ask for confirmation */
+	message = ngettext ("Do you want to search for this now?", "Do you want to search for these now?", len);
+	g_string_append_printf (string, "\n%s\n", message);
+
+	/* remove last \n */
+	g_string_set_size (string, string->len - 1);
+
+	/* display messagebox  */
+	message = g_string_free (string, FALSE);
+
+	/* make title using application name */
+	if (dtask->priv->parent_title != NULL) {
+		if (is_decoder && !is_encoder) {
+			/* TRANSLATORS: a program wants to decode something (unknown) -- string is a program name, e.g. "Movie Player" */
+			title = g_strdup_printf (ngettext ("%s requires an additional plugin to decode this file",
+							   "%s requires additional plugins to decode this file", len), dtask->priv->parent_title);
+		} else if (!is_decoder && is_encoder) {
+			/* TRANSLATORS: a program wants to encode something (unknown) -- string is a program name, e.g. "Movie Player" */
+			title = g_strdup_printf (ngettext ("%s requires an additional plugin to encode this file",
+							   "%s requires additional plugins to encode this file", len), dtask->priv->parent_title);
+		} else {
+			/* TRANSLATORS: a program wants to do something (unknown) -- string is a program name, e.g. "Movie Player" */
+			title = g_strdup_printf (ngettext ("%s requires an additional plugin for this operation",
+							   "%s requires additional plugins for this operation", len), dtask->priv->parent_title);
+		}
+	} else {
+		if (is_decoder && !is_encoder) {
+			/* TRANSLATORS: a random program which we can't get the name wants to decode something */
+			title = g_strdup (ngettext ("A program requires an additional plugin to decode this file",
+						    "A program requires additional plugins to decode this file", len));
+		} else if (!is_decoder && is_encoder) {
+			/* TRANSLATORS: a random program which we can't get the name wants to encode something */
+			title = g_strdup (ngettext ("A program requires an additional plugin to encode this file",
+						    "A program requires additional plugins to encode this file", len));
+		} else {
+			/* TRANSLATORS: a random program which we can't get the name wants to do something (unknown) */
+			title = g_strdup (ngettext ("A program requires an additional plugin for this operation",
+						    "A program requires additional plugins for this operation", len));
+		}
+	}
+
+	/* TRANSLATORS: button: confirm to search for packages */
+	ret = gpk_dbus_task_confirm_action (dtask, title, message, _("Search"));
+	g_free (title);
+	g_free (message);
+
+	return ret;
+}
+
+/**
+ * gpk_dbus_task_codec_what_provides_cb:
+ **/
+static void
+gpk_dbus_task_codec_what_provides_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	PkResults *results = NULL;
+	GPtrArray *array = NULL;
+	PkError *error_code = NULL;
+	GtkResponseType button;
+	gchar *info_url;
+	const gchar *title;
+	const gchar *message;
+
+	/* get the results */
+	results = pk_client_generic_finish (client, res, &error);
+	if (results == NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to resolve: %s", error->message);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* check error code */
+	error_code = pk_results_get_error_code (results);
+	if (error_code != NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to resolve: %s", pk_error_get_details (error_code));
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* get results */
+	array = pk_results_get_package_array (results);
+
+	/* found nothing? */
+	if (array->len == 0) {
+		if (dtask->priv->show_warning) {
+			info_url = gpk_vendor_get_not_found_url (dtask->priv->vendor, GPK_VENDOR_URL_TYPE_CODEC);
+			/* only show the "more info" button if there is a valid link */
+			if (info_url != NULL)
+				gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION);
+			else
+				gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+			/* TRANSLATORS: failed to search for codec */
+			gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to search for plugin"));
+			/* TRANSLATORS: no package sources have the wanted codec */
+			gpk_modal_dialog_set_message (dtask->priv->dialog, _("Could not find plugin in any configured package source"));
+
+			/* TRANSLATORS: button text */
+			gpk_modal_dialog_set_action (dtask->priv->dialog, _("More information"));
+			gpk_modal_dialog_present (dtask->priv->dialog);
+			button = gpk_modal_dialog_run (dtask->priv->dialog);
+			if (button == GTK_RESPONSE_OK)
+				gpk_gnome_open (info_url);
+			g_free (info_url);
+		}
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "failed to find codec");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* optional */
+	if (!dtask->priv->show_confirm_install) {
+		g_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks2;
+	}
+
+	title = ngettext ("Install the following plugin", "Install the following plugins", array->len);
+	message = ngettext ("Do you want to install this package now?", "Do you want to install these packages now?", array->len);
+
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST);
+	gpk_modal_dialog_set_package_list (dtask->priv->dialog, array);
+	gpk_modal_dialog_set_title (dtask->priv->dialog, title);
+	gpk_modal_dialog_set_message (dtask->priv->dialog, message);
+	gpk_modal_dialog_set_image (dtask->priv->dialog, "dialog-information");
+	/* TRANSLATORS: button: install codecs */
+	gpk_modal_dialog_set_action (dtask->priv->dialog, _("Install"));
+	gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp);
+	button = gpk_modal_dialog_run (dtask->priv->dialog);
+
+	/* close, we're going to fail the method */
+	if (button != GTK_RESPONSE_OK) {
+		gpk_modal_dialog_close (dtask->priv->dialog);
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to download");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+skip_checks2:
+	/* install with deps */
+	dtask->priv->package_ids = pk_package_array_to_strv (array);
+	gpk_dbus_task_install_package_ids (dtask);
+out:
+	if (error_code != NULL)
+		g_object_unref (error_code);
+	if (array != NULL)
+		g_ptr_array_unref (array);
+	if (results != NULL)
+		g_object_unref (results);
+}
+
+/**
+ * gpk_dbus_task_install_gstreamer_resources:
+ * @task: a valid #GpkDbusTask instance
+ * @codecs: a codec_type such as <literal>application/text</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a application to handle a gstreamer request
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_gstreamer_resources (GpkDbusTask *dtask, gchar **codec_names, GpkDbusTaskFinishedCb finished_cb, gpointer userdata)
+{
+	gboolean ret = TRUE;
+	GError *error_dbus = NULL;
+	gchar **parts = NULL;
+	gchar *message = NULL;
+	GPtrArray *array_title = NULL;
+	GPtrArray *array_search = NULL;
+	gchar **search = NULL;
+	gchar **title = NULL;
+	gchar *title_str = NULL;
+	guint i;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (dtask));
+	g_return_if_fail (codec_names != NULL);
+
+	/* save callback information */
+	dtask->priv->finished_cb = finished_cb;
+	dtask->priv->finished_userdata = userdata;
+
+	/* check it's not session wide banned */
+	ret = g_settings_get_boolean (dtask->priv->settings, GPK_SETTINGS_ENABLE_CODEC_HELPER);
+	if (!ret) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_NOT_AUTHORIZED, "not enabled in GSettings : %s", GPK_SETTINGS_ENABLE_CODEC_HELPER);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* optional */
+	if (!dtask->priv->show_confirm_search) {
+		g_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	/* confirm */
+	ret = gpk_dbus_task_install_gstreamer_resources_confirm (dtask, codec_names);
+	if (!ret) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+skip_checks:
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING);
+	/* TRANSLATORS: search for codec */
+	gpk_modal_dialog_set_title (dtask->priv->dialog, _("Searching for plugins"));
+	gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT);
+
+	/* setup the UI */
+	if (dtask->priv->show_progress)
+		gpk_modal_dialog_present (dtask->priv->dialog);
+
+	/* get the request */
+	array_title = g_ptr_array_new_with_free_func (g_free);
+	array_search = g_ptr_array_new_with_free_func (g_free);
+	for (i=0; codec_names[i] != NULL; i++) {
+		parts = g_strsplit (codec_names[i], "|", 2);
+		g_ptr_array_add (array_title, g_strdup (parts[0]));
+		g_ptr_array_add (array_search, g_strdup (parts[1]));
+		g_strfreev (parts);
+	}
+
+	/* TRANSLATORS: title, searching for codecs */
+	title = pk_ptr_array_to_strv (array_title);
+	title_str = g_strjoinv (", ", title);
+	message = g_strdup_printf (_("Searching for plugin: %s"), title_str);
+	gpk_modal_dialog_set_message (dtask->priv->dialog, message);
+
+	/* get codec packages */
+	search = pk_ptr_array_to_strv (array_search);
+	pk_client_what_provides_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_NOT_INSTALLED, PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, -1),
+#if PK_CHECK_VERSION(0,9,0)
+				       search, NULL,
+#else
+				       PK_PROVIDES_ENUM_CODEC, search, NULL,
+#endif
+			               (PkProgressCallback) gpk_dbus_task_progress_cb, dtask,
+				       (GAsyncReadyCallback) gpk_dbus_task_codec_what_provides_cb, dtask);
+out:
+	if (array_title != NULL)
+		g_ptr_array_unref (array_title);
+	if (array_search != NULL)
+		g_ptr_array_unref (array_search);
+	g_strfreev (search);
+	g_strfreev (title);
+	g_free (message);
+	g_free (title_str);
+}
+
+/**
+ * gpk_dbus_task_mime_what_provides_cb:
+ **/
+static void
+gpk_dbus_task_mime_what_provides_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	PkResults *results = NULL;
+	GPtrArray *array = NULL;
+	PkError *error_code = NULL;
+	gchar *info_url;
+	GtkResponseType button;
+
+	/* get the results */
+	results = pk_client_generic_finish (client, res, &error);
+	if (results == NULL) {
+		/* TRANSLATORS: we failed to find the package, this shouldn't happen */
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to search for provides: %s", error->message);
+		gpk_dbus_task_error_msg (dtask, _("Failed to search for provides"), error_dbus);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* check error code */
+	error_code = pk_results_get_error_code (results);
+	if (error_code != NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to search for provides: %s", pk_error_get_details (error_code));
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* get results */
+	array = pk_results_get_package_array (results);
+
+	/* found nothing? */
+	if (array->len == 0) {
+		if (dtask->priv->show_warning) {
+			info_url = gpk_vendor_get_not_found_url (dtask->priv->vendor, GPK_VENDOR_URL_TYPE_MIME);
+			/* only show the "more info" button if there is a valid link */
+			if (info_url != NULL)
+				gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION);
+			else
+				gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+			/* TRANSLATORS: title */
+			gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to find software"));
+			/* TRANSLATORS: nothing found in the package sources that helps */
+			gpk_modal_dialog_set_message (dtask->priv->dialog, _("No new applications can be found to handle this type of file"));
+			/* TRANSLATORS: button: show the user a button to get more help finding stuff */
+			gpk_modal_dialog_set_action (dtask->priv->dialog, _("More information"));
+			gpk_modal_dialog_present (dtask->priv->dialog);
+			button = gpk_modal_dialog_run (dtask->priv->dialog);
+			if (button == GTK_RESPONSE_OK)
+				gpk_gnome_open (info_url);
+			g_free (info_url);
+		}
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "nothing was found to handle mime type");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* populate a chooser and wait for response */
+	gpk_helper_chooser_show (dtask->priv->helper_chooser, array);
+out:
+	if (error_code != NULL)
+		g_object_unref (error_code);
+	if (array != NULL)
+		g_ptr_array_unref (array);
+	if (results != NULL)
+		g_object_unref (results);
+}
+
+/**
+ * gpk_dbus_task_install_mime_types:
+ * @task: a valid #GpkDbusTask instance
+ * @mime_type: a mime_type such as <literal>application/text</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a application to handle a mime type
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_mime_types (GpkDbusTask *dtask, gchar **mime_types, GpkDbusTaskFinishedCb finished_cb, gpointer userdata)
+{
+	gboolean ret;
+	GError *error_dbus = NULL;
+	guint len;
+	gchar *message = NULL;
+	gchar *text = NULL;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (dtask));
+	g_return_if_fail (mime_types != NULL);
+
+	/* save callback information */
+	dtask->priv->finished_cb = finished_cb;
+	dtask->priv->finished_userdata = userdata;
+
+	/* check it's not session wide banned */
+	ret = g_settings_get_boolean (dtask->priv->settings, GPK_SETTINGS_ENABLE_MIME_TYPE_HELPER);
+	if (!ret) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_NOT_AUTHORIZED, "not enabled in GSettings : %s", GPK_SETTINGS_ENABLE_MIME_TYPE_HELPER);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* optional */
+	if (!dtask->priv->show_confirm_search) {
+		g_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	/* make sure the user wants to do action */
+	message = g_strdup_printf ("%s\n\n%s\n\n%s",
+				    /* TRANSLATORS: message: mime type opener required */
+				   _("An additional program is required to open this type of file:"),
+				   mime_types[0],
+				   /* TRANSLATORS: message: confirm with the user */
+				   _("Do you want to search for a program to open this file type now?"));
+
+	/* hardcode for now as we only support one mime type at a time */
+	len = 1;
+
+	/* make title using application name */
+	if (dtask->priv->parent_title != NULL) {
+		/* TRANSLATORS: string is a program name, e.g. "Movie Player" */
+		text = g_strdup_printf (ngettext ("%s requires a new mime type", "%s requires new mime types", len), dtask->priv->parent_title);
+	} else {
+		/* TRANSLATORS: a random program which we can't get the name wants to do something */
+		text = g_strdup (ngettext ("A program requires a new mime type", "A program requires new mime types", len));
+	}
+
+	/* TRANSLATORS: button: confirm to search for packages */
+	ret = gpk_dbus_task_confirm_action (dtask, text, message, _("Search"));
+	if (!ret) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+skip_checks:
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	/* TRANSLATORS: title: searching for mime type handlers */
+	gpk_modal_dialog_set_title (dtask->priv->dialog, _("Searching for file handlers"));
+	gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT);
+
+	/* setup the UI */
+	if (dtask->priv->show_progress)
+		gpk_modal_dialog_present (dtask->priv->dialog);
+
+	/* action */
+	pk_client_what_provides_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_NOT_INSTALLED, PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, -1),
+#if PK_CHECK_VERSION(0,9,0)
+				       mime_types, NULL,
+#else
+				       PK_PROVIDES_ENUM_MIMETYPE, mime_types, NULL,
+#endif
+			               (PkProgressCallback) gpk_dbus_task_progress_cb, dtask,
+				       (GAsyncReadyCallback) gpk_dbus_task_mime_what_provides_cb, dtask);
+	/* wait for async reply */
+out:
+	g_free (text);
+	g_free (message);
+}
+
+/**
+ * gpk_dbus_task_font_tag_to_lang:
+ **/
+gchar *
+gpk_dbus_task_font_tag_to_lang (const gchar *tag)
+{
+	gchar *lang = NULL;
+#if 0
+	*** We do not yet enable this code due to a few bugs in fontconfig ***
+	http://bugs.freedesktop.org/show_bug.cgi?id=18846 and
+	http://bugs.freedesktop.org/show_bug.cgi?id=18847
+
+	FcPattern *pat = NULL;
+	FcChar8 *fclang;
+	FcResult res;
+
+	/* parse the tag */
+	pat = FcNameParse ((FcChar8 *) tag);
+	if (pat == NULL) {
+		g_warning ("cannot parse: '%s'", tag);
+		goto out;
+	}
+	FcPatternPrint (pat);
+	res = FcPatternGetString (pat, FC_LANG, 0, &fclang);
+	if (res != FcResultMatch) {
+		g_warning ("failed to get string for: '%s': %i", tag, res);
+		goto out;
+	}
+	lang = g_strdup ((gchar *) fclang);
+out:
+	if (pat != NULL)
+		FcPatternDestroy (pat);
+#else
+	guint len;
+
+	/* verify we have enough to remove prefix */
+	len = strlen (tag);
+	if (len < 7)
+		goto out;
+	/* this is a bodge */
+	lang = g_strdup (&tag[6]);
+out:
+#endif
+	return lang;
+}
+
+/**
+ * gpk_dbus_task_font_tag_to_localised_name:
+ **/
+gchar *
+gpk_dbus_task_font_tag_to_localised_name (GpkDbusTask *dtask, const gchar *tag)
+{
+	gchar *lang;
+	gchar *language = NULL;
+	gchar *name;
+
+	/* use fontconfig to get the language code */
+	lang = gpk_dbus_task_font_tag_to_lang (tag);
+	if (lang == NULL) {
+		/* TRANSLATORS: we could not parse the ISO639 code from the fontconfig tag name */
+		name = g_strdup_printf ("%s: %s", _("Language tag not parsed"), tag);
+		goto out;
+	}
+
+	/* convert to localisable name */
+	language = gpk_language_iso639_to_language (dtask->priv->language, lang);
+	if (language == NULL) {
+		/* TRANSLATORS: we could not find en_US string for ISO639 code */
+		name = g_strdup_printf ("%s: %s", _("Language code not matched"), lang);
+		goto out;
+	}
+
+	/* get translation, or return untranslated string */
+	name = g_strdup (dgettext("iso_639", language));
+	if (name == NULL)
+		name = g_strdup (language);
+out:
+	g_free (lang);
+	g_free (language);
+	return name;
+}
+
+/**
+ * gpk_dbus_task_fontconfig_what_provides_cb:
+ **/
+static void
+gpk_dbus_task_fontconfig_what_provides_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	PkResults *results = NULL;
+	GPtrArray *array = NULL;
+	PkError *error_code = NULL;
+	gchar *title;
+	gchar *info_url;
+	GtkResponseType button;
+
+	/* get the results */
+	results = pk_client_generic_finish (client, res, &error);
+	if (results == NULL) {
+		/* TRANSLATORS: we failed to find the package, this shouldn't happen */
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to search for provides: %s", error->message);
+//		gpk_dbus_task_error_msg (dtask, _("Failed to search for provides"), error_dbus);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* check error code */
+	error_code = pk_results_get_error_code (results);
+	if (error_code != NULL) {
+		/* TRANSLATORS: we failed to find the package, this shouldn't happen */
+//		gpk_dbus_task_error_msg (dtask, _("Failed to search for provides"), pk_error_get_details (error_code));
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to search for provides: %s", pk_error_get_details (error_code));
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* get results */
+	array = pk_results_get_package_array (results);
+
+	/* found nothing? */
+	if (array->len == 0) {
+		if (dtask->priv->show_warning) {
+			info_url = gpk_vendor_get_not_found_url (dtask->priv->vendor, GPK_VENDOR_URL_TYPE_FONT);
+			/* TRANSLATORS: title: cannot find in sources */
+			title = ngettext ("Failed to find font", "Failed to find fonts", array->len);
+			/* only show the "more info" button if there is a valid link */
+			if (info_url != NULL)
+				gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION);
+			else
+				gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+			gpk_modal_dialog_set_title (dtask->priv->dialog, title);
+			/* TRANSLATORS: message: tell the user we suck */
+			gpk_modal_dialog_set_message (dtask->priv->dialog, _("No new fonts can be found for this document"));
+			/* TRANSLATORS: button: show the user a button to get more help finding stuff */
+			gpk_modal_dialog_set_action (dtask->priv->dialog, _("More information"));
+			gpk_modal_dialog_present (dtask->priv->dialog);
+			button = gpk_modal_dialog_run (dtask->priv->dialog);
+			if (button == GTK_RESPONSE_OK)
+				gpk_gnome_open (info_url);
+			g_free (info_url);
+		}
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "failed to find font");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* optional */
+	if (!dtask->priv->show_confirm_install) {
+		g_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	/* TRANSLATORS: title: show a list of fonts */
+	title = ngettext ("Do you want to install this package now?", "Do you want to install these packages now?", array->len);
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST);
+	gpk_modal_dialog_set_package_list (dtask->priv->dialog, array);
+	gpk_modal_dialog_set_title (dtask->priv->dialog, title);
+	gpk_modal_dialog_set_message (dtask->priv->dialog, title);
+	gpk_modal_dialog_set_image (dtask->priv->dialog, "dialog-information");
+	/* TRANSLATORS: button: install a font */
+	gpk_modal_dialog_set_action (dtask->priv->dialog, _("Install"));
+	gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp);
+	button = gpk_modal_dialog_run (dtask->priv->dialog);
+
+	/* close, we're going to fail the method */
+	if (button != GTK_RESPONSE_OK) {
+		gpk_modal_dialog_close (dtask->priv->dialog);
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to download");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+skip_checks:
+	/* convert to list of package id's */
+	dtask->priv->package_ids = pk_package_array_to_strv (array);
+	gpk_dbus_task_install_package_ids (dtask);
+out:
+	if (error_code != NULL)
+		g_object_unref (error_code);
+	if (array != NULL)
+		g_ptr_array_unref (array);
+	if (results != NULL)
+		g_object_unref (results);
+}
+
+/**
+ * gpk_dbus_task_install_check_exec_ignored:
+ *
+ * Returns %FALSE if the executed program is in the ignored list.
+ **/
+static gboolean
+gpk_dbus_task_install_check_exec_ignored (GpkDbusTask *dtask)
+{
+	gchar *ignored_str;
+	gchar **ignored = NULL;
+	gboolean ret = TRUE;
+	guint i;
+
+	/* check it's not session wide banned */
+	ignored_str = g_settings_get_string (dtask->priv->settings, GPK_SETTINGS_IGNORED_DBUS_REQUESTS);
+	if (ignored_str == NULL)
+		goto out;
+
+	/* check each one */
+	ignored = g_strsplit (ignored_str, ",", -1);
+	for (i=0; ignored[i] != NULL; i++) {
+		if (g_strcmp0 (dtask->priv->exec, ignored[i]) == 0) {
+			ret = FALSE;
+			break;
+		}
+	}
+out:
+	g_free (ignored_str);
+	g_strfreev (ignored);
+	return ret;
+}
+
+/**
+ * gpk_dbus_task_install_fontconfig_resources:
+ * @task: a valid #GpkDbusTask instance
+ * @fonts: font description such as <literal>lang:fr</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a application to handle a mime type
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_fontconfig_resources (GpkDbusTask *dtask, gchar **fonts, GpkDbusTaskFinishedCb finished_cb, gpointer userdata)
+{
+	gboolean ret;
+	GPtrArray *array = NULL;
+//	GtkResponseType button;
+//	gchar *info_url;
+	GError *error_dbus = NULL;
+	guint i;
+	guint len;
+	guint size;
+	gchar *text;
+	gchar *message;
+	const gchar *title;
+	const gchar *title_part;
+	GString *string;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (dtask));
+	g_return_if_fail (fonts != NULL);
+
+	/* save callback information */
+	dtask->priv->finished_cb = finished_cb;
+	dtask->priv->finished_userdata = userdata;
+
+	/* if this program banned? */
+	ret = gpk_dbus_task_install_check_exec_ignored (dtask);
+	if (!ret) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_NOT_AUTHORIZED, "skipping ignored program: %s", dtask->priv->exec);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* get number of fonts to install */
+	len = g_strv_length (fonts);
+
+	/* check it's not session wide banned */
+	ret = g_settings_get_boolean (dtask->priv->settings, GPK_SETTINGS_ENABLE_FONT_HELPER);
+	if (!ret) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_NOT_AUTHORIZED, "not enabled in GSettings : %s", GPK_SETTINGS_ENABLE_FONT_HELPER);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* optional */
+	if (!dtask->priv->show_confirm_search) {
+		g_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	/* check we got valid data */
+	for (i=0; i<len; i++) {
+		/* correct prefix */
+		if (!g_str_has_prefix (fonts[i], ":lang=")) {
+			error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_INTERNAL_ERROR, "not recognized prefix: '%s'", fonts[i]);
+			gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+			g_error_free (error_dbus);
+			goto out;
+		}
+		/* no lang code */
+		size = strlen (fonts[i]);
+		if (size < 7 || size > 20) {
+			error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_INTERNAL_ERROR, "lang tag malformed: '%s'", fonts[i]);
+			gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+			g_error_free (error_dbus);
+			goto out;
+		}
+	}
+
+	string = g_string_new ("");
+
+	/* don't use a bullet for one item */
+	if (len == 1) {
+		text = gpk_dbus_task_font_tag_to_localised_name (dtask, fonts[0]);
+		g_string_append_printf (string, "%s\n", text);
+		g_free (text);
+	} else {
+		for (i=0; i<len; i++) {
+			text = gpk_dbus_task_font_tag_to_localised_name (dtask, fonts[i]);
+			g_string_append_printf (string, "• %s\n", text);
+			g_free (text);
+		}
+	}
+	/* display messagebox  */
+	text = g_string_free (string, FALSE);
+
+	/* TRANSLATORS: we need to download a new font package to display a document */
+	title = ngettext ("An additional font is required to view this document correctly.",
+			  "Additional fonts are required to view this document correctly.", len);
+
+	/* TRANSLATORS: we need to download a new font package to display a document */
+	title_part = ngettext ("Do you want to search for a suitable package now?",
+			       "Do you want to search for suitable packages now?", len);
+
+	/* check user wanted operation */
+	message = g_strdup_printf ("%s\n\n%s\n%s", title, text, title_part);
+	g_free (text);
+
+	/* make title using application name */
+	if (dtask->priv->parent_title != NULL) {
+		/* TRANSLATORS: string is a program name, e.g. "Movie Player" */
+		text = g_strdup_printf (ngettext ("%s wants to install a font", "%s wants to install fonts", len), dtask->priv->parent_title);
+	} else {
+		/* TRANSLATORS: a random program which we can't get the name wants to do something */
+		text = g_strdup (ngettext ("A program wants to install a font", "A program wants to install fonts", len));
+	}
+
+	/* TRANSLATORS: button: confirm to search for packages */
+	ret = gpk_dbus_task_confirm_action (dtask, text, message, _("Search"));
+	g_free (text);
+	g_free (message);
+	if (!ret) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+skip_checks:
+	/* TRANSLATORS: title to show when searching for font files */
+	title = ngettext ("Searching for font", "Searching for fonts", len);
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	gpk_modal_dialog_set_title (dtask->priv->dialog, title);
+	gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT);
+
+	/* setup the UI */
+	if (dtask->priv->show_progress)
+		gpk_modal_dialog_present (dtask->priv->dialog);
+
+	/* do each one */
+	pk_client_what_provides_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_NOT_INSTALLED, PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, -1),
+#if PK_CHECK_VERSION(0,9,0)
+				       fonts, NULL,
+#else
+				       PK_PROVIDES_ENUM_FONT, fonts, NULL,
+#endif
+			               (PkProgressCallback) gpk_dbus_task_progress_cb, dtask,
+				       (GAsyncReadyCallback) gpk_dbus_task_fontconfig_what_provides_cb, dtask);
+out:
+	if (array != NULL)
+		g_ptr_array_unref (array);
+}
+
+/**
+ * gpk_dbus_task_install_plasma_resources_confirm:
+ **/
+static gboolean
+gpk_dbus_task_install_plasma_resources_confirm (GpkDbusTask *dtask, gchar **service_names)
+{
+	guint i;
+	guint len;
+	const gchar *text;
+	gboolean ret;
+	GString *string;
+	gchar *title;
+	gchar *message;
+
+	len = g_strv_length (service_names);
+
+	/* TRANSLATORS: we are listing the services in a box */
+	text = ngettext ("The following service is required:", "The following services are required:", len);
+	string = g_string_new ("");
+	g_string_append_printf (string, "%s\n\n", text);
+
+	/* don't use a bullet for one item */
+	if (len == 1)
+		g_string_append_printf (string, "%s\n", service_names[0]);
+	else
+		for (i=0; i<len; i++)
+			g_string_append_printf (string, "• %s\n", service_names[i]);
+
+	/* TRANSLATORS: ask for confirmation */
+	message = ngettext ("Do you want to search for this now?", "Do you want to search for these now?", len);
+	g_string_append_printf (string, "\n%s\n", message);
+
+	/* remove last \n */
+	g_string_set_size (string, string->len - 1);
+
+	/* display messagebox  */
+	message = g_string_free (string, FALSE);
+	title = g_strdup (ngettext ("Plasma requires an additional service for this operation",
+				    "Plasma requires additional services for this operation", len));
+
+	/* TRANSLATORS: button: confirm to search for packages */
+	ret = gpk_dbus_task_confirm_action (dtask, title, message, _("Search"));
+	g_free (title);
+	g_free (message);
+
+	return ret;
+}
+
+/**
+ * gpk_dbus_task_plasma_service_what_provides_cb:
+ **/
+static void
+gpk_dbus_task_plasma_service_what_provides_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	PkResults *results = NULL;
+	GPtrArray *array = NULL;
+	PkError *error_code = NULL;
+	GtkResponseType button;
+	gchar *info_url;
+	const gchar *title;
+	const gchar *message;
+
+	/* get the results */
+	results = pk_client_generic_finish (client, res, &error);
+	if (results == NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to resolve: %s", error->message);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* check error code */
+	error_code = pk_results_get_error_code (results);
+	if (error_code != NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to resolve: %s", pk_error_get_details (error_code));
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* get results */
+	array = pk_results_get_package_array (results);
+
+	/* found nothing? */
+	if (array->len == 0) {
+		if (dtask->priv->show_warning) {
+			info_url = gpk_vendor_get_not_found_url (dtask->priv->vendor, GPK_VENDOR_URL_TYPE_DEFAULT);
+			/* only show the "more info" button if there is a valid link */
+			if (info_url != NULL)
+				gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, GPK_MODAL_DIALOG_BUTTON_ACTION);
+			else
+				gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+			gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to search for Plasma service"));
+			/* TRANSLATORS: no package sources have the wanted Plasma service */
+			gpk_modal_dialog_set_message (dtask->priv->dialog, _("Could not find service in any configured package source"));
+
+			/* TRANSLATORS: button text */
+			gpk_modal_dialog_set_action (dtask->priv->dialog, _("More information"));
+			gpk_modal_dialog_present (dtask->priv->dialog);
+			button = gpk_modal_dialog_run (dtask->priv->dialog);
+			if (button == GTK_RESPONSE_OK)
+				gpk_gnome_open (info_url);
+			g_free (info_url);
+		}
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "failed to find Plasma service");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* optional */
+	if (!dtask->priv->show_confirm_install) {
+		g_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks2;
+	}
+
+	title = ngettext ("Install the following plugin", "Install the following plugins", array->len);
+	message = ngettext ("Do you want to install this package now?", "Do you want to install these packages now?", array->len);
+
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST);
+	gpk_modal_dialog_set_package_list (dtask->priv->dialog, array);
+	gpk_modal_dialog_set_title (dtask->priv->dialog, title);
+	gpk_modal_dialog_set_message (dtask->priv->dialog, message);
+	gpk_modal_dialog_set_image (dtask->priv->dialog, "dialog-information");
+	/* TRANSLATORS: button: install Plasma services */
+	gpk_modal_dialog_set_action (dtask->priv->dialog, _("Install"));
+	gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp);
+	button = gpk_modal_dialog_run (dtask->priv->dialog);
+
+	/* close, we're going to fail the method */
+	if (button != GTK_RESPONSE_OK) {
+		gpk_modal_dialog_close (dtask->priv->dialog);
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to download");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+skip_checks2:
+	/* install with deps */
+	dtask->priv->package_ids = pk_package_array_to_strv (array);
+	gpk_dbus_task_install_package_ids (dtask);
+out:
+	if (error_code != NULL)
+		g_object_unref (error_code);
+	if (array != NULL)
+		g_ptr_array_unref (array);
+	if (results != NULL)
+		g_object_unref (results);
+}
+
+/**
+ * gpk_dbus_task_install_plasma_resources:
+ * @task: a valid #GpkDbusTask instance
+ * @service_names: a service type such as <literal>dataengine-weather</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a service to handle a Plasma request
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+static void
+gpk_dbus_task_install_plasma_resources (GpkDbusTask *dtask, gchar **service_names, GpkDbusTaskFinishedCb finished_cb, gpointer userdata)
+{
+	gboolean ret = TRUE;
+	GError *error_dbus = NULL;
+	gchar *message = NULL;
+	GPtrArray *array_title = NULL;
+	GPtrArray *array_search = NULL;
+	gchar **search = NULL;
+	gchar **title = NULL;
+	gchar *title_str = NULL;
+	guint i;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (dtask));
+	g_return_if_fail (service_names != NULL);
+
+	/* save callback information */
+	dtask->priv->finished_cb = finished_cb;
+	dtask->priv->finished_userdata = userdata;
+
+	/* optional */
+	if (!dtask->priv->show_confirm_search) {
+		g_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	/* confirm */
+	ret = gpk_dbus_task_install_plasma_resources_confirm (dtask, service_names);
+	if (!ret) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+skip_checks:
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING);
+	/* TRANSLATORS: search for Plasma services */
+	gpk_modal_dialog_set_title (dtask->priv->dialog, _("Searching for services"));
+	gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT);
+
+	/* setup the UI */
+	if (dtask->priv->show_progress)
+		gpk_modal_dialog_present (dtask->priv->dialog);
+
+	/* get the request */
+	array_title = g_ptr_array_new_with_free_func (g_free);
+	array_search = g_ptr_array_new_with_free_func (g_free);
+	for (i=0; service_names[i] != NULL; i++) {
+		g_ptr_array_add (array_title, g_strdup (service_names[i]));
+		g_ptr_array_add (array_search, g_strdup (service_names[i]));
+	}
+
+	/* TRANSLATORS: title, searching for Plasma services */
+	title = pk_ptr_array_to_strv (array_title);
+	title_str = g_strjoinv (", ", title);
+	message = g_strdup_printf (_("Searching for service: %s"), title_str);
+	gpk_modal_dialog_set_message (dtask->priv->dialog, message);
+
+	/* get service packages */
+	search = pk_ptr_array_to_strv (array_search);
+	pk_client_what_provides_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_NOT_INSTALLED, PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, -1),
+#if PK_CHECK_VERSION(0,9,0)
+				       search, NULL,
+#else
+				       PK_PROVIDES_ENUM_PLASMA_SERVICE, search, NULL,
+#endif
+				       (PkProgressCallback) gpk_dbus_task_progress_cb, dtask,
+				       (GAsyncReadyCallback) gpk_dbus_task_plasma_service_what_provides_cb, dtask);
+out:
+	if (array_title != NULL)
+		g_ptr_array_unref (array_title);
+	if (array_search != NULL)
+		g_ptr_array_unref (array_search);
+	g_strfreev (search);
+	g_strfreev (title);
+	g_free (message);
+	g_free (title_str);
+}
+
+/**
+ * gpk_dbus_task_install_resources:
+ * @task: a valid #GpkDbusTask instance
+ * @type: type of the resource
+ * @resources: a list of resources
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install a resource of the given type
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_resources (GpkDbusTask *dtask, gchar **resources, GpkDbusTaskFinishedCb finished_cb, gpointer userdata)
+{
+	gpk_dbus_task_install_plasma_resources (dtask, resources, finished_cb, userdata);
+}
+
+/**
+ * gpk_dbus_task_remove_packages_cb:
+ **/
+static void
+gpk_dbus_task_remove_packages_cb (PkTask *task, GAsyncResult *res, GpkDbusTask *dtask)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	PkResults *results = NULL;
+	PkError *error_code = NULL;
+
+	/* get the results */
+	results = pk_task_generic_finish (task, res, &error);
+	if (results == NULL) {
+		/* TRANSLATORS: error: failed to remove, detailed error follows */
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to remove package: %s", error->message);
+		gpk_dbus_task_error_msg (dtask, _("Failed to remove package"), error_dbus);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* check error code */
+	error_code = pk_results_get_error_code (results);
+	if (error_code != NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to remove package: %s", pk_error_get_details (error_code));
+		gpk_dbus_task_handle_error (dtask, error_code);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* we're done */
+	gpk_dbus_task_dbus_return_value (dtask, TRUE);
+out:
+	if (error_code != NULL)
+		g_object_unref (error_code);
+	if (results != NULL)
+		g_object_unref (results);
+}
+
+/**
+ * gpk_dbus_task_printer_driver_what_provides_cb:
+ **/
+static void
+gpk_dbus_task_printer_driver_what_provides_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	PkResults *results = NULL;
+	GPtrArray *array = NULL;
+	PkError *error_code = NULL;
+	GtkResponseType button;
+	const gchar *title;
+	const gchar *message;
+
+	/* get the results */
+	results = pk_client_generic_finish (client, res, &error);
+	if (results == NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to resolve: %s", error->message);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* check error code */
+	error_code = pk_results_get_error_code (results);
+	if (error_code != NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to resolve: %s", pk_error_get_details (error_code));
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* get results */
+	array = pk_results_get_package_array (results);
+
+	/* found nothing?  No problem*/
+	if (array->len == 0) {
+		gpk_modal_dialog_close (dtask->priv->dialog);
+		gpk_dbus_task_dbus_return_value (dtask, FALSE);
+		goto out;
+	}
+
+	/* optional */
+	if (!dtask->priv->show_confirm_install) {
+		g_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks2;
+	}
+
+	title = ngettext ("Install the following driver", "Install the following drivers", array->len);
+	message = ngettext ("Do you want to install this package now?", "Do you want to install these packages now?", array->len);
+
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST);
+	gpk_modal_dialog_set_package_list (dtask->priv->dialog, array);
+	gpk_modal_dialog_set_title (dtask->priv->dialog, title);
+	gpk_modal_dialog_set_message (dtask->priv->dialog, message);
+	gpk_modal_dialog_set_image (dtask->priv->dialog, "dialog-information");
+	/* TRANSLATORS: button: install printer drivers */
+	gpk_modal_dialog_set_action (dtask->priv->dialog, _("Install"));
+	gpk_modal_dialog_present_with_time (dtask->priv->dialog, dtask->priv->timestamp);
+	button = gpk_modal_dialog_run (dtask->priv->dialog);
+
+	/* close, we're going to fail the method */
+	if (button != GTK_RESPONSE_OK) {
+		gpk_modal_dialog_close (dtask->priv->dialog);
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to download");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+skip_checks2:
+	/* install with deps */
+	dtask->priv->package_ids = pk_package_array_to_strv (array);
+	gpk_dbus_task_install_package_ids (dtask);
+out:
+	if (error_code != NULL)
+		g_object_unref (error_code);
+	if (array != NULL)
+		g_ptr_array_unref (array);
+	if (results != NULL)
+		g_object_unref (results);
+}
+
+/**
+ * gpk_dbus_task_install_printer_drivers:
+ * @task: a valid #GpkDbusTask instance
+ * @device_ids: list of Device IDs such as <literal>MFG:Foo Inc;MDL:Bar 3000;</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Install printer drivers for a given set of models.
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_install_printer_drivers (GpkDbusTask *dtask, gchar **device_ids, GpkDbusTaskFinishedCb finished_cb, gpointer userdata)
+{
+	guint i, j;
+	guint len;
+	guint n_tags;
+	guint n_fields;
+	gchar **fields;
+	gchar *mfg;
+	gchar *mdl;
+	gchar *tag;
+	gchar **tags;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (dtask));
+	g_return_if_fail (device_ids != NULL);
+
+	/* save callback information */
+	dtask->priv->finished_cb = finished_cb;
+	dtask->priv->finished_userdata = userdata;
+
+	gpk_modal_dialog_setup (dtask->priv->dialog,
+				GPK_MODAL_DIALOG_PAGE_PROGRESS,
+				GPK_MODAL_DIALOG_PACKAGE_PADDING);
+	gpk_modal_dialog_set_title (dtask->priv->dialog,
+				    _("Searching for packages"));
+	gpk_modal_dialog_set_image_status (dtask->priv->dialog,
+					   PK_STATUS_ENUM_WAIT);
+
+	/* setup the UI */
+	if (dtask->priv->show_progress)
+		gpk_modal_dialog_present (dtask->priv->dialog);
+
+	len = g_strv_length (device_ids);
+	if (len > 1)
+		/* hardcode for now as we only support one at a time */
+		len = 1;
+
+	/* make a list of provides tags */
+	tags = g_new0 (gchar *, len);
+	n_tags = 0;
+	for (i=0; i<len; i++) {
+		gchar *p, *ltag;
+		fields = g_strsplit (device_ids[i], ";", 0);
+		n_fields = g_strv_length (fields);
+		mfg = mdl = NULL;
+		for (j=0; j<n_fields && (!mfg || !mdl); j++) {
+			if (g_str_has_prefix (fields[j], "MFG:"))
+				mfg = g_strdup (fields[j] + 4);
+			else if (g_str_has_prefix (fields[j], "MDL:"))
+				mdl = g_strdup (fields[j] + 4);
+		}
+		g_strfreev (fields);
+
+		if (!mfg || !mdl) {
+			g_warning("invalid line '%s', missing field",
+				    device_ids[i]);
+			continue;
+		}
+
+		tag = g_strconcat (mfg, ";", mdl, ";", NULL);
+		ltag = g_ascii_strdown (tag, -1);
+		g_free (tag);
+
+		/* Replace spaces with underscores */
+		for (p = ltag; *p != '\0'; p++)
+			if (*p == ' ')
+				*p = '_';
+
+		tags[n_tags++] = g_strdup (ltag);
+		g_free (ltag);
+	}
+
+	if (n_tags == 0) {
+		gpk_dbus_task_dbus_return_value (dtask, FALSE);
+		goto out;
+	}
+
+	tags = g_renew (gchar *, tags, n_tags + 1);
+	tags[n_tags] = NULL;
+
+	/* get driver packages */
+	pk_client_what_provides_async (PK_CLIENT(dtask->priv->task),
+				       pk_bitfield_from_enums (PK_FILTER_ENUM_NOT_INSTALLED,
+							       PK_FILTER_ENUM_ARCH,
+							       PK_FILTER_ENUM_NEWEST,
+							       -1),
+#if !PK_CHECK_VERSION(0,9,0)
+				       PK_PROVIDES_ENUM_POSTSCRIPT_DRIVER,
+#endif
+				       tags, NULL,
+				       (PkProgressCallback) gpk_dbus_task_progress_cb, dtask,
+				       (GAsyncReadyCallback) gpk_dbus_task_printer_driver_what_provides_cb, dtask);
+
+ out:
+	g_strfreev (tags);
+}
+
+/**
+ * gpk_dbus_task_remove_package_ids:
+ * @task: a valid #GpkDbusTask instance
+ **/
+static void
+gpk_dbus_task_remove_package_ids (GpkDbusTask *dtask)
+{
+	GtkWindow *window;
+
+	gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING);
+	/* TRANSLATORS: title: removing packages */
+	gpk_modal_dialog_set_title (dtask->priv->dialog, _("Removing packages"));
+	if (dtask->priv->show_progress)
+		gpk_modal_dialog_present (dtask->priv->dialog);
+
+	/* ensure parent is set */
+	window = gpk_modal_dialog_get_window (dtask->priv->dialog);
+	gpk_task_set_parent_window (GPK_TASK (dtask->priv->task), window);
+
+	/* remove async */
+	pk_task_remove_packages_async (dtask->priv->task, dtask->priv->package_ids, TRUE, TRUE, NULL,
+					(PkProgressCallback) gpk_dbus_task_progress_cb, dtask,
+					(GAsyncReadyCallback) gpk_dbus_task_remove_packages_cb, dtask);
+}
+
+/**
+ * gpk_dbus_task_remove_package_by_file_search_file_cb:
+ **/
+static void
+gpk_dbus_task_remove_package_by_file_search_file_cb (PkClient *client, GAsyncResult *res, GpkDbusTask *dtask)
+{
+	GError *error = NULL;
+	GError *error_dbus = NULL;
+	PkResults *results = NULL;
+	GPtrArray *array = NULL;
+	PkError *error_code = NULL;
+
+	/* get the results */
+	results = pk_client_generic_finish (client, res, &error);
+	if (results == NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_gerror (error), "failed to search by file: %s", error->message);
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_warning ("failed to resolve: %s", error->message);
+		g_error_free (error);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* check error code */
+	error_code = pk_results_get_error_code (results);
+	if (error_code != NULL) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, gpk_dbus_task_get_code_from_pkerror (error_code), "failed to search by file: %s", pk_error_get_details (error_code));
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* get results */
+	array = pk_results_get_package_array (results);
+
+	/* found nothing? */
+	if (array->len == 0) {
+		if (dtask->priv->show_warning) {
+			gpk_modal_dialog_setup (dtask->priv->dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+			/* TRANSLATORS: failed to find the package for the file */
+			gpk_modal_dialog_set_title (dtask->priv->dialog, _("Failed to find package for this file"));
+			/* TRANSLATORS: nothing found */
+			gpk_modal_dialog_set_message (dtask->priv->dialog, _("The file could not be found in any packages"));
+			/* TRANSLATORS: button: show the user a button to get more help finding stuff */
+			gpk_modal_dialog_present (dtask->priv->dialog);
+			gpk_modal_dialog_run (dtask->priv->dialog);
+		}
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_PACKAGE_NOT_FOUND, "no packages found for this file");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+	/* convert to data */
+	dtask->priv->package_ids = pk_package_array_to_strv (array);
+
+	/* remove these packages with deps */
+	gpk_dbus_task_remove_package_ids (dtask);
+out:
+	if (error_code != NULL)
+		g_object_unref (error_code);
+	if (array != NULL)
+		g_ptr_array_unref (array);
+	if (results != NULL)
+		g_object_unref (results);
+}
+
+/**
+ * gpk_dbus_task_remove_package_by_file:
+ * @task: a valid #GpkDbusTask instance
+ * @full_path: a file path name such as <literal>/usr/sbin/packagekitd</literal>
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * Remove a package which provides a file on the system.
+ *
+ * Return value: %TRUE if the method succeeded
+ **/
+void
+gpk_dbus_task_remove_package_by_file (GpkDbusTask *dtask, gchar **full_paths, GpkDbusTaskFinishedCb finished_cb, gpointer userdata)
+{
+	gboolean ret;
+	GError *error_dbus = NULL;
+	guint len;
+	guint i;
+	gchar *text;
+	gchar *message;
+	GString *string;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (dtask));
+	g_return_if_fail (full_paths != NULL);
+
+	/* save callback information */
+	dtask->priv->finished_cb = finished_cb;
+	dtask->priv->finished_userdata = userdata;
+
+	/* optional */
+	if (!dtask->priv->show_confirm_search) {
+		g_debug ("skip confirm as not allowed to interact with user");
+		goto skip_checks;
+	}
+
+	string = g_string_new ("");
+	len = g_strv_length (full_paths);
+
+	/* don't use a bullet for one item */
+	if (len == 1) {
+		g_string_append_printf (string, "%s\n", full_paths[0]);
+	} else {
+		for (i=0; i<len; i++)
+			g_string_append_printf (string, "• %s\n", full_paths[i]);
+	}
+	/* display messagebox  */
+	text = g_string_free (string, FALSE);
+
+	/* check user wanted operation */
+	message = g_strdup_printf ("%s\n\n%s\n\n%s",
+				   /* TRANSLATORS: a program wants to remove a file, e.g. /lib/moo.so */
+				   ngettext ("The following file will be removed:", "The following files will be removed:", len),
+				   text,
+				   /* TRANSLATORS: confirm with the user */
+				   ngettext ("Do you want to remove this file now?", "Do you want to remove these files now?", len));
+
+	/* make title using application name */
+	if (dtask->priv->parent_title != NULL) {
+		/* TRANSLATORS: string is a program name, e.g. "Movie Player" */
+		text = g_strdup_printf (ngettext ("%s wants to remove a file", "%s wants to remove files", len), dtask->priv->parent_title);
+	} else {
+		/* TRANSLATORS: a random program which we can't get the name wants to do something */
+		text = g_strdup (ngettext ("A program wants to remove a file", "A program wants to remove files", len));
+	}
+
+	/* TRANSLATORS: button: confirm to search for packages */
+	ret = gpk_dbus_task_confirm_action (dtask, text, message, _("Remove"));
+	g_free (text);
+	g_free (message);
+	if (!ret) {
+		error_dbus = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_TRANSACTION_CANCELLED, "did not agree to search");
+		gpk_dbus_task_dbus_return_error (dtask, error_dbus);
+		g_error_free (error_dbus);
+		goto out;
+	}
+
+skip_checks:
+	/* TRANSLATORS: searching for the package that provides the file */
+	gpk_modal_dialog_set_title (dtask->priv->dialog, _("Searching for file"));
+	gpk_modal_dialog_set_image_status (dtask->priv->dialog, PK_STATUS_ENUM_WAIT);
+
+	/* do search */
+	pk_client_search_files_async (PK_CLIENT(dtask->priv->task), pk_bitfield_from_enums (PK_FILTER_ENUM_ARCH, PK_FILTER_ENUM_NEWEST, PK_FILTER_ENUM_INSTALLED, -1), full_paths, NULL,
+			             (PkProgressCallback) gpk_dbus_task_progress_cb, dtask,
+				     (GAsyncReadyCallback) gpk_dbus_task_remove_package_by_file_search_file_cb, dtask);
+
+	/* wait for async reply */
+out:
+	return;
+}
+
+/**
+ * gpk_dbus_task_get_package_for_exec:
+ **/
+gchar *
+gpk_dbus_task_get_package_for_exec (GpkDbusTask *dtask, const gchar *exec)
+{
+	const gchar *package_id;
+	gchar *package = NULL;
+	GError *error = NULL;
+	GPtrArray *array = NULL;
+	PkPackage *item;
+	PkResults *results = NULL;
+	gchar **values = NULL;
+	gchar **split = NULL;
+
+	/* find the package name */
+	values = g_strsplit (exec, "&", -1);
+	results = pk_client_search_files (PK_CLIENT(dtask->priv->task), pk_bitfield_value (PK_FILTER_ENUM_INSTALLED), values, NULL,
+					 (PkProgressCallback) gpk_dbus_task_progress_cb, dtask, &error);
+	if (results == NULL) {
+		g_warning ("failed to search file: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* get the list of packages */
+	array = pk_results_get_package_array (results);
+
+	/* nothing found */
+	if (array->len == 0) {
+		g_debug ("cannot find installed package that provides : %s", exec);
+		goto out;
+	}
+
+	/* check we have one */
+	if (array->len != 1)
+		g_warning ("not one return, using first");
+
+	/* copy name */
+	item = g_ptr_array_index (array, 0);
+	package_id = pk_package_get_id (item);
+	split = pk_package_id_split (package_id);
+	package = g_strdup (split[0]);
+	g_debug ("got package %s", package);
+out:
+	g_strfreev (values);
+	g_strfreev (split);
+	if (array != NULL)
+		g_ptr_array_unref (array);
+	if (results != NULL)
+		g_object_unref (results);
+	return package;
+}
+
+/**
+ * gpk_dbus_task_path_is_trusted:
+ **/
+gboolean
+gpk_dbus_task_path_is_trusted (const gchar *exec)
+{
+	gboolean res = FALSE;
+	gchar *path;
+
+	/* special case the plugin helper -- it's trusted */
+
+	path = g_build_filename (LIBEXECDIR, "gst-install-plugins-helper", NULL);
+	res = res || (g_strcmp0 (exec, path) == 0);
+	g_free (path);
+
+	path = g_build_filename (LIBEXECDIR, "pk-gstreamer-install", NULL);
+	res = res || (g_strcmp0 (exec, path) == 0);
+	g_free (path);
+
+	return res;
+}
+
+/**
+ * gpk_dbus_task_set_exec:
+ *
+ * This sets the package name of the application that is trying to install
+ * software, e.g. "totem" and is used for the PkDesktop lookup to provide
+ * a translated name and icon.
+ **/
+gboolean
+gpk_dbus_task_set_exec (GpkDbusTask *dtask, const gchar *exec)
+{
+	GpkX11 *x11;
+	gchar *package = NULL;
+
+	g_return_val_if_fail (GPK_IS_DBUS_TASK (dtask), FALSE);
+
+	/* old values invalid */
+	g_free (dtask->priv->exec);
+	g_free (dtask->priv->parent_title);
+	g_free (dtask->priv->parent_icon_name);
+	dtask->priv->exec = g_strdup (exec);
+	dtask->priv->parent_title = NULL;
+	dtask->priv->parent_icon_name = NULL;
+
+	/* is the binary trusted, i.e. can we probe it's window properties */
+	if (gpk_dbus_task_path_is_trusted (exec) &&
+            dtask->priv->parent_window != NULL) {
+		g_debug ("using application window properties");
+		/* get from window properties */
+		x11 = gpk_x11_new ();
+		gpk_x11_set_window (x11, dtask->priv->parent_window);
+		dtask->priv->parent_title = gpk_x11_get_title (x11);
+		g_object_unref (x11);
+		goto out;
+	}
+
+	/* get from installed database */
+	package = gpk_dbus_task_get_package_for_exec (dtask, exec);
+	g_debug ("got package %s", package);
+	if (package != NULL)
+		dtask->priv->parent_title = g_strdup (package);
+
+	/* fallback to exec - eugh... */
+	if (dtask->priv->parent_title == NULL) {
+		g_debug ("did not get package for %s, using exec basename", package);
+		dtask->priv->parent_title = g_path_get_basename (exec);
+	}
+out:
+	g_free (package);
+	g_debug ("got name=%s, icon=%s", dtask->priv->parent_title, dtask->priv->parent_icon_name);
+	return TRUE;
+}
+
+/**
+ * gpk_dbus_task_class_init:
+ * @klass: The #GpkDbusTaskClass
+ **/
+static void
+gpk_dbus_task_class_init (GpkDbusTaskClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_dbus_task_finalize;
+	g_type_class_add_private (klass, sizeof (GpkDbusTaskPrivate));
+}
+
+/**
+ * gpk_dbus_task_init:
+ * @task: a valid #GpkDbusTask instance
+ **/
+static void
+gpk_dbus_task_init (GpkDbusTask *dtask)
+{
+	GtkWindow *main_window;
+
+	dtask->priv = GPK_DBUS_TASK_GET_PRIVATE (dtask);
+
+	dtask->priv->package_ids = NULL;
+	dtask->priv->files = NULL;
+	dtask->priv->parent_window = NULL;
+	dtask->priv->parent_title = NULL;
+	dtask->priv->exec = NULL;
+	dtask->priv->parent_icon_name = NULL;
+	dtask->priv->cached_error_code = NULL;
+	dtask->priv->context = NULL;
+	dtask->priv->cancellable = g_cancellable_new ();
+	dtask->priv->exit = PK_EXIT_ENUM_FAILED;
+	dtask->priv->show_confirm_search = TRUE;
+	dtask->priv->show_confirm_deps = TRUE;
+	dtask->priv->show_confirm_install = TRUE;
+	dtask->priv->show_progress = TRUE;
+	dtask->priv->show_finished = TRUE;
+	dtask->priv->show_warning = TRUE;
+	dtask->priv->timestamp = 0;
+
+	/* add application specific icons to search path */
+	gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
+					   GPK_DATA G_DIR_SEPARATOR_S "icons");
+
+	/* only initialize if the application didn't do it before */
+	if (!notify_is_initted ())
+		notify_init (_("Software Install"));
+
+	dtask->priv->vendor = gpk_vendor_new ();
+	dtask->priv->dialog = gpk_modal_dialog_new ();
+	main_window = gpk_modal_dialog_get_window (dtask->priv->dialog);
+	gpk_modal_dialog_set_window_icon (dtask->priv->dialog, "pk-package-installed");
+	g_signal_connect (dtask->priv->dialog, "cancel",
+			  G_CALLBACK (gpk_dbus_task_button_cancel_cb), dtask);
+	g_signal_connect (dtask->priv->dialog, "close",
+			  G_CALLBACK (gpk_dbus_task_button_close_cb), dtask);
+
+	/* helpers */
+	dtask->priv->helper_run = gpk_helper_run_new ();
+	gpk_helper_run_set_parent (dtask->priv->helper_run, main_window);
+
+	dtask->priv->helper_chooser = gpk_helper_chooser_new ();
+	g_signal_connect (dtask->priv->helper_chooser, "event", G_CALLBACK (gpk_dbus_task_chooser_event_cb), dtask);
+	gpk_helper_chooser_set_parent (dtask->priv->helper_chooser, main_window);
+
+	/* map ISO639 to language names */
+	dtask->priv->language = gpk_language_new ();
+	gpk_language_populate (dtask->priv->language, NULL);
+
+	/* gat session settings */
+	dtask->priv->settings = g_settings_new (GPK_SETTINGS_SCHEMA);
+
+	/* get actions */
+	dtask->priv->control = pk_control_new ();
+	dtask->priv->task = PK_TASK(gpk_task_new ());
+	dtask->priv->roles = pk_control_get_properties (dtask->priv->control, NULL, NULL);
+}
+
+/**
+ * gpk_dbus_task_finalize:
+ * @object: The object to finalize
+ **/
+static void
+gpk_dbus_task_finalize (GObject *object)
+{
+	GpkDbusTask *dtask;
+	GError *error;
+
+	g_return_if_fail (GPK_IS_DBUS_TASK (object));
+
+	dtask = GPK_DBUS_TASK (object);
+	g_return_if_fail (dtask->priv != NULL);
+
+	/* no reply was sent */
+	if (dtask->priv->context != NULL) {
+		error = g_error_new (GPK_DBUS_ERROR, PK_ERROR_ENUM_INTERNAL_ERROR, "context never was returned");
+		gpk_dbus_task_dbus_return_error (dtask, error);
+		g_error_free (error);
+	}
+
+	g_free (dtask->priv->parent_title);
+	g_free (dtask->priv->parent_icon_name);
+	g_free (dtask->priv->exec);
+	if (dtask->priv->cached_error_code != NULL)
+		g_object_unref (dtask->priv->cached_error_code);
+	g_strfreev (dtask->priv->files);
+	g_strfreev (dtask->priv->package_ids);
+	g_object_unref (PK_CLIENT(dtask->priv->task));
+	g_object_unref (dtask->priv->control);
+	g_object_unref (dtask->priv->settings);
+	g_object_unref (dtask->priv->dialog);
+	g_object_unref (dtask->priv->vendor);
+	g_object_unref (dtask->priv->language);
+	g_object_unref (dtask->priv->cancellable);
+	g_object_unref (dtask->priv->helper_run);
+	g_object_unref (dtask->priv->helper_chooser);
+
+	G_OBJECT_CLASS (gpk_dbus_task_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_dbus_task_new:
+ *
+ * PkClient is a nice GObject wrapper for gnome-packagekit and makes installing software easy
+ *
+ * Return value: A new %GpkDbusTask instance
+ **/
+GpkDbusTask *
+gpk_dbus_task_new (void)
+{
+	GpkDbusTask *dtask;
+	dtask = g_object_new (GPK_TYPE_DBUS_TASK, NULL);
+	return GPK_DBUS_TASK (dtask);
+}
Index: gnome-packagekit-3.20.0/src/gpk-dbus-task.h
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-dbus-task.h
@@ -0,0 +1,161 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GPK_DBUS_TASK_H
+#define __GPK_DBUS_TASK_H
+
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+#include <packagekit-glib2/packagekit.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_DBUS_TASK		(gpk_dbus_task_get_type ())
+#define GPK_DBUS_TASK(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_DBUS_TASK, GpkDbusTask))
+#define GPK_DBUS_TASK_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_DBUS_TASK, GpkDbusTaskClass))
+#define GPK_IS_DBUS_TASK(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_DBUS_TASK))
+#define GPK_IS_DBUS_TASK_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_DBUS_TASK))
+#define GPK_DBUS_TASK_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_DBUS_TASK, GpkDbusTaskClass))
+
+typedef struct _GpkDbusTaskPrivate	 GpkDbusTaskPrivate;
+typedef struct _GpkDbusTask		 GpkDbusTask;
+typedef struct _GpkDbusTaskClass	 GpkDbusTaskClass;
+
+struct _GpkDbusTask
+{
+	GObject				 parent;
+	GpkDbusTaskPrivate		*priv;
+};
+
+struct _GpkDbusTaskClass
+{
+	GObjectClass	parent_class;
+};
+
+/**
+ * GpkDbusTaskInteract:
+ */
+typedef enum
+{
+	GPK_CLIENT_INTERACT_CONFIRM_SEARCH,
+	GPK_CLIENT_INTERACT_CONFIRM_DEPS,
+	GPK_CLIENT_INTERACT_CONFIRM_INSTALL,
+	GPK_CLIENT_INTERACT_PROGRESS,
+	GPK_CLIENT_INTERACT_FINISHED,
+	GPK_CLIENT_INTERACT_WARNING,
+	GPK_CLIENT_INTERACT_UNKNOWN
+} GpkDbusTaskInteract;
+
+#define GPK_CLIENT_INTERACT_NEVER			0
+#define GPK_CLIENT_INTERACT_ALWAYS			pk_bitfield_from_enums (GPK_CLIENT_INTERACT_WARNING, \
+										GPK_CLIENT_INTERACT_CONFIRM_SEARCH, \
+										GPK_CLIENT_INTERACT_CONFIRM_DEPS, \
+										GPK_CLIENT_INTERACT_CONFIRM_INSTALL, \
+										GPK_CLIENT_INTERACT_PROGRESS, \
+										GPK_CLIENT_INTERACT_FINISHED, -1)
+#define GPK_CLIENT_INTERACT_WARNING_CONFIRM_PROGRESS	pk_bitfield_from_enums (GPK_CLIENT_INTERACT_WARNING, \
+										GPK_CLIENT_INTERACT_CONFIRM_SEARCH, \
+										GPK_CLIENT_INTERACT_CONFIRM_DEPS, \
+										GPK_CLIENT_INTERACT_CONFIRM_INSTALL, \
+										GPK_CLIENT_INTERACT_PROGRESS, -1)
+#define GPK_CLIENT_INTERACT_WARNING			pk_bitfield_from_enums (GPK_CLIENT_INTERACT_WARNING, -1)
+#define GPK_CLIENT_INTERACT_WARNING_PROGRESS		pk_bitfield_from_enums (GPK_CLIENT_INTERACT_WARNING, \
+										GPK_CLIENT_INTERACT_PROGRESS, -1)
+
+GQuark		 gpk_dbus_task_error_quark		(void);
+GType		 gpk_dbus_task_get_type			(void);
+GType		 gpk_dbus_task_error_get_type		(void);
+GpkDbusTask	*gpk_dbus_task_new			(void);
+
+/* callback when done */
+typedef void	(*GpkDbusTaskFinishedCb)		(GpkDbusTask	*dtask,
+							 gpointer	 userdata);
+
+/* methods that expect a DBusGMethodInvocation return */
+void		 gpk_dbus_task_is_installed		(GpkDbusTask	*dtask,
+							 const gchar	*package_name,
+							 GpkDbusTaskFinishedCb finished_cb,
+							 gpointer	 userdata);
+void		 gpk_dbus_task_search_file		(GpkDbusTask	*dtask,
+							 const gchar	*search_file,
+							 GpkDbusTaskFinishedCb finished_cb,
+							 gpointer	 userdata);
+void		 gpk_dbus_task_install_package_files	(GpkDbusTask	*dtask,
+							 gchar		**files_rel,
+							 GpkDbusTaskFinishedCb finished_cb,
+							 gpointer	 userdata);
+void		 gpk_dbus_task_install_provide_files	(GpkDbusTask	*dtask,
+							 gchar		**full_paths,
+							 GpkDbusTaskFinishedCb finished_cb,
+							 gpointer	 userdata);
+void		 gpk_dbus_task_install_mime_types	(GpkDbusTask	*dtask,
+							 gchar		**mime_types,
+							 GpkDbusTaskFinishedCb finished_cb,
+							 gpointer	 userdata);
+void		 gpk_dbus_task_install_gstreamer_resources (GpkDbusTask	*dtask,
+							 gchar		**codec_names,
+							 GpkDbusTaskFinishedCb finished_cb,
+							 gpointer	 userdata);
+void		 gpk_dbus_task_install_fontconfig_resources (GpkDbusTask *dtask,
+							 gchar		**fonts,
+							 GpkDbusTaskFinishedCb finished_cb,
+							 gpointer	 userdata);
+void		 gpk_dbus_task_install_resources	(GpkDbusTask	*dtask,
+							 gchar		**resources,
+							 GpkDbusTaskFinishedCb finished_cb,
+							 gpointer	 userdata);
+void		 gpk_dbus_task_install_printer_drivers (GpkDbusTask *dtask,
+							gchar		**ids,
+							GpkDbusTaskFinishedCb finished_cb,
+							gpointer	userdata);
+void		 gpk_dbus_task_install_package_names	(GpkDbusTask	*dtask,
+							 gchar		**packages,
+							 GpkDbusTaskFinishedCb finished_cb,
+							 gpointer	 userdata);
+void		 gpk_dbus_task_remove_package_by_file	(GpkDbusTask	*dtask,
+							 gchar		**full_paths,
+							 GpkDbusTaskFinishedCb finished_cb,
+							 gpointer	 userdata);
+
+/* set state */
+gboolean	 gpk_dbus_task_set_interaction		(GpkDbusTask	*dtask,
+							 PkBitfield	 interact);
+gboolean	 gpk_dbus_task_set_timestamp		(GpkDbusTask	*dtask,
+							 guint		 timeout);
+gboolean	 gpk_dbus_task_set_context		(GpkDbusTask	*dtask,
+							 DBusGMethodInvocation *context);
+gboolean	 gpk_dbus_task_set_xid			(GpkDbusTask	*dtask,
+							 guint		 xid);
+gboolean	 gpk_dbus_task_set_exec			(GpkDbusTask	*dtask,
+							 const gchar	*exec);
+
+/* for self checks */
+gchar		*gpk_dbus_task_font_tag_to_localised_name (GpkDbusTask	*dtask,
+							 const gchar	*tag);
+gboolean	 gpk_dbus_task_path_is_trusted		(const gchar	*exec);
+gchar		*gpk_dbus_task_get_package_for_exec	(GpkDbusTask	*dtask,
+							 const gchar	*exec);
+gchar		*gpk_dbus_task_font_tag_to_lang		(const gchar	*tag);
+
+
+G_END_DECLS
+
+#endif /* __GPK_DBUS_TASK_H */
Index: gnome-packagekit-3.20.0/src/gpk-dbus.c
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-dbus.c
@@ -0,0 +1,590 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008-2009 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <string.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include <sys/wait.h>
+#include <fcntl.h>
+
+#include <glib/gi18n.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <packagekit-glib2/packagekit.h>
+
+#include "egg-string.h"
+
+#include "gpk-dbus.h"
+#include "gpk-dbus-task.h"
+#include "gpk-x11.h"
+#include "gpk-common.h"
+
+static void     gpk_dbus_finalize	(GObject	*object);
+
+#define GPK_DBUS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_DBUS, GpkDbusPrivate))
+
+struct GpkDbusPrivate
+{
+	GSettings		*settings;
+	gint			 timeout_tmp;
+	GTimer			*timer;
+	guint			 refcount;
+	GpkX11			*x11;
+	DBusGProxy		*proxy_session_pid;
+	DBusGProxy		*proxy_system_pid;
+};
+
+G_DEFINE_TYPE (GpkDbus, gpk_dbus, G_TYPE_OBJECT)
+
+/**
+ * gpk_dbus_error_quark:
+ * Return value: Our personal error quark.
+ **/
+GQuark
+gpk_dbus_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("gpk_dbus_error");
+	return quark;
+}
+
+/**
+ * gpk_dbus_error_get_type:
+ **/
+GType
+gpk_dbus_error_get_type (void)
+{
+	static GType etype = 0;
+
+	if (etype == 0) {
+		guint i;
+		static GEnumValue values[PK_ERROR_ENUM_LAST];
+		for (i = 0; i < PK_ERROR_ENUM_LAST; i++) {
+			values[i].value = i;
+			values[i].value_name = pk_error_enum_to_string (i);
+			values[i].value_nick = pk_error_enum_to_string (i);
+		}
+		etype = g_enum_register_static ("GpkDbusError", values);
+	}
+	return etype;
+}
+
+/**
+ * gpk_dbus_get_idle_time:
+ **/
+guint
+gpk_dbus_get_idle_time (GpkDbus	*dbus)
+{
+	guint idle = 0;
+
+	/* we need to return 0 if there is a task in progress */
+	if (dbus->priv->refcount > 0)
+		goto out;
+
+	idle = (guint) g_timer_elapsed (dbus->priv->timer, NULL);
+	g_debug ("we've been idle for %is", idle);
+out:
+	return idle;
+}
+
+/**
+ * gpk_dbus_get_pid_session:
+ **/
+static guint
+gpk_dbus_get_pid_session (GpkDbus *dbus, const gchar *sender)
+{
+	guint pid = G_MAXUINT;
+	gboolean ret;
+	GError *error = NULL;
+
+	/* get pid from DBus (quite slow) */
+	ret = dbus_g_proxy_call (dbus->priv->proxy_session_pid, "GetConnectionUnixProcessID", &error,
+				 G_TYPE_STRING, sender,
+				 G_TYPE_INVALID,
+				 G_TYPE_UINT, &pid,
+				 G_TYPE_INVALID);
+	if (!ret) {
+		g_debug ("failed to get pid from session: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	return pid;
+}
+
+/**
+ * gpk_dbus_get_pid_system:
+ **/
+static guint
+gpk_dbus_get_pid_system (GpkDbus *dbus, const gchar *sender)
+{
+	guint pid = G_MAXUINT;
+	gboolean ret;
+	GError *error = NULL;
+
+	/* get pid from DBus (quite slow) */
+	ret = dbus_g_proxy_call (dbus->priv->proxy_system_pid, "GetConnectionUnixProcessID", &error,
+				 G_TYPE_STRING, sender,
+				 G_TYPE_INVALID,
+				 G_TYPE_UINT, &pid,
+				 G_TYPE_INVALID);
+	if (!ret) {
+		g_debug ("failed to get pid from system: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+out:
+	return pid;
+}
+
+/**
+ * gpk_dbus_get_pid:
+ **/
+static guint
+gpk_dbus_get_pid (GpkDbus *dbus, const gchar *sender)
+{
+	guint pid;
+
+	g_return_val_if_fail (PK_IS_DBUS (dbus), G_MAXUINT);
+	g_return_val_if_fail (dbus->priv->proxy_session_pid != NULL, G_MAXUINT);
+	g_return_val_if_fail (dbus->priv->proxy_system_pid != NULL, G_MAXUINT);
+	g_return_val_if_fail (sender != NULL, G_MAXUINT);
+
+	/* check system bus first */
+	pid = gpk_dbus_get_pid_system (dbus, sender);
+	if (pid != G_MAXUINT)
+		goto out;
+
+	/* and then session bus */
+	pid = gpk_dbus_get_pid_session (dbus, sender);
+	if (pid != G_MAXUINT)
+		goto out;
+
+	/* should be impossible */
+	g_warning ("could not find pid!");
+out:
+	return pid;
+}
+
+/**
+ * gpk_dbus_get_exec_for_sender:
+ **/
+static gchar *
+gpk_dbus_get_exec_for_sender (GpkDbus *dbus, const gchar *sender)
+{
+	gchar *filename = NULL;
+	gchar *cmdline = NULL;
+	GError *error = NULL;
+	guint pid;
+
+	g_return_val_if_fail (PK_IS_DBUS (dbus), NULL);
+	g_return_val_if_fail (sender != NULL, NULL);
+
+	/* get pid */
+	pid = gpk_dbus_get_pid (dbus, sender);
+	if (pid == G_MAXUINT) {
+		g_warning ("failed to get PID");
+		goto out;
+	}
+
+	/* get command line from proc */
+	filename = g_strdup_printf ("/proc/%i/exe", pid);
+	cmdline = g_file_read_link (filename, &error);
+	if (cmdline == NULL) {
+		g_warning ("failed to find exec: %s", error->message);
+		g_error_free (error);
+	}
+out:
+	g_free (filename);
+	return cmdline;
+}
+
+/**
+ * gpk_dbus_set_interaction_from_text:
+ **/
+static void
+gpk_dbus_set_interaction_from_text (PkBitfield *interact, gint *timeout, const gchar *interaction)
+{
+	guint i;
+	guint len;
+	gchar **interactions;
+	interactions = g_strsplit (interaction, ",", -1);
+	len = g_strv_length (interactions);
+
+	/* do special keys first */
+	for (i=0; i<len; i++) {
+		if (g_strcmp0 (interactions[i], "always") == 0)
+			*interact = GPK_CLIENT_INTERACT_ALWAYS;
+		else if (g_strcmp0 (interactions[i], "never") == 0)
+			*interact = GPK_CLIENT_INTERACT_NEVER;
+	}
+
+	/* add or remove from defaults */
+	for (i=0; i<len; i++) {
+		/* show */
+		if (g_strcmp0 (interactions[i], "show-confirm-search") == 0)
+			pk_bitfield_add (*interact, GPK_CLIENT_INTERACT_CONFIRM_SEARCH);
+		else if (g_strcmp0 (interactions[i], "show-confirm-deps") == 0)
+			pk_bitfield_add (*interact, GPK_CLIENT_INTERACT_CONFIRM_DEPS);
+		else if (g_strcmp0 (interactions[i], "show-confirm-install") == 0)
+			pk_bitfield_add (*interact, GPK_CLIENT_INTERACT_CONFIRM_INSTALL);
+		else if (g_strcmp0 (interactions[i], "show-progress") == 0)
+			pk_bitfield_add (*interact, GPK_CLIENT_INTERACT_PROGRESS);
+		else if (g_strcmp0 (interactions[i], "show-finished") == 0)
+			pk_bitfield_add (*interact, GPK_CLIENT_INTERACT_FINISHED);
+		else if (g_strcmp0 (interactions[i], "show-warning") == 0)
+			pk_bitfield_add (*interact, GPK_CLIENT_INTERACT_WARNING);
+		/* hide */
+		else if (g_strcmp0 (interactions[i], "hide-confirm-search") == 0)
+			pk_bitfield_remove (*interact, GPK_CLIENT_INTERACT_CONFIRM_SEARCH);
+		else if (g_strcmp0 (interactions[i], "hide-confirm-deps") == 0)
+			pk_bitfield_remove (*interact, GPK_CLIENT_INTERACT_CONFIRM_DEPS);
+		else if (g_strcmp0 (interactions[i], "hide-confirm-install") == 0)
+			pk_bitfield_remove (*interact, GPK_CLIENT_INTERACT_CONFIRM_INSTALL);
+		else if (g_strcmp0 (interactions[i], "hide-progress") == 0)
+			pk_bitfield_remove (*interact, GPK_CLIENT_INTERACT_PROGRESS);
+		else if (g_strcmp0 (interactions[i], "hide-finished") == 0)
+			pk_bitfield_remove (*interact, GPK_CLIENT_INTERACT_FINISHED);
+		else if (g_strcmp0 (interactions[i], "hide-warning") == 0)
+			pk_bitfield_remove (*interact, GPK_CLIENT_INTERACT_WARNING);
+		/* wait */
+		else if (g_str_has_prefix (interactions[i], "timeout="))
+			*timeout = atoi (&interactions[i][8]);
+	}
+	g_strfreev (interactions);
+}
+
+/**
+ * gpk_dbus_parse_interaction:
+ **/
+static void
+gpk_dbus_parse_interaction (GpkDbus *dbus, const gchar *interaction, PkBitfield *interact, gint *timeout)
+{
+	gchar *policy;
+
+	/* set temp default */
+	*interact = 0;
+	dbus->priv->timeout_tmp = -1;
+
+	/* get default policy from settings */
+	policy = g_settings_get_string (dbus->priv->settings, GPK_SETTINGS_DBUS_DEFAULT_INTERACTION);
+	if (policy != NULL) {
+		g_debug ("default is %s", policy);
+		gpk_dbus_set_interaction_from_text (interact, &dbus->priv->timeout_tmp, policy);
+	}
+	g_free (policy);
+
+	/* now override with policy from client */
+	gpk_dbus_set_interaction_from_text (interact, &dbus->priv->timeout_tmp, interaction);
+	g_debug ("client is %s", interaction);
+
+	/* now override with enforced policy */
+	policy = g_settings_get_string (dbus->priv->settings, GPK_SETTINGS_DBUS_ENFORCED_INTERACTION);
+	if (policy != NULL) {
+		g_debug ("enforced is %s", policy);
+		gpk_dbus_set_interaction_from_text (interact, &dbus->priv->timeout_tmp, policy);
+	}
+	g_free (policy);
+
+	/* copy from temp */
+	*timeout = dbus->priv->timeout_tmp;
+}
+
+/**
+ * gpk_dbus_create_task:
+ **/
+static GpkDbusTask *
+gpk_dbus_create_task (GpkDbus *dbus, guint32 xid, const gchar *interaction, DBusGMethodInvocation *context)
+{
+	GpkDbusTask *task;
+	PkBitfield interact = 0;
+	gint timeout = 0;
+	gchar *sender;
+	gchar *exec;
+	guint timestamp = 0;
+	gboolean ret;
+
+	task = gpk_dbus_task_new ();
+
+	/* work out what interaction the task should use */
+	gpk_dbus_parse_interaction (dbus, interaction, &interact, &timeout);
+
+	/* set interaction mode */
+	g_debug ("interact=%i", (gint) interact);
+	gpk_dbus_task_set_interaction (task, interact);
+
+	/* try to get the user time of the window */
+	if (xid != 0) {
+		ret = gpk_x11_set_xid (dbus->priv->x11, xid);
+		if (ret)
+			timestamp = gpk_x11_get_user_time (dbus->priv->x11);
+	}
+
+	/* set the context for the return values */
+	gpk_dbus_task_set_context (task, context);
+
+	/* set the last interaction */
+	gpk_dbus_task_set_timestamp (task, timestamp);
+
+	/* set the window for the modal and timestamp */
+        if (xid != 0)
+        	gpk_dbus_task_set_xid (task, xid);
+
+	/* get the program name and set */
+	sender = dbus_g_method_get_sender (context);
+	exec = gpk_dbus_get_exec_for_sender (dbus, sender);
+	if (exec != NULL)
+		gpk_dbus_task_set_exec (task, exec);
+
+	/* unref on delete */
+	//g_signal_connect...
+
+	/* reset time */
+	g_timer_reset (dbus->priv->timer);
+	dbus->priv->refcount++;
+
+	g_free (sender);
+	g_free (exec);
+	return task;
+}
+
+/**
+ * gpk_dbus_task_finished_cb:
+ **/
+static void
+gpk_dbus_task_finished_cb (GpkDbusTask *task, GpkDbus *dbus)
+{
+	/* one context has returned */
+	if (dbus->priv->refcount > 0)
+		dbus->priv->refcount--;
+
+	/* reset time */
+	g_timer_reset (dbus->priv->timer);
+
+	g_object_unref (task);
+}
+
+/**
+ * gpk_dbus_is_installed:
+ **/
+void
+gpk_dbus_is_installed (GpkDbus *dbus, const gchar *package_name, const gchar *interaction, DBusGMethodInvocation *context)
+{
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, 0, interaction, context);
+	gpk_dbus_task_is_installed (task, package_name, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus);
+}
+
+/**
+ * gpk_dbus_search_file:
+ **/
+void
+gpk_dbus_search_file (GpkDbus *dbus, const gchar *file_name, const gchar *interaction, DBusGMethodInvocation *context)
+{
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, 0, interaction, context);
+	gpk_dbus_task_search_file (task, file_name, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus);
+}
+
+/**
+ * gpk_dbus_install_package_files:
+ **/
+void
+gpk_dbus_install_package_files (GpkDbus *dbus, guint32 xid, gchar **files, const gchar *interaction, DBusGMethodInvocation *context)
+{
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_package_files (task, files, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus);
+}
+
+/**
+ * gpk_dbus_install_provide_files:
+ **/
+void
+gpk_dbus_install_provide_files (GpkDbus *dbus, guint32 xid, gchar **files, const gchar *interaction, DBusGMethodInvocation *context)
+{
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_provide_files (task, files, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus);
+}
+
+/**
+ * gpk_dbus_remove_package_by_files:
+ **/
+void
+gpk_dbus_remove_package_by_files (GpkDbus *dbus, guint32 xid, gchar **files, const gchar *interaction, DBusGMethodInvocation *context)
+{
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_remove_package_by_file (task, files, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus);
+}
+
+/**
+ * gpk_dbus_install_package_names:
+ **/
+void
+gpk_dbus_install_package_names (GpkDbus *dbus, guint32 xid, gchar **packages, const gchar *interaction, DBusGMethodInvocation *context)
+{
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_package_names (task, packages, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus);
+}
+
+/**
+ * gpk_dbus_install_mime_types:
+ **/
+void
+gpk_dbus_install_mime_types (GpkDbus *dbus, guint32 xid, gchar **mime_types, const gchar *interaction, DBusGMethodInvocation *context)
+{
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_mime_types (task, mime_types, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus);
+}
+
+/**
+ * gpk_dbus_install_fontconfig_resources:
+ **/
+void
+gpk_dbus_install_fontconfig_resources (GpkDbus *dbus, guint32 xid, gchar **resources, const gchar *interaction, DBusGMethodInvocation *context)
+{
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_fontconfig_resources (task, resources, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus);
+}
+
+/**
+ * gpk_dbus_install_gstreamer_resources:
+ **/
+void
+gpk_dbus_install_gstreamer_resources (GpkDbus *dbus, guint32 xid, gchar **resources, const gchar *interaction, DBusGMethodInvocation *context)
+{
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_gstreamer_resources (task, resources, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus);
+}
+
+/**
+ * gpk_dbus_install_resources:
+ **/
+void
+gpk_dbus_install_resources (GpkDbus *dbus, guint32 xid, const gchar *type, gchar **resources, const gchar *interaction, DBusGMethodInvocation *context)
+{
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_resources (task, resources, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus);
+}
+
+/**
+ * gpk_dbus_install_printer_drivers:
+ **/
+void
+gpk_dbus_install_printer_drivers (GpkDbus *dbus, guint32 xid, gchar **device_ids, const gchar *interaction, DBusGMethodInvocation *context)
+{
+	GpkDbusTask *task;
+	task = gpk_dbus_create_task (dbus, xid, interaction, context);
+	gpk_dbus_task_install_printer_drivers (task, device_ids, (GpkDbusTaskFinishedCb) gpk_dbus_task_finished_cb, dbus);
+}
+
+/**
+ * gpk_dbus_class_init:
+ * @klass: The GpkDbusClass
+ **/
+static void
+gpk_dbus_class_init (GpkDbusClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_dbus_finalize;
+	g_type_class_add_private (klass, sizeof (GpkDbusPrivate));
+}
+
+/**
+ * gpk_dbus_init:
+ * @dbus: This class instance
+ **/
+static void
+gpk_dbus_init (GpkDbus *dbus)
+{
+	DBusGConnection *connection;
+
+	dbus->priv = GPK_DBUS_GET_PRIVATE (dbus);
+	dbus->priv->timeout_tmp = -1;
+	dbus->priv->settings = g_settings_new (GPK_SETTINGS_SCHEMA);
+	dbus->priv->x11 = gpk_x11_new ();
+	dbus->priv->timer = g_timer_new ();
+
+	/* find out PIDs on the session bus */
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
+	dbus->priv->proxy_session_pid = dbus_g_proxy_new_for_name_owner (connection,
+								 "org.freedesktop.DBus",
+								 "/org/freedesktop/DBus/Bus",
+								 "org.freedesktop.DBus", NULL);
+	/* find out PIDs on the system bus */
+	connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);
+	dbus->priv->proxy_system_pid = dbus_g_proxy_new_for_name_owner (connection,
+								 "org.freedesktop.DBus",
+								 "/org/freedesktop/DBus/Bus",
+								 "org.freedesktop.DBus", NULL);
+}
+
+/**
+ * gpk_dbus_finalize:
+ * @object: The object to finalize
+ **/
+static void
+gpk_dbus_finalize (GObject *object)
+{
+	GpkDbus *dbus;
+	g_return_if_fail (PK_IS_DBUS (object));
+
+	dbus = GPK_DBUS (object);
+	g_return_if_fail (dbus->priv != NULL);
+	g_timer_destroy (dbus->priv->timer);
+	g_object_unref (dbus->priv->settings);
+	g_object_unref (dbus->priv->x11);
+	g_object_unref (dbus->priv->proxy_session_pid);
+	g_object_unref (dbus->priv->proxy_system_pid);
+
+	G_OBJECT_CLASS (gpk_dbus_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_dbus_new:
+ *
+ * Return value: a new GpkDbus object.
+ **/
+GpkDbus *
+gpk_dbus_new (void)
+{
+	GpkDbus *dbus;
+	dbus = g_object_new (GPK_TYPE_DBUS, NULL);
+	return GPK_DBUS (dbus);
+}
Index: gnome-packagekit-3.20.0/src/gpk-dbus.h
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-dbus.h
@@ -0,0 +1,124 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#ifndef __GPK_DBUS_H
+#define __GPK_DBUS_H
+
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_DBUS		(gpk_dbus_get_type ())
+#define GPK_DBUS(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_DBUS, GpkDbus))
+#define GPK_DBUS_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_DBUS, GpkDbusClass))
+#define PK_IS_DBUS(o)	 	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_DBUS))
+#define PK_IS_DBUS_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_DBUS))
+#define GPK_DBUS_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_DBUS, GpkDbusClass))
+#define GPK_DBUS_ERROR		(gpk_dbus_error_quark ())
+#define GPK_DBUS_TYPE_ERROR	(gpk_dbus_error_get_type ())
+
+typedef struct GpkDbusPrivate GpkDbusPrivate;
+
+typedef struct
+{
+	 GObject		 parent;
+	 GpkDbusPrivate	*priv;
+} GpkDbus;
+
+typedef struct
+{
+	GObjectClass	parent_class;
+} GpkDbusClass;
+
+GQuark		 gpk_dbus_error_quark			(void);
+GType		 gpk_dbus_error_get_type		(void);
+GType		 gpk_dbus_get_type			(void);
+GpkDbus		*gpk_dbus_new				(void);
+
+guint		 gpk_dbus_get_idle_time			(GpkDbus	*dbus);
+
+/* org.freedesktop.PackageKit.Query */
+void		 gpk_dbus_is_installed			(GpkDbus	*dbus,
+							 const gchar	*package_name,
+							 const gchar	*interaction,
+							 DBusGMethodInvocation *context);
+void		 gpk_dbus_search_file			(GpkDbus	*dbus,
+							 const gchar	*file_name,
+							 const gchar	*interaction,
+							 DBusGMethodInvocation *context);
+
+/* org.freedesktop.PackageKit.Modify */
+void		 gpk_dbus_install_provide_files		(GpkDbus	*dbus,
+							 guint32	 xid,
+							 gchar		**files,
+							 const gchar	*interaction,
+							 DBusGMethodInvocation *context);
+void		 gpk_dbus_install_catalogs		(GpkDbus	*dbus,
+							 guint32	 xid,
+							 gchar		**files,
+							 const gchar	*interaction,
+							 DBusGMethodInvocation *context);
+void		 gpk_dbus_install_package_files		(GpkDbus	*dbus,
+							 guint32	 xid,
+							 gchar		**files,
+							 const gchar	*interaction,
+							 DBusGMethodInvocation *context);
+void		 gpk_dbus_install_package_names		(GpkDbus	*dbus,
+							 guint32	 xid,
+							 gchar		**packages,
+							 const gchar	*interaction,
+							 DBusGMethodInvocation *context);
+void		 gpk_dbus_install_mime_types		(GpkDbus	*dbus,
+							 guint32	 xid,
+							 gchar		**mime_types,
+							 const gchar	*interaction,
+							 DBusGMethodInvocation *context);
+void		 gpk_dbus_install_fontconfig_resources	(GpkDbus 	*dbus,
+							 guint32	 xid,
+							 gchar		**fonts,
+							 const gchar	*interaction,
+							 DBusGMethodInvocation *context);
+void		 gpk_dbus_install_gstreamer_resources	(GpkDbus 	*dbus,
+							 guint32	 xid,
+							 gchar		**codecs,
+							 const gchar	*interaction,
+							 DBusGMethodInvocation *context);
+void		 gpk_dbus_install_resources		(GpkDbus 	*dbus,
+							 guint32	 xid,
+							 const gchar	*type,
+							 gchar		**resources,
+							 const gchar	*interaction,
+							 DBusGMethodInvocation *context);
+void		 gpk_dbus_remove_package_by_files	(GpkDbus	*dbus,
+							 guint32	 xid,
+							 gchar		**files,
+							 const gchar	*interaction,
+							 DBusGMethodInvocation *context);
+
+void		 gpk_dbus_install_printer_drivers	(GpkDbus 	*dbus,
+							 guint32	 xid,
+							 gchar		**device_ids,
+							 const gchar	*interaction,
+							 DBusGMethodInvocation *context);
+G_END_DECLS
+
+#endif /* __GPK_DBUS_H */
Index: gnome-packagekit-3.20.0/src/gpk-enum.c
===================================================================
--- gnome-packagekit-3.20.0.orig/src/gpk-enum.c
+++ gnome-packagekit-3.20.0/src/gpk-enum.c
@@ -100,6 +100,46 @@ static const PkEnumMatch enum_status_ico
 	{0, NULL}
 };
 
+static const PkEnumMatch enum_status_animation[] = {
+	{PK_STATUS_ENUM_UNKNOWN,		"help-browser"},
+	{PK_STATUS_ENUM_CANCEL,			"pk-action-cleanup"},
+	{PK_STATUS_ENUM_CLEANUP,		"pk-action-cleanup"},
+	{PK_STATUS_ENUM_COMMIT,			"pk-setup"},
+	{PK_STATUS_ENUM_DEP_RESOLVE,		"pk-action-testing"},
+	{PK_STATUS_ENUM_DOWNLOAD_CHANGELOG,	"pk-action-refresh-cache"},
+	{PK_STATUS_ENUM_DOWNLOAD_FILELIST,	"pk-action-refresh-cache"},
+	{PK_STATUS_ENUM_DOWNLOAD_GROUP,		"pk-action-refresh-cache"},
+	{PK_STATUS_ENUM_DOWNLOAD_PACKAGELIST,	"pk-action-refresh-cache"},
+	{PK_STATUS_ENUM_DOWNLOAD,		"pk-action-download"},
+	{PK_STATUS_ENUM_DOWNLOAD_REPOSITORY,	"pk-action-refresh-cache"},
+	{PK_STATUS_ENUM_DOWNLOAD_UPDATEINFO,	"pk-action-refresh-cache"},
+	{PK_STATUS_ENUM_FINISHED,		"pk-package-cleanup"},
+	{PK_STATUS_ENUM_GENERATE_PACKAGE_LIST,	"pk-action-searching"},
+	{PK_STATUS_ENUM_WAITING_FOR_LOCK,	"pk-action-waiting"},
+	{PK_STATUS_ENUM_WAITING_FOR_AUTH,	"pk-action-waiting"},
+	{PK_STATUS_ENUM_INFO,			"process-working"},
+	{PK_STATUS_ENUM_INSTALL,		"pk-action-installing"},
+	{PK_STATUS_ENUM_LOADING_CACHE,		"pk-action-refresh-cache"},
+	{PK_STATUS_ENUM_OBSOLETE,		"pk-package-cleanup"},
+	{PK_STATUS_ENUM_QUERY,			"pk-action-searching"},
+	{PK_STATUS_ENUM_REFRESH_CACHE,		"pk-action-refresh-cache"},
+	{PK_STATUS_ENUM_REMOVE,			"pk-action-removing"},
+	{PK_STATUS_ENUM_REPACKAGING,		"pk-package-info"},
+	{PK_STATUS_ENUM_REQUEST,		"process-working"},
+	{PK_STATUS_ENUM_RUNNING,		"pk-setup"},
+	{PK_STATUS_ENUM_SCAN_APPLICATIONS,	"pk-action-searching"},
+	{PK_STATUS_ENUM_SETUP,			"pk-package-info"},
+	{PK_STATUS_ENUM_SIG_CHECK,		"pk-package-info"},
+	{PK_STATUS_ENUM_TEST_COMMIT,		"pk-action-testing"},
+	{PK_STATUS_ENUM_UPDATE,			"pk-action-installing"},
+	{PK_STATUS_ENUM_WAIT,			"pk-action-waiting"},
+	{PK_STATUS_ENUM_SCAN_PROCESS_LIST,	"pk-package-info"},
+	{PK_STATUS_ENUM_CHECK_EXECUTABLE_FILES,	"pk-package-info"},
+	{PK_STATUS_ENUM_CHECK_LIBRARIES,	"pk-package-info"},
+	{PK_STATUS_ENUM_COPY_FILES,		"pk-package-info"},
+	{0, NULL}
+};
+
 static const PkEnumMatch enum_role_icon_name[] = {
 	{PK_ROLE_ENUM_UNKNOWN,			"help-browser"},	/* fall though value */
 	{PK_ROLE_ENUM_ACCEPT_EULA,		"pk-package-info"},
@@ -187,6 +227,17 @@ static const PkEnumMatch enum_restart_ic
 	{0, NULL}
 };
 
+static const PkEnumMatch enum_restart_dialog_icon_name[] = {
+	{PK_RESTART_ENUM_UNKNOWN,		"help-browser"},	/* fall though value */
+	{PK_RESTART_ENUM_NONE,			"dialog-information"},
+	{PK_RESTART_ENUM_SYSTEM,		"dialog-error"},
+	{PK_RESTART_ENUM_SESSION,		"dialog-warning"},
+	{PK_RESTART_ENUM_APPLICATION,		"dialog-warning"},
+	{PK_RESTART_ENUM_SECURITY_SYSTEM,	"dialog-error"},
+	{PK_RESTART_ENUM_SECURITY_SESSION,	"dialog-error"},
+	{0, NULL}
+};
+
 /**
  * gpk_media_type_enum_to_localised_text:
  **/
@@ -757,6 +808,32 @@ gpk_restart_enum_to_localised_text (PkRe
 }
 
 /**
+ * gpk_update_state_enum_to_localised_text:
+ **/
+const gchar *
+gpk_update_state_enum_to_localised_text (PkUpdateStateEnum state)
+{
+	const gchar *text = NULL;
+	switch (state) {
+	case PK_UPDATE_STATE_ENUM_STABLE:
+		/* TRANSLATORS: A distribution stability level */
+		text = _("Stable");
+		break;
+	case PK_UPDATE_STATE_ENUM_UNSTABLE:
+		/* TRANSLATORS: A distribution stability level */
+		text = _("Unstable");
+		break;
+	case PK_UPDATE_STATE_ENUM_TESTING:
+		/* TRANSLATORS: A distribution stability level */
+		text = _("Testing");
+		break;
+	default:
+		g_warning ("state unrecognized: %i", state);
+	}
+	return text;
+}
+
+/**
  * gpk_status_enum_to_localised_text:
  **/
 const gchar *
@@ -915,6 +992,48 @@ gpk_status_enum_to_localised_text (PkSta
 }
 
 /**
+ * gpk_update_enum_to_localised_text:
+ **/
+gchar *
+gpk_update_enum_to_localised_text (PkInfoEnum info, guint number)
+{
+	gchar *text = NULL;
+	switch (info) {
+	case PK_INFO_ENUM_LOW:
+		/* TRANSLATORS: type of update */
+		text = g_strdup_printf (ngettext ("%i trivial update", "%i trivial updates", number), number);
+		break;
+	case PK_INFO_ENUM_NORMAL:
+		/* TRANSLATORS: type of update in the case that we don't have any data */
+		text = g_strdup_printf (ngettext ("%i update", "%i updates", number), number);
+		break;
+	case PK_INFO_ENUM_IMPORTANT:
+		/* TRANSLATORS: type of update */
+		text = g_strdup_printf (ngettext ("%i important update", "%i important updates", number), number);
+		break;
+	case PK_INFO_ENUM_SECURITY:
+		/* TRANSLATORS: type of update */
+		text = g_strdup_printf (ngettext ("%i security update", "%i security updates", number), number);
+		break;
+	case PK_INFO_ENUM_BUGFIX:
+		/* TRANSLATORS: type of update */
+		text = g_strdup_printf (ngettext ("%i bug fix update", "%i bug fix updates", number), number);
+		break;
+	case PK_INFO_ENUM_ENHANCEMENT:
+		/* TRANSLATORS: type of update */
+		text = g_strdup_printf (ngettext ("%i enhancement update", "%i enhancement updates", number), number);
+		break;
+	case PK_INFO_ENUM_BLOCKED:
+		/* TRANSLATORS: number of updates that cannot be installed due to deps */
+		text = g_strdup_printf (ngettext ("%i blocked update", "%i blocked updates", number), number);
+		break;
+	default:
+		g_warning ("update info unrecognized: %s", pk_info_enum_to_string (info));
+	}
+	return text;
+}
+
+/**
  * gpk_info_enum_to_localised_text:
  **/
 const gchar *
@@ -977,7 +1096,7 @@ gpk_info_enum_to_localised_text (PkInfoE
 /**
  * gpk_info_enum_to_localised_present:
  **/
-static const gchar *
+const gchar *
 gpk_info_enum_to_localised_present (PkInfoEnum info)
 {
 	const gchar *text = NULL;
@@ -1529,6 +1648,15 @@ gpk_status_enum_to_icon_name (PkStatusEn
 }
 
 /**
+ * gpk_status_enum_to_animation:
+ **/
+const gchar *
+gpk_status_enum_to_animation (PkStatusEnum status)
+{
+	return pk_enum_find_string (enum_status_animation, status);
+}
+
+/**
  * gpk_role_enum_to_icon_name:
  **/
 const gchar *
@@ -1560,6 +1688,15 @@ gpk_restart_enum_to_icon_name (PkRestart
 }
 
 /**
+ * gpk_restart_enum_to_dialog_icon_name:
+ **/
+const gchar *
+gpk_restart_enum_to_dialog_icon_name (PkRestartEnum restart)
+{
+	return pk_enum_find_string (enum_restart_dialog_icon_name, restart);
+}
+
+/**
  * gpk_info_status_enum_to_string:
  **/
 const gchar *
Index: gnome-packagekit-3.20.0/src/gpk-enum.h
===================================================================
--- gnome-packagekit-3.20.0.orig/src/gpk-enum.h
+++ gnome-packagekit-3.20.0/src/gpk-enum.h
@@ -84,10 +84,13 @@ const gchar	*gpk_info_enum_to_localised_
 							 G_GNUC_CONST;
 const gchar	*gpk_info_enum_to_localised_past	(PkInfoEnum	 info)
 							 G_GNUC_CONST;
+const gchar	*gpk_info_enum_to_localised_present	(PkInfoEnum	 info)
+							 G_GNUC_CONST;
 const gchar	*gpk_info_enum_to_icon_name		(PkInfoEnum	 info);
 const gchar	*gpk_status_enum_to_localised_text	(PkStatusEnum	 status)
 							 G_GNUC_CONST;
 const gchar	*gpk_status_enum_to_icon_name		(PkStatusEnum	 status);
+const gchar	*gpk_status_enum_to_animation		(PkStatusEnum	 status);
 const gchar	*gpk_restart_enum_to_icon_name		(PkRestartEnum	 restart);
 const gchar	*gpk_restart_enum_to_dialog_icon_name	(PkRestartEnum	 restart);
 const gchar	*gpk_error_enum_to_localised_text	(PkErrorEnum code)
@@ -95,11 +98,16 @@ const gchar	*gpk_error_enum_to_localised
 const gchar	*gpk_error_enum_to_localised_message	(PkErrorEnum code);
 const gchar	*gpk_restart_enum_to_localised_text	(PkRestartEnum	 restart)
 							 G_GNUC_CONST;
+const gchar	*gpk_update_state_enum_to_localised_text (PkUpdateStateEnum state)
+							 G_GNUC_CONST;
 const gchar	*gpk_restart_enum_to_localised_text_future(PkRestartEnum	 restart)
 							 G_GNUC_CONST;
 const gchar	*gpk_group_enum_to_localised_text	(PkGroupEnum	 group)
 							 G_GNUC_CONST;
 const gchar	*gpk_group_enum_to_icon_name		(PkGroupEnum	 group);
+gchar		*gpk_update_enum_to_localised_text	(PkInfoEnum	 info,
+							 guint		 number)
+							 G_GNUC_CONST;
 const gchar	*gpk_info_status_enum_to_string		(GpkInfoStatusEnum info);
 const gchar	*gpk_info_status_enum_to_icon_name	(GpkInfoStatusEnum info);
 
Index: gnome-packagekit-3.20.0/src/gpk-error.c
===================================================================
--- gnome-packagekit-3.20.0.orig/src/gpk-error.c
+++ gnome-packagekit-3.20.0/src/gpk-error.c
@@ -58,7 +58,7 @@ gpk_error_dialog_expanded_cb (GObject *o
  *
  * Shows a modal error, and blocks until the user clicks close
  **/
-static gboolean
+gboolean
 gpk_error_dialog_modal_with_time (GtkWindow *window, const gchar *title, const gchar *message, const gchar *details, guint timestamp)
 {
 	GtkWidget *widget;
Index: gnome-packagekit-3.20.0/src/gpk-error.h
===================================================================
--- gnome-packagekit-3.20.0.orig/src/gpk-error.h
+++ gnome-packagekit-3.20.0/src/gpk-error.h
@@ -33,6 +33,11 @@ gboolean	 gpk_error_dialog_modal			(GtkW
 							 const gchar	*title,
 							 const gchar	*message,
 							 const gchar	*details);
+gboolean	 gpk_error_dialog_modal_with_time	(GtkWindow	*window,
+							 const gchar	*title,
+							 const gchar	*message,
+							 const gchar	*details,
+							 guint		 timestamp);
 
 G_END_DECLS
 
Index: gnome-packagekit-3.20.0/src/gpk-gnome.c
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-gnome.c
@@ -0,0 +1,49 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+#include "gpk-gnome.h"
+
+/**
+ * gpk_gnome_open:
+ * @url: a url such as <literal>http://www.hughsie.com</literal>
+ **/
+gboolean
+gpk_gnome_open (const gchar *url)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	g_return_val_if_fail (url != NULL, FALSE);
+
+	ret = gtk_show_uri (NULL, url, GDK_CURRENT_TIME, &error);
+
+	if (!ret) {
+		g_warning ("spawn of '%s' failed", url);
+		g_error_free (error);
+	}
+	return ret;
+}
Index: gnome-packagekit-3.20.0/src/gpk-gnome.h
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-gnome.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#ifndef __GPK_GNOME_H
+#define __GPK_GNOME_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gboolean	 gpk_gnome_open				(const gchar	*url);
+
+G_END_DECLS
+
+#endif	/* __GPK_GNOME_H */
Index: gnome-packagekit-3.20.0/src/gpk-helper-chooser.c
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-helper-chooser.c
@@ -0,0 +1,348 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <packagekit-glib2/packagekit.h>
+
+#include "gpk-helper-chooser.h"
+#include "gpk-marshal.h"
+#include "gpk-gnome.h"
+#include "gpk-common.h"
+#include "gpk-enum.h"
+
+static void     gpk_helper_chooser_finalize	(GObject	  *object);
+
+#define GPK_HELPER_CHOOSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_HELPER_CHOOSER, GpkHelperChooserPrivate))
+
+struct GpkHelperChooserPrivate
+{
+	GtkBuilder		*builder;
+	gchar			*package_id;
+	GtkListStore		*list_store;
+};
+
+enum {
+	GPK_HELPER_CHOOSER_EVENT,
+	GPK_HELPER_CHOOSER_LAST_SIGNAL
+};
+
+enum {
+	GPK_CHOOSER_COLUMN_ICON,
+	GPK_CHOOSER_COLUMN_TEXT,
+	GPK_CHOOSER_COLUMN_ID,
+	GPK_CHOOSER_COLUMN_LAST
+};
+
+static guint signals [GPK_HELPER_CHOOSER_LAST_SIGNAL] = { 0 };
+G_DEFINE_TYPE (GpkHelperChooser, gpk_helper_chooser, G_TYPE_OBJECT)
+
+/**
+ * gpk_helper_chooser_button_install_cb:
+ **/
+static void
+gpk_helper_chooser_button_install_cb (GtkWidget *widget, GpkHelperChooser *helper)
+{
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_widget_hide (widget);
+	g_signal_emit (helper, signals [GPK_HELPER_CHOOSER_EVENT], 0, GTK_RESPONSE_YES, helper->priv->package_id);
+}
+
+/**
+ * gpk_helper_chooser_button_cancel_cb:
+ **/
+static void
+gpk_helper_chooser_button_cancel_cb (GtkWidget *widget, GpkHelperChooser *helper)
+{
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_widget_hide (widget);
+	g_signal_emit (helper, signals [GPK_HELPER_CHOOSER_EVENT], 0, GTK_RESPONSE_NO, helper->priv->package_id);
+}
+
+/**
+ * gpk_helper_chooser_button_response_cb:
+ **/
+static void
+gpk_helper_chooser_button_response_cb (GtkDialog *dialog, GtkResponseType response_id, GpkHelperChooser *helper)
+{
+	if (response_id == GTK_RESPONSE_DELETE_EVENT) {
+		gtk_widget_hide (GTK_WIDGET (dialog));
+		g_signal_emit (helper, signals [GPK_HELPER_CHOOSER_EVENT], 0, GTK_RESPONSE_NO, helper->priv->package_id);
+	}
+}
+
+/**
+ * gpk_helper_chooser_treeview_clicked_cb:
+ **/
+static void
+gpk_helper_chooser_treeview_clicked_cb (GtkTreeSelection *selection, GpkHelperChooser *helper)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	/* This will only work in single or browse selection mode! */
+	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+		g_free (helper->priv->package_id);
+		gtk_tree_model_get (model, &iter, GPK_CHOOSER_COLUMN_ID, &helper->priv->package_id, -1);
+
+		/* show package_id */
+		g_debug ("selected row is: %s", helper->priv->package_id);
+	} else {
+		g_debug ("no row selected");
+	}
+}
+
+/**
+ * pk_treeview_add_general_columns:
+ **/
+static void
+pk_treeview_add_general_columns (GtkTreeView *treeview)
+{
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+
+	/* image */
+	renderer = gtk_cell_renderer_pixbuf_new ();
+        g_object_set (renderer, "stock-size", GTK_ICON_SIZE_DIALOG, NULL);
+	/* TRANSLATORS: column for the application icon */
+	column = gtk_tree_view_column_new_with_attributes (_("Icon"), renderer,
+							   "icon-name", GPK_CHOOSER_COLUMN_ICON, NULL);
+	gtk_tree_view_append_column (treeview, column);
+
+	/* column for text */
+	renderer = gtk_cell_renderer_text_new ();
+	/* TRANSLATORS: column for the application name */
+	column = gtk_tree_view_column_new_with_attributes (_("Package"), renderer,
+							   "markup", GPK_CHOOSER_COLUMN_TEXT, NULL);
+	gtk_tree_view_column_set_sort_column_id (column, GPK_CHOOSER_COLUMN_TEXT);
+	gtk_tree_view_append_column (treeview, column);
+	gtk_tree_view_column_set_expand (column, TRUE);
+}
+
+/**
+ * gpk_helper_chooser_show:
+ *
+ * Return value: if we agreed
+ **/
+gboolean
+gpk_helper_chooser_show (GpkHelperChooser *helper, GPtrArray *list)
+{
+	GtkWidget *widget;
+	gchar *text;
+	const gchar *icon_name;
+	guint i;
+	PkPackage *item;
+	GtkTreeIter iter;
+	PkInfoEnum info;
+	gchar *package_id = NULL;
+	gchar *summary = NULL;
+
+	g_return_val_if_fail (GPK_IS_HELPER_CHOOSER (helper), FALSE);
+	g_return_val_if_fail (list != NULL, FALSE);
+
+	/* see what we've got already */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	for (i=0; i<list->len; i++) {
+		item = g_ptr_array_index (list, i);
+		g_object_get (item,
+			      "info", &info,
+			      "package-id", &package_id,
+			      "summary", &summary,
+			      NULL);
+		g_debug ("package '%s' got:", package_id);
+
+		/* put formatted text into treeview */
+		gtk_list_store_append (helper->priv->list_store, &iter);
+		text = gpk_package_id_format_twoline (gtk_widget_get_style_context (widget),
+						      package_id,
+						      summary);
+		icon_name = gpk_info_enum_to_icon_name (info);
+		gtk_list_store_set (helper->priv->list_store, &iter,
+				    GPK_CHOOSER_COLUMN_TEXT, text,
+				    GPK_CHOOSER_COLUMN_ID, package_id, -1);
+		gtk_list_store_set (helper->priv->list_store, &iter, GPK_CHOOSER_COLUMN_ICON, icon_name, -1);
+		g_free (package_id);
+		g_free (summary);
+		g_free (text);
+	}
+
+	/* show window */
+	gtk_widget_show (widget);
+
+	return TRUE;
+}
+
+/**
+ * gpk_helper_chooser_set_parent:
+ **/
+gboolean
+gpk_helper_chooser_set_parent (GpkHelperChooser *helper, GtkWindow *window)
+{
+	GtkWindow *widget;
+
+	g_return_val_if_fail (GPK_IS_HELPER_CHOOSER (helper), FALSE);
+	g_return_val_if_fail (window != NULL, FALSE);
+
+	/* make modal if window set */
+	widget = GTK_WINDOW (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_window_set_transient_for (widget, window);
+	gtk_window_set_modal (widget, TRUE);
+
+	/* this is a modal popup, so don't show a window title */
+	gtk_window_set_title (widget, "");
+
+	return TRUE;
+}
+
+/**
+ * gpk_helper_chooser_class_init:
+ * @klass: The GpkHelperChooserClass
+ **/
+static void
+gpk_helper_chooser_class_init (GpkHelperChooserClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_helper_chooser_finalize;
+	g_type_class_add_private (klass, sizeof (GpkHelperChooserPrivate));
+	signals [GPK_HELPER_CHOOSER_EVENT] =
+		g_signal_new ("event",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkHelperChooserClass, event),
+			      NULL, NULL, gpk_marshal_VOID__UINT_STRING,
+			      G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+}
+
+/**
+ * gpk_helper_chooser_init:
+ **/
+static void
+gpk_helper_chooser_init (GpkHelperChooser *helper)
+{
+	GtkWidget *widget;
+	guint retval;
+	GError *error = NULL;
+	GtkWidget *button;
+	GtkTreeSelection *selection;
+
+	helper->priv = GPK_HELPER_CHOOSER_GET_PRIVATE (helper);
+
+	helper->priv->package_id = NULL;
+
+	/* get UI */
+	helper->priv->builder = gtk_builder_new ();
+	retval = gtk_builder_add_from_file (helper->priv->builder, GPK_DATA "/gpk-log.ui", &error);
+	if (retval == 0) {
+		g_warning ("failed to load ui: %s", error->message);
+		g_error_free (error);
+	}
+
+	/* connect up default actions */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	g_signal_connect (GTK_DIALOG (widget), "response", G_CALLBACK (gpk_helper_chooser_button_response_cb), helper);
+
+	/* set icon name */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_window_set_icon_name (GTK_WINDOW (widget), GPK_ICON_SOFTWARE_INSTALLER);
+	gtk_window_set_title (GTK_WINDOW (widget), _("Applications that can open this type of file"));
+
+	/* set a size, if the screen allows */
+	gpk_window_set_size_request (GTK_WINDOW (widget), 600, 300);
+
+	/* connect up buttons */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_close"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_helper_chooser_button_cancel_cb), helper);
+
+	/* TRANSLATORS: button label, install */
+	button = gtk_button_new_with_mnemonic (_("_Install"));
+	g_signal_connect (button, "clicked", G_CALLBACK (gpk_helper_chooser_button_install_cb), helper);
+
+	/* TRANSLATORS: button tooltip */
+	gtk_widget_set_tooltip_text (button, _("Install package"));
+
+	/* add to box */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	widget = gtk_dialog_get_action_area (GTK_DIALOG(widget));
+	gtk_box_pack_start (GTK_BOX (widget), button, FALSE, FALSE, 0);
+	gtk_widget_show (button);
+
+	/* hide the filter box */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "hbox_filter"));
+	gtk_widget_hide (widget);
+
+	/* hide the refresh button */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_refresh"));
+	gtk_widget_hide (widget);
+
+	/* create list stores */
+	helper->priv->list_store = gtk_list_store_new (GPK_CHOOSER_COLUMN_LAST, G_TYPE_STRING,
+						       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+	/* create package_id tree view */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "treeview_simple"));
+	gtk_tree_view_set_model (GTK_TREE_VIEW (widget),
+				 GTK_TREE_MODEL (helper->priv->list_store));
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+	g_signal_connect (selection, "changed",
+			  G_CALLBACK (gpk_helper_chooser_treeview_clicked_cb), helper);
+
+	/* add columns to the tree view */
+	pk_treeview_add_general_columns (GTK_TREE_VIEW (widget));
+	gtk_tree_view_columns_autosize (GTK_TREE_VIEW (widget));
+	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget), FALSE);
+}
+
+/**
+ * gpk_helper_chooser_finalize:
+ **/
+static void
+gpk_helper_chooser_finalize (GObject *object)
+{
+	GtkWidget *widget;
+	GpkHelperChooser *helper;
+
+	g_return_if_fail (GPK_IS_HELPER_CHOOSER (object));
+
+	helper = GPK_HELPER_CHOOSER (object);
+
+	/* hide window */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	if (GTK_IS_WIDGET (widget))
+		gtk_widget_hide (widget);
+	g_free (helper->priv->package_id);
+	g_object_unref (helper->priv->builder);
+
+	G_OBJECT_CLASS (gpk_helper_chooser_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_helper_chooser_new:
+ **/
+GpkHelperChooser *
+gpk_helper_chooser_new (void)
+{
+	GpkHelperChooser *helper;
+	helper = g_object_new (GPK_TYPE_HELPER_CHOOSER, NULL);
+	return GPK_HELPER_CHOOSER (helper);
+}
+
Index: gnome-packagekit-3.20.0/src/gpk-helper-chooser.h
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-helper-chooser.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GPK_HELPER_CHOOSER_H
+#define __GPK_HELPER_CHOOSER_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <packagekit-glib2/packagekit.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_HELPER_CHOOSER		(gpk_helper_chooser_get_type ())
+#define GPK_HELPER_CHOOSER(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_HELPER_CHOOSER, GpkHelperChooser))
+#define GPK_HELPER_CHOOSER_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_HELPER_CHOOSER, GpkHelperChooserClass))
+#define GPK_IS_HELPER_CHOOSER(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_HELPER_CHOOSER))
+#define GPK_IS_HELPER_CHOOSER_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_HELPER_CHOOSER))
+#define GPK_HELPER_CHOOSER_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_HELPER_CHOOSER, GpkHelperChooserClass))
+#define GPK_HELPER_CHOOSER_ERROR	(gpk_helper_chooser_error_quark ())
+#define GPK_HELPER_CHOOSER_TYPE_ERROR	(gpk_helper_chooser_error_get_type ())
+
+typedef struct GpkHelperChooserPrivate GpkHelperChooserPrivate;
+
+typedef struct
+{
+	 GObject			 parent;
+	 GpkHelperChooserPrivate	*priv;
+} GpkHelperChooser;
+
+typedef struct
+{
+	void		(* event)			(GpkHelperChooser	*helper,
+							 GtkResponseType	 type,
+							 const gchar		*package_id);
+	GObjectClass	parent_class;
+} GpkHelperChooserClass;
+
+GType		 gpk_helper_chooser_get_type	  	(void);
+GpkHelperChooser	*gpk_helper_chooser_new		(void);
+gboolean	 gpk_helper_chooser_set_parent		(GpkHelperChooser	*helper,
+							 GtkWindow		*window);
+gboolean	 gpk_helper_chooser_show		(GpkHelperChooser	*helper,
+							 GPtrArray		*list);
+
+G_END_DECLS
+
+#endif /* __GPK_HELPER_CHOOSER_H */
Index: gnome-packagekit-3.20.0/src/gpk-helper-run.c
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-helper-run.c
@@ -0,0 +1,392 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <packagekit-glib2/packagekit.h>
+#include <gio/gdesktopappinfo.h>
+
+#include "gpk-helper-run.h"
+#include "gpk-marshal.h"
+#include "gpk-gnome.h"
+#include "gpk-common.h"
+#include "gpk-enum.h"
+
+static void     gpk_helper_run_finalize	(GObject	  *object);
+
+#define GPK_HELPER_RUN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_HELPER_RUN, GpkHelperRunPrivate))
+
+struct GpkHelperRunPrivate
+{
+	GtkBuilder		*builder;
+	GtkListStore		*list_store;
+};
+
+enum {
+	GPK_CHOOSER_COLUMN_ICON,
+	GPK_CHOOSER_COLUMN_TEXT,
+	GPK_CHOOSER_COLUMN_FILENAME,
+	GPK_CHOOSER_COLUMN_LAST
+};
+
+G_DEFINE_TYPE (GpkHelperRun, gpk_helper_run, G_TYPE_OBJECT)
+
+/**
+ * gpk_helper_run_path:
+ **/
+static gboolean
+gpk_helper_run_path (GpkHelperRun *helper, const gchar *filename)
+{
+	gboolean ret = FALSE;
+	GError *error = NULL;
+	GAppInfo *app = NULL;
+
+	/* check have value */
+	if (filename == NULL) {
+		g_warning ("no full path");
+		goto out;
+	}
+
+	/* launch application */
+	app = G_APP_INFO(g_desktop_app_info_new_from_filename (filename));
+	ret = g_app_info_launch (app, NULL, NULL, &error);
+	if (!ret) {
+		g_warning ("failed to launch: %s", error->message);
+		g_error_free (error);
+	}
+out:
+	if (app != NULL)
+		g_object_unref (app);
+	return ret;
+}
+
+/**
+ * gpk_helper_run_button_run_cb:
+ **/
+static void
+gpk_helper_run_button_run_cb (GtkWidget *widget, GpkHelperRun *helper)
+{
+	GtkTreeView *treeview;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	GtkTreeSelection *selection;
+	gboolean ret;
+	gchar *filename;
+
+	/* get selection */
+	treeview = GTK_TREE_VIEW (gtk_builder_get_object (helper->priv->builder, "treeview_simple"));
+	selection = gtk_tree_view_get_selection (treeview);
+	ret = gtk_tree_selection_get_selected (selection, &model, &iter);
+	if (!ret) {
+		g_warning ("failed to get selection");
+		return;
+	}
+
+	gtk_tree_model_get (model, &iter, GPK_CHOOSER_COLUMN_FILENAME, &filename, -1);
+	gpk_helper_run_path (helper, filename);
+	g_free (filename);
+}
+
+/**
+ * gpk_helper_run_button_close_cb:
+ **/
+static void
+gpk_helper_run_button_close_cb (GtkWidget *widget, GpkHelperRun *helper)
+{
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_widget_hide (widget);
+}
+
+/**
+ * gpk_helper_run_delete_event_cb:
+ **/
+static gboolean
+gpk_helper_run_delete_event_cb (GtkWidget *widget, GdkEvent *event, GpkHelperRun *helper)
+{
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_widget_hide (widget);
+	return FALSE;
+}
+
+/**
+ * gpk_helper_run_treeview_clicked_cb:
+ **/
+static void
+gpk_helper_run_treeview_clicked_cb (GtkTreeSelection *selection, GpkHelperRun *helper)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gchar *filename = NULL;
+
+	/* This will only work in single or browse selection mode! */
+	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+		g_free (filename);
+		gtk_tree_model_get (model, &iter, GPK_CHOOSER_COLUMN_FILENAME, &filename, -1);
+
+		/* show full path */
+		g_debug ("selected row is: %s", filename);
+	} else {
+		g_debug ("no row selected");
+	}
+	g_free (filename);
+}
+
+/**
+ * gpk_helper_run_row_activated_cb:
+ **/
+static void
+gpk_helper_run_row_activated_cb (GtkTreeView *treeview, GtkTreePath *path,
+				 GtkTreeViewColumn *col, GpkHelperRun *helper)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gboolean ret;
+	gchar *filename;
+
+	/* get selection */
+	model = gtk_tree_view_get_model (treeview);
+	ret = gtk_tree_model_get_iter (model, &iter, path);
+	if (!ret) {
+		g_warning ("failed to get selection");
+		return;
+	}
+
+	gtk_tree_model_get (model, &iter, GPK_CHOOSER_COLUMN_FILENAME, &filename, -1);
+	gpk_helper_run_path (helper, filename);
+	g_free (filename);
+}
+
+/**
+ * pk_treeview_add_general_columns:
+ **/
+static void
+pk_treeview_add_general_columns (GtkTreeView *treeview)
+{
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+
+	/* image */
+	renderer = gtk_cell_renderer_pixbuf_new ();
+        g_object_set (renderer, "stock-size", GTK_ICON_SIZE_DIALOG, NULL);
+	/* TRANSLATORS: column for the application icon */
+	column = gtk_tree_view_column_new_with_attributes (_("Icon"), renderer,
+							   "icon-name", GPK_CHOOSER_COLUMN_ICON, NULL);
+	gtk_tree_view_append_column (treeview, column);
+
+	/* column for text */
+	renderer = gtk_cell_renderer_text_new ();
+	/* TRANSLATORS: column for the package name */
+	column = gtk_tree_view_column_new_with_attributes (_("Package"), renderer,
+							   "markup", GPK_CHOOSER_COLUMN_TEXT, NULL);
+	gtk_tree_view_column_set_sort_column_id (column, GPK_CHOOSER_COLUMN_TEXT);
+	gtk_tree_view_append_column (treeview, column);
+	gtk_tree_view_column_set_expand (column, TRUE);
+}
+
+/**
+ * gpk_helper_run_add_package_ids:
+ **/
+static guint
+gpk_helper_run_add_package_ids (GpkHelperRun *helper, gchar **package_ids)
+{
+	return 0;
+}
+
+/**
+ * gpk_helper_run_show:
+ *
+ * Return value: if we agreed
+ **/
+gboolean
+gpk_helper_run_show (GpkHelperRun *helper, gchar **package_ids)
+{
+	GtkWidget *widget;
+	guint len;
+
+	g_return_val_if_fail (GPK_IS_HELPER_RUN (helper), FALSE);
+	g_return_val_if_fail (package_ids != NULL, FALSE);
+
+	/* clear old list */
+	gtk_list_store_clear (helper->priv->list_store);
+
+	/* add all the apps */
+	len = gpk_helper_run_add_package_ids (helper, package_ids);
+	if (len == 0) {
+		g_debug ("no executable file for %s", package_ids[0]);
+		goto out;
+	}
+
+	/* show window */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_widget_show (widget);
+out:
+	return TRUE;
+}
+
+/**
+ * gpk_helper_run_set_parent:
+ **/
+gboolean
+gpk_helper_run_set_parent (GpkHelperRun *helper, GtkWindow *window)
+{
+	GtkWindow *widget;
+
+	g_return_val_if_fail (GPK_IS_HELPER_RUN (helper), FALSE);
+	g_return_val_if_fail (window != NULL, FALSE);
+
+	/* make modal if window set */
+	widget = GTK_WINDOW (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_window_set_transient_for (widget, window);
+	gtk_window_set_modal (widget, TRUE);
+
+	/* this is a modal popup */
+	gtk_window_set_type_hint (widget, GDK_WINDOW_TYPE_HINT_DIALOG);
+
+	return TRUE;
+}
+
+/**
+ * gpk_helper_run_class_init:
+ * @klass: The GpkHelperRunClass
+ **/
+static void
+gpk_helper_run_class_init (GpkHelperRunClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_helper_run_finalize;
+	g_type_class_add_private (klass, sizeof (GpkHelperRunPrivate));
+}
+
+/**
+ * gpk_helper_run_init:
+ **/
+static void
+gpk_helper_run_init (GpkHelperRun *helper)
+{
+	GtkWidget *widget;
+	GtkWidget *button;
+	guint retval;
+	GError *error = NULL;
+	GtkTreeSelection *selection;
+	GtkBox *box;
+
+	helper->priv = GPK_HELPER_RUN_GET_PRIVATE (helper);
+
+	/* get UI */
+	helper->priv->builder = gtk_builder_new ();
+	retval = gtk_builder_add_from_file (helper->priv->builder, GPK_DATA "/gpk-log.ui", &error);
+	if (retval == 0) {
+		g_warning ("failed to load ui: %s", error->message);
+		g_error_free (error);
+	}
+
+	/* connect up default actions */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	g_signal_connect (widget, "delete_event", G_CALLBACK (gpk_helper_run_delete_event_cb), helper);
+
+	/* set icon name */
+	gtk_window_set_icon_name (GTK_WINDOW (widget), GPK_ICON_SOFTWARE_INSTALLER);
+
+	/* set a size, if the screen allows */
+	gpk_window_set_size_request (GTK_WINDOW (widget), 600, 300);
+
+	/* connect up buttons */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_close"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_helper_run_button_close_cb), helper);
+
+	/* hide the filter box */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "hbox_filter"));
+	gtk_widget_hide (widget);
+
+	/* hide the refresh button */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "button_refresh"));
+	gtk_widget_hide (widget);
+
+	/* set icon name */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	gtk_window_set_icon_name (GTK_WINDOW (widget), GPK_ICON_SOFTWARE_INSTALLER);
+	/* TRANSLATORS: window title: do we want to execute a program we just installed? */
+	gtk_window_set_title (GTK_WINDOW (widget), _("Run new application?"));
+
+	/* add run button */
+	button = gtk_button_new_with_mnemonic (_("_Run"));
+	box = GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (widget)));
+	gtk_box_pack_start (box, button, FALSE, FALSE, 0);
+	gtk_widget_show (button);
+	g_signal_connect (button, "clicked", G_CALLBACK (gpk_helper_run_button_run_cb), helper);
+
+	/* create list stores */
+	helper->priv->list_store = gtk_list_store_new (GPK_CHOOSER_COLUMN_LAST, G_TYPE_STRING,
+						       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+	/* create package_id tree view */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "treeview_simple"));
+	gtk_tree_view_set_model (GTK_TREE_VIEW (widget),
+				 GTK_TREE_MODEL (helper->priv->list_store));
+	g_signal_connect (GTK_TREE_VIEW (widget), "row-activated",
+			  G_CALLBACK (gpk_helper_run_row_activated_cb), helper);
+
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+	g_signal_connect (selection, "changed",
+			  G_CALLBACK (gpk_helper_run_treeview_clicked_cb), helper);
+
+	/* add columns to the tree view */
+	pk_treeview_add_general_columns (GTK_TREE_VIEW (widget));
+	gtk_tree_view_columns_autosize (GTK_TREE_VIEW (widget));
+	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget), FALSE);
+}
+
+/**
+ * gpk_helper_run_finalize:
+ **/
+static void
+gpk_helper_run_finalize (GObject *object)
+{
+	GtkWidget *widget;
+	GpkHelperRun *helper;
+
+	g_return_if_fail (GPK_IS_HELPER_RUN (object));
+
+	helper = GPK_HELPER_RUN (object);
+
+	/* hide window */
+	widget = GTK_WIDGET (gtk_builder_get_object (helper->priv->builder, "dialog_simple"));
+	if (GTK_IS_WIDGET (widget))
+		gtk_widget_hide (widget);
+	g_object_unref (helper->priv->builder);
+	g_object_unref (helper->priv->list_store);
+
+	G_OBJECT_CLASS (gpk_helper_run_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_helper_run_new:
+ **/
+GpkHelperRun *
+gpk_helper_run_new (void)
+{
+	GpkHelperRun *helper;
+	helper = g_object_new (GPK_TYPE_HELPER_RUN, NULL);
+	return GPK_HELPER_RUN (helper);
+}
+
Index: gnome-packagekit-3.20.0/src/gpk-helper-run.h
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-helper-run.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GPK_HELPER_RUN_H
+#define __GPK_HELPER_RUN_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_HELPER_RUN		(gpk_helper_run_get_type ())
+#define GPK_HELPER_RUN(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_HELPER_RUN, GpkHelperRun))
+#define GPK_HELPER_RUN_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_HELPER_RUN, GpkHelperRunClass))
+#define GPK_IS_HELPER_RUN(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_HELPER_RUN))
+#define GPK_IS_HELPER_RUN_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_HELPER_RUN))
+#define GPK_HELPER_RUN_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_HELPER_RUN, GpkHelperRunClass))
+#define GPK_HELPER_RUN_ERROR		(gpk_helper_run_error_quark ())
+#define GPK_HELPER_RUN_TYPE_ERROR	(gpk_helper_run_error_get_type ())
+
+typedef struct GpkHelperRunPrivate GpkHelperRunPrivate;
+
+typedef struct
+{
+	 GObject			 parent;
+	 GpkHelperRunPrivate		*priv;
+} GpkHelperRun;
+
+typedef struct
+{
+	GObjectClass	parent_class;
+} GpkHelperRunClass;
+
+GType		 gpk_helper_run_get_type	  	(void);
+GpkHelperRun	*gpk_helper_run_new			(void);
+gboolean	 gpk_helper_run_set_parent		(GpkHelperRun		*helper,
+							 GtkWindow		*window);
+gboolean	 gpk_helper_run_show			(GpkHelperRun		*helper,
+							 gchar			**package_ids);
+
+G_END_DECLS
+
+#endif /* __GPK_HELPER_RUN_H */
Index: gnome-packagekit-3.20.0/src/gpk-install-local-file.c
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-install-local-file.c
@@ -0,0 +1,139 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007-2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <locale.h>
+#include <dbus/dbus-glib.h>
+
+#include "gpk-common.h"
+#include "gpk-error.h"
+#include "gpk-dbus.h"
+#include "gpk-debug.h"
+
+/**
+ * main:
+ **/
+int
+main (int argc, char *argv[])
+{
+	GOptionContext *context;
+	gboolean ret;
+	GError *error = NULL;
+	gchar **files = NULL;
+	gchar *tmp;
+	gchar *current_dir;
+	guint i;
+	DBusGConnection *connection;
+	DBusGProxy *proxy = NULL;
+
+	const GOptionEntry options[] = {
+		{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &files,
+		  /* TRANSLATORS: command line option: a list of files to install */
+		  _("Files to install"), NULL },
+		{ NULL}
+	};
+
+	setlocale (LC_ALL, "");
+
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+	textdomain (GETTEXT_PACKAGE);
+
+	gtk_init (&argc, &argv);
+
+	/* TRANSLATORS: program name: application to install a package to provide a file */
+	g_set_application_name (_("Software Install"));
+	context = g_option_context_new ("gpk-install-local-file");
+	g_option_context_set_summary (context, _("PackageKit File Installer"));
+	g_option_context_add_main_entries (context, options, NULL);
+	g_option_context_add_group (context, gpk_debug_get_option_group ());
+	g_option_context_add_group (context, gtk_get_option_group (TRUE));
+	g_option_context_parse (context, &argc, &argv, NULL);
+	g_option_context_free (context);
+
+	/* TRANSLATORS: title to pass to to the user if there are not enough privs */
+	ret = gpk_check_privileged_user (_("Local file installer"), TRUE);
+	if (!ret)
+		goto out;
+
+	if (files == NULL) {
+		/* TRANSLATORS: could not install a package that contained the file we wanted */
+		gpk_error_dialog (_("Failed to install a package to provide a file"),
+				  /* TRANSLATORS: nothing selected */
+				  _("You need to specify a file to install"), NULL);
+		goto out;
+	}
+
+	/* make sure we don't pass relative paths to the session-interface */
+	/* (this is needed if install-local-files is executed from the command-line) */
+	current_dir = g_get_current_dir ();
+	for (i = 0; files[i] != NULL; i++) {
+		if (!g_str_has_prefix (files[i], "/")) {
+			tmp = g_build_filename (current_dir, files[i], NULL);
+			g_free (files[i]);
+			files[i] = tmp;
+		}
+	}
+	g_free (current_dir);
+
+	/* check dbus connections, exit if not valid */
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+	if (connection == NULL) {
+		g_warning ("%s", error->message);
+		goto out;
+	}
+
+	/* get a connection */
+	proxy = dbus_g_proxy_new_for_name (connection,
+					   "org.freedesktop.PackageKit",
+					   "/org/freedesktop/PackageKit",
+					   "org.freedesktop.PackageKit.Modify");
+	if (proxy == NULL) {
+		g_warning ("Cannot connect to session service");
+		goto out;
+	}
+
+	/* don't timeout, as dbus-glib sets the timeout ~25 seconds */
+	dbus_g_proxy_set_default_timeout (proxy, INT_MAX);
+
+	/* do method */
+	ret = dbus_g_proxy_call (proxy, "InstallPackageFiles", &error,
+				 G_TYPE_UINT, 0, /* xid */
+				 G_TYPE_STRV, files, /* data */
+				 G_TYPE_STRING, "hide-finished,show-warnings", /* interaction */
+				 G_TYPE_INVALID,
+				 G_TYPE_INVALID);
+	if (!ret) {
+		g_warning ("%s", error->message);
+		goto out;
+	}
+out:
+	if (error != NULL)
+		g_error_free (error);
+	if (proxy != NULL)
+		g_object_unref (proxy);
+	g_strfreev (files);
+	return !ret;
+}
Index: gnome-packagekit-3.20.0/src/gpk-language.c
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-language.c
@@ -0,0 +1,196 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib.h>
+
+#include "gpk-language.h"
+
+static void     gpk_language_finalize	(GObject	  *object);
+
+#define GPK_LANGUAGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_LANGUAGE, GpkLanguagePrivate))
+
+struct GpkLanguagePrivate
+{
+	GHashTable		*hash;
+};
+
+G_DEFINE_TYPE (GpkLanguage, gpk_language, G_TYPE_OBJECT)
+
+/**
+ * gpk_language_parser_start_element:
+ **/
+static void
+gpk_language_parser_start_element (GMarkupParseContext *context, const gchar *element_name,
+				   const gchar **attribute_names, const gchar **attribute_values,
+				   gpointer user_data, GError **error)
+{
+	guint i, len;
+	const gchar *code1 = NULL;
+	const gchar *code2b = NULL;
+	const gchar *name = NULL;
+	GpkLanguage *language = user_data;
+
+	if (strcmp (element_name, "iso_639_entry") != 0)
+		return;
+
+	/* find data */
+	len = g_strv_length ((gchar**)attribute_names);
+	for (i=0; i<len; i++) {
+		if (strcmp (attribute_names[i], "iso_639_1_code") == 0)
+			code1 = attribute_values[i];
+		if (strcmp (attribute_names[i], "iso_639_2B_code") == 0)
+			code2b = attribute_values[i];
+		if (strcmp (attribute_names[i], "name") == 0)
+			name = attribute_values[i];
+	}
+
+	/* not valid entry */
+	if (name == NULL)
+		return;
+
+	/* add both to hash */
+	if (code1 != NULL)
+		g_hash_table_insert (language->priv->hash, g_strdup (code1), g_strdup (name));
+	if (code2b != NULL)
+		g_hash_table_insert (language->priv->hash, g_strdup (code2b), g_strdup (name));
+}
+
+/* trivial parser */
+static const GMarkupParser gpk_language_markup_parser =
+{
+	gpk_language_parser_start_element,
+	NULL, /* end_element */
+	NULL, /* characters */
+	NULL, /* passthrough */
+	NULL /* error */
+};
+
+/**
+ * gpk_language_populate:
+ *
+ * <iso_639_entry iso_639_2B_code="hun" iso_639_2T_code="hun" iso_639_1_code="hu" name="Hungarian" />
+ **/
+gboolean
+gpk_language_populate (GpkLanguage *language, GError **error)
+{
+	gboolean ret = FALSE;
+	gchar *contents = NULL;
+	gchar *filename;
+	gsize size;
+	GMarkupParseContext *context = NULL;
+
+	/* find filename */
+	filename = g_build_filename (DATADIR, "xml", "iso-codes", "iso_639.xml", NULL);
+	if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
+		g_free (filename);
+		filename = g_build_filename ("/usr", "share", "xml", "iso-codes", "iso_639.xml", NULL);
+	}
+	if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
+		g_set_error (error, 1, 0, "cannot find source file : '%s'", filename);
+		goto out;
+	}
+
+	/* get contents */
+	ret = g_file_get_contents (filename, &contents, &size, error);
+	if (!ret)
+		goto out;
+
+	/* create parser */
+	context = g_markup_parse_context_new (&gpk_language_markup_parser, G_MARKUP_PREFIX_ERROR_POSITION, language, NULL);
+
+	/* parse data */
+	ret = g_markup_parse_context_parse (context, contents, (gssize) size, error);
+	if (!ret)
+		goto out;
+out:
+	if (context != NULL)
+		g_markup_parse_context_free (context);
+	g_free (filename);
+	g_free (contents);
+	return ret;
+}
+
+/**
+ * gpk_language_iso639_to_language:
+ **/
+gchar *
+gpk_language_iso639_to_language (GpkLanguage *language, const gchar *iso639)
+{
+	return g_strdup (g_hash_table_lookup (language->priv->hash, iso639));
+}
+
+/**
+ * gpk_language_finalize:
+ * @object: The object to finalize
+ **/
+static void
+gpk_language_finalize (GObject *object)
+{
+	GpkLanguage *language;
+
+	g_return_if_fail (GPK_IS_LANGUAGE (object));
+
+	language = GPK_LANGUAGE (object);
+
+	g_return_if_fail (language->priv != NULL);
+	g_hash_table_unref (language->priv->hash);
+
+	G_OBJECT_CLASS (gpk_language_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_language_init:
+ * @language: This class instance
+ **/
+static void
+gpk_language_init (GpkLanguage *language)
+{
+	language->priv = GPK_LANGUAGE_GET_PRIVATE (language);
+	language->priv->hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free);
+}
+
+/**
+ * gpk_language_class_init:
+ * @klass: The GpkLanguageClass
+ **/
+static void
+gpk_language_class_init (GpkLanguageClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_language_finalize;
+	g_type_class_add_private (klass, sizeof (GpkLanguagePrivate));
+}
+
+/**
+ * gpk_language_new:
+ *
+ * Return value: a new GpkLanguage object.
+ **/
+GpkLanguage *
+gpk_language_new (void)
+{
+	GpkLanguage *language;
+	language = g_object_new (GPK_TYPE_LANGUAGE, NULL);
+	return GPK_LANGUAGE (language);
+}
Index: gnome-packagekit-3.20.0/src/gpk-language.h
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-language.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#ifndef __GPK_LANGUAGE_H
+#define __GPK_LANGUAGE_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_LANGUAGE		(gpk_language_get_type ())
+#define GPK_LANGUAGE(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_LANGUAGE, GpkLanguage))
+#define GPK_LANGUAGE_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_LANGUAGE, GpkLanguageClass))
+#define GPK_IS_LANGUAGE(o)	 	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_LANGUAGE))
+#define GPK_IS_LANGUAGE_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_LANGUAGE))
+#define GPK_LANGUAGE_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_LANGUAGE, GpkLanguageClass))
+#define GPK_LANGUAGE_ERROR		(gpk_language_error_quark ())
+#define GPK_LANGUAGE_TYPE_ERROR		(gpk_language_error_get_type ())
+
+typedef struct GpkLanguagePrivate GpkLanguagePrivate;
+
+typedef struct
+{
+	 GObject		 parent;
+	 GpkLanguagePrivate	*priv;
+} GpkLanguage;
+
+typedef struct
+{
+	GObjectClass	parent_class;
+} GpkLanguageClass;
+
+GType		 gpk_language_get_type		  	(void);
+GpkLanguage	*gpk_language_new			(void);
+gboolean	 gpk_language_populate			(GpkLanguage	*language,
+							 GError		**error);
+gchar		*gpk_language_iso639_to_language	(GpkLanguage	*language,
+							 const gchar	*iso639);
+
+G_END_DECLS
+
+#endif /* __GPK_LANGUAGE_H */
Index: gnome-packagekit-3.20.0/src/gpk-log.c
===================================================================
--- gnome-packagekit-3.20.0.orig/src/gpk-log.c
+++ gnome-packagekit-3.20.0/src/gpk-log.c
@@ -32,6 +32,7 @@
 #include <packagekit-glib2/packagekit.h>
 
 #include "gpk-common.h"
+#include "gpk-gnome.h"
 #include "gpk-debug.h"
 
 static GtkBuilder *builder = NULL;
Index: gnome-packagekit-3.20.0/src/gpk-marshal.list
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-marshal.list
@@ -0,0 +1,3 @@
+VOID:UINT,STRING
+VOID:UINT,STRING,STRING
+
Index: gnome-packagekit-3.20.0/src/gpk-modal-dialog.c
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-modal-dialog.c
@@ -0,0 +1,861 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <string.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <glib/gi18n.h>
+#include <packagekit-glib2/packagekit.h>
+
+#include "egg-string.h"
+
+#include "gpk-animated-icon.h"
+#include "gpk-modal-dialog.h"
+#include "gpk-common.h"
+#include "gpk-gnome.h"
+#include "gpk-enum.h"
+
+static void     gpk_modal_dialog_finalize	(GObject		*object);
+
+#define GPK_MODAL_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_CLIENT_DIALOG, GpkModalDialogPrivate))
+
+struct _GpkModalDialogPrivate
+{
+	GtkBuilder		*builder;
+	guint			 pulse_timer_id;
+	gboolean		 show_progress_files;
+	gboolean		 has_parent;
+	GMainLoop		*loop;
+	GtkResponseType		 response;
+	GtkListStore		*store;
+	gchar			*title;
+	gboolean		 set_image;
+	GpkModalDialogPage	 page;
+	PkBitfield		 options;
+	GtkWidget		*image_status;
+};
+
+enum {
+	GPK_MODAL_DIALOG_CLOSE,
+	GPK_MODAL_DIALOG_QUIT,
+	GPK_MODAL_DIALOG_ACTION,
+	GPK_MODAL_DIALOG_CANCEL,
+	LAST_SIGNAL
+};
+
+enum {
+	GPK_MODAL_DIALOG_STORE_IMAGE,
+	GPK_MODAL_DIALOG_STORE_ID,
+	GPK_MODAL_DIALOG_STORE_TEXT,
+	GPK_MODAL_DIALOG_STORE_LAST
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+G_DEFINE_TYPE (GpkModalDialog, gpk_modal_dialog, G_TYPE_OBJECT)
+
+/**
+ * gpk_modal_dialog_show_widget:
+ **/
+static void
+gpk_modal_dialog_show_widget (GpkModalDialog *dialog, const gchar *name, gboolean enabled)
+{
+	GtkWidget *widget;
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, name));
+	if (enabled)
+		gtk_widget_show (widget);
+	else
+		gtk_widget_hide (widget);
+}
+
+/**
+ * gpk_modal_dialog_setup:
+ **/
+gboolean
+gpk_modal_dialog_setup (GpkModalDialog *dialog, GpkModalDialogPage page, PkBitfield options)
+{
+	GtkLabel *label;
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	/* reset state */
+	dialog->priv->set_image = FALSE;
+	dialog->priv->page = page;
+	dialog->priv->options = options;
+	label = GTK_LABEL (gtk_builder_get_object (dialog->priv->builder, "label_message"));
+	gtk_label_set_label (label, "");
+	gpk_modal_dialog_set_action (dialog, NULL);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_present_with_time:
+ **/
+gboolean
+gpk_modal_dialog_present_with_time (GpkModalDialog *dialog, guint32 timestamp)
+{
+	GtkWidget *widget;
+	PkBitfield bitfield = 0;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "label_title"));
+	gtk_widget_show (widget);
+	gtk_widget_show (dialog->priv->image_status);
+	/* helper */
+	if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_CONFIRM) {
+		if (!dialog->priv->set_image)
+			gpk_modal_dialog_set_image (dialog, "dialog-question");
+		bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CANCEL,
+						   GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION,
+						   GPK_MODAL_DIALOG_WIDGET_MESSAGE,
+						   -1);
+		gpk_modal_dialog_set_allow_cancel (dialog, TRUE);
+	} else if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_FINISHED) {
+		if (!dialog->priv->set_image)
+			gpk_modal_dialog_set_image (dialog, "dialog-information");
+		bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE,
+						   GPK_MODAL_DIALOG_WIDGET_MESSAGE,
+						   -1);
+	} else if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_CONFIRM) {
+		if (!dialog->priv->set_image)
+			gpk_modal_dialog_set_image (dialog, "dialog-question");
+		bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE,
+						   GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION,
+						   GPK_MODAL_DIALOG_WIDGET_MESSAGE,
+						   -1);
+	} else if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_WARNING) {
+		if (!dialog->priv->set_image)
+			gpk_modal_dialog_set_image (dialog, "dialog-warning");
+		bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE,
+						   GPK_MODAL_DIALOG_WIDGET_MESSAGE,
+						   -1);
+	} else if (dialog->priv->page == GPK_MODAL_DIALOG_PAGE_PROGRESS) {
+		if (!dialog->priv->set_image)
+			gpk_modal_dialog_set_image (dialog, "dialog-warning");
+		bitfield = pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE,
+						   GPK_MODAL_DIALOG_WIDGET_BUTTON_CANCEL,
+						   GPK_MODAL_DIALOG_WIDGET_PROGRESS_BAR,
+						   -1);
+	}
+
+	/* we can specify extras */
+	bitfield += dialog->priv->options;
+
+	gpk_modal_dialog_show_widget (dialog, "button_cancel", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_BUTTON_CANCEL));
+	gpk_modal_dialog_show_widget (dialog, "button_close", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE));
+	gpk_modal_dialog_show_widget (dialog, "button_action", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION));
+	gpk_modal_dialog_show_widget (dialog, "progressbar_percent", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_PROGRESS_BAR));
+	gpk_modal_dialog_show_widget (dialog, "label_message", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_MESSAGE));
+	gpk_modal_dialog_show_widget (dialog, "scrolledwindow_packages", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_PACKAGE_LIST));
+	gpk_modal_dialog_show_widget (dialog, "label_force_height", pk_bitfield_contain (bitfield, GPK_MODAL_DIALOG_WIDGET_PADDING));
+
+	/* always force width */
+	gpk_modal_dialog_show_widget (dialog, "label_force_width", TRUE);
+
+	/* show */
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	gtk_widget_realize (widget);
+	gtk_window_present_with_time (GTK_WINDOW (widget), timestamp);
+
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_present:
+ **/
+gboolean
+gpk_modal_dialog_present (GpkModalDialog *dialog)
+{
+	return gpk_modal_dialog_present_with_time (dialog, 0);
+}
+
+/**
+ * gpk_modal_dialog_set_parent:
+ **/
+gboolean
+gpk_modal_dialog_set_parent (GpkModalDialog *dialog, GdkWindow *window)
+{
+	GtkWidget *widget;
+	GdkWindow *window_ours;
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	/* never set, and nothing now */
+	if (window == NULL && !dialog->priv->has_parent)
+		return TRUE;
+
+	/* not sure what to do here, should probably unparent somehow */
+	if (window == NULL) {
+		g_warning ("parent set NULL when already modal with another window, setting non-modal");
+		widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+		gtk_window_set_modal (GTK_WINDOW (widget), FALSE);
+		dialog->priv->has_parent = FALSE;
+
+		/* use the saved title if it exists */
+		if (dialog->priv->title != NULL)
+			gpk_modal_dialog_set_title (dialog, dialog->priv->title);
+
+		return FALSE;
+	}
+
+	/* check we are a valid window */
+	if (!GDK_WINDOW (window)) {
+		g_warning ("not a valid GdkWindow!");
+		return FALSE;
+	}
+
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	gtk_widget_realize (widget);
+	gtk_window_set_modal (GTK_WINDOW (widget), TRUE);
+	window_ours = gtk_widget_get_window (widget);
+	gdk_window_set_transient_for (window_ours, window);
+	dialog->priv->has_parent = TRUE;
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_window_title:
+ **/
+static gboolean
+gpk_modal_dialog_set_window_title (GpkModalDialog *dialog, const gchar *title)
+{
+	GtkWindow *window;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+	g_return_val_if_fail (title != NULL, FALSE);
+
+	g_debug ("setting window title: %s", title);
+	window = GTK_WINDOW (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	gtk_window_set_title (window, title);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_window_icon:
+ **/
+gboolean
+gpk_modal_dialog_set_window_icon (GpkModalDialog *dialog, const gchar *icon)
+{
+	GtkWindow *window;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+	g_return_val_if_fail (icon != NULL, FALSE);
+
+	g_debug ("setting window icon: %s", icon);
+	window = GTK_WINDOW (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	gtk_window_set_icon_name (window, icon);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_title:
+ **/
+gboolean
+gpk_modal_dialog_set_title (GpkModalDialog *dialog, const gchar *title)
+{
+	GtkLabel *label;
+	GtkWidget *widget;
+	gchar *title_bold;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+	g_return_val_if_fail (title != NULL, FALSE);
+
+	/* only set the window title if we are non-modal */
+	if (!dialog->priv->has_parent) {
+		widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder,
+							     "dialog_client"));
+		gtk_window_set_modal (GTK_WINDOW (widget), FALSE);
+	}
+
+	/* we save this in case we are non-modal and have to use a title */
+	g_free (dialog->priv->title);
+	dialog->priv->title = g_strdup (title);
+
+	title_bold = g_strdup_printf ("<b><big>%s</big></b>", title);
+	g_debug ("setting title: %s", title_bold);
+	label = GTK_LABEL (gtk_builder_get_object (dialog->priv->builder, "label_title"));
+	gtk_label_set_markup (label, title_bold);
+	g_free (title_bold);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_message:
+ **/
+gboolean
+gpk_modal_dialog_set_message (GpkModalDialog *dialog, const gchar *message)
+{
+	GtkLabel *label;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+	g_return_val_if_fail (message != NULL, FALSE);
+
+	/* ignore this if it's uninteresting */
+	if (!dialog->priv->show_progress_files)
+		return FALSE;
+
+	g_debug ("setting message: %s", message);
+	label = GTK_LABEL (gtk_builder_get_object (dialog->priv->builder, "label_message"));
+	gtk_label_set_markup (label, message);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_action:
+ **/
+gboolean
+gpk_modal_dialog_set_action (GpkModalDialog *dialog, const gchar *action)
+{
+	GtkWidget *widget;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	g_debug ("setting action: %s", action);
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_action"));
+	if (action != NULL)
+		gtk_button_set_label (GTK_BUTTON (widget), action);
+	else
+		gtk_widget_hide (widget);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_pulse_progress:
+ **/
+static gboolean
+gpk_modal_dialog_pulse_progress (GpkModalDialog *dialog)
+{
+	GtkWidget *widget;
+	static guint rate_limit = 0;
+	
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	/* debug so we can catch polling */
+	if (rate_limit++ % 20 == 0)
+		g_debug ("polling check");
+
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "progressbar_percent"));
+	gtk_progress_bar_pulse (GTK_PROGRESS_BAR (widget));
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_make_progressbar_pulse:
+ **/
+static void
+gpk_modal_dialog_make_progressbar_pulse (GpkModalDialog *dialog)
+{
+	GtkProgressBar *progress_bar;
+	if (dialog->priv->pulse_timer_id == 0) {
+		progress_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (dialog->priv->builder, "progressbar_percent"));
+		gtk_progress_bar_set_pulse_step (progress_bar, 0.04);
+		dialog->priv->pulse_timer_id = g_timeout_add (75, (GSourceFunc) gpk_modal_dialog_pulse_progress, dialog);
+		g_source_set_name_by_id (dialog->priv->pulse_timer_id, "[GpkModalDialog] pulse");
+	}
+}
+
+/**
+ * gpk_modal_dialog_set_percentage:
+ **/
+gboolean
+gpk_modal_dialog_set_percentage (GpkModalDialog *dialog, gint percentage)
+{
+	GtkProgressBar *progress_bar;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+	g_return_val_if_fail (percentage <= 100, FALSE);
+
+	g_debug ("setting percentage: %u", percentage);
+
+	progress_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (dialog->priv->builder, "progressbar_percent"));
+	if (dialog->priv->pulse_timer_id != 0) {
+		g_source_remove (dialog->priv->pulse_timer_id);
+		dialog->priv->pulse_timer_id = 0;
+	}
+
+	/* either pulse or set percentage */
+	if (percentage < 0)
+		gpk_modal_dialog_make_progressbar_pulse (dialog);
+	else
+		gtk_progress_bar_set_fraction (progress_bar, (gfloat) percentage / 100.0);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_remaining:
+ **/
+gboolean
+gpk_modal_dialog_set_remaining (GpkModalDialog *dialog, guint remaining)
+{
+	GtkProgressBar *progress_bar;
+	gchar *timestring = NULL;
+	gchar *text = NULL;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	g_debug ("setting remaining: %u", remaining);
+	progress_bar = GTK_PROGRESS_BAR (gtk_builder_get_object (dialog->priv->builder, "progressbar_percent"));
+
+	/* unknown */
+	if (remaining == 0) {
+		gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progress_bar), "");
+		goto out;
+	}
+
+	/* get time text */
+	timestring = gpk_time_to_imprecise_string (remaining);
+	text = g_strdup_printf (_("Remaining time: %s"), timestring);
+	gtk_progress_bar_set_text (progress_bar, text);
+out:
+	g_free (timestring);
+	g_free (text);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_image:
+ **/
+gboolean
+gpk_modal_dialog_set_image (GpkModalDialog *dialog, const gchar *image)
+{
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+	g_return_val_if_fail (image != NULL, FALSE);
+
+	/* set state */
+	dialog->priv->set_image = TRUE;
+
+	g_debug ("setting image: %s", image);
+	gpk_animated_icon_enable_animation (GPK_ANIMATED_ICON (dialog->priv->image_status), FALSE);
+	gtk_image_set_from_icon_name (GTK_IMAGE (dialog->priv->image_status), image, GTK_ICON_SIZE_DIALOG);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_set_image_status:
+ **/
+gboolean
+gpk_modal_dialog_set_image_status (GpkModalDialog *dialog, PkStatusEnum status)
+{
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	/* set state */
+	dialog->priv->set_image = TRUE;
+	gpk_set_animated_icon_from_status (GPK_ANIMATED_ICON (dialog->priv->image_status), status, GTK_ICON_SIZE_DIALOG);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_get_window:
+ **/
+GtkWindow *
+gpk_modal_dialog_get_window (GpkModalDialog *dialog)
+{
+	GtkWindow *window;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), NULL);
+
+	window = GTK_WINDOW (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	return window;
+}
+
+/**
+ * gpk_modal_dialog_set_allow_cancel:
+ **/
+gboolean
+gpk_modal_dialog_set_allow_cancel (GpkModalDialog *dialog, gboolean can_cancel)
+{
+	GtkWidget *widget;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_cancel"));
+	gtk_widget_set_sensitive (widget, can_cancel);
+
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_run:
+ **/
+GtkResponseType
+gpk_modal_dialog_run (GpkModalDialog *dialog)
+{
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	/* already running */
+	if (g_main_loop_is_running (dialog->priv->loop))
+		g_main_loop_quit (dialog->priv->loop);
+
+	dialog->priv->response = GTK_RESPONSE_NONE;
+	g_main_loop_run (dialog->priv->loop);
+
+	return dialog->priv->response;
+}
+
+/**
+ * gpk_modal_dialog_close:
+ **/
+gboolean
+gpk_modal_dialog_close (GpkModalDialog *dialog)
+{
+	GtkWidget *widget;
+
+	g_return_val_if_fail (GPK_IS_CLIENT_DIALOG (dialog), FALSE);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	gtk_widget_hide (widget);
+
+	if (dialog->priv->pulse_timer_id != 0) {
+		g_source_remove (dialog->priv->pulse_timer_id);
+		dialog->priv->pulse_timer_id = 0;
+	}
+
+	gpk_animated_icon_enable_animation (GPK_ANIMATED_ICON (dialog->priv->image_status), FALSE);
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_window_delete_cb:
+ **/
+static gboolean
+gpk_modal_dialog_window_delete_cb (GtkWidget *widget, GdkEvent *event, GpkModalDialog *dialog)
+{
+	dialog->priv->response = GTK_RESPONSE_DELETE_EVENT;
+	gpk_modal_dialog_close (dialog);
+	if (g_main_loop_is_running (dialog->priv->loop))
+		g_main_loop_quit (dialog->priv->loop);
+	/* do not destroy the window */
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_button_close_cb:
+ **/
+static void
+gpk_modal_dialog_button_close_cb (GtkWidget *widget_button, GpkModalDialog *dialog)
+{
+	dialog->priv->response = GTK_RESPONSE_CLOSE;
+	g_main_loop_quit (dialog->priv->loop);
+
+	if (dialog->priv->pulse_timer_id != 0) {
+		g_source_remove (dialog->priv->pulse_timer_id);
+		dialog->priv->pulse_timer_id = 0;
+	}
+
+	gpk_animated_icon_enable_animation (GPK_ANIMATED_ICON (dialog->priv->image_status), FALSE);
+	if (g_main_loop_is_running (dialog->priv->loop))
+		g_main_loop_quit (dialog->priv->loop);
+	else
+		g_signal_emit (dialog, signals [GPK_MODAL_DIALOG_CLOSE], 0);
+}
+
+/**
+ * gpk_modal_dialog_button_action_cb:
+ **/
+static void
+gpk_modal_dialog_button_action_cb (GtkWidget *widget_button, GpkModalDialog *dialog)
+{
+	dialog->priv->response = GTK_RESPONSE_OK;
+	g_main_loop_quit (dialog->priv->loop);
+	if (g_main_loop_is_running (dialog->priv->loop))
+		g_main_loop_quit (dialog->priv->loop);
+	else
+		g_signal_emit (dialog, signals [GPK_MODAL_DIALOG_ACTION], 0);
+}
+
+/**
+ * gpk_modal_dialog_button_cancel_cb:
+ **/
+static void
+gpk_modal_dialog_button_cancel_cb (GtkWidget *widget_button, GpkModalDialog *dialog)
+{
+	dialog->priv->response = GTK_RESPONSE_CANCEL;
+	if (g_main_loop_is_running (dialog->priv->loop))
+		g_main_loop_quit (dialog->priv->loop);
+	else
+		g_signal_emit (dialog, signals [GPK_MODAL_DIALOG_CANCEL], 0);
+}
+
+/**
+ * gpk_modal_dialog_set_package_list:
+ **/
+gboolean
+gpk_modal_dialog_set_package_list (GpkModalDialog *dialog, const GPtrArray *list)
+{
+	GtkTreeIter iter;
+	PkPackage *item;
+	const gchar *icon;
+	gchar *text;
+	guint i;
+	GtkWidget *widget;
+	gchar **split;
+	PkInfoEnum info;
+	gchar *package_id = NULL;
+	gchar *summary = NULL;
+
+	gtk_list_store_clear (dialog->priv->store);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "scrolledwindow_packages"));
+	if (list->len > 5)
+		gtk_widget_set_size_request (widget, -1, 300);
+	else if (list->len > 1)
+		gtk_widget_set_size_request (widget, -1, 150);
+
+	/* add each well */
+	for (i=0; i<list->len; i++) {
+		item = g_ptr_array_index (list, i);
+		g_object_get (item,
+			      "info", &info,
+			      NULL);
+
+		/* not installed, so ignore icon */
+		if (info == PK_INFO_ENUM_DOWNLOADING ||
+		    info == PK_INFO_ENUM_CLEANUP)
+			continue;
+
+		g_object_get (item,
+			      "package-id", &package_id,
+			      "summary", &summary,
+			      NULL);
+
+		text = gpk_package_id_format_twoline (gtk_widget_get_style_context (widget),
+						      package_id, summary);
+
+		/* get the icon */
+		split = pk_package_id_split (package_id);
+		icon = gpk_info_enum_to_icon_name (PK_INFO_ENUM_INSTALLED);
+		gtk_list_store_append (dialog->priv->store, &iter);
+		gtk_list_store_set (dialog->priv->store, &iter,
+				    GPK_MODAL_DIALOG_STORE_IMAGE, icon,
+				    GPK_MODAL_DIALOG_STORE_ID, package_id,
+				    GPK_MODAL_DIALOG_STORE_TEXT, text,
+				    -1);
+		g_strfreev (split);
+		g_free (package_id);
+		g_free (summary);
+		g_free (text);
+	}
+
+	return TRUE;
+}
+
+/**
+ * gpk_dialog_treeview_for_package_list:
+ **/
+static gboolean
+gpk_dialog_treeview_for_package_list (GpkModalDialog *dialog)
+{
+	GtkTreeView *treeview;
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+	GtkTreeSelection *selection;
+
+	treeview = GTK_TREE_VIEW (gtk_builder_get_object (dialog->priv->builder, "treeview_packages"));
+
+	/* column for images */
+	column = gtk_tree_view_column_new ();
+	renderer = gtk_cell_renderer_pixbuf_new ();
+	g_object_set (renderer, "stock-size", GTK_ICON_SIZE_DND, NULL);
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+	gtk_tree_view_column_add_attribute (column, renderer, "icon-name", GPK_MODAL_DIALOG_STORE_IMAGE);
+	gtk_tree_view_append_column (treeview, column);
+
+	/* column for name */
+	renderer = gtk_cell_renderer_text_new ();
+	/* TRANSLATORS: column for the package name */
+	column = gtk_tree_view_column_new_with_attributes (_("Name"), renderer,
+							   "markup", GPK_MODAL_DIALOG_STORE_TEXT, NULL);
+	gtk_tree_view_column_set_sort_column_id (column, GPK_MODAL_DIALOG_STORE_TEXT);
+	gtk_tree_view_append_column (treeview, column);
+
+	/* set some common options */
+	gtk_tree_view_set_headers_visible (treeview, FALSE);
+	selection = gtk_tree_view_get_selection (treeview);
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
+	gtk_tree_selection_unselect_all (selection);
+
+	return TRUE;
+}
+
+/**
+ * gpk_modal_dialog_class_init:
+ * @klass: The GpkModalDialogClass
+ **/
+static void
+gpk_modal_dialog_class_init (GpkModalDialogClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_modal_dialog_finalize;
+	g_type_class_add_private (klass, sizeof (GpkModalDialogPrivate));
+	signals [GPK_MODAL_DIALOG_QUIT] =
+		g_signal_new ("quit",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+	signals [GPK_MODAL_DIALOG_CLOSE] =
+		g_signal_new ("close",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+	signals [GPK_MODAL_DIALOG_ACTION] =
+		g_signal_new ("action",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+	signals [GPK_MODAL_DIALOG_CANCEL] =
+		g_signal_new ("cancel",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+}
+
+/**
+ * gpk_modal_dialog_init:
+ * @dialog: This class instance
+ **/
+static void
+gpk_modal_dialog_init (GpkModalDialog *dialog)
+{
+	GtkWidget *widget;
+	GtkTreeView *treeview;
+	guint retval;
+	GError *error = NULL;
+	GtkBox *box;
+
+	dialog->priv = GPK_MODAL_DIALOG_GET_PRIVATE (dialog);
+
+	dialog->priv->loop = g_main_loop_new (NULL, FALSE);
+	dialog->priv->response = GTK_RESPONSE_NONE;
+	dialog->priv->pulse_timer_id = 0;
+	dialog->priv->show_progress_files = TRUE;
+	dialog->priv->has_parent = FALSE;
+	dialog->priv->set_image = FALSE;
+	dialog->priv->page = GPK_MODAL_DIALOG_PAGE_UNKNOWN;
+	dialog->priv->options = 0;
+	dialog->priv->title = NULL;
+
+	dialog->priv->store = gtk_list_store_new (GPK_MODAL_DIALOG_STORE_LAST,
+						  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+	/* get UI */
+	dialog->priv->builder = gtk_builder_new ();
+	retval = gtk_builder_add_from_file (dialog->priv->builder, GPK_DATA "/gpk-client.ui", &error);
+	if (retval == 0) {
+		g_warning ("failed to load ui: %s", error->message);
+		g_error_free (error);
+		goto out_build;
+	}
+
+	/* add animated widget */
+	dialog->priv->image_status = gpk_animated_icon_new ();
+	box = GTK_BOX (gtk_builder_get_object (dialog->priv->builder, "hbox_status"));
+	gtk_box_pack_start (box, dialog->priv->image_status, FALSE, FALSE, 0);
+	gtk_widget_show (dialog->priv->image_status);
+
+	gpk_dialog_treeview_for_package_list (dialog);
+
+	treeview = GTK_TREE_VIEW (gtk_builder_get_object (dialog->priv->builder, "treeview_packages"));
+	gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (dialog->priv->store));
+
+	/* common stuff */
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "dialog_client"));
+	g_signal_connect (widget, "delete_event", G_CALLBACK (gpk_modal_dialog_window_delete_cb), dialog);
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_close"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_modal_dialog_button_close_cb), dialog);
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_action"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_modal_dialog_button_action_cb), dialog);
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "button_cancel"));
+	g_signal_connect (widget, "clicked", G_CALLBACK (gpk_modal_dialog_button_cancel_cb), dialog);
+
+	/* set the message text an absolute width so it's forced to wrap */
+	widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->builder, "label_message"));
+	gtk_label_set_max_width_chars (GTK_LABEL (widget), 80);
+
+out_build:
+	/* clear status and progress text */
+	gpk_modal_dialog_set_window_title (dialog, "");
+	gpk_modal_dialog_set_title (dialog, "");
+	gpk_modal_dialog_set_message (dialog, "");
+}
+
+/**
+ * gpk_modal_dialog_finalize:
+ * @object: The object to finalize
+ **/
+static void
+gpk_modal_dialog_finalize (GObject *object)
+{
+	GpkModalDialog *dialog;
+	g_return_if_fail (GPK_IS_CLIENT_DIALOG (object));
+
+	dialog = GPK_MODAL_DIALOG (object);
+	g_return_if_fail (dialog->priv != NULL);
+
+	/* no updates, we're about to rip the builder up  */
+	if (dialog->priv->pulse_timer_id != 0)
+		g_source_remove (dialog->priv->pulse_timer_id);
+
+	/* if it's closed, then hide */
+	gpk_modal_dialog_close (dialog);
+
+	/* shouldn't be, but just in case */
+	if (g_main_loop_is_running (dialog->priv->loop)) {
+		g_warning ("mainloop running on exit");
+		g_main_loop_quit (dialog->priv->loop);
+	}
+
+	g_object_unref (dialog->priv->store);
+	g_object_unref (dialog->priv->builder);
+	g_main_loop_unref (dialog->priv->loop);
+	g_free (dialog->priv->title);
+
+	G_OBJECT_CLASS (gpk_modal_dialog_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_modal_dialog_new:
+ *
+ * Return value: a new GpkModalDialog object.
+ **/
+GpkModalDialog *
+gpk_modal_dialog_new (void)
+{
+	GpkModalDialog *dialog;
+	dialog = g_object_new (GPK_TYPE_CLIENT_DIALOG, NULL);
+	return GPK_MODAL_DIALOG (dialog);
+}
Index: gnome-packagekit-3.20.0/src/gpk-modal-dialog.h
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-modal-dialog.h
@@ -0,0 +1,127 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#ifndef __GPK_MODAL_DIALOG_H
+#define __GPK_MODAL_DIALOG_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <packagekit-glib2/packagekit.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_CLIENT_DIALOG		(gpk_modal_dialog_get_type ())
+#define GPK_MODAL_DIALOG(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_CLIENT_DIALOG, GpkModalDialog))
+#define GPK_MODAL_DIALOG_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_CLIENT_DIALOG, GpkModalDialogClass))
+#define GPK_IS_CLIENT_DIALOG(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_CLIENT_DIALOG))
+#define GPK_IS_CLIENT_DIALOG_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_CLIENT_DIALOG))
+#define GPK_MODAL_DIALOG_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_CLIENT_DIALOG, GpkModalDialogClass))
+#define GPK_MODAL_DIALOG_ERROR		(gpk_modal_dialog_error_quark ())
+#define GPK_MODAL_DIALOG_TYPE_ERROR	(gpk_modal_dialog_error_get_type ())
+
+/**
+ * GpkModalDialogPage:
+ */
+typedef enum
+{
+	GPK_MODAL_DIALOG_PAGE_CONFIRM,
+	GPK_MODAL_DIALOG_PAGE_PROGRESS,
+	GPK_MODAL_DIALOG_PAGE_FINISHED,
+	GPK_MODAL_DIALOG_PAGE_WARNING,
+	GPK_MODAL_DIALOG_PAGE_CUSTOM,
+	GPK_MODAL_DIALOG_PAGE_UNKNOWN
+} GpkModalDialogPage;
+
+/**
+ * GpkModalDialogWidgets:
+ */
+typedef enum
+{
+	GPK_MODAL_DIALOG_WIDGET_BUTTON_CANCEL,
+	GPK_MODAL_DIALOG_WIDGET_BUTTON_CLOSE,
+	GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION,
+	GPK_MODAL_DIALOG_WIDGET_PADDING,
+	GPK_MODAL_DIALOG_WIDGET_PACKAGE_LIST,
+	GPK_MODAL_DIALOG_WIDGET_PROGRESS_BAR,
+	GPK_MODAL_DIALOG_WIDGET_MESSAGE,
+	GPK_MODAL_DIALOG_WIDGET_UNKNOWN
+} GpkModalDialogWidgets;
+
+/* helpers */
+#define GPK_MODAL_DIALOG_PACKAGE_PADDING	pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_PADDING, GPK_MODAL_DIALOG_WIDGET_MESSAGE, -1)
+#define GPK_MODAL_DIALOG_PACKAGE_LIST		pk_bitfield_value (GPK_MODAL_DIALOG_WIDGET_PACKAGE_LIST)
+#define GPK_MODAL_DIALOG_BUTTON_ACTION		pk_bitfield_value (GPK_MODAL_DIALOG_WIDGET_BUTTON_ACTION)
+
+typedef struct _GpkModalDialogPrivate	 GpkModalDialogPrivate;
+typedef struct _GpkModalDialog		 GpkModalDialog;
+typedef struct _GpkModalDialogClass	 GpkModalDialogClass;
+
+struct _GpkModalDialog
+{
+	GObject				 parent;
+	GpkModalDialogPrivate		*priv;
+};
+
+struct _GpkModalDialogClass
+{
+	GObjectClass	parent_class;
+};
+
+GQuark		 gpk_modal_dialog_error_quark		(void);
+GType		 gpk_modal_dialog_get_type		(void);
+GpkModalDialog	*gpk_modal_dialog_new			(void);
+
+gboolean	 gpk_modal_dialog_present		(GpkModalDialog		*dialog);
+gboolean	 gpk_modal_dialog_present_with_time	(GpkModalDialog		*dialog,
+							 guint32		 timestamp);
+gboolean	 gpk_modal_dialog_set_package_list	(GpkModalDialog		*dialog,
+							 const GPtrArray	*list);
+gboolean	 gpk_modal_dialog_set_parent		(GpkModalDialog		*dialog,
+							 GdkWindow		*window);
+gboolean	 gpk_modal_dialog_set_window_icon	(GpkModalDialog		*dialog,
+							 const gchar		*icon);
+gboolean	 gpk_modal_dialog_set_title		(GpkModalDialog		*dialog,
+							 const gchar		*title);
+gboolean	 gpk_modal_dialog_set_message		(GpkModalDialog		*dialog,
+							 const gchar		*message);
+gboolean	 gpk_modal_dialog_set_action		(GpkModalDialog		*dialog,
+							 const gchar		*action);
+gboolean	 gpk_modal_dialog_set_percentage	(GpkModalDialog		*dialog,
+							 gint			 percentage);
+gboolean	 gpk_modal_dialog_set_remaining		(GpkModalDialog		*dialog,
+							 guint			 remaining);
+gboolean	 gpk_modal_dialog_set_image		(GpkModalDialog		*dialog,
+							 const gchar		*image);
+gboolean	 gpk_modal_dialog_set_image_status	(GpkModalDialog		*dialog,
+							 PkStatusEnum		 status);
+gboolean	 gpk_modal_dialog_set_allow_cancel	(GpkModalDialog		*dialog,
+							 gboolean		 can_cancel);
+GtkWindow	*gpk_modal_dialog_get_window		(GpkModalDialog		*dialog);
+GtkResponseType	 gpk_modal_dialog_run			(GpkModalDialog		*dialog);
+gboolean	 gpk_modal_dialog_close			(GpkModalDialog		*dialog);
+gboolean	 gpk_modal_dialog_setup			(GpkModalDialog		*dialog,
+							 GpkModalDialogPage	 page,
+							 PkBitfield		 options);
+
+G_END_DECLS
+
+#endif /* __GPK_MODAL_DIALOG_H */
+
Index: gnome-packagekit-3.20.0/src/gpk-prefs.c
===================================================================
--- gnome-packagekit-3.20.0.orig/src/gpk-prefs.c
+++ gnome-packagekit-3.20.0/src/gpk-prefs.c
@@ -32,6 +32,7 @@
 #include "gpk-debug.h"
 #include "gpk-enum.h"
 #include "gpk-error.h"
+#include "gpk-gnome.h"
 
 typedef struct {
 	const gchar		*id_tmp;
Index: gnome-packagekit-3.20.0/src/gpk-self-test.c
===================================================================
--- gnome-packagekit-3.20.0.orig/src/gpk-self-test.c
+++ gnome-packagekit-3.20.0/src/gpk-self-test.c
@@ -25,8 +25,12 @@
 #include "egg-markdown.h"
 
 #include "gpk-common.h"
+#include "gpk-dbus.h"
+#include "gpk-dbus-task.h"
 #include "gpk-enum.h"
 #include "gpk-error.h"
+#include "gpk-language.h"
+#include "gpk-modal-dialog.h"
 #include "gpk-task.h"
 
 
@@ -106,6 +110,15 @@ gpk_test_enum_func (void)
 		}
 	}
 
+	/* check we convert all the status animation enums */
+	for (i = PK_STATUS_ENUM_UNKNOWN+1; i < PK_STATUS_ENUM_UNKNOWN; i++) {
+		string = gpk_status_enum_to_animation (i);
+		if (string == NULL || g_strcmp0 (string, "help-browser") == 0) {
+			g_warning ("failed to get %s", pk_status_enum_to_string (i));
+			break;
+		}
+	}
+
 	/* check we convert all the info icon names enums */
 	for (i = PK_INFO_ENUM_UNKNOWN+1; i < PK_INFO_ENUM_LAST; i++) {
 		string = gpk_info_enum_to_icon_name (i);
@@ -199,6 +212,197 @@ gpk_test_enum_func (void)
 }
 
 static void
+gpk_test_dbus_task_func (void)
+{
+	GpkDbusTask *dtask;
+	gchar *lang;
+	gchar *language;
+	gchar *package;
+	gboolean ret;
+//	const gchar *fonts[] = { ":lang=mn", NULL };
+//	GError *error;
+
+	/* get GpkDbusTask object */
+	dtask = gpk_dbus_task_new ();
+	g_assert (dtask);
+
+	/* convert tag to lang */
+	lang = gpk_dbus_task_font_tag_to_lang (":lang=mn");
+	g_assert_cmpstr (lang, ==, "mn");
+	g_free (lang);
+
+	/* convert tag to language */
+	language = gpk_dbus_task_font_tag_to_localised_name (dtask, ":lang=mn");
+	g_assert_cmpstr (language, ==, "Mongolian");
+	g_free (language);
+
+	/* test trusted path */
+//	ret = gpk_dbus_task_path_is_trusted ("/usr/libexec/gst-install-plugins-helper");
+//	g_assert (ret);
+
+	/* test trusted path */
+	ret = gpk_dbus_task_path_is_trusted ("/usr/bin/totem");
+	g_assert (!ret);
+
+	/* get package for exec */
+	package = gpk_dbus_task_get_package_for_exec (dtask, "/usr/bin/totem");
+	g_assert_cmpstr (package, ==, "totem");
+	g_free (package);
+
+	/* set exec */
+	ret = gpk_dbus_task_set_exec (dtask, "/usr/bin/totem");
+	g_assert (ret);
+#if 0
+	/* install fonts (no UI) */
+	error = NULL;
+	gpk_dbus_task_set_interaction (dtask, GPK_CLIENT_INTERACT_NEVER);
+	ret = gpk_dbus_task_install_fontconfig_resources (dtask, (gchar**)fonts, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (ret);
+
+	/* install fonts (if found) */
+	error = NULL;
+	gpk_dbus_task_set_interaction (dtask, pk_bitfield_from_enums (GPK_CLIENT_INTERACT_CONFIRM_SEARCH, GPK_CLIENT_INTERACT_FINISHED, -1));
+	ret = gpk_dbus_task_install_fontconfig_resources (dtask, (gchar**)fonts, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (ret);
+
+	/* install fonts (always) */
+	error = NULL;
+	gpk_dbus_task_set_interaction (dtask, GPK_CLIENT_INTERACT_ALWAYS);
+	ret = gpk_dbus_task_install_fontconfig_resources (dtask, (gchar**)fonts, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (ret);
+#endif
+}
+
+static void
+gpk_test_modal_dialog_func (void)
+{
+	GtkResponseType button;
+	GpkModalDialog *dialog = NULL;
+	GPtrArray *array;
+	PkPackage *item;
+	gboolean ret;
+
+	/* get GpkModalDialog object */
+	dialog = gpk_modal_dialog_new ();
+	g_assert (dialog);
+
+	/* set some packages */
+	array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+	item = pk_package_new ();
+	ret = pk_package_set_id (item, "totem;001;i386;fedora", NULL);
+	g_assert (ret);
+	g_object_set (item,
+		      "info", PK_INFO_ENUM_INSTALLED,
+		      "summary", "Totem is a music player for GNOME",
+		      NULL);
+	g_ptr_array_add (array, item);
+	item = pk_package_new ();
+	ret = pk_package_set_id (item, "totem;001;i386;fedora", NULL);
+	g_assert (ret);
+	g_object_set (item,
+		      "info", PK_INFO_ENUM_AVAILABLE,
+		      "summary", "Amarok is a music player for KDE",
+		      NULL);
+	g_ptr_array_add (array, item);
+	gpk_modal_dialog_set_package_list (dialog, array);
+	g_ptr_array_unref (array);
+
+	/* help button */
+	gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_WARNING, 0);
+	gpk_modal_dialog_set_title (dialog, "Button press test");
+	gpk_modal_dialog_set_message (dialog, "Please press close");
+	gpk_modal_dialog_set_image (dialog, "dialog-warning");
+	gpk_modal_dialog_present (dialog);
+	button = gpk_modal_dialog_run (dialog);
+	g_assert_cmpint (button, ==, GTK_RESPONSE_CLOSE);
+
+	/* confirm button */
+	gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, 0);
+	gpk_modal_dialog_set_title (dialog, "Button press test with a really really long title");
+	gpk_modal_dialog_set_message (dialog, "Please press Uninstall\n\nThis is a really really, really,\nreally long title <i>with formatting</i>");
+	gpk_modal_dialog_set_image (dialog, "dialog-information");
+	gpk_modal_dialog_set_action (dialog, "Uninstall");
+	gpk_modal_dialog_present (dialog);
+	button = gpk_modal_dialog_run (dialog);
+	g_assert_cmpint (button, ==, GTK_RESPONSE_OK);
+
+	/* no message */
+	gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, 0);
+	gpk_modal_dialog_set_title (dialog, "Refresh cache");
+	gpk_modal_dialog_set_image_status (dialog, PK_STATUS_ENUM_REFRESH_CACHE);
+	gpk_modal_dialog_set_percentage (dialog, -1);
+	gpk_modal_dialog_present (dialog);
+	gpk_modal_dialog_run (dialog);
+
+	/* progress */
+	gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, GPK_MODAL_DIALOG_PACKAGE_PADDING);
+	gpk_modal_dialog_set_title (dialog, "Button press test");
+	gpk_modal_dialog_set_message (dialog, "Please press cancel");
+	gpk_modal_dialog_set_image_status (dialog, PK_STATUS_ENUM_RUNNING);
+	gpk_modal_dialog_set_percentage (dialog, 50);
+	gpk_modal_dialog_present (dialog);
+	button = gpk_modal_dialog_run (dialog);
+	g_assert_cmpint (button, ==, GTK_RESPONSE_CANCEL);
+
+	/* progress */
+	gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_PROGRESS, pk_bitfield_from_enums (GPK_MODAL_DIALOG_WIDGET_MESSAGE, -1));
+	gpk_modal_dialog_set_title (dialog, "Button press test");
+	gpk_modal_dialog_set_message (dialog, "Please press close");
+	gpk_modal_dialog_set_image_status (dialog, PK_STATUS_ENUM_INSTALL);
+	gpk_modal_dialog_set_percentage (dialog, -1);
+	gpk_modal_dialog_present (dialog);
+	button = gpk_modal_dialog_run (dialog);
+	g_assert_cmpint (button, ==, GTK_RESPONSE_CLOSE);
+
+	/* confirm install button */
+	gpk_modal_dialog_setup (dialog, GPK_MODAL_DIALOG_PAGE_CONFIRM, GPK_MODAL_DIALOG_PACKAGE_LIST);
+	gpk_modal_dialog_set_title (dialog, "Button press test");
+	gpk_modal_dialog_set_message (dialog, "Please press Install if you can see the package list");
+	gpk_modal_dialog_set_image (dialog, "dialog-information");
+	gpk_modal_dialog_set_action (dialog, "Install");
+	gpk_modal_dialog_present (dialog);
+	button = gpk_modal_dialog_run (dialog);
+	g_assert_cmpint (button, ==, GTK_RESPONSE_OK);
+
+	gpk_modal_dialog_close (dialog);
+
+	g_object_unref (dialog);
+}
+
+static void
+gpk_test_language_func (void)
+{
+	gboolean ret;
+	gchar *lang;
+	GError *error = NULL;
+	GpkLanguage *language = NULL;
+
+	/* get GpkLanguage object */
+	language = gpk_language_new ();
+	g_assert (language != NULL);
+
+	/* populate */
+	ret = gpk_language_populate (language, &error);
+	g_assert_no_error (error);
+	g_assert (ret);
+
+	/* get data (present) */
+	lang = gpk_language_iso639_to_language (language, "en");
+	g_assert_cmpstr (lang, ==, "English");
+	g_free (lang);
+
+	/* get data (missing) */
+	lang = gpk_language_iso639_to_language (language, "notgoingtoexist");
+	g_assert_cmpstr (lang, ==, NULL);
+
+	g_object_unref (language);
+>>>>>>> parent of 52b1ece... Remove unused functionality
+}
+
+static void
 gpk_test_error_func (void)
 {
 	gboolean ret;
@@ -212,6 +416,17 @@ gpk_test_error_func (void)
 }
 
 static void
+gpk_test_dbus_func (void)
+{
+	GpkDbus *dbus = NULL;
+
+	/* get GpkDbus object */
+	dbus = gpk_dbus_new ();
+	g_assert (dbus);
+	g_object_unref (dbus);
+}
+
+static void
 gpk_test_common_func (void)
 {
 	gchar *text;
@@ -554,8 +769,12 @@ main (int argc, char **argv)
 
 	g_test_add_func ("/gnome-packagekit/enum", gpk_test_enum_func);
 	g_test_add_func ("/gnome-packagekit/common", gpk_test_common_func);
+	g_test_add_func ("/gnome-packagekit/language", gpk_test_language_func);
 	g_test_add_func ("/gnome-packagekit/markdown", gpk_test_markdown_func);
+	g_test_add_func ("/gnome-packagekit/dbus", gpk_test_dbus_func);
+	g_test_add_func ("/gnome-packagekit/dbus-task", gpk_test_dbus_task_func);
 	if (g_test_thorough ()) {
+		g_test_add_func ("/gnome-packagekit/modal-dialog", gpk_test_modal_dialog_func);
 		g_test_add_func ("/gnome-packagekit/error", gpk_test_error_func);
 		g_test_add_func ("/gnome-packagekit/task", gpk_test_task_func);
 	}
Index: gnome-packagekit-3.20.0/src/gpk-session.c
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-session.c
@@ -0,0 +1,361 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008-2009 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus-glib.h>
+
+#include "gpk-session.h"
+#include "gpk-common.h"
+
+static void     gpk_session_finalize   (GObject		*object);
+
+#define GPK_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_SESSION, GpkSessionPrivate))
+
+#define GPK_SESSION_MANAGER_SERVICE			"org.gnome.SessionManager"
+#define GPK_SESSION_MANAGER_PATH			"/org/gnome/SessionManager"
+#define GPK_SESSION_MANAGER_INTERFACE			"org.gnome.SessionManager"
+#define GPK_SESSION_MANAGER_PRESENCE_PATH		"/org/gnome/SessionManager/Presence"
+#define GPK_SESSION_MANAGER_PRESENCE_INTERFACE		"org.gnome.SessionManager.Presence"
+#define GPK_SESSION_MANAGER_CLIENT_PRIVATE_INTERFACE	"org.gnome.SessionManager.ClientPrivate"
+#define GPK_DBUS_PROPERTIES_INTERFACE			"org.freedesktop.DBus.Properties"
+
+typedef enum {
+	GPK_SESSION_STATUS_ENUM_AVAILABLE = 0,
+	GPK_SESSION_STATUS_ENUM_INVISIBLE,
+	GPK_SESSION_STATUS_ENUM_BUSY,
+	GPK_SESSION_STATUS_ENUM_IDLE,
+	GPK_SESSION_STATUS_ENUM_UNKNOWN
+} GpkSessionStatusEnum;
+
+typedef enum {
+	GPK_SESSION_INHIBIT_MASK_LOGOUT = 1,
+	GPK_SESSION_INHIBIT_MASK_SWITCH = 2,
+	GPK_SESSION_INHIBIT_MASK_SUSPEND = 4,
+	GPK_SESSION_INHIBIT_MASK_IDLE = 8
+} GpkSessionInhibitMask;
+
+struct GpkSessionPrivate
+{
+	DBusGProxy		*proxy;
+	DBusGProxy		*proxy_presence;
+	DBusGProxy		*proxy_client_private;
+	DBusGProxy		*proxy_prop;
+	gboolean		 is_idle_old;
+	gboolean		 is_inhibited_old;
+};
+
+enum {
+	IDLE_CHANGED,
+	INHIBITED_CHANGED,
+	STOP,
+	QUERY_END_SESSION,
+	END_SESSION,
+	CANCEL_END_SESSION,
+	LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+static gpointer gpk_session_object = NULL;
+
+G_DEFINE_TYPE (GpkSession, gpk_session, G_TYPE_OBJECT)
+
+/**
+ * gpk_session_logout:
+ **/
+gboolean
+gpk_session_logout (GpkSession *session)
+{
+	g_return_val_if_fail (GPK_IS_SESSION (session), FALSE);
+
+	/* no gnome-session */
+	if (session->priv->proxy == NULL) {
+		g_warning ("no gnome-session");
+		return FALSE;
+	}
+
+	/* we have to use no reply, as the SM calls into g-p-m to get the can_suspend property */
+	dbus_g_proxy_call_no_reply (session->priv->proxy, "Logout",
+				    G_TYPE_UINT, 1, /* no confirmation, but use inhibitors */
+				    G_TYPE_INVALID);
+	return TRUE;
+}
+
+/**
+ * gpk_session_presence_status_changed_cb:
+ **/
+static void
+gpk_session_presence_status_changed_cb (DBusGProxy *proxy, guint status, GpkSession *session)
+{
+	gboolean is_idle;
+	is_idle = (status == GPK_SESSION_STATUS_ENUM_IDLE);
+	if (is_idle != session->priv->is_idle_old) {
+		g_debug ("emitting idle-changed : (%i)", is_idle);
+		session->priv->is_idle_old = is_idle;
+		g_signal_emit (session, signals [IDLE_CHANGED], 0, is_idle);
+	}
+}
+
+/**
+ * gpk_session_is_idle:
+ **/
+static gboolean
+gpk_session_is_idle (GpkSession *session)
+{
+	gboolean ret;
+	gboolean is_idle = FALSE;
+	GError *error = NULL;
+	GValue *value;
+
+	/* no gnome-session */
+	if (session->priv->proxy_prop == NULL) {
+		g_warning ("no gnome-session");
+		goto out;
+	}
+
+	value = g_new0(GValue, 1);
+	/* find out if this change altered the inhibited state */
+	ret = dbus_g_proxy_call (session->priv->proxy_prop, "Get", &error,
+				 G_TYPE_STRING, GPK_SESSION_MANAGER_PRESENCE_INTERFACE,
+				 G_TYPE_STRING, "status",
+				 G_TYPE_INVALID,
+				 G_TYPE_VALUE, value,
+				 G_TYPE_INVALID);
+	if (!ret) {
+		g_warning ("failed to get idle status: %s", error->message);
+		g_error_free (error);
+		is_idle = FALSE;
+		goto out;
+	}
+	is_idle = (g_value_get_uint (value) == GPK_SESSION_STATUS_ENUM_IDLE);
+	g_free (value);
+out:
+	return is_idle;
+}
+
+/**
+ * gpk_session_is_inhibited:
+ **/
+static gboolean
+gpk_session_is_inhibited (GpkSession *session)
+{
+	gboolean ret;
+	gboolean is_inhibited = FALSE;
+	GError *error = NULL;
+
+	/* no gnome-session */
+	if (session->priv->proxy == NULL) {
+		g_warning ("no gnome-session");
+		goto out;
+	}
+
+	/* find out if this change altered the inhibited state */
+	ret = dbus_g_proxy_call (session->priv->proxy, "IsInhibited", &error,
+				 G_TYPE_UINT, GPK_SESSION_INHIBIT_MASK_IDLE,
+				 G_TYPE_INVALID,
+				 G_TYPE_BOOLEAN, &is_inhibited,
+				 G_TYPE_INVALID);
+	if (!ret) {
+		g_warning ("failed to get inhibit status: %s", error->message);
+		g_error_free (error);
+		is_inhibited = FALSE;
+	}
+out:
+	return is_inhibited;
+}
+
+/**
+ * gpk_session_inhibit_changed_cb:
+ **/
+static void
+gpk_session_inhibit_changed_cb (DBusGProxy *proxy, const gchar *id, GpkSession *session)
+{
+	gboolean is_inhibited;
+
+	is_inhibited = gpk_session_is_inhibited (session);
+	if (is_inhibited != session->priv->is_inhibited_old) {
+		g_debug ("emitting inhibited-changed : (%i)", is_inhibited);
+		session->priv->is_inhibited_old = is_inhibited;
+		g_signal_emit (session, signals [INHIBITED_CHANGED], 0, is_inhibited);
+	}
+}
+
+/**
+ * gpk_session_class_init:
+ * @klass: This class instance
+ **/
+static void
+gpk_session_class_init (GpkSessionClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_session_finalize;
+	g_type_class_add_private (klass, sizeof (GpkSessionPrivate));
+
+	signals [IDLE_CHANGED] =
+		g_signal_new ("idle-changed",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkSessionClass, idle_changed),
+			      NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN,
+			      G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+	signals [INHIBITED_CHANGED] =
+		g_signal_new ("inhibited-changed",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkSessionClass, inhibited_changed),
+			      NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN,
+			      G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+	signals [STOP] =
+		g_signal_new ("stop",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkSessionClass, stop),
+			      NULL, NULL, g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+	signals [QUERY_END_SESSION] =
+		g_signal_new ("query-end-session",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkSessionClass, query_end_session),
+			      NULL, NULL, g_cclosure_marshal_VOID__UINT,
+			      G_TYPE_NONE, 1, G_TYPE_UINT);
+	signals [END_SESSION] =
+		g_signal_new ("end-session",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkSessionClass, end_session),
+			      NULL, NULL, g_cclosure_marshal_VOID__UINT,
+			      G_TYPE_NONE, 1, G_TYPE_UINT);
+	signals [CANCEL_END_SESSION] =
+		g_signal_new ("cancel-end-session",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GpkSessionClass, cancel_end_session),
+			      NULL, NULL, g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+}
+
+/**
+ * gpk_session_init:
+ * @session: This class instance
+ **/
+static void
+gpk_session_init (GpkSession *session)
+{
+	DBusGConnection *connection;
+	GError *error = NULL;
+
+	session->priv = GPK_SESSION_GET_PRIVATE (session);
+	session->priv->is_idle_old = FALSE;
+	session->priv->is_inhibited_old = FALSE;
+	session->priv->proxy_client_private = NULL;
+
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
+
+	/* get org.gnome.Session interface */
+	session->priv->proxy = dbus_g_proxy_new_for_name_owner (connection, GPK_SESSION_MANAGER_SERVICE,
+								GPK_SESSION_MANAGER_PATH,
+								GPK_SESSION_MANAGER_INTERFACE, &error);
+	if (session->priv->proxy == NULL) {
+		g_warning ("DBUS error: %s", error->message);
+		g_error_free (error);
+		return;
+	}
+
+	/* get org.gnome.Session.Presence interface */
+	session->priv->proxy_presence = dbus_g_proxy_new_for_name_owner (connection, GPK_SESSION_MANAGER_SERVICE,
+									 GPK_SESSION_MANAGER_PRESENCE_PATH,
+									 GPK_SESSION_MANAGER_PRESENCE_INTERFACE, &error);
+	if (session->priv->proxy_presence == NULL) {
+		g_warning ("DBUS error: %s", error->message);
+		g_error_free (error);
+		return;
+	}
+
+	/* get properties interface */
+	session->priv->proxy_prop = dbus_g_proxy_new_for_name_owner (connection, GPK_SESSION_MANAGER_SERVICE,
+								     GPK_SESSION_MANAGER_PRESENCE_PATH,
+								     GPK_DBUS_PROPERTIES_INTERFACE, &error);
+	if (session->priv->proxy_prop == NULL) {
+		g_warning ("DBUS error: %s", error->message);
+		g_error_free (error);
+		return;
+	}
+
+	/* get StatusChanged */
+	dbus_g_proxy_add_signal (session->priv->proxy_presence, "StatusChanged", G_TYPE_UINT, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (session->priv->proxy_presence, "StatusChanged", G_CALLBACK (gpk_session_presence_status_changed_cb), session, NULL);
+
+	/* get InhibitorAdded */
+	dbus_g_proxy_add_signal (session->priv->proxy, "InhibitorAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (session->priv->proxy, "InhibitorAdded", G_CALLBACK (gpk_session_inhibit_changed_cb), session, NULL);
+
+	/* get InhibitorRemoved */
+	dbus_g_proxy_add_signal (session->priv->proxy, "InhibitorRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (session->priv->proxy, "InhibitorRemoved", G_CALLBACK (gpk_session_inhibit_changed_cb), session, NULL);
+
+	/* coldplug */
+	session->priv->is_inhibited_old = gpk_session_is_inhibited (session);
+	session->priv->is_idle_old = gpk_session_is_idle (session);
+	g_debug ("idle: %i, inhibited: %i", session->priv->is_idle_old, session->priv->is_inhibited_old);
+}
+
+/**
+ * gpk_session_finalize:
+ * @object: This class instance
+ **/
+static void
+gpk_session_finalize (GObject *object)
+{
+	GpkSession *session;
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (GPK_IS_SESSION (object));
+
+	session = GPK_SESSION (object);
+	session->priv = GPK_SESSION_GET_PRIVATE (session);
+
+	g_object_unref (session->priv->proxy);
+	g_object_unref (session->priv->proxy_presence);
+	if (session->priv->proxy_client_private != NULL)
+		g_object_unref (session->priv->proxy_client_private);
+	g_object_unref (session->priv->proxy_prop);
+
+	G_OBJECT_CLASS (gpk_session_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_session_new:
+ * Return value: new GpkSession instance.
+ **/
+GpkSession *
+gpk_session_new (void)
+{
+	if (gpk_session_object != NULL) {
+		g_object_ref (gpk_session_object);
+	} else {
+		gpk_session_object = g_object_new (GPK_TYPE_SESSION, NULL);
+		g_object_add_weak_pointer (gpk_session_object, &gpk_session_object);
+	}
+	return GPK_SESSION (gpk_session_object);
+}
Index: gnome-packagekit-3.20.0/src/gpk-session.h
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-session.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008-2009 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GPK_SESSION_H
+#define __GPK_SESSION_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_SESSION		(gpk_session_get_type ())
+#define GPK_SESSION(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_SESSION, GpkSession))
+#define GPK_SESSION_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_SESSION, GpkSessionClass))
+#define GPK_IS_SESSION(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_SESSION))
+#define GPK_IS_SESSION_CLASS(k)		(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_SESSION))
+#define GPK_SESSION_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_SESSION, GpkSessionClass))
+
+typedef struct GpkSessionPrivate GpkSessionPrivate;
+
+typedef struct
+{
+	GObject			 parent;
+	GpkSessionPrivate	*priv;
+} GpkSession;
+
+typedef struct
+{
+	GObjectClass	parent_class;
+	void		(* idle_changed)		(GpkSession	*session,
+							 gboolean	 is_idle);
+	void		(* inhibited_changed)		(GpkSession	*session,
+							 gboolean	 is_inhibited);
+	/* just exit */
+	void		(* stop)			(GpkSession	*session);
+	/* reply with EndSessionResponse */
+	void		(* query_end_session)		(GpkSession	*session,
+							 guint		 flags);
+	/* reply with EndSessionResponse */
+	void		(* end_session)			(GpkSession	*session,
+							 guint		 flags);
+	void		(* cancel_end_session)		(GpkSession	*session);
+} GpkSessionClass;
+
+GType		 gpk_session_get_type			(void);
+GpkSession	*gpk_session_new			(void);
+
+gboolean	 gpk_session_logout			(GpkSession	*session);
+
+G_END_DECLS
+
+#endif	/* __GPK_SESSION_H */
Index: gnome-packagekit-3.20.0/src/gpk-task.c
===================================================================
--- gnome-packagekit-3.20.0.orig/src/gpk-task.c
+++ gnome-packagekit-3.20.0/src/gpk-task.c
@@ -25,6 +25,7 @@
 #include <packagekit-glib2/packagekit.h>
 
 #include "gpk-task.h"
+#include "gpk-gnome.h"
 #include "gpk-common.h"
 #include "gpk-enum.h"
 #include "gpk-dialog.h"
Index: gnome-packagekit-3.20.0/src/gpk-vendor.c
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-vendor.c
@@ -0,0 +1,159 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "egg-string.h"
+#include "gpk-vendor.h"
+
+static void     gpk_vendor_finalize	(GObject          *object);
+
+#define GPK_VENDOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_VENDOR, GpkVendorPrivate))
+
+struct GpkVendorPrivate
+{
+	GKeyFile			 *file;
+};
+
+G_DEFINE_TYPE (GpkVendor, gpk_vendor, G_TYPE_OBJECT)
+
+/**
+ * gpk_vendor_class_init:
+ * @klass: The GpkVendorClass
+ **/
+static void
+gpk_vendor_class_init (GpkVendorClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_vendor_finalize;
+	g_type_class_add_private (klass, sizeof (GpkVendorPrivate));
+}
+
+/**
+ * gpk_vendor_type_to_string:
+ **/
+static const gchar *
+gpk_vendor_type_to_string (GpkVendorUrlType type)
+{
+	if (type == GPK_VENDOR_URL_TYPE_CODEC)
+		return "CodecUrl";
+	if (type == GPK_VENDOR_URL_TYPE_FONT)
+		return "FontUrl";
+	if (type == GPK_VENDOR_URL_TYPE_MIME)
+		return "MimeUrl";
+	if (type == GPK_VENDOR_URL_TYPE_HARDWARE)
+		return "HardwareUrl";
+	return "DefaultUrl";
+}
+
+/**
+ * gpk_vendor_get_not_found_url:
+ **/
+gchar *
+gpk_vendor_get_not_found_url (GpkVendor *vendor, GpkVendorUrlType type)
+{
+	const gchar *key;
+	gchar *url = NULL;
+
+	/* get data */
+	key = gpk_vendor_type_to_string (type);
+	url = g_key_file_get_string (vendor->priv->file, "PackagesNotFound", key, NULL);
+
+	/* none is a special value */
+	if (g_strcmp0 (url, "none") == 0) {
+		g_free (url);
+		url = NULL;
+	}
+
+	/* got a valid URL */
+	if (url != NULL)
+		goto out;
+
+	/* default has no fallback */
+	if (type == GPK_VENDOR_URL_TYPE_DEFAULT)
+		goto out;
+
+	/* get fallback data */
+	g_debug ("using fallback");
+	key = gpk_vendor_type_to_string (GPK_VENDOR_URL_TYPE_DEFAULT);
+	url = g_key_file_get_string (vendor->priv->file, "PackagesNotFound", key, NULL);
+
+	/* none is a special value */
+	if (g_strcmp0 (url, "none") == 0) {
+		g_free (url);
+		url = NULL;
+	}
+out:
+	g_debug ("url=%s", url);
+	return url;
+}
+
+/**
+ * gpk_vendor_init:
+ * @vendor: This class instance
+ **/
+static void
+gpk_vendor_init (GpkVendor *vendor)
+{
+	gboolean ret;
+
+	vendor->priv = GPK_VENDOR_GET_PRIVATE (vendor);
+
+	vendor->priv->file = g_key_file_new ();
+	ret = g_key_file_load_from_file (vendor->priv->file, "/etc/PackageKit/Vendor.conf", G_KEY_FILE_NONE, NULL);
+	if (!ret)
+		g_warning ("file not found");
+}
+
+/**
+ * gpk_vendor_finalize:
+ * @object: The object to finalize
+ **/
+static void
+gpk_vendor_finalize (GObject *object)
+{
+	GpkVendor *vendor;
+
+	g_return_if_fail (PK_IS_VENDOR (object));
+
+	vendor = GPK_VENDOR (object);
+	g_return_if_fail (vendor->priv != NULL);
+
+	g_key_file_free (vendor->priv->file);
+
+	G_OBJECT_CLASS (gpk_vendor_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_vendor_new:
+ *
+ * Return value: a new GpkVendor object.
+ **/
+GpkVendor *
+gpk_vendor_new (void)
+{
+	GpkVendor *vendor;
+	vendor = g_object_new (GPK_TYPE_VENDOR, NULL);
+	return GPK_VENDOR (vendor);
+}
+
Index: gnome-packagekit-3.20.0/src/gpk-vendor.h
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-vendor.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#ifndef __GPK_VENDOR_H
+#define __GPK_VENDOR_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_VENDOR			(gpk_vendor_get_type ())
+#define GPK_VENDOR(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_VENDOR, GpkVendor))
+#define GPK_VENDOR_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_VENDOR, GpkVendorClass))
+#define PK_IS_VENDOR(o)	 		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_VENDOR))
+#define PK_IS_VENDOR_CLASS(k)		(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_VENDOR))
+#define GPK_VENDOR_GET_CLASS(o)		(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_VENDOR, GpkVendorClass))
+#define GPK_VENDOR_ERROR		(gpk_vendor_error_quark ())
+#define GPK_VENDOR_TYPE_ERROR		(gpk_vendor_error_get_type ())
+
+typedef struct GpkVendorPrivate GpkVendorPrivate;
+
+typedef struct
+{
+	 GObject		 parent;
+	 GpkVendorPrivate	*priv;
+} GpkVendor;
+
+typedef struct
+{
+	GObjectClass	parent_class;
+} GpkVendorClass;
+
+/**
+ * GpkModalDialogWidgets:
+ */
+typedef enum
+{
+	GPK_VENDOR_URL_TYPE_CODEC,
+	GPK_VENDOR_URL_TYPE_FONT,
+	GPK_VENDOR_URL_TYPE_MIME,
+	GPK_VENDOR_URL_TYPE_HARDWARE,
+	GPK_VENDOR_URL_TYPE_DEFAULT
+} GpkVendorUrlType;
+
+GType		 gpk_vendor_get_type			(void);
+GpkVendor	*gpk_vendor_new				(void);
+gchar		*gpk_vendor_get_not_found_url		(GpkVendor		*vendor,
+							 GpkVendorUrlType	 type);
+
+G_END_DECLS
+
+#endif /* __GPK_VENDOR_H */
Index: gnome-packagekit-3.20.0/src/gpk-x11.c
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-x11.c
@@ -0,0 +1,250 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007-2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+
+#include "egg-string.h"
+
+#include "gpk-x11.h"
+
+static void     gpk_x11_finalize	(GObject	  *object);
+
+#define GPK_X11_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPK_TYPE_X11, GpkX11Private))
+
+struct GpkX11Private
+{
+	GdkDisplay		*gdk_display;
+	Display			*display;
+	Window			 window;
+};
+
+G_DEFINE_TYPE (GpkX11, gpk_x11, G_TYPE_OBJECT)
+
+/**
+ * gpk_x11_set_xid:
+ **/
+gboolean
+gpk_x11_set_xid (GpkX11 *x11, guint32 xid)
+{
+	GdkWindow *window;
+
+	g_return_val_if_fail (GPK_IS_X11 (x11), FALSE);
+
+	window = gdk_x11_window_foreign_new_for_display (x11->priv->gdk_display, xid);
+	if (window == NULL)
+		return FALSE;
+
+	/* save the x state */
+	x11->priv->display = GDK_DISPLAY_XDISPLAY (x11->priv->gdk_display);
+	x11->priv->window = GDK_WINDOW_XID (window);
+
+	return TRUE;
+}
+
+/**
+ * gpk_x11_set_window:
+ **/
+gboolean
+gpk_x11_set_window (GpkX11 *x11, GdkWindow *window)
+{
+	g_return_val_if_fail (GPK_IS_X11 (x11), FALSE);
+
+	/* save the x state */
+	x11->priv->display = GDK_DISPLAY_XDISPLAY (x11->priv->gdk_display);
+	x11->priv->window = GDK_WINDOW_XID (window);
+
+	return TRUE;
+}
+
+/**
+ * gpk_x11_get_user_time:
+ **/
+guint32
+gpk_x11_get_user_time (GpkX11 *x11)
+{
+	guint32 timestamp = 0;
+	Atom atom = None;
+	Atom type;
+	gint format;
+	gulong nitems;
+	gulong bytes_after;
+	Window *win = NULL;
+	int rc;
+	int err;
+
+	g_return_val_if_fail (GPK_IS_X11 (x11), 0);
+
+	/* check we have a window */
+	if (x11->priv->window == None) {
+		g_debug ("no window, so cannot get user_time");
+		goto out;
+	}
+
+	/* get _NET_WM_USER_TIME_WINDOW which points to a window on which you can find the _NET_WM_USER_TIME property */
+	gdk_error_trap_push ();
+	atom = gdk_x11_get_xatom_by_name_for_display (x11->priv->gdk_display, "_NET_WM_USER_TIME_WINDOW");
+	rc = XGetWindowProperty (x11->priv->display, x11->priv->window, atom, 0, G_MAXLONG, False, XA_WINDOW,
+				 &type, &format, &nitems, &bytes_after, (void*) &win);
+	err = gdk_error_trap_pop ();
+	if (err != Success || rc != Success) {
+		g_warning ("couldn't get _NET_WM_USER_TIME_WINDOW");
+		goto out;
+	}
+
+	/* is not a window */
+	if (type != XA_WINDOW) {
+		g_warning ("not type XA_WINDOW");
+		goto out;
+	}
+
+	/* get _NET_WM_USER_TIME so we can get the user time */
+	gdk_error_trap_push ();
+	atom = gdk_x11_get_xatom_by_name_for_display (x11->priv->gdk_display, "_NET_WM_USER_TIME");
+	rc = XGetWindowProperty (x11->priv->display, *win, atom, 0, G_MAXLONG, False, XA_CARDINAL,
+				 &type, &format, &nitems, &bytes_after, (void*) &timestamp);
+	err = gdk_error_trap_pop ();
+	if (err != Success || rc != Success) {
+		g_warning ("couldn't get _NET_WM_USER_TIME");
+		goto out;
+	}
+
+	/* is not a window */
+	if (type != XA_CARDINAL) {
+		g_warning ("not type XA_CARDINAL");
+		goto out;
+	}
+out:
+	if (win != NULL)
+		XFree (win);
+	return timestamp;
+}
+
+/**
+ * gpk_x11_get_title:
+ **/
+gchar *
+gpk_x11_get_title (GpkX11 *x11)
+{
+	gchar *title = NULL;
+	Atom atom = None;
+	Atom atom_type = None;
+	gchar *data = NULL;
+	Atom type;
+	gint format;
+	gulong nitems;
+	gulong bytes_after;
+	int rc;
+
+	g_return_val_if_fail (GPK_IS_X11 (x11), NULL);
+
+	/* check we have a window */
+	if (x11->priv->window == None) {
+		g_debug ("no window, so cannot get user_time");
+		goto out;
+	}
+
+	/* get _NET_WM_NAME */
+	gdk_error_trap_push ();
+	atom = gdk_x11_get_xatom_by_name_for_display (x11->priv->gdk_display, "_NET_WM_NAME");
+	atom_type = gdk_x11_get_xatom_by_name_for_display (x11->priv->gdk_display, "UTF8_STRING");
+	rc = XGetWindowProperty (x11->priv->display, x11->priv->window, atom, 0, G_MAXLONG, False, atom_type,
+				 &type, &format, &nitems, &bytes_after, (void*) &data);
+	gdk_error_trap_pop_ignored ();
+	if (rc == Success && nitems > 0) {
+		title = g_strdup (data);
+		goto out;
+	}
+
+	/* we failed to get the UTF8 title, try plain old WM_NAME */
+	gdk_error_trap_push ();
+	rc = XGetWindowProperty (x11->priv->display, x11->priv->window, XA_WM_NAME, 0, G_MAXLONG, False, XA_STRING,
+				 &type, &format, &nitems, &bytes_after, (void*) &data);
+	gdk_error_trap_pop_ignored ();
+	if (rc == Success && nitems > 0) {
+		title = g_strdup (data);
+		goto out;
+	}
+	g_warning ("failed to get X11 name for window %i", (gint) x11->priv->window);
+out:
+	if (data != NULL)
+		XFree (data);
+	return title;
+}
+
+/**
+ * gpk_x11_class_init:
+ * @klass: The GpkX11Class
+ **/
+static void
+gpk_x11_class_init (GpkX11Class *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gpk_x11_finalize;
+	g_type_class_add_private (klass, sizeof (GpkX11Private));
+}
+
+/**
+ * gpk_x11_init:
+ * @x11: This class instance
+ **/
+static void
+gpk_x11_init (GpkX11 *x11)
+{
+	x11->priv = GPK_X11_GET_PRIVATE (x11);
+	x11->priv->display = NULL;
+	x11->priv->window = None;
+	x11->priv->gdk_display = gdk_display_get_default ();
+}
+
+/**
+ * gpk_x11_finalize:
+ * @object: The object to finalize
+ **/
+static void
+gpk_x11_finalize (GObject *object)
+{
+	GpkX11 *x11;
+	g_return_if_fail (GPK_IS_X11 (object));
+	x11 = GPK_X11 (object);
+
+	g_return_if_fail (x11->priv != NULL);
+
+	G_OBJECT_CLASS (gpk_x11_parent_class)->finalize (object);
+}
+
+/**
+ * gpk_x11_new:
+ *
+ * Return value: a new GpkX11 object.
+ **/
+GpkX11 *
+gpk_x11_new (void)
+{
+	GpkX11 *x11;
+	x11 = g_object_new (GPK_TYPE_X11, NULL);
+	return GPK_X11 (x11);
+}
+
Index: gnome-packagekit-3.20.0/src/gpk-x11.h
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/gpk-x11.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#ifndef __GPK_X11_H
+#define __GPK_X11_H
+
+#include <glib-object.h>
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GPK_TYPE_X11		(gpk_x11_get_type ())
+#define GPK_X11(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GPK_TYPE_X11, GpkX11))
+#define GPK_X11_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GPK_TYPE_X11, GpkX11Class))
+#define GPK_IS_X11(o)	 	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GPK_TYPE_X11))
+#define GPK_IS_X11_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GPK_TYPE_X11))
+#define GPK_X11_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GPK_TYPE_X11, GpkX11Class))
+#define GPK_X11_ERROR		(gpk_x11_error_quark ())
+#define GPK_X11_TYPE_ERROR	(gpk_x11_error_get_type ())
+
+typedef struct GpkX11Private GpkX11Private;
+
+typedef struct
+{
+	 GObject		 parent;
+	 GpkX11Private		*priv;
+} GpkX11;
+
+typedef struct
+{
+	GObjectClass		parent_class;
+} GpkX11Class;
+
+GType		 gpk_x11_get_type		  	(void);
+GpkX11		*gpk_x11_new				(void);
+gboolean	 gpk_x11_set_xid			(GpkX11		*x11,
+							 guint32	 xid);
+gboolean	 gpk_x11_set_window			(GpkX11		*x11,
+							 GdkWindow	*window);
+guint32		 gpk_x11_get_user_time			(GpkX11		*x11);
+gchar		*gpk_x11_get_title			(GpkX11		*x11);
+
+G_END_DECLS
+
+#endif /* __GPK_X11_H */
Index: gnome-packagekit-3.20.0/src/org.freedesktop.PackageKit.xml
===================================================================
--- /dev/null
+++ gnome-packagekit-3.20.0/src/org.freedesktop.PackageKit.xml
@@ -0,0 +1,506 @@
+<!DOCTYPE node PUBLIC
+"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" [
+  <!ENTITY ERROR_GENERAL "org.freedesktop.PackageKit.Denied">
+]>
+<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+
+  <interface name="org.freedesktop.PackageKit.Query">
+    <doc:doc>
+      <doc:description>
+        <doc:para>
+          The interface used for quering the package database.
+        </doc:para>
+      </doc:description>
+    </doc:doc>
+
+    <!--*****************************************************************************************-->
+    <method name="IsInstalled">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+            Finds out if the package is installed.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+      <arg type="s" name="package_name" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              A package name, e.g. <doc:tt>hal-info</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="interaction" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An optional interaction mode, e.g.
+              <doc:tt>timeout=10</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="b" name="installed" direction="out">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              If the package is installed.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+    </method>
+
+    <!--*****************************************************************************************-->
+    <method name="SearchFile">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+            Finds the package name for an installed or available file
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+      <arg type="s" name="file_name" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              A package name, e.g. <doc:tt>/usr/share/help/gimp/index.html</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="interaction" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An optional interaction mode, e.g.
+              <doc:tt>timeout=10</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="b" name="installed" direction="out">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              If the package is installed.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="package_name" direction="out">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              The package name of the file, e.g. <doc:tt>hal-info</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+    </method>
+  </interface>
+
+  <!-- ######################################################################################### -->
+  <interface name="org.freedesktop.PackageKit.Modify">
+    <doc:doc>
+      <doc:description>
+        <doc:para>
+          The interface used for modifying the package database.
+        </doc:para>
+      </doc:description>
+    </doc:doc>
+
+    <!--*****************************************************************************************-->
+    <method name="InstallPackageFiles">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+            Installs local package files or service packs.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+      <arg type="u" name="xid" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              The X window handle ID, used for focus stealing prevention and setting modality.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="as" name="files" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An array of file names.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="interaction" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An interaction mode that specifies which UI elements should be shown
+              or hidden different from the user default, e.g.
+              <doc:tt>hide-confirm-search,hide-confirm-deps,hide-confirm-install,show-progress</doc:tt>.
+              The show options are:
+              <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt>.
+              The hide options are:
+              <doc:tt>hide-confirm-search,hide-confirm-deps,hide-confirm-install,hide-progress,hide-finished,hide-warning</doc:tt>.
+              Convenience options such as:
+              <doc:tt>never</doc:tt>, <doc:tt>defaults</doc:tt> or <doc:tt>always</doc:tt>.
+              are also available.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+    </method>
+
+    <!--*****************************************************************************************-->
+    <method name="InstallProvideFiles">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+            Installs packages to provide files.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+      <arg type="u" name="xid" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              The X window handle ID, used for focus stealing prevention and setting modality.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="as" name="files" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An array of file names.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="interaction" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An optional interaction mode, e.g.
+              <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+    </method>
+
+    <!--*****************************************************************************************-->
+    <method name="InstallPackageNames">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+            Installs packages from a configured package source.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+      <arg type="u" name="xid" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              The X window handle ID, used for focus stealing prevention and setting modality.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="as" name="packages" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An array of package names.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="interaction" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An optional interaction mode, e.g.
+              <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+    </method>
+
+    <!--*****************************************************************************************-->
+    <method name="InstallMimeTypes">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+            Installs mimetype handlers from a configured package source.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+      <arg type="u" name="xid" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              The X window handle ID, used for focus stealing prevention and setting modality.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="as" name="mime_types" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An array of mime types, e.g. <doc:tt>text/plain</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="interaction" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An optional interaction mode, e.g.
+              <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+    </method>
+
+    <!--*****************************************************************************************-->
+    <method name="InstallFontconfigResources">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+            Installs fontconfig resources (usually fonts) from a configured package source.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+      <arg type="u" name="xid" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              The X window handle ID, used for focus stealing prevention and setting modality.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="as" name="resources" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An array of font descriptors from fontconfig, e.g. <doc:tt>:lang=mn</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="interaction" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An optional interaction mode, e.g.
+              <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+    </method>
+
+    <!--*****************************************************************************************-->
+    <method name="InstallGStreamerResources">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+            Installs GStreamer fontconfig resources (usually codecs) from a configured package source.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+      <arg type="u" name="xid" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              The X window handle ID, used for focus stealing prevention and setting modality.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="as" name="resources" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An array of codecs descriptors from <doc:tt>pk-gstreamer-install</doc:tt>, e.g.
+              <doc:tt>Advanced Streaming Format (ASF) demuxer|decoder-video/x-ms-asf</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="interaction" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An optional interaction mode, e.g.
+              <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+    </method>
+
+    <!--*****************************************************************************************-->
+    <method name="InstallResources">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+            Installs resources of a given type from a configured package source.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+      <arg type="u" name="xid" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              The X window handle ID, used for focus stealing prevention and setting modality.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="type" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              The type of resource to request, e.g. <doc:tt>plasma-service</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="as" name="resources" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An array of resource descriptors
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="interaction" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An optional interaction mode, e.g.
+              <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+    </method>
+
+    <!--*****************************************************************************************-->
+    <method name="RemovePackageByFiles">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+            Removes packages that provide the given local files.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+      <arg type="u" name="xid" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              The X window handle ID, used for focus stealing prevention and setting modality.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="as" name="files" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An array of file names.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="interaction" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An interaction mode that specifies which UI elements should be shown
+              or hidden different from the user default, e.g.
+              <doc:tt>hide-confirm-search,hide-confirm-deps,hide-confirm-install,show-progress</doc:tt>.
+              The show options are:
+              <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt>.
+              The hide options are:
+              <doc:tt>hide-confirm-search,hide-confirm-deps,hide-confirm-install,hide-progress,hide-finished,hide-warning</doc:tt>.
+              Convenience options such as:
+              <doc:tt>never</doc:tt>, <doc:tt>defaults</doc:tt> or <doc:tt>always</doc:tt>.
+              are also available.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+    </method>
+
+    <method name="InstallPrinterDrivers">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+            Installs printer drivers from a configured package source.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+      <arg type="u" name="xid" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              The X window handle ID, used for focus stealing prevention and setting modality.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="as" name="resources" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An array of printer model descriptors in IEEE 1284
+              Device ID format,
+              e.g. <doc:tt>MFG:Hewlett-Packard;MDL:HP LaserJet
+              6MP;</doc:tt>.
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg type="s" name="interaction" direction="in">
+        <doc:doc>
+          <doc:summary>
+            <doc:para>
+              An optional interaction mode, e.g.
+              <doc:tt>show-confirm-search,show-confirm-deps,show-confirm-install,show-progress,show-finished,show-warning</doc:tt>
+            </doc:para>
+          </doc:summary>
+        </doc:doc>
+      </arg>
+    </method>
+  </interface>
+</node>
+
Index: gnome-packagekit-3.20.0/src/gpk-update-viewer.c
===================================================================
--- gnome-packagekit-3.20.0.orig/src/gpk-update-viewer.c
+++ gnome-packagekit-3.20.0/src/gpk-update-viewer.c
@@ -21,6 +21,7 @@
 
 #include "config.h"
 
+#include <dbus/dbus-glib.h>
 #include <gdk/gdkkeysyms.h>
 #include <glib/gi18n.h>
 #include <glib/gi18n.h>
@@ -42,6 +43,7 @@
 #include "gpk-dialog.h"
 #include "gpk-enum.h"
 #include "gpk-error.h"
+#include "gpk-session.h"
 #include "gpk-task.h"
 #include "gpk-debug.h"
 
@@ -206,28 +208,33 @@ gpk_update_viewer_check_restart (void)
 	gboolean show_button = TRUE;
 	GError *error = NULL;
 
+	g_print ("gpk update viewer check restart\n");
 	/* get the text */
 	title = gpk_restart_enum_to_localised_text (restart_update);
 	if (restart_update == PK_RESTART_ENUM_SYSTEM) {
 		/* TRANSLATORS: the message text for the restart */
 		message = _("Some of the updates that were installed require the computer to be restarted before the changes will be applied.");
+		g_print ("%s\n", message);
 		/* TRANSLATORS: the button text for the restart */
 		button = _("Restart Computer");
 
 	} else if (restart_update == PK_RESTART_ENUM_SECURITY_SYSTEM) {
 		/* TRANSLATORS: the message text for the restart */
 		message = _("Some of the updates that were installed require the computer to be restarted to remain secure.");
+		g_print ("%s\n", message);
 		/* TRANSLATORS: the button text for the restart */
 		button = _("Restart Computer");
 
 	} else if (restart_update == PK_RESTART_ENUM_SESSION) {
 		/* TRANSLATORS: the message text for the log out */
 		message = _("Some of the updates that were installed require you to log out and back in before the changes will be applied.");
+		g_print ("%s\n", message);
 		/* TRANSLATORS: the button text for the log out */
 		button = _("Log Out");
 	} else if (restart_update == PK_RESTART_ENUM_APPLICATION) {
         	/* TRANSLATORS: the message text for the application restart */
               	message = _("Some of the updates that were installed require you to restart this application before the changes will be applied.");
+		g_print ("%s\n", message);
               	/* TRANSLATORS: the button text for the application restart */
               	button = _("Restart Application");
 
@@ -239,6 +246,7 @@ gpk_update_viewer_check_restart (void)
 	} else if (restart_update == PK_RESTART_ENUM_SECURITY_SESSION) {
 		/* TRANSLATORS: the message text for the log out */
 		message = _("Some of the updates that were installed require you to log out and back in to remain secure.");
+		g_print ("%s\n", message);
 		/* TRANSLATORS: the button text for the log out */
 		button = _("Log Out");
 
@@ -288,6 +296,13 @@ gpk_update_viewer_check_restart (void)
 			g_error_free (error);
 		}
 #endif
+	} else if (restart_update == PK_RESTART_ENUM_SESSION) {
+		GpkSession *session;
+		session = gpk_session_new ();
+		/* use gnome-session to log out */
+		g_print ("gpk session logout\n");
+		gpk_session_logout (session);
+		g_object_unref (session);
 	} else if (restart_update == PK_RESTART_ENUM_APPLICATION) {
 		char cmd[256] = {0};
 		/* need to wait for PackageKit to finish too */
@@ -425,9 +440,11 @@ gpk_update_viewer_update_packages_cb (Pk
 	GtkTreeView *treeview;
 	GtkTreeModel *model;
 
+	g_print ("gpk update viewer update packages cb\n");
 	/* get the results */
 	results = pk_task_generic_finish (task, res, &error);
 	if (results == NULL) {
+		g_print ("results == NULL\n");
 		/* not a PK error */
 		if (error->domain != PK_CLIENT_ERROR) {
 			/* TRANSLATORS: the PackageKit request did not complete, and it did not send an error */
@@ -459,6 +476,7 @@ gpk_update_viewer_update_packages_cb (Pk
 	/* check error code */
 	error_code = pk_results_get_error_code (results);
 	if (error_code != NULL) {
+		g_print ("failed to update packages\n");
 		g_warning ("failed to update packages: %s, %s",
 			   pk_error_enum_to_string (pk_error_get_code (error_code)),
 			   pk_error_get_details (error_code));
@@ -481,6 +499,7 @@ gpk_update_viewer_update_packages_cb (Pk
 
 	/* get the worst restart case */
 	restart = pk_results_get_require_restart_worst (results);
+	g_print ("require restart worst: %d\n", restart);
 	if (restart > restart_update)
 		restart_update = restart;
 
@@ -489,6 +508,8 @@ gpk_update_viewer_update_packages_cb (Pk
 	gpk_update_viewer_check_blocked_packages (array);
 
 	/* check restart */
+	g_print ("restart: %d\n", restart);
+	g_print ("check restart: %d\n", restart_update);
 	if (restart_update == PK_RESTART_ENUM_SYSTEM ||
 	    restart_update == PK_RESTART_ENUM_SESSION ||
 	    restart_update == PK_RESTART_ENUM_APPLICATION ||
@@ -498,6 +519,7 @@ gpk_update_viewer_update_packages_cb (Pk
 		gpk_update_viewer_quit ();
 		goto out;
 	} else {
+		g_print ("no need to restart update\n");
 		goto out;
 	}
 
@@ -1221,6 +1243,7 @@ gpk_update_viewer_button_install_cb (Gtk
 	GtkTreeView *treeview;
 	gchar **package_ids = NULL;
 
+	g_print ("button install cb\n");
 	/* hide the upgrade viewbox from now on */
 	widget = GTK_WIDGET(gtk_builder_get_object (builder, "viewport_upgrade"));
 	gtk_widget_hide (widget);
@@ -1438,6 +1461,7 @@ gpk_update_viewer_reconsider_info (void)
 	gchar *text_size;
 	PkNetworkEnum state;
 
+	g_print ("reconsider info\n");
 	/* update global state */
 	gpk_update_viewer_update_global_state ();
 
@@ -1561,6 +1585,7 @@ gpk_update_viewer_treeview_update_toggle
 	GtkTreeView *treeview;
 	GtkTreeModel *model;
 
+	g_print ("treeview update toggled\n");
 	treeview = GTK_TREE_VIEW(gtk_builder_get_object (builder, "treeview_updates"));
 	model = gtk_tree_view_get_model (treeview);
 
@@ -3663,6 +3688,7 @@ main (int argc, char *argv[])
 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 	textdomain (GETTEXT_PACKAGE);
 
+	dbus_g_thread_init ();
 	gtk_init (&argc, &argv);
 
 	context = g_option_context_new (NULL);
