diff --git a/lib/packagekit-glib2/pk-common.c b/lib/packagekit-glib2/pk-common.c index 12f18cd..59ffc19 100644 --- a/lib/packagekit-glib2/pk-common.c +++ b/lib/packagekit-glib2/pk-common.c @@ -131,6 +131,50 @@ out: } /** + * pk_iso8601_to_datetime: (skip) + * @iso_date: The ISO8601 date to convert + * + * Return value: If valid then a new %GDateTime, else NULL + * + * Since: 0.8.11 + **/ +GDateTime * +pk_iso8601_to_datetime (const gchar *iso_date) +{ + gboolean ret = FALSE; + guint retval; + guint d = 0; + guint m = 0; + guint y = 0; + GTimeVal time_val; + GDateTime *date = NULL; + + if (iso_date == NULL || iso_date[0] == '\0') + goto out; + + /* try to parse complete ISO8601 date */ + if (g_strstr_len (iso_date, -1, " ") != NULL) + ret = g_time_val_from_iso8601 (iso_date, &time_val); + if (ret && time_val.tv_sec != 0) { + g_debug ("Parsed %s %i", iso_date, ret); + date = g_date_time_new_from_timeval_utc (&time_val); + goto out; + } + + /* g_time_val_from_iso8601() blows goats and won't + * accept a valid ISO8601 formatted date without a + * time value - try and parse this case */ + retval = sscanf (iso_date, "%u-%u-%u", &y, &m, &d); + if (retval != 3) + goto out; + + /* create valid object */ + date = g_date_time_new_utc (y, m, d, 0, 0, 0); +out: + return date; +} + +/** * pk_ptr_array_to_strv: * @array: the GPtrArray of strings * diff --git a/lib/packagekit-glib2/pk-common.h b/lib/packagekit-glib2/pk-common.h index f3d4315..379fd73 100644 --- a/lib/packagekit-glib2/pk-common.h +++ b/lib/packagekit-glib2/pk-common.h @@ -88,6 +88,7 @@ gchar *pk_iso8601_present (void) G_GNUC_WARN_UNUSED_RESULT; gchar *pk_iso8601_from_date (const GDate *date); GDate *pk_iso8601_to_date (const gchar *iso_date); +GDateTime *pk_iso8601_to_datetime (const gchar *iso_date); gchar *pk_get_distro_id (void); G_END_DECLS diff --git a/lib/packagekit-glib2/pk-control.c b/lib/packagekit-glib2/pk-control.c index 9477e65..e319bea 100644 --- a/lib/packagekit-glib2/pk-control.c +++ b/lib/packagekit-glib2/pk-control.c @@ -2447,6 +2447,24 @@ pk_control_name_appeared_cb (GDBusConnection *connection, } /** + * pk_control_proxy_destroy: + **/ +static void +pk_control_proxy_destroy (PkControl *control) +{ + if (control->priv->proxy == NULL) + return; + g_signal_handlers_disconnect_by_func (control->priv->proxy, + G_CALLBACK (pk_control_properties_changed_cb), + control); + g_signal_handlers_disconnect_by_func (control->priv->proxy, + G_CALLBACK (pk_control_signal_cb), + control); + g_object_unref (control->priv->proxy); + control->priv->proxy = NULL; +} + +/** * pk_control_name_vanished_cb: **/ static void @@ -2458,6 +2476,11 @@ pk_control_name_vanished_cb (GDBusConnection *connection, control->priv->connected = FALSE; g_debug ("notify::connected"); g_object_notify (G_OBJECT(control), "connected"); + + /* destroy the proxy, as even though it's "well known" we get a + * GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown if we try to + * use this after the server has restarted */ + pk_control_proxy_destroy (control); } /** @@ -2497,6 +2520,9 @@ pk_control_finalize (GObject *object) g_cancellable_cancel (priv->cancellable); g_bus_unwatch_name (priv->watch_id); + /* disconnect proxy and destroy it */ + pk_control_proxy_destroy (control); + /* remove pending sources */ if (priv->transaction_list_changed_id != 0) g_source_remove (priv->transaction_list_changed_id); @@ -2506,15 +2532,6 @@ pk_control_finalize (GObject *object) g_source_remove (priv->updates_changed_id); if (priv->repo_list_changed_id != 0) g_source_remove (priv->repo_list_changed_id); - if (priv->proxy != NULL) { - g_signal_handlers_disconnect_by_func (priv->proxy, - G_CALLBACK (pk_control_properties_changed_cb), - control); - g_signal_handlers_disconnect_by_func (priv->proxy, - G_CALLBACK (pk_control_signal_cb), - control); - g_object_unref (priv->proxy); - } g_free (priv->backend_name); g_free (priv->backend_description); diff --git a/lib/packagekit-glib2/pk-package.c b/lib/packagekit-glib2/pk-package.c index 0c9e86d..4f7deb1 100644 --- a/lib/packagekit-glib2/pk-package.c +++ b/lib/packagekit-glib2/pk-package.c @@ -196,6 +196,46 @@ out: } /** + * pk_package_parse: + * @package: a valid #PkPackage instance + * @data: the data describing the package + * @error: a %GError to put the error code and message in, or %NULL + * + * Parses the data to populate the #PkPackage. + * + * Return value: %TRUE if the data was parsed correcty + * + * Since: 0.8.11 + **/ +gboolean +pk_package_parse (PkPackage *package, const gchar *data, GError **error) +{ + gboolean ret = TRUE; + gchar **sections; + + g_return_val_if_fail (PK_IS_PACKAGE (package), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* split */ + sections = g_strsplit (data, "\t", -1); + if (g_strv_length (sections) != 3) { + ret = FALSE; + g_set_error_literal (error, 1, 0, "data invalid"); + } + + /* parse object */ + package->priv->info = pk_info_enum_from_string (sections[0]); + ret = pk_package_set_id (package, sections[1], error); + if (!ret) + goto out; + g_free (package->priv->summary); + package->priv->summary = g_strdup (sections[2]); +out: + g_strfreev (sections); + return ret; +} + +/** * pk_package_get_info: * @package: a valid #PkPackage instance * diff --git a/lib/packagekit-glib2/pk-package.h b/lib/packagekit-glib2/pk-package.h index 60d0a10..8ca803b 100644 --- a/lib/packagekit-glib2/pk-package.h +++ b/lib/packagekit-glib2/pk-package.h @@ -72,6 +72,9 @@ void pk_package_test (gpointer user_data); gboolean pk_package_set_id (PkPackage *package, const gchar *package_id, GError **error); +gboolean pk_package_parse (PkPackage *package, + const gchar *data, + GError **error); void pk_package_print (PkPackage *package); gboolean pk_package_equal (PkPackage *package1, PkPackage *package2); diff --git a/lib/packagekit-glib2/pk-transaction-past.c b/lib/packagekit-glib2/pk-transaction-past.c index 13c2cb4..fa91b1d 100644 --- a/lib/packagekit-glib2/pk-transaction-past.c +++ b/lib/packagekit-glib2/pk-transaction-past.c @@ -33,6 +33,7 @@ #include #include +#include #include static void pk_transaction_past_finalize (GObject *object); @@ -72,6 +73,187 @@ enum { G_DEFINE_TYPE (PkTransactionPast, pk_transaction_past, PK_TYPE_SOURCE) /** + * pk_transaction_past_get_id: + * @past: a valid #PkTransactionPast instance + * + * Gets the past transaction ID value; + * + * Return value: The transaction data + * + * Since: 0.8.11 + **/ +const gchar * +pk_transaction_past_get_id (PkTransactionPast *past) +{ + g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), NULL); + return past->priv->tid; +} + +/** + * pk_transaction_past_get_timespec: + * @past: a valid #PkTransactionPast instance + * + * Gets the past transaction timespec value; + * + * Return value: The transaction data + * + * Since: 0.8.11 + **/ +const gchar * +pk_transaction_past_get_timespec (PkTransactionPast *past) +{ + g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), NULL); + return past->priv->timespec; +} + +/** + * pk_transaction_past_get_datetime: + * @past: a valid #PkTransactionPast instance + * + * Gets the past transaction date & time value; + * + * Return value: The transaction data, or %NULL if it's not available + * + * Since: 0.8.11 + **/ +GDateTime * +pk_transaction_past_get_datetime (PkTransactionPast *past) +{ + g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), NULL); + if (past->priv->timespec == NULL) + return NULL; + return pk_iso8601_to_datetime (past->priv->timespec); +} + +/** + * pk_transaction_past_get_timestamp: + * @past: a valid #PkTransactionPast instance + * + * Gets the past transaction timestamp + * + * Return value: The transaction data, or 0 if it's not available + * + * Since: 0.8.11 + **/ +gint64 +pk_transaction_past_get_timestamp (PkTransactionPast *past) +{ + GDateTime *datetime; + gint64 timestamp; + + g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), 0); + + datetime = pk_transaction_past_get_datetime (past); + if (datetime == NULL) + return 0; + timestamp = g_date_time_to_unix (datetime); + g_date_time_unref (datetime); + return timestamp; +} + +/** + * pk_transaction_past_get_succeeded: + * @past: a valid #PkTransactionPast instance + * + * Gets the past transaction succeeded value; + * + * Return value: The transaction data + * + * Since: 0.8.11 + **/ +gboolean +pk_transaction_past_get_succeeded (PkTransactionPast *past) +{ + g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), FALSE); + return past->priv->succeeded; +} + +/** + * pk_transaction_past_get_role: + * @past: a valid #PkTransactionPast instance + * + * Gets the past transaction role; + * + * Return value: The transaction data + * + * Since: 0.8.11 + **/ +PkRoleEnum +pk_transaction_past_get_role (PkTransactionPast *past) +{ + g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), PK_ROLE_ENUM_UNKNOWN); + return past->priv->role; +} + +/** + * pk_transaction_past_get_duration: + * @past: a valid #PkTransactionPast instance + * + * Gets the past transaction duration; + * + * Return value: The transaction data + * + * Since: 0.8.11 + **/ +guint +pk_transaction_past_get_duration (PkTransactionPast *past) +{ + g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), 0); + return past->priv->duration; +} + +/** + * pk_transaction_past_get_data: + * @past: a valid #PkTransactionPast instance + * + * Gets the past transaction data; + * + * Return value: The transaction data + * + * Since: 0.8.11 + **/ +const gchar * +pk_transaction_past_get_data (PkTransactionPast *past) +{ + g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), NULL); + return past->priv->data; +} + +/** + * pk_transaction_past_get_uid: + * @past: a valid #PkTransactionPast instance + * + * Gets the past transaction uid; + * + * Return value: The transaction data + * + * Since: 0.8.11 + **/ +guint +pk_transaction_past_get_uid (PkTransactionPast *past) +{ + g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), 0); + return past->priv->uid; +} + +/** + * pk_transaction_past_get_cmdline: + * @past: a valid #PkTransactionPast instance + * + * Gets the past transaction cmdline value; + * + * Return value: The transaction data + * + * Since: 0.8.11 + **/ +const gchar * +pk_transaction_past_get_cmdline (PkTransactionPast *past) +{ + g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), NULL); + return past->priv->cmdline; +} + +/** * pk_transaction_past_get_property: **/ static void diff --git a/lib/packagekit-glib2/pk-transaction-past.h b/lib/packagekit-glib2/pk-transaction-past.h index fcec8a5..5aa174b 100644 --- a/lib/packagekit-glib2/pk-transaction-past.h +++ b/lib/packagekit-glib2/pk-transaction-past.h @@ -28,6 +28,7 @@ #include +#include #include G_BEGIN_DECLS @@ -62,6 +63,16 @@ struct _PkTransactionPastClass GType pk_transaction_past_get_type (void); PkTransactionPast *pk_transaction_past_new (void); +const gchar *pk_transaction_past_get_cmdline (PkTransactionPast *past); +const gchar *pk_transaction_past_get_data (PkTransactionPast *past); +const gchar *pk_transaction_past_get_id (PkTransactionPast *past); +const gchar *pk_transaction_past_get_timespec (PkTransactionPast *past); +GDateTime *pk_transaction_past_get_datetime (PkTransactionPast *past); +gint64 pk_transaction_past_get_timestamp (PkTransactionPast *past); +gboolean pk_transaction_past_get_succeeded (PkTransactionPast *past); +guint pk_transaction_past_get_duration (PkTransactionPast *past); +guint pk_transaction_past_get_uid (PkTransactionPast *past); +PkRoleEnum pk_transaction_past_get_role (PkTransactionPast *past); G_END_DECLS diff --git a/src/org.freedesktop.PackageKit.xml b/src/org.freedesktop.PackageKit.xml index 297cbeb..b8038ca 100644 --- a/src/org.freedesktop.PackageKit.xml +++ b/src/org.freedesktop.PackageKit.xml @@ -316,6 +316,54 @@ + + + + + Gets the history for a given package name. + This uses the internal PackageKit history database and will not + return transactions done outside of PackageKit using a distribution + native tool. + + + + + + + + The package names to return history for, e.g. [ colord ]. + + + + + + + + + The maximum number of past transactions to return, or 0 for no limit. + + + + + + + + + The list of actions performed on this package. The array may contain + the following keys of types: + info[uint], + user-id[uint], + version[string], + source[string], + timestamp[uint64]. + Other keys and values may be added in the future. + + + + + + + diff --git a/src/pk-engine.c b/src/pk-engine.c index 338cbaa..f7265bd 100644 --- a/src/pk-engine.c +++ b/src/pk-engine.c @@ -1255,6 +1255,165 @@ out: } /** + * pk_engine_package_name_in_strv: + **/ +static gboolean +pk_engine_package_name_in_strv (gchar **strv, PkPackage *pkg) +{ + guint i; + for (i = 0; strv[i] != NULL; i++) { + if (g_strcmp0 (strv[i], pk_package_get_name (pkg)) == 0) + return TRUE; + } + return FALSE; +} + +/** + * pk_engine_get_package_history_pkg: + * + * Create a 'a{sv}' GVariant instance from all the PkTransactionPast data + **/ +static GVariant * +pk_engine_get_package_history_pkg (PkTransactionPast *item, PkPackage *pkg) +{ + GVariantBuilder builder; + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + g_variant_builder_add (&builder, "{sv}", "info", + g_variant_new_uint32 (pk_package_get_info (pkg))); + g_variant_builder_add (&builder, "{sv}", "source", + g_variant_new_string (pk_package_get_data (pkg))); + g_variant_builder_add (&builder, "{sv}", "version", + g_variant_new_string (pk_package_get_version (pkg))); + g_variant_builder_add (&builder, "{sv}", "timestamp", + g_variant_new_uint64 (pk_transaction_past_get_timestamp (item))); + g_variant_builder_add (&builder, "{sv}", "user-id", + g_variant_new_uint32 (pk_transaction_past_get_uid (item))); + return g_variant_builder_end (&builder); +} +/** + * pk_engine_get_package_history: + **/ +static GVariant * +pk_engine_get_package_history (PkEngine *engine, + gchar **package_names, + guint max_size, + GError **error) +{ + const gchar *data; + const gchar *pkgname; + gboolean ret; + gchar *key; + gchar **package_lines; + GHashTable *deduplicate_hash; + GHashTable *pkgname_hash; + gint64 timestamp; + GList *keys = NULL; + GList *l; + GList *list; + GPtrArray *array = NULL; + guint i; + GVariantBuilder builder; + GVariant *value = NULL; + PkPackage *package_tmp; + PkTransactionPast *item; + + list = pk_transaction_db_get_list (engine->priv->transaction_db, max_size); + + /* simplify the loop */ + if (max_size == 0) + max_size = G_MAXUINT; + + pkgname_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref); + deduplicate_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + package_tmp = pk_package_new (); + for (l = list; l != NULL; l = l->next) { + item = PK_TRANSACTION_PAST (l->data); + + /* ignore anything that failed */ + if (!pk_transaction_past_get_succeeded (item)) + continue; + + /* split up data */ + data = pk_transaction_past_get_data (item); + if (data == NULL) + continue; + package_lines = g_strsplit (data, "\n", -1); + for (i = 0; package_lines[i] != NULL; i++) { + ret = pk_package_parse (package_tmp, package_lines[i], error); + g_assert (ret); + + /* not the package we care about */ + if (!pk_engine_package_name_in_strv (package_names, package_tmp)) + continue; + + /* not a state we care about */ + if (pk_package_get_info (package_tmp) == PK_INFO_ENUM_CLEANUP) + continue; + + /* transactions without a timestamp are not interesting */ + timestamp = pk_transaction_past_get_timestamp (item); + if (timestamp == 0) + continue; + + /* de-duplicate the entry, in the case of multiarch */ + key = g_strdup_printf ("%s-%" G_GINT64_FORMAT, + pk_package_get_name (package_tmp), + timestamp); + if (g_hash_table_lookup (deduplicate_hash, key) != NULL) { + g_free (key); + continue; + } + g_hash_table_insert (deduplicate_hash, key, package_lines[i]); + + /* get the blob for this data item */ + value = pk_engine_get_package_history_pkg (item, package_tmp); + if (value == NULL) + continue; + + /* find the array */ + pkgname = pk_package_get_name (package_tmp); + array = g_hash_table_lookup (pkgname_hash, pkgname); + if (array == NULL) { + array = g_ptr_array_new (); + g_hash_table_insert (pkgname_hash, + g_strdup (pkgname), + array); + } + g_ptr_array_add (array, value); + } + g_strfreev (package_lines); + } + + /* no history returns an empty array */ + if (g_hash_table_size (pkgname_hash) == 0) { + value = g_variant_new_array (G_VARIANT_TYPE ("{saa{sv}}"), NULL, 0); + goto out; + } + + /* we have a hash of pkgname:GPtrArray where the GPtrArray is an array + * of GVariants of type a{sv} */ + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + keys = g_hash_table_get_keys (pkgname_hash); + for (l = keys; l != NULL; l = l->next) { + pkgname = l->data; + array = g_hash_table_lookup (pkgname_hash, pkgname); + /* create aa{sv} */ + value = g_variant_new_array (NULL, + (GVariant * const *) array->pdata, + MIN (array->len, max_size)); + g_variant_builder_add (&builder, "{s@aa{sv}}", pkgname, value); + } + value = g_variant_builder_end (&builder); +out: + g_list_free (keys); + g_hash_table_unref (pkgname_hash); + g_hash_table_unref (deduplicate_hash); + g_object_unref (package_tmp); + g_list_free_full (list, (GDestroyNotify) g_object_unref); + return value; +} + +/** * pk_engine_daemon_method_call: **/ static void @@ -1269,11 +1428,13 @@ pk_engine_daemon_method_call (GDBusConnection *connection_, const gchar *sender, GError *error = NULL; guint time_since; GVariant *value = NULL; + GVariant *tuple = NULL; PkAuthorizeEnum result_enum; PkEngine *engine = PK_ENGINE (user_data); PkRoleEnum role; gchar **transaction_list; gchar **array = NULL; + gchar **package_names; guint size; gboolean is_priority = TRUE; @@ -1298,6 +1459,31 @@ pk_engine_daemon_method_call (GDBusConnection *connection_, const gchar *sender, goto out; } + if (g_strcmp0 (method_name, "GetPackageHistory") == 0) { + g_variant_get (parameters, "(^a&su)", &package_names, &size); + if (package_names == NULL || g_strv_length (package_names) == 0) { + g_dbus_method_invocation_return_error (invocation, + PK_ENGINE_ERROR, + PK_ENGINE_ERROR_NOT_SUPPORTED, + "history for package name invalid"); + goto out; + } + value = pk_engine_get_package_history (engine, package_names, size, &error); + if (value == NULL) { + g_dbus_method_invocation_return_error (invocation, + PK_ENGINE_ERROR, + PK_ENGINE_ERROR_NOT_SUPPORTED, + "history for package name %s failed: %s", + package_names[0], + error->message); + g_error_free (error); + goto out; + } + tuple = g_variant_new_tuple (&value, 1); + g_dbus_method_invocation_return_value (invocation, tuple); + goto out; + } + if (g_strcmp0 (method_name, "CreateTransaction") == 0) { g_debug ("CreateTransaction method called"); diff --git a/src/pk-transaction-db.c b/src/pk-transaction-db.c index 41c3807..2b20f3a 100644 --- a/src/pk-transaction-db.c +++ b/src/pk-transaction-db.c @@ -56,13 +56,6 @@ struct PkTransactionDbPrivate guint database_save_id; }; -enum { - SIGNAL_TRANSACTION, - SIGNAL_LAST -}; - -static guint signals [SIGNAL_LAST] = { 0 }; - G_DEFINE_TYPE (PkTransactionDb, pk_transaction_db, G_TYPE_OBJECT) typedef struct { @@ -79,21 +72,21 @@ typedef struct { * pk_transaction_sqlite_transaction_cb: **/ static gint -pk_transaction_sqlite_transaction_cb (void *data, gint argc, gchar **argv, gchar **col_name) +pk_transaction_db_add_transaction_cb (void *data, + gint argc, + gchar **argv, + gchar **col_name) { PkTransactionPast *item; - PkTransactionDb *tdb = PK_TRANSACTION_DB (data); + GList **list = (GList **) data; gint i; gchar *col; gchar *value; guint temp; gboolean ret; - g_return_val_if_fail (tdb != NULL, 0); - g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), 0); - item = pk_transaction_past_new (); - for (i=0; ipriv->db != NULL, FALSE); - rc = sqlite3_exec (tdb->priv->db, sql, pk_transaction_sqlite_transaction_cb, tdb, &error_msg); + rc = sqlite3_exec (tdb->priv->db, sql, NULL, tdb, &error_msg); if (rc != SQLITE_OK) { g_warning ("SQL error: %s\n", error_msg); sqlite3_free (error_msg); @@ -307,24 +299,36 @@ out: /** * pk_transaction_db_get_list: **/ -gboolean +GList * pk_transaction_db_get_list (PkTransactionDb *tdb, guint limit) { + gchar *error_msg = NULL; gchar *statement; + gint rc; + GList *list = NULL; - g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), FALSE); + g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), NULL); - if (limit == 0) + if (limit == 0) { statement = g_strdup ("SELECT transaction_id, timespec, succeeded, duration, role, data, uid, cmdline " "FROM transactions ORDER BY timespec DESC"); - else + } else { statement = g_strdup_printf ("SELECT transaction_id, timespec, succeeded, duration, role, data, uid, cmdline " "FROM transactions ORDER BY timespec DESC LIMIT %i", limit); - - pk_transaction_db_sql_statement (tdb, statement); + } + rc = sqlite3_exec (tdb->priv->db, + statement, + pk_transaction_db_add_transaction_cb, + &list, + &error_msg); + if (rc != SQLITE_OK) { + g_warning ("SQL error: %s\n", error_msg); + sqlite3_free (error_msg); + goto out; + } +out: g_free (statement); - - return TRUE; + return list; } /** @@ -830,11 +834,6 @@ pk_transaction_db_class_init (PkTransactionDbClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = pk_transaction_db_finalize; - signals [SIGNAL_TRANSACTION] = - g_signal_new ("transaction", - G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); g_type_class_add_private (klass, sizeof (PkTransactionDbPrivate)); } diff --git a/src/pk-transaction-db.h b/src/pk-transaction-db.h index 41e9b94..4a66c62 100644 --- a/src/pk-transaction-db.h +++ b/src/pk-transaction-db.h @@ -77,7 +77,7 @@ gboolean pk_transaction_db_set_finished (PkTransactionDb *tdb, gboolean pk_transaction_db_set_data (PkTransactionDb *tdb, const gchar *tid, const gchar *data); -gboolean pk_transaction_db_get_list (PkTransactionDb *tdb, +GList *pk_transaction_db_get_list (PkTransactionDb *tdb, guint limit); gboolean pk_transaction_db_action_time_reset (PkTransactionDb *tdb, PkRoleEnum role); diff --git a/src/pk-transaction.c b/src/pk-transaction.c index 73a6960..123ad3f 100644 --- a/src/pk-transaction.c +++ b/src/pk-transaction.c @@ -1742,67 +1742,6 @@ pk_transaction_status_changed_cb (PkBackendJob *job, } /** - * pk_transaction_transaction_cb: - **/ -static void -pk_transaction_transaction_cb (PkTransactionDb *tdb, - PkTransactionPast *item, - PkTransaction *transaction) -{ - gchar *tid; - gchar *timespec; - gchar *data; - gchar *cmdline; - guint duration; - guint uid; - gboolean succeeded; - PkRoleEnum role; - - g_return_if_fail (PK_IS_TRANSACTION (transaction)); - g_return_if_fail (transaction->priv->tid != NULL); - - /* add to results */ - pk_results_add_transaction (transaction->priv->results, item); - - /* get data */ - g_object_get (item, - "role", &role, - "tid", &tid, - "timespec", ×pec, - "succeeded", &succeeded, - "duration", &duration, - "data", &data, - "uid", &uid, - "cmdline", &cmdline, - NULL); - - /* emit */ - g_debug ("emitting transaction %s, %s, %i, %s, %i, %s, %i, %s", - tid, timespec, succeeded, - pk_role_enum_to_string (role), - duration, data, uid, cmdline); - g_dbus_connection_emit_signal (transaction->priv->connection, - NULL, - transaction->priv->tid, - PK_DBUS_INTERFACE_TRANSACTION, - "Transaction", - g_variant_new ("(osbuusus)", - tid, - timespec, - succeeded, - role, - duration, - data != NULL ? data : "", - uid, - cmdline != NULL ? cmdline : ""), - NULL); - g_free (tid); - g_free (timespec); - g_free (data); - g_free (cmdline); -} - -/** * pk_transaction_update_detail_cb: **/ static void @@ -3764,8 +3703,19 @@ pk_transaction_get_old_transactions (PkTransaction *transaction, GVariant *params, GDBusMethodInvocation *context) { + const gchar *cmdline; + const gchar *data; + const gchar *modified; + const gchar *tid; + gboolean succeeded; + GList *l; + GList *transactions = NULL; + guint duration; guint idle_id; guint number; + guint uid; + PkRoleEnum role; + PkTransactionPast *item; g_return_if_fail (PK_IS_TRANSACTION (transaction)); g_return_if_fail (transaction->priv->tid != NULL); @@ -3776,7 +3726,46 @@ pk_transaction_get_old_transactions (PkTransaction *transaction, g_debug ("GetOldTransactions method called"); pk_transaction_set_role (transaction, PK_ROLE_ENUM_GET_OLD_TRANSACTIONS); - pk_transaction_db_get_list (transaction->priv->transaction_db, number); + transactions = pk_transaction_db_get_list (transaction->priv->transaction_db, number); + for (l = transactions; l != NULL; l = l->next) { + item = PK_TRANSACTION_PAST (l->data); + + /* add to results */ + pk_results_add_transaction (transaction->priv->results, item); + + /* get data */ + role = pk_transaction_past_get_role (item); + tid = pk_transaction_past_get_id (item); + modified = pk_transaction_past_get_timespec (item); + succeeded = pk_transaction_past_get_succeeded (item); + duration = pk_transaction_past_get_duration (item); + data = pk_transaction_past_get_data (item); + uid = pk_transaction_past_get_uid (item); + cmdline = pk_transaction_past_get_cmdline (item); + + /* emit */ + g_debug ("adding transaction %s, %s, %i, %s, %i, %s, %i, %s", + tid, modified, succeeded, + pk_role_enum_to_string (role), + duration, data, uid, cmdline); + g_dbus_connection_emit_signal (transaction->priv->connection, + NULL, + transaction->priv->tid, + PK_DBUS_INTERFACE_TRANSACTION, + "Transaction", + g_variant_new ("(osbuusus)", + tid, + modified, + succeeded, + role, + duration, + data != NULL ? data : "", + uid, + cmdline != NULL ? cmdline : ""), + NULL); + } + g_list_free_full (transactions, (GDestroyNotify) g_object_unref); + idle_id = g_idle_add ((GSourceFunc) pk_transaction_finished_idle_cb, transaction); g_source_set_name_by_id (idle_id, "[PkTransaction] finished from get-old-transactions"); @@ -5805,8 +5794,6 @@ pk_transaction_init (PkTransaction *transaction) error->message); g_error_free (error); } - g_signal_connect (transaction->priv->transaction_db, "transaction", - G_CALLBACK (pk_transaction_transaction_cb), transaction); /* load introspection from file */ transaction->priv->introspection = pk_load_introspection (DATADIR "/dbus-1/interfaces/"