static gint
pacman_package_compare_pkgver (PacmanPackage *a, PacmanPackage *b)
{
	gint result;
	const gchar *version_a, *version_b, *last_a, *last_b;
	gchar *pkgver_a, *pkgver_b;

	g_return_val_if_fail (a != NULL, (b == NULL) ? 0 : -1);
	g_return_val_if_fail (b != NULL, 1);

	version_a = pacman_package_get_version (a);
	version_b = pacman_package_get_version (b);

	last_a = strrchr (version_a, '-');
	last_b = strrchr (version_b, '-');

	if (last_a != NULL) {
		pkgver_a = g_strndup (version_a, last_a - version_a);
	} else {
		pkgver_a = g_strdup (version_a);
	}

	if (last_b != NULL) {
		pkgver_b = g_strndup (version_b, last_b - version_b);
	} else {
		pkgver_b = g_strdup (version_b);
	}

	result = pacman_package_compare_version (pkgver_a, pkgver_b);

	g_free (pkgver_a);
	g_free (pkgver_b);

	return result;
}
static void pacman_transaction_question_cb (pmtransconv_t question, gpointer data1, gpointer data2, gpointer data3, gint *response) {
	PacmanTransaction *transaction;
	
	g_return_if_fail (pacman_manager != NULL);
	transaction = pacman_manager_get_transaction (pacman_manager);
	g_return_if_fail (transaction != NULL);
	
	switch (question) {
		case PM_TRANS_CONV_INSTALL_IGNOREPKG: {
			/* called in sync_addtarget only, data1 = ignored package */
			const gchar *name = pacman_package_get_name ((PacmanPackage *) data1), *version = pacman_package_get_version ((PacmanPackage *) data1);
			
			pacman_transaction_set_marked_packages (transaction, pacman_list_add (NULL, data1));
			*response = (gint) pacman_transaction_ask (transaction, PACMAN_TRANSACTION_QUESTION_INSTALL_IGNORE_PACKAGE, _("%s is marked as ignored. Do you want to install version %s anyway?"), name, version);
			pacman_transaction_set_marked_packages (transaction, NULL);
			break;
		} case PM_TRANS_CONV_REPLACE_PKG: {
			/* called in sync_sysupgrade, data1 = package to replace, data2 = replacement package, data3 = database name */
			const gchar *replace = pacman_package_get_name ((PacmanPackage *) data1), *replacement = pacman_package_get_name ((PacmanPackage *) data2);
			PacmanConflict *conflict = pacman_conflict_new (replacement, replace, replace);
			
			pacman_transaction_set_conflicts (transaction, pacman_list_add (NULL, conflict));
			*response = (gint) pacman_transaction_ask (transaction, PACMAN_TRANSACTION_QUESTION_REPLACE_PACKAGE, _("Do you want to replace %s with %s from [%s]?"), replace, replacement, (const gchar *) data3);
			pacman_transaction_set_conflicts (transaction, NULL);
			break;
		} case PM_TRANS_CONV_CONFLICT_PKG: {
			/* called in sync_prepare, data1 = name of sync package, data2 = name of local package, data3 = conflict reason */
			const gchar *replacement = (const gchar *) data1, *replace = (const gchar *) data2, *reason = (const gchar *) data3;
			PacmanConflict *conflict = pacman_conflict_new (replacement, replace, reason);
			
			pacman_transaction_set_conflicts (transaction, pacman_list_add (NULL, conflict));
			if (g_strcmp0 (reason, replacement) == 0 || g_strcmp0 (reason, replace) == 0) {
				*response = (gint) pacman_transaction_ask (transaction, PACMAN_TRANSACTION_QUESTION_REMOVE_CONFLICTING_PACKAGE, _("%s conflicts with %s. Do you want to remove %s?"), replacement, replace, replace);
			} else {
				*response = (gint) pacman_transaction_ask (transaction, PACMAN_TRANSACTION_QUESTION_REMOVE_CONFLICTING_PACKAGE, _("%s conflicts with %s (%s). Do you want to remove %s?"), replacement, replace, reason, replace);
			}
			pacman_transaction_set_conflicts (transaction, NULL);
			break;
		} case PM_TRANS_CONV_REMOVE_PKGS: {
			/* called in sync_prepare, data1 = list of unsyncable packages */
			gchar *packages = pacman_package_make_list ((PacmanList *) data1);
			
			pacman_transaction_set_marked_packages (transaction, pacman_list_copy ((PacmanList *) data1));
			*response = (gint) pacman_transaction_ask (transaction, PACMAN_TRANSACTION_QUESTION_SKIP_UNRESOLVABLE_PACKAGES, _("The following packages have unresolved dependencies: %s. Do you want to continue without them?"), packages);
			pacman_transaction_set_marked_packages (transaction, NULL);
			
			g_free (packages);
			break;
		} case PM_TRANS_CONV_LOCAL_NEWER: {
			/* isn't called anywhere..., data1 = package that is older than local version */
			PacmanDatabase *database;
			PacmanPackage *package;
			const gchar *version, *name = (const gchar *) data1;
			
			database = pacman_manager_get_local_database (pacman_manager);
			g_return_if_fail (database != NULL);
			
			package = pacman_database_find_package (database, name);
			version = pacman_package_get_version (package);
			
			pacman_transaction_set_marked_packages (transaction, pacman_list_add (NULL, package));
			*response = (gint) pacman_transaction_ask (transaction, PACMAN_TRANSACTION_QUESTION_INSTALL_OLDER_PACKAGE, _("%s-%s is older than the installed version. Do you want to install it anyway?"), name, version);
			pacman_transaction_set_marked_packages (transaction, NULL);
			break;
		} case PM_TRANS_CONV_CORRUPTED_PKG: {
			/* called in sync_commit, data1 = location of corrupted package */
			
			pacman_transaction_set_invalid_files (transaction, pacman_list_add (NULL, data1));
			*response = (gint) pacman_transaction_ask (transaction, PACMAN_TRANSACTION_QUESTION_DELETE_CORRUPTED_PACKAGE, _("The package at %s is corrupted. Do you want to delete it?"), (const gchar *) data1);
			pacman_transaction_set_invalid_files (transaction, NULL);
			break;
		} default: {
			g_debug ("Unrecognised question: %d\n", question);
			break;
		}
	}
}
static void pacman_transaction_event_cb (pmtransevt_t event, gpointer data1, gpointer data2) {
	PacmanTransaction *transaction;
	
	g_return_if_fail (pacman_manager != NULL);
	transaction = pacman_manager_get_transaction (pacman_manager);
	g_return_if_fail (transaction != NULL);
	
	switch (event) {
		case PM_TRANS_EVT_CHECKDEPS_START: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DEPENDENCY_CHECK_START, _("Checking dependencies"));
			break;
		} case PM_TRANS_EVT_CHECKDEPS_DONE: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DEPENDENCY_CHECK_END, _("Finished checking dependencies"));
			break;
		} case PM_TRANS_EVT_FILECONFLICTS_START: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_FILE_CONFLICT_CHECK_START, _("Checking for file conflicts"));
			break;
		} case PM_TRANS_EVT_FILECONFLICTS_DONE: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_FILE_CONFLICT_CHECK_END, _("Finished checking for file conflicts"));
			break;
		} case PM_TRANS_EVT_RESOLVEDEPS_START: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DEPENDENCY_RESOLVE_START, _("Resolving dependencies"));
			break;
		} case PM_TRANS_EVT_RESOLVEDEPS_DONE: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DEPENDENCY_RESOLVE_END, _("Finished resolving dependencies"));
			break;
		} case PM_TRANS_EVT_INTERCONFLICTS_START: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_CONFLICT_CHECK_START, _("Checking for conflicts"));
			break;
		} case PM_TRANS_EVT_INTERCONFLICTS_DONE: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_CONFLICT_CHECK_END, _("Finished checking for conflicts"));
			break;
		} case PM_TRANS_EVT_ADD_START: {
			pacman_transaction_set_marked_packages (transaction, pacman_list_add (NULL, data1));
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_INSTALL_START, _("Installing %s"), pacman_package_get_name ((PacmanPackage *) data1));
			pacman_transaction_set_marked_packages (transaction, NULL);
			break;
		} case PM_TRANS_EVT_ADD_DONE: {
			PacmanPackage *package = (PacmanPackage *) data1;
			const PacmanList *optional_dependencies, *i;
			alpm_logaction ("installed %s (%s)\n", pacman_package_get_name (package), pacman_package_get_version (package));
			
			pacman_transaction_set_marked_packages (transaction, pacman_list_add (NULL, data1));
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_INSTALL_END, _("Finished installing %s"), pacman_package_get_name (package));
			pacman_transaction_set_marked_packages (transaction, NULL);
			
			optional_dependencies = pacman_package_get_optional_dependencies (package);
			if (optional_dependencies != NULL) {
				GString *depends = g_string_new ("");
				gchar *message;
				
				g_string_append_printf (depends, _("Optional dependencies for %s:\n"), pacman_package_get_name (package));
				for (i = optional_dependencies; i != NULL; i = pacman_list_next (i)) {
					const gchar *line = (const gchar *) pacman_list_get (i);
					g_string_append_printf (depends, "%s\n", line);
				}
				
				message = g_string_free (depends, FALSE);
				g_message ("%s", message);
				g_free (message);
			}
			break;
		} case PM_TRANS_EVT_REMOVE_START: {
			pacman_transaction_set_marked_packages (transaction, pacman_list_add (NULL, data1));
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_REMOVE_START, _("Removing %s"), pacman_package_get_name ((PacmanPackage *) data1));
			pacman_transaction_set_marked_packages (transaction, NULL);
			break;
		} case PM_TRANS_EVT_REMOVE_DONE: {
			PacmanPackage *package = (PacmanPackage *) data1;
			alpm_logaction ("removed %s (%s)\n", pacman_package_get_name (package), pacman_package_get_version (package));
			
			pacman_transaction_set_marked_packages (transaction, pacman_list_add (NULL, data1));
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_REMOVE_END, _("Finished removing %s"), pacman_package_get_name (package));
			pacman_transaction_set_marked_packages (transaction, NULL);
			break;
		} case PM_TRANS_EVT_UPGRADE_START: {
			PacmanList *new_then_old = NULL;
			new_then_old = pacman_list_add (new_then_old, data1);
			new_then_old = pacman_list_add (new_then_old, data2);
			
			pacman_transaction_set_marked_packages (transaction, new_then_old);
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_UPGRADE_START, _("Upgrading %s"), pacman_package_get_name ((PacmanPackage *) data1));
			pacman_transaction_set_marked_packages (transaction, NULL);
			break;
		} case PM_TRANS_EVT_UPGRADE_DONE: {
			PacmanPackage *package = (PacmanPackage *) data1, *old_package = (PacmanPackage *) data2;
			PacmanList *optional_dependencies, *i, *new_then_old = NULL;
			alpm_logaction ("upgraded %s (%s -> %s)\n", pacman_package_get_name (package), pacman_package_get_version (old_package), pacman_package_get_version (package));
			
			new_then_old = pacman_list_add (new_then_old, data1);
			new_then_old = pacman_list_add (new_then_old, data2);
			
			pacman_transaction_set_marked_packages (transaction, new_then_old);
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_UPGRADE_END, _("Finished upgrading %s"), pacman_package_get_name (package));
			pacman_transaction_set_marked_packages (transaction, NULL);
			
			optional_dependencies = pacman_list_diff (pacman_package_get_optional_dependencies (package), pacman_package_get_optional_dependencies (old_package), (GCompareFunc) g_strcmp0);
			if (optional_dependencies != NULL) {
				GString *depends = g_string_new ("");
				gchar *message;
				
				g_string_append_printf (depends, _("New optional dependencies for %s\n"), pacman_package_get_name (package));
				for (i = optional_dependencies; i != NULL; i = pacman_list_next (i)) {
					const gchar *line = (const gchar *) pacman_list_get (i);
					g_string_append_printf (depends, "%s\n", line);
				}
				
				message = g_string_free (depends, FALSE);
				g_message ("%s", message);
				g_free (message);
				pacman_list_free (optional_dependencies);
			}
			break;
		} case PM_TRANS_EVT_INTEGRITY_START: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_PACKAGE_INTEGRITY_CHECK_START, _("Checking package integrity"));
			break;
		} case PM_TRANS_EVT_INTEGRITY_DONE: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_PACKAGE_INTEGRITY_CHECK_END, _("Finished checking package integrity"));
			break;
		} case PM_TRANS_EVT_DELTA_INTEGRITY_START: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DELTA_INTEGRITY_CHECK_START, _("Checking delta integrity"));
			break;
		} case PM_TRANS_EVT_DELTA_INTEGRITY_DONE: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DELTA_INTEGRITY_CHECK_END, _("Finished checking delta integrity"));
			break;
		} case PM_TRANS_EVT_DELTA_PATCHES_START: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DELTA_PATCHING_START, _("Applying delta patches"));
			break;
		} case PM_TRANS_EVT_DELTA_PATCHES_DONE: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DELTA_PATCHING_END, _("Finished applying delta patches"));
			break;
		} case PM_TRANS_EVT_DELTA_PATCH_START: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DELTA_PATCH_START, _("Creating %s from the delta patch %s"), (const gchar *) data1, (const gchar *) data2);
			break;
		} case PM_TRANS_EVT_DELTA_PATCH_DONE: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DELTA_PATCH_END, _("Finished applying delta patch"));
			break;
		} case PM_TRANS_EVT_DELTA_PATCH_FAILED: {
			/* already reported as an error */
			break;
		} case PM_TRANS_EVT_SCRIPTLET_INFO: {
			g_message ("%s\n", (const gchar *) data1);
			break;
		} case PM_TRANS_EVT_RETRIEVE_START: {
			pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DOWNLOAD_FROM, _("Downloading packages from [%s]"), (const gchar *) data1);
			break;
		} default: {
			g_debug ("Unrecognised event: %d\n", event);
			break;
		}
	}
}