Blame src/connection-editor/nm-connection-list.c

Packit Service d328f3
// SPDX-License-Identifier: GPL-2.0+
Packit Service d328f3
/* NetworkManager Connection editor -- Connection editor for NetworkManager
Packit Service d328f3
 *
Packit Service d328f3
 * Rodrigo Moya <rodrigo@gnome-db.org>
Packit Service d328f3
 * Dan Williams <dcbw@redhat.com>
Packit Service d328f3
 * Lubomir Rintel <lkundrak@v3.sk>
Packit Service d328f3
 *
Packit Service d328f3
 * Copyright 2007 - 2017 Red Hat, Inc.
Packit Service d328f3
 */
Packit Service d328f3
Packit Service d328f3
#include "nm-default.h"
Packit Service d328f3
Packit Service d328f3
#include <string.h>
Packit Service d328f3
#include <sys/types.h>
Packit Service d328f3
#include <unistd.h>
Packit Service d328f3
#include <gdk/gdkx.h>
Packit Service d328f3
Packit Service d328f3
#include "ce-page.h"
Packit Service d328f3
#include "nm-connection-editor.h"
Packit Service d328f3
#include "nm-connection-list.h"
Packit Service d328f3
#include "ce-polkit.h"
Packit Service d328f3
#include "connection-helpers.h"
Packit Service d328f3
Packit Service d328f3
extern gboolean nm_ce_keep_above;
Packit Service d328f3
Packit Service d328f3
enum {
Packit Service d328f3
	NEW_EDITOR,
Packit Service d328f3
	LIST_LAST_SIGNAL
Packit Service d328f3
};
Packit Service d328f3
Packit Service d328f3
static guint list_signals[LIST_LAST_SIGNAL] = { 0 };
Packit Service d328f3
Packit Service d328f3
struct _NMConnectionListPrivate {
Packit Service d328f3
	GtkWidget *connection_add;
Packit Service d328f3
	GtkWidget *connection_del;
Packit Service d328f3
	GtkWidget *connection_edit;
Packit Service d328f3
	GtkTreeView *connection_list;
Packit Service d328f3
	GtkSearchBar *search_bar;
Packit Service d328f3
	GtkEntry *search_entry;
Packit Service d328f3
	GtkTreeModel *model;
Packit Service d328f3
	GtkTreeModelFilter *filter;
Packit Service d328f3
	GtkTreeSortable *sortable;
Packit Service d328f3
	GType displayed_type;
Packit Service d328f3
Packit Service d328f3
	NMClient *client;
Packit Service d328f3
Packit Service d328f3
	gboolean populated;
Packit Service d328f3
};
Packit Service d328f3
Packit Service d328f3
#define NM_CONNECTION_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
Packit Service d328f3
                                           NM_TYPE_CONNECTION_LIST, \
Packit Service d328f3
                                           NMConnectionListPrivate))
Packit Service d328f3
Packit Service d328f3
G_DEFINE_TYPE_WITH_CODE (NMConnectionList, nm_connection_list, GTK_TYPE_APPLICATION_WINDOW,
Packit Service d328f3
                         G_ADD_PRIVATE (NMConnectionList))
Packit Service d328f3
Packit Service d328f3
#define COL_ID         0
Packit Service d328f3
#define COL_LAST_USED  1
Packit Service d328f3
#define COL_TIMESTAMP  2
Packit Service d328f3
#define COL_CONNECTION 3
Packit Service d328f3
#define COL_GTYPE0     4
Packit Service d328f3
#define COL_GTYPE1     5
Packit Service d328f3
#define COL_GTYPE2     6
Packit Service d328f3
#define COL_ORDER      7
Packit Service d328f3
Packit Service d328f3
static NMRemoteConnection *
Packit Service d328f3
get_active_connection (GtkTreeView *treeview)
Packit Service d328f3
{
Packit Service d328f3
	GtkTreeSelection *selection;
Packit Service d328f3
	GList *selected_rows;
Packit Service d328f3
	GtkTreeModel *model = NULL;
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	NMRemoteConnection *connection = NULL;
Packit Service d328f3
Packit Service d328f3
	selection = gtk_tree_view_get_selection (treeview);
Packit Service d328f3
	selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
Packit Service d328f3
	if (!selected_rows)
Packit Service d328f3
		return NULL;
Packit Service d328f3
Packit Service d328f3
	if (gtk_tree_model_get_iter (model, &iter, (GtkTreePath *) selected_rows->data))
Packit Service d328f3
		gtk_tree_model_get (model, &iter, COL_CONNECTION, &connection, -1);
Packit Service d328f3
Packit Service d328f3
	g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
Packit Service d328f3
Packit Service d328f3
	/* gtk_tree_model_get() will have reffed connection, but we don't
Packit Service d328f3
	 * need that since we know the model will continue to hold a ref.
Packit Service d328f3
	 */
Packit Service d328f3
	if (connection)
Packit Service d328f3
		g_object_unref (connection);
Packit Service d328f3
Packit Service d328f3
	return connection;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
get_iter_for_connection (NMConnectionList *list,
Packit Service d328f3
                         NMRemoteConnection *connection,
Packit Service d328f3
                         GtkTreeIter *iter)
Packit Service d328f3
{
Packit Service d328f3
	GtkTreeIter types_iter;
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
Packit Service d328f3
	if (!gtk_tree_model_get_iter_first (priv->model, &types_iter))
Packit Service d328f3
		return FALSE;
Packit Service d328f3
Packit Service d328f3
	do {
Packit Service d328f3
		if (!gtk_tree_model_iter_children (priv->model, iter, &types_iter))
Packit Service d328f3
			continue;
Packit Service d328f3
Packit Service d328f3
		do {
Packit Service d328f3
			NMRemoteConnection *candidate = NULL;
Packit Service d328f3
Packit Service d328f3
			gtk_tree_model_get (priv->model, iter,
Packit Service d328f3
			                    COL_CONNECTION, &candidate,
Packit Service d328f3
			                    -1);
Packit Service d328f3
			if (candidate == connection) {
Packit Service d328f3
				g_object_unref (candidate);
Packit Service d328f3
				return TRUE;
Packit Service d328f3
			}
Packit Service d328f3
			g_object_unref (candidate);
Packit Service d328f3
		} while (gtk_tree_model_iter_next (priv->model, iter));
Packit Service d328f3
	} while (gtk_tree_model_iter_next (priv->model, &types_iter));
Packit Service d328f3
Packit Service d328f3
	return FALSE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static char *
Packit Service d328f3
format_last_used (guint64 timestamp)
Packit Service d328f3
{
Packit Service d328f3
	GTimeVal now_tv;
Packit Service d328f3
	GDate *now, *last;
Packit Service d328f3
	char *last_used = NULL;
Packit Service d328f3
Packit Service d328f3
	if (!timestamp)
Packit Service d328f3
		return g_strdup (_("never"));
Packit Service d328f3
Packit Service d328f3
	g_get_current_time (&now_tv);
Packit Service d328f3
	now = g_date_new ();
Packit Service d328f3
	g_date_set_time_val (now, &now_tv);
Packit Service d328f3
Packit Service d328f3
	last = g_date_new ();
Packit Service d328f3
	g_date_set_time_t (last, (time_t) timestamp);
Packit Service d328f3
Packit Service d328f3
	/* timestamp is now or in the future */
Packit Service d328f3
	if (now_tv.tv_sec <= timestamp) {
Packit Service d328f3
		last_used = g_strdup (_("now"));
Packit Service d328f3
		goto out;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (g_date_compare (now, last) <= 0) {
Packit Service d328f3
		guint minutes, hours;
Packit Service d328f3
Packit Service d328f3
		/* Same day */
Packit Service d328f3
Packit Service d328f3
		minutes = (now_tv.tv_sec - timestamp) / 60;
Packit Service d328f3
		if (minutes == 0) {
Packit Service d328f3
			last_used = g_strdup (_("now"));
Packit Service d328f3
			goto out;
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		hours = (now_tv.tv_sec - timestamp) / 3600;
Packit Service d328f3
		if (hours == 0) {
Packit Service d328f3
			/* less than an hour ago */
Packit Service d328f3
			last_used = g_strdup_printf (ngettext ("%d minute ago", "%d minutes ago", minutes), minutes);
Packit Service d328f3
			goto out;
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		last_used = g_strdup_printf (ngettext ("%d hour ago", "%d hours ago", hours), hours);
Packit Service d328f3
	} else {
Packit Service d328f3
		guint days, months, years;
Packit Service d328f3
Packit Service d328f3
		days = g_date_get_julian (now) - g_date_get_julian (last);
Packit Service d328f3
		if (days == 0) {
Packit Service d328f3
			last_used = g_strdup ("today");
Packit Service d328f3
			goto out;
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		months = days / 30;
Packit Service d328f3
		if (months == 0) {
Packit Service d328f3
			last_used = g_strdup_printf (ngettext ("%d day ago", "%d days ago", days), days);
Packit Service d328f3
			goto out;
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		years = days / 365;
Packit Service d328f3
		if (years == 0) {
Packit Service d328f3
			last_used = g_strdup_printf (ngettext ("%d month ago", "%d months ago", months), months);
Packit Service d328f3
			goto out;
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		last_used = g_strdup_printf (ngettext ("%d year ago", "%d years ago", years), years);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
out:
Packit Service d328f3
	g_date_free (now);
Packit Service d328f3
	g_date_free (last);
Packit Service d328f3
	return last_used;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
update_connection_row (NMConnectionList *self,
Packit Service d328f3
                       GtkTreeIter *iter,
Packit Service d328f3
                       NMRemoteConnection *connection)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (self);
Packit Service d328f3
	NMSettingConnection *s_con;
Packit Service d328f3
	char *last_used, *id;
Packit Service d328f3
Packit Service d328f3
	s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
Packit Service d328f3
	g_assert (s_con);
Packit Service d328f3
Packit Service d328f3
	last_used = format_last_used (nm_setting_connection_get_timestamp (s_con));
Packit Service d328f3
	id = g_markup_escape_text (nm_setting_connection_get_id (s_con), -1);
Packit Service d328f3
	gtk_tree_store_set (GTK_TREE_STORE (priv->model), iter,
Packit Service d328f3
	                    COL_ID, id,
Packit Service d328f3
	                    COL_LAST_USED, last_used,
Packit Service d328f3
	                    COL_TIMESTAMP, nm_setting_connection_get_timestamp (s_con),
Packit Service d328f3
	                    COL_CONNECTION, connection,
Packit Service d328f3
	                    -1);
Packit Service d328f3
	g_free (last_used);
Packit Service d328f3
	g_free (id);
Packit Service d328f3
Packit Service d328f3
	gtk_tree_model_filter_refilter (priv->filter);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
delete_slaves_of_connection (NMConnectionList *list, NMConnection *connection)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
	const char *uuid, *iface;
Packit Service d328f3
	GtkTreeIter iter, types_iter;
Packit Service d328f3
Packit Service d328f3
	if (!gtk_tree_model_get_iter_first (priv->model, &types_iter))
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	uuid = nm_connection_get_uuid (connection);
Packit Service d328f3
	iface = nm_connection_get_interface_name (connection);
Packit Service d328f3
Packit Service d328f3
	do {
Packit Service d328f3
		if (!gtk_tree_model_iter_children (priv->model, &iter, &types_iter))
Packit Service d328f3
			continue;
Packit Service d328f3
Packit Service d328f3
		do {
Packit Service d328f3
			NMRemoteConnection *candidate = NULL;
Packit Service d328f3
			NMSettingConnection *s_con;
Packit Service d328f3
			const char *master;
Packit Service d328f3
Packit Service d328f3
			gtk_tree_model_get (priv->model, &iter,
Packit Service d328f3
			                    COL_CONNECTION, &candidate,
Packit Service d328f3
			                    -1);
Packit Service d328f3
			s_con = nm_connection_get_setting_connection (NM_CONNECTION (candidate));
Packit Service d328f3
			master = nm_setting_connection_get_master (s_con);
Packit Service d328f3
			if (master) {
Packit Service d328f3
				if (!g_strcmp0 (master, uuid) || !g_strcmp0 (master, iface))
Packit Service d328f3
					nm_remote_connection_delete (candidate, NULL, NULL);
Packit Service d328f3
			}
Packit Service d328f3
Packit Service d328f3
			g_object_unref (candidate);
Packit Service d328f3
		} while (gtk_tree_model_iter_next (priv->model, &iter));
Packit Service d328f3
	} while (gtk_tree_model_iter_next (priv->model, &types_iter));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
Packit Service d328f3
/**********************************************/
Packit Service d328f3
/* dialog/UI handling stuff */
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
add_response_cb (NMConnectionEditor *editor, GtkResponseType response, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *list = user_data;
Packit Service d328f3
Packit Service d328f3
	if (response == GTK_RESPONSE_CANCEL)
Packit Service d328f3
		delete_slaves_of_connection (list, nm_connection_editor_get_connection (editor));
Packit Service d328f3
Packit Service d328f3
	g_object_unref (editor);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
new_editor_cb (NMConnectionEditor *editor, NMConnectionEditor *new_editor, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *list = user_data;
Packit Service d328f3
Packit Service d328f3
	g_signal_emit (list, list_signals[NEW_EDITOR], 0, new_editor);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
typedef struct {
Packit Service d328f3
	NMConnectionList *list;
Packit Service d328f3
	NMConnectionListCallbackFunc callback;
Packit Service d328f3
	gpointer user_data;
Packit Service d328f3
} ConnectionResultData;
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
really_add_connection (FUNC_TAG_NEW_CONNECTION_RESULT_IMPL,
Packit Service d328f3
                       NMConnection *connection,
Packit Service d328f3
                       gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	ConnectionResultData *data = user_data;
Packit Service d328f3
	NMConnectionList *list = data->list;
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
	NMConnectionEditor *editor = NULL;
Packit Service d328f3
Packit Service d328f3
	if (!connection)
Packit Service d328f3
		goto out;
Packit Service d328f3
Packit Service d328f3
	if (connection_supports_proxy (connection) && !nm_connection_get_setting_proxy (connection))
Packit Service d328f3
		nm_connection_add_setting (connection, nm_setting_proxy_new ());
Packit Service d328f3
	if (connection_supports_ip4 (connection) && !nm_connection_get_setting_ip4_config (connection))
Packit Service d328f3
		nm_connection_add_setting (connection, nm_setting_ip4_config_new ());
Packit Service d328f3
	if (connection_supports_ip6 (connection) && !nm_connection_get_setting_ip6_config (connection))
Packit Service d328f3
		nm_connection_add_setting (connection, nm_setting_ip6_config_new ());
Packit Service d328f3
Packit Service d328f3
	editor = nm_connection_editor_new (GTK_WINDOW (list), connection, priv->client);
Packit Service d328f3
	if (!editor)
Packit Service d328f3
		goto out;
Packit Service d328f3
Packit Service d328f3
	g_signal_connect (editor, NM_CONNECTION_EDITOR_DONE, G_CALLBACK (add_response_cb), list);
Packit Service d328f3
	g_signal_connect (editor, NM_CONNECTION_EDITOR_NEW_EDITOR, G_CALLBACK (new_editor_cb), list);
Packit Service d328f3
Packit Service d328f3
	g_signal_emit (list, list_signals[NEW_EDITOR], 0, editor);
Packit Service d328f3
Packit Service d328f3
out:
Packit Service d328f3
	if (data->callback)
Packit Service d328f3
		data->callback (data->list, data->user_data);
Packit Service d328f3
	g_slice_free (ConnectionResultData, data);
Packit Service d328f3
Packit Service d328f3
	if (editor)
Packit Service d328f3
		nm_connection_editor_run (editor);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
add_clicked (GtkButton *button, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	nm_connection_list_add (user_data, NULL, NULL);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
void
Packit Service d328f3
nm_connection_list_add (NMConnectionList *list,
Packit Service d328f3
                        NMConnectionListCallbackFunc callback,
Packit Service d328f3
                        gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionListPrivate *priv;
Packit Service d328f3
	ConnectionResultData *data;
Packit Service d328f3
Packit Service d328f3
	g_return_if_fail (NM_IS_CONNECTION_LIST (list));
Packit Service d328f3
	priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
Packit Service d328f3
	data = g_slice_new0 (ConnectionResultData);
Packit Service d328f3
	data->list = list;
Packit Service d328f3
	data->callback = callback;
Packit Service d328f3
	data->user_data = user_data;
Packit Service d328f3
Packit Service d328f3
	new_connection_dialog (GTK_WINDOW (list),
Packit Service d328f3
	                       priv->client,
Packit Service d328f3
	                       NULL,
Packit Service d328f3
	                       really_add_connection,
Packit Service d328f3
	                       data);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
edit_done_cb (NMConnectionEditor *editor, GtkResponseType response, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *list = user_data;
Packit Service d328f3
Packit Service d328f3
	if (response == GTK_RESPONSE_OK) {
Packit Service d328f3
		NMRemoteConnection *connection = NM_REMOTE_CONNECTION (nm_connection_editor_get_connection (editor));
Packit Service d328f3
		GtkTreeIter iter;
Packit Service d328f3
Packit Service d328f3
		if (get_iter_for_connection (list, connection, &iter))
Packit Service d328f3
			update_connection_row (list, &iter, connection);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	g_object_unref (editor);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
edit_connection (NMConnectionList *list, NMConnection *connection)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
	NMConnectionEditor *editor;
Packit Service d328f3
Packit Service d328f3
	g_return_if_fail (connection != NULL);
Packit Service d328f3
Packit Service d328f3
	/* Don't allow two editors for the same connection */
Packit Service d328f3
	editor = nm_connection_editor_get (connection);
Packit Service d328f3
	if (editor) {
Packit Service d328f3
		nm_connection_editor_present (editor);
Packit Service d328f3
		return;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	editor = nm_connection_editor_new (GTK_WINDOW (list),
Packit Service d328f3
	                                   NM_CONNECTION (connection),
Packit Service d328f3
	                                   priv->client);
Packit Service d328f3
	if (!editor)
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	g_signal_connect (editor, NM_CONNECTION_EDITOR_DONE, G_CALLBACK (edit_done_cb), list);
Packit Service d328f3
	g_signal_connect (editor, NM_CONNECTION_EDITOR_NEW_EDITOR, G_CALLBACK (new_editor_cb), list);
Packit Service d328f3
Packit Service d328f3
	g_signal_emit (list, list_signals[NEW_EDITOR], 0, editor);
Packit Service d328f3
	nm_connection_editor_run (editor);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
do_edit (NMConnectionList *list)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
Packit Service d328f3
	if (gtk_widget_get_sensitive (priv->connection_edit))
Packit Service d328f3
		edit_connection (list, NM_CONNECTION (get_active_connection (priv->connection_list)));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
delete_connection_cb (FUNC_TAG_DELETE_CONNECTION_RESULT_IMPL,
Packit Service d328f3
                      NMRemoteConnection *connection,
Packit Service d328f3
                      gboolean deleted,
Packit Service d328f3
                      gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *list = user_data;
Packit Service d328f3
Packit Service d328f3
	if (deleted)
Packit Service d328f3
		delete_slaves_of_connection (list, NM_CONNECTION (connection));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
delete_clicked (GtkButton *button, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *list = user_data;
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
	NMRemoteConnection *connection;
Packit Service d328f3
Packit Service d328f3
	connection = get_active_connection (priv->connection_list);
Packit Service d328f3
	g_return_if_fail (connection != NULL);
Packit Service d328f3
Packit Service d328f3
	delete_connection (GTK_WINDOW (list), connection,
Packit Service d328f3
	                   delete_connection_cb, list);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *list = user_data;
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	GtkTreeModel *model;
Packit Service d328f3
	NMRemoteConnection *connection = NULL;
Packit Service d328f3
	NMSettingConnection *s_con;
Packit Service d328f3
	gboolean sensitive = FALSE;
Packit Service d328f3
Packit Service d328f3
	if (gtk_tree_selection_get_selected (selection, &model, &iter))
Packit Service d328f3
		connection = get_active_connection (priv->connection_list);
Packit Service d328f3
Packit Service d328f3
	if (connection) {
Packit Service d328f3
		s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
Packit Service d328f3
		g_assert (s_con);
Packit Service d328f3
Packit Service d328f3
		sensitive = !nm_setting_connection_get_read_only (s_con);
Packit Service d328f3
Packit Service d328f3
		ce_polkit_set_widget_validation_error (priv->connection_edit,
Packit Service d328f3
		                                       sensitive ? NULL : _("Connection cannot be modified"));
Packit Service d328f3
		ce_polkit_set_widget_validation_error (priv->connection_del,
Packit Service d328f3
		                                       sensitive ? NULL : _("Connection cannot be deleted"));
Packit Service d328f3
	} else {
Packit Service d328f3
		ce_polkit_set_widget_validation_error (priv->connection_edit,
Packit Service d328f3
		                                       _("Select a connection to edit"));
Packit Service d328f3
		ce_polkit_set_widget_validation_error (priv->connection_del,
Packit Service d328f3
		                                       _("Select a connection to delete"));
Packit Service d328f3
	}
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
key_press_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *list = user_data;
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
	GdkEventKey *key_event = (GdkEventKey *) event;
Packit Service d328f3
Packit Service d328f3
	if (gtk_search_bar_handle_event (priv->search_bar, event) == GDK_EVENT_STOP)
Packit Service d328f3
		return GDK_EVENT_STOP;
Packit Service d328f3
Packit Service d328f3
	if (key_event->keyval == GDK_KEY_Escape) {
Packit Service d328f3
		if (gtk_search_bar_get_search_mode (priv->search_bar))
Packit Service d328f3
			gtk_search_bar_set_search_mode (priv->search_bar, FALSE);
Packit Service d328f3
		else
Packit Service d328f3
			gtk_window_close (GTK_WINDOW (user_data));
Packit Service d328f3
		return GDK_EVENT_STOP;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	return GDK_EVENT_PROPAGATE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
start_search (GtkTreeView *treeview, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *list = user_data;
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
Packit Service d328f3
	gtk_search_bar_set_search_mode (priv->search_bar, TRUE);
Packit Service d328f3
Packit Service d328f3
	return TRUE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
search_changed (GtkSearchEntry *entry, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *list = user_data;
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
Packit Service d328f3
	gtk_tree_model_filter_refilter (priv->filter);
Packit Service d328f3
	gtk_tree_view_expand_all (priv->connection_list);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
nm_connection_list_init (NMConnectionList *list)
Packit Service d328f3
{
Packit Service d328f3
	gtk_widget_init_template (GTK_WIDGET (list));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
dispose (GObject *object)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *list = NM_CONNECTION_LIST (object);
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
Packit Service d328f3
	g_clear_object (&priv->client);
Packit Service d328f3
Packit Service d328f3
	G_OBJECT_CLASS (nm_connection_list_parent_class)->dispose (object);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
nm_connection_list_class_init (NMConnectionListClass *klass)
Packit Service d328f3
{
Packit Service d328f3
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit Service d328f3
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
Packit Service d328f3
Packit Service d328f3
	/* virtual methods */
Packit Service d328f3
	object_class->dispose = dispose;
Packit Service d328f3
Packit Service d328f3
	/* Signals */
Packit Service d328f3
	list_signals[NEW_EDITOR] =
Packit Service d328f3
		g_signal_new (NM_CONNECTION_LIST_NEW_EDITOR,
Packit Service d328f3
		              G_OBJECT_CLASS_TYPE (object_class),
Packit Service d328f3
		              G_SIGNAL_RUN_FIRST,
Packit Service d328f3
		              0, NULL, NULL, NULL,
Packit Service d328f3
		              G_TYPE_NONE, 1, G_TYPE_POINTER);
Packit Service d328f3
Packit Service d328f3
	/* Initialize the widget template */
Packit Service d328f3
        gtk_widget_class_set_template_from_resource (widget_class,
Packit Service d328f3
	                                             "/org/gnome/nm_connection_editor/nm-connection-list.ui");
Packit Service d328f3
Packit Service d328f3
        gtk_widget_class_bind_template_child_private (widget_class, NMConnectionList, connection_list);
Packit Service d328f3
        gtk_widget_class_bind_template_child_private (widget_class, NMConnectionList, connection_add);
Packit Service d328f3
        gtk_widget_class_bind_template_child_private (widget_class, NMConnectionList, connection_del);
Packit Service d328f3
        gtk_widget_class_bind_template_child_private (widget_class, NMConnectionList, connection_edit);
Packit Service d328f3
        gtk_widget_class_bind_template_child_private (widget_class, NMConnectionList, search_bar);
Packit Service d328f3
        gtk_widget_class_bind_template_child_private (widget_class, NMConnectionList, search_entry);
Packit Service d328f3
Packit Service d328f3
        gtk_widget_class_bind_template_callback (widget_class, add_clicked);
Packit Service d328f3
        gtk_widget_class_bind_template_callback (widget_class, do_edit);
Packit Service d328f3
        gtk_widget_class_bind_template_callback (widget_class, delete_clicked);
Packit Service d328f3
        gtk_widget_class_bind_template_callback (widget_class, selection_changed_cb);
Packit Service d328f3
        gtk_widget_class_bind_template_callback (widget_class, key_press_cb);
Packit Service d328f3
        gtk_widget_class_bind_template_callback (widget_class, start_search);
Packit Service d328f3
        gtk_widget_class_bind_template_callback (widget_class, search_changed);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
column_header_clicked_cb (GtkTreeViewColumn *treeviewcolumn, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	gint sort_col_id = GPOINTER_TO_INT (user_data);
Packit Service d328f3
Packit Service d328f3
	gtk_tree_view_column_set_sort_column_id (treeviewcolumn, sort_col_id);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gint
Packit Service d328f3
sort_connection_types (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	GtkTreeSortable *sortable = user_data;
Packit Service d328f3
	int order_a, order_b;
Packit Service d328f3
	GtkSortType order;
Packit Service d328f3
Packit Service d328f3
	gtk_tree_model_get (model, a, COL_ORDER, &order_a, -1);
Packit Service d328f3
	gtk_tree_model_get (model, b, COL_ORDER, &order_b, -1);
Packit Service d328f3
Packit Service d328f3
	/* The connection types should stay in the same order regardless of whether
Packit Service d328f3
	 * the table is sorted ascending or descending.
Packit Service d328f3
	 */
Packit Service d328f3
	gtk_tree_sortable_get_sort_column_id (sortable, NULL, &order);
Packit Service d328f3
	if (order == GTK_SORT_ASCENDING)
Packit Service d328f3
		return order_a - order_b;
Packit Service d328f3
	else
Packit Service d328f3
		return order_b - order_a;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gint
Packit Service d328f3
id_sort_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnection *conn_a, *conn_b;
Packit Service d328f3
	gint ret;
Packit Service d328f3
Packit Service d328f3
	gtk_tree_model_get (model, a, COL_CONNECTION, &conn_a, -1);
Packit Service d328f3
	gtk_tree_model_get (model, b, COL_CONNECTION, &conn_b, -1);
Packit Service d328f3
Packit Service d328f3
	if (!conn_a || !conn_b) {
Packit Service d328f3
		g_assert (!conn_a && !conn_b);
Packit Service d328f3
		return sort_connection_types (model, a, b, user_data);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	ret = strcmp (nm_connection_get_id (conn_a), nm_connection_get_id (conn_b));
Packit Service d328f3
	g_object_unref (conn_a);
Packit Service d328f3
	g_object_unref (conn_b);
Packit Service d328f3
Packit Service d328f3
	return ret;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gint
Packit Service d328f3
timestamp_sort_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnection *conn_a, *conn_b;
Packit Service d328f3
	guint64 time_a, time_b;
Packit Service d328f3
Packit Service d328f3
	gtk_tree_model_get (model, a,
Packit Service d328f3
	                    COL_CONNECTION, &conn_a,
Packit Service d328f3
	                    COL_TIMESTAMP, &time_a,
Packit Service d328f3
	                    -1);
Packit Service d328f3
	gtk_tree_model_get (model, b,
Packit Service d328f3
	                    COL_CONNECTION, &conn_b,
Packit Service d328f3
	                    COL_TIMESTAMP, &time_b,
Packit Service d328f3
	                    -1);
Packit Service d328f3
Packit Service d328f3
	if (!conn_a || !conn_b) {
Packit Service d328f3
		g_assert (!conn_a && !conn_b);
Packit Service d328f3
		return sort_connection_types (model, a, b, user_data);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	g_object_unref (conn_a);
Packit Service d328f3
	g_object_unref (conn_b);
Packit Service d328f3
Packit Service d328f3
	return time_b - time_a;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
has_visible_children (NMConnectionList *self, GtkTreeModel *model, GtkTreeIter *parent)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (self);
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	const char *search;
Packit Service d328f3
	char *id = NULL;
Packit Service d328f3
Packit Service d328f3
	if (!gtk_search_bar_get_search_mode (priv->search_bar))
Packit Service d328f3
		return gtk_tree_model_iter_has_child  (model, parent);
Packit Service d328f3
Packit Service d328f3
	if (!gtk_tree_model_iter_children (model, &iter, parent))
Packit Service d328f3
		return FALSE;
Packit Service d328f3
Packit Service d328f3
	search = gtk_entry_get_text (GTK_ENTRY (priv->search_entry));
Packit Service d328f3
	do {
Packit Service d328f3
		gtk_tree_model_get (model, &iter, COL_ID, &id, -1);
Packit Service d328f3
		if (!id) {
Packit Service d328f3
			/* gtk_tree_store_append() inserts an empty row, ignore
Packit Service d328f3
			 * it until it is fully populated. */
Packit Service d328f3
			continue;
Packit Service d328f3
		}
Packit Service d328f3
		if (strcasestr (id, search) != NULL) {
Packit Service d328f3
			g_free (id);
Packit Service d328f3
			return TRUE;
Packit Service d328f3
		}
Packit Service d328f3
		g_free (id);
Packit Service d328f3
	} while (gtk_tree_model_iter_next (model, &iter));
Packit Service d328f3
Packit Service d328f3
	return FALSE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
tree_model_visible_func (GtkTreeModel *model,
Packit Service d328f3
                         GtkTreeIter *iter,
Packit Service d328f3
                         gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *self = user_data;
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (self);
Packit Service d328f3
	gs_unref_object NMConnection *connection = NULL;
Packit Service d328f3
	NMSettingConnection *s_con;
Packit Service d328f3
	const char *master;
Packit Service d328f3
	const char *slave_type;
Packit Service d328f3
	gs_free char *id = NULL;
Packit Service d328f3
Packit Service d328f3
	gtk_tree_model_get (model, iter,
Packit Service d328f3
	                    COL_ID, &id,
Packit Service d328f3
	                    COL_CONNECTION, &connection,
Packit Service d328f3
	                    -1);
Packit Service d328f3
	if (!connection) {
Packit Service d328f3
		/* Top-level type nodes are visible iff they have visible children */
Packit Service d328f3
		return has_visible_children (self, model, iter);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (   gtk_search_bar_get_search_mode (priv->search_bar)
Packit Service d328f3
	    && strcasestr (id, gtk_entry_get_text (GTK_ENTRY (priv->search_entry))) == NULL)
Packit Service d328f3
		return FALSE;
Packit Service d328f3
Packit Service d328f3
	/* A connection node is visible unless it is a slave to a known
Packit Service d328f3
	 * bond or team or bridge.
Packit Service d328f3
	 */
Packit Service d328f3
	s_con = nm_connection_get_setting_connection (connection);
Packit Service d328f3
	if (   !s_con
Packit Service d328f3
	    || !nm_remote_connection_get_visible (NM_REMOTE_CONNECTION (connection)))
Packit Service d328f3
		return FALSE;
Packit Service d328f3
Packit Service d328f3
	master = nm_setting_connection_get_master (s_con);
Packit Service d328f3
	if (!master)
Packit Service d328f3
		return TRUE;
Packit Service d328f3
	slave_type = nm_setting_connection_get_slave_type (s_con);
Packit Service d328f3
	if (   g_strcmp0 (slave_type, NM_SETTING_BOND_SETTING_NAME) != 0
Packit Service d328f3
	    && g_strcmp0 (slave_type, NM_SETTING_TEAM_SETTING_NAME) != 0
Packit Service d328f3
	    && g_strcmp0 (slave_type, NM_SETTING_BRIDGE_SETTING_NAME) != 0)
Packit Service d328f3
		return TRUE;
Packit Service d328f3
Packit Service d328f3
	if (nm_client_get_connection_by_uuid (priv->client, master))
Packit Service d328f3
		return FALSE;
Packit Service d328f3
	if (nm_connection_editor_get_master (connection))
Packit Service d328f3
		return FALSE;
Packit Service d328f3
Packit Service d328f3
	/* FIXME: what if master is an interface name */
Packit Service d328f3
Packit Service d328f3
	return TRUE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
connection_list_equal (GtkTreeModel *model, gint column, const gchar *key,
Packit Service d328f3
                       GtkTreeIter *iter, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	gs_free char *id = NULL;
Packit Service d328f3
	gs_unref_object NMConnection *connection = NULL;
Packit Service d328f3
Packit Service d328f3
	gtk_tree_model_get (model, iter,
Packit Service d328f3
	                    COL_ID, &id,
Packit Service d328f3
	                    COL_CONNECTION, &connection,
Packit Service d328f3
	                    -1);
Packit Service d328f3
Packit Service d328f3
	if (!connection)
Packit Service d328f3
		return TRUE;
Packit Service d328f3
Packit Service d328f3
	return strcasestr (id, key) == NULL;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
initialize_treeview (NMConnectionList *self)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (self);
Packit Service d328f3
	GtkCellRenderer *renderer;
Packit Service d328f3
	GtkTreeViewColumn *column;
Packit Service d328f3
	GtkTreeSelection *selection;
Packit Service d328f3
	ConnectionTypeData *types;
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	char *id, *tmp;
Packit Service d328f3
	int i;
Packit Service d328f3
Packit Service d328f3
	/* Model */
Packit Service d328f3
	priv->model = GTK_TREE_MODEL (gtk_tree_store_new (8, G_TYPE_STRING,
Packit Service d328f3
	                                                     G_TYPE_STRING,
Packit Service d328f3
	                                                     G_TYPE_UINT64,
Packit Service d328f3
	                                                     G_TYPE_OBJECT,
Packit Service d328f3
	                                                     G_TYPE_GTYPE,
Packit Service d328f3
	                                                     G_TYPE_GTYPE,
Packit Service d328f3
	                                                     G_TYPE_GTYPE,
Packit Service d328f3
	                                                     G_TYPE_INT));
Packit Service d328f3
Packit Service d328f3
	/* Filter */
Packit Service d328f3
	priv->filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (priv->model, NULL));
Packit Service d328f3
	gtk_tree_model_filter_set_visible_func (priv->filter,
Packit Service d328f3
	                                        tree_model_visible_func,
Packit Service d328f3
	                                        self, NULL);
Packit Service d328f3
Packit Service d328f3
	/* Sortable */
Packit Service d328f3
	priv->sortable = GTK_TREE_SORTABLE (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (priv->filter)));
Packit Service d328f3
	gtk_tree_sortable_set_default_sort_func (priv->sortable, NULL, NULL, NULL);
Packit Service d328f3
	gtk_tree_sortable_set_sort_func (priv->sortable, COL_TIMESTAMP, timestamp_sort_func,
Packit Service d328f3
	                                 priv->sortable, NULL);
Packit Service d328f3
	gtk_tree_sortable_set_sort_func (priv->sortable, COL_ID, id_sort_func,
Packit Service d328f3
	                                 priv->sortable, NULL);
Packit Service d328f3
	gtk_tree_sortable_set_sort_column_id (priv->sortable, COL_TIMESTAMP, GTK_SORT_ASCENDING);
Packit Service d328f3
Packit Service d328f3
	gtk_tree_view_set_model (priv->connection_list, GTK_TREE_MODEL (priv->sortable));
Packit Service d328f3
	gtk_tree_view_set_search_equal_func (priv->connection_list, connection_list_equal, NULL, NULL);
Packit Service d328f3
	gtk_tree_view_set_search_entry (priv->connection_list, priv->search_entry);
Packit Service d328f3
Packit Service d328f3
	/* Name column */
Packit Service d328f3
	renderer = gtk_cell_renderer_text_new ();
Packit Service d328f3
	column = gtk_tree_view_column_new_with_attributes (_("Name"),
Packit Service d328f3
	                                                   renderer,
Packit Service d328f3
	                                                   "markup", COL_ID,
Packit Service d328f3
	                                                   NULL);
Packit Service d328f3
	gtk_tree_view_column_set_expand (column, TRUE);
Packit Service d328f3
	gtk_tree_view_column_set_sort_column_id (column, COL_ID);
Packit Service d328f3
	g_signal_connect (column, "clicked", G_CALLBACK (column_header_clicked_cb), GINT_TO_POINTER (COL_ID));
Packit Service d328f3
	gtk_tree_view_append_column (priv->connection_list, column);
Packit Service d328f3
Packit Service d328f3
	/* Last Used column */
Packit Service d328f3
	renderer = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
Packit Service d328f3
	                         "foreground", "SlateGray",
Packit Service d328f3
	                         NULL);
Packit Service d328f3
	column = gtk_tree_view_column_new_with_attributes (_("Last Used"),
Packit Service d328f3
	                                                   renderer,
Packit Service d328f3
	                                                   "text", COL_LAST_USED,
Packit Service d328f3
	                                                   NULL);
Packit Service d328f3
	gtk_tree_view_column_set_sort_column_id (column, COL_TIMESTAMP);
Packit Service d328f3
	g_signal_connect (column, "clicked", G_CALLBACK (column_header_clicked_cb), GINT_TO_POINTER (COL_TIMESTAMP));
Packit Service d328f3
	gtk_tree_view_append_column (priv->connection_list, column);
Packit Service d328f3
Packit Service d328f3
	/* Selection */
Packit Service d328f3
	selection = gtk_tree_view_get_selection (priv->connection_list);
Packit Service d328f3
	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
Packit Service d328f3
Packit Service d328f3
	/* Fill in connection types */
Packit Service d328f3
	types = get_connection_type_list ();
Packit Service d328f3
	for (i = 0; types[i].name; i++) {
Packit Service d328f3
Packit Service d328f3
		tmp = g_markup_escape_text (types[i].name, -1);
Packit Service d328f3
		id = g_strdup_printf ("%s", tmp);
Packit Service d328f3
		g_free (tmp);
Packit Service d328f3
Packit Service d328f3
		gtk_tree_store_append (GTK_TREE_STORE (priv->model), &iter, NULL);
Packit Service d328f3
		gtk_tree_store_set (GTK_TREE_STORE (priv->model), &iter,
Packit Service d328f3
		                    COL_ID, id,
Packit Service d328f3
		                    COL_GTYPE0, types[i].setting_types[0],
Packit Service d328f3
		                    COL_GTYPE1, types[i].setting_types[1],
Packit Service d328f3
		                    COL_GTYPE2, types[i].setting_types[2],
Packit Service d328f3
		                    COL_ORDER, i,
Packit Service d328f3
		                    -1);
Packit Service d328f3
		g_free (id);
Packit Service d328f3
	}
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
add_connection_buttons (NMConnectionList *self)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (self);
Packit Service d328f3
Packit Service d328f3
	ce_polkit_connect_widget (priv->connection_edit,
Packit Service d328f3
	                          _("Edit the selected connection"),
Packit Service d328f3
	                          _("Authenticate to edit the selected connection"),
Packit Service d328f3
	                          priv->client,
Packit Service d328f3
	                          NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM);
Packit Service d328f3
Packit Service d328f3
	ce_polkit_connect_widget (priv->connection_del,
Packit Service d328f3
	                          _("Delete the selected connection"),
Packit Service d328f3
	                          _("Authenticate to delete the selected connection"),
Packit Service d328f3
	                          priv->client,
Packit Service d328f3
	                          NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
connection_removed (NMClient *client,
Packit Service d328f3
                    NMRemoteConnection *connection,
Packit Service d328f3
                    gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *self = NM_CONNECTION_LIST (user_data);
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (self);
Packit Service d328f3
	GtkTreeIter iter, parent_iter;
Packit Service d328f3
Packit Service d328f3
	if (get_iter_for_connection (self, connection, &iter)) {
Packit Service d328f3
		gtk_tree_model_iter_parent (priv->model, &parent_iter, &iter);
Packit Service d328f3
		gtk_tree_store_remove (GTK_TREE_STORE (priv->model), &iter);
Packit Service d328f3
	}
Packit Service d328f3
	gtk_tree_model_filter_refilter (priv->filter);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
connection_changed (NMRemoteConnection *connection, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *self = NM_CONNECTION_LIST (user_data);
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
Packit Service d328f3
	if (   !nm_remote_connection_get_visible (connection)
Packit Service d328f3
	    || !nm_connection_get_setting_connection (NM_CONNECTION (connection))) {
Packit Service d328f3
		return;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (get_iter_for_connection (self, connection, &iter))
Packit Service d328f3
		update_connection_row (self, &iter, connection);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
get_parent_iter_for_connection (NMConnectionList *list,
Packit Service d328f3
                                NMRemoteConnection *connection,
Packit Service d328f3
                                GtkTreeIter *iter)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
	NMSettingConnection *s_con;
Packit Service d328f3
	const char *str_type;
Packit Service d328f3
	GType type, row_type0, row_type1, row_type2;
Packit Service d328f3
Packit Service d328f3
	s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
Packit Service d328f3
	g_assert (s_con);
Packit Service d328f3
	str_type = nm_setting_connection_get_connection_type (s_con);
Packit Service d328f3
	if (!str_type) {
Packit Service d328f3
		g_warning ("Ignoring incomplete connection");
Packit Service d328f3
		return FALSE;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	type = nm_setting_lookup_type (str_type);
Packit Service d328f3
Packit Service d328f3
	if (gtk_tree_model_get_iter_first (priv->model, iter)) {
Packit Service d328f3
		do {
Packit Service d328f3
			gtk_tree_model_get (priv->model, iter,
Packit Service d328f3
			                    COL_GTYPE0, &row_type0,
Packit Service d328f3
			                    COL_GTYPE1, &row_type1,
Packit Service d328f3
			                    COL_GTYPE2, &row_type2,
Packit Service d328f3
			                    -1);
Packit Service d328f3
			if (row_type0 == type || row_type1 == type || row_type2 == type)
Packit Service d328f3
				return TRUE;
Packit Service d328f3
		} while (gtk_tree_model_iter_next (priv->model, iter));
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	return FALSE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
connection_added (NMClient *client,
Packit Service d328f3
                  NMRemoteConnection *connection,
Packit Service d328f3
                  gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *self = NM_CONNECTION_LIST (user_data);
Packit Service d328f3
	NMConnectionListPrivate *priv = NM_CONNECTION_LIST_GET_PRIVATE (self);
Packit Service d328f3
	GtkTreeIter parent_iter, iter;
Packit Service d328f3
	NMSettingConnection *s_con;
Packit Service d328f3
	char *last_used, *id;
Packit Service d328f3
	gboolean expand = TRUE;
Packit Service d328f3
Packit Service d328f3
	if (!get_parent_iter_for_connection (self, connection, &parent_iter))
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
Packit Service d328f3
Packit Service d328f3
	last_used = format_last_used (nm_setting_connection_get_timestamp (s_con));
Packit Service d328f3
Packit Service d328f3
	id = g_markup_escape_text (nm_setting_connection_get_id (s_con), -1);
Packit Service d328f3
Packit Service d328f3
	gtk_tree_store_append (GTK_TREE_STORE (priv->model), &iter, &parent_iter);
Packit Service d328f3
	gtk_tree_store_set (GTK_TREE_STORE (priv->model), &iter,
Packit Service d328f3
	                    COL_ID, id,
Packit Service d328f3
	                    COL_LAST_USED, last_used,
Packit Service d328f3
	                    COL_TIMESTAMP, nm_setting_connection_get_timestamp (s_con),
Packit Service d328f3
	                    COL_CONNECTION, connection,
Packit Service d328f3
	                    -1);
Packit Service d328f3
Packit Service d328f3
	g_free (id);
Packit Service d328f3
	g_free (last_used);
Packit Service d328f3
Packit Service d328f3
	if (priv->displayed_type) {
Packit Service d328f3
		GType added_type0, added_type1, added_type2;
Packit Service d328f3
Packit Service d328f3
		gtk_tree_model_get (priv->model, &parent_iter,
Packit Service d328f3
		                    COL_GTYPE0, &added_type0,
Packit Service d328f3
		                    COL_GTYPE1, &added_type1,
Packit Service d328f3
		                    COL_GTYPE2, &added_type2,
Packit Service d328f3
		                    -1);
Packit Service d328f3
		if (   added_type0 != priv->displayed_type
Packit Service d328f3
		    && added_type1 != priv->displayed_type
Packit Service d328f3
		    && added_type2 != priv->displayed_type)
Packit Service d328f3
			expand = FALSE;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (expand) {
Packit Service d328f3
		GtkTreePath *path, *filtered_path;
Packit Service d328f3
Packit Service d328f3
		path = gtk_tree_model_get_path (priv->model, &parent_iter);
Packit Service d328f3
		filtered_path = gtk_tree_model_filter_convert_child_path_to_path (priv->filter, path);
Packit Service d328f3
		gtk_tree_view_expand_row (priv->connection_list, filtered_path, FALSE);
Packit Service d328f3
		gtk_tree_path_free (filtered_path);
Packit Service d328f3
		gtk_tree_path_free (path);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	g_signal_connect (connection, NM_CONNECTION_CHANGED, G_CALLBACK (connection_changed), self);
Packit Service d328f3
	gtk_tree_model_filter_refilter (priv->filter);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
NMConnectionList *
Packit Service d328f3
nm_connection_list_new (void)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionList *list;
Packit Service d328f3
	NMConnectionListPrivate *priv;
Packit Service d328f3
	GError *error = NULL;
Packit Service d328f3
Packit Service d328f3
	list = g_object_new (NM_TYPE_CONNECTION_LIST, NULL);
Packit Service d328f3
	if (!list)
Packit Service d328f3
		return NULL;
Packit Service d328f3
Packit Service d328f3
	priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
Packit Service d328f3
	gtk_window_set_default_icon_name ("preferences-system-network");
Packit Service d328f3
Packit Service d328f3
	priv->client = nm_client_new (NULL, &error);
Packit Service d328f3
	if (!priv->client) {
Packit Service d328f3
		g_warning ("Couldn't construct the client instance: %s", error->message);
Packit Service d328f3
		g_error_free (error);
Packit Service d328f3
		goto error;
Packit Service d328f3
	}
Packit Service d328f3
	g_signal_connect (priv->client,
Packit Service d328f3
	                  NM_CLIENT_CONNECTION_ADDED,
Packit Service d328f3
	                  G_CALLBACK (connection_added),
Packit Service d328f3
	                  list);
Packit Service d328f3
	g_signal_connect (priv->client,
Packit Service d328f3
	                  NM_CLIENT_CONNECTION_REMOVED,
Packit Service d328f3
	                  G_CALLBACK (connection_removed),
Packit Service d328f3
	                  list);
Packit Service d328f3
Packit Service d328f3
	add_connection_buttons (list);
Packit Service d328f3
	initialize_treeview (list);
Packit Service d328f3
Packit Service d328f3
	if (nm_ce_keep_above)
Packit Service d328f3
		gtk_window_set_keep_above (GTK_WINDOW (list), TRUE);
Packit Service d328f3
Packit Service d328f3
	return list;
Packit Service d328f3
Packit Service d328f3
error:
Packit Service d328f3
	g_object_unref (list);
Packit Service d328f3
	return NULL;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
void
Packit Service d328f3
nm_connection_list_set_type (NMConnectionList *self, GType ctype)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionListPrivate *priv;
Packit Service d328f3
Packit Service d328f3
	g_return_if_fail (NM_IS_CONNECTION_LIST (self));
Packit Service d328f3
	priv = NM_CONNECTION_LIST_GET_PRIVATE (self);
Packit Service d328f3
Packit Service d328f3
	priv->displayed_type = ctype;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
void
Packit Service d328f3
nm_connection_list_create (NMConnectionList *list,
Packit Service d328f3
                           GType ctype,
Packit Service d328f3
                           const char *detail,
Packit Service d328f3
                           const char *import_filename,
Packit Service d328f3
                           NMConnectionListCallbackFunc callback,
Packit Service d328f3
                           gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionListPrivate *priv;
Packit Service d328f3
	ConnectionTypeData *types;
Packit Service d328f3
	ConnectionResultData *data;
Packit Service d328f3
	gs_unref_object NMConnection *connection = NULL;
Packit Service d328f3
	gs_free_error GError *error = NULL;
Packit Service d328f3
	int i;
Packit Service d328f3
Packit Service d328f3
	g_return_if_fail (NM_IS_CONNECTION_LIST (list));
Packit Service d328f3
	priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
Packit Service d328f3
	if (import_filename) {
Packit Service d328f3
		if (ctype == G_TYPE_INVALID) {
Packit Service d328f3
			/* Atempt a VPN import */
Packit Service d328f3
			connection = vpn_connection_from_file (import_filename, NULL);
Packit Service d328f3
			if (connection)
Packit Service d328f3
				ctype = NM_TYPE_SETTING_VPN;
Packit Service d328f3
			else
Packit Service d328f3
				g_set_error (&error, NMA_ERROR, NMA_ERROR_GENERIC, _("Unrecognized connection type"));
Packit Service d328f3
		} else if (ctype == NM_TYPE_SETTING_VPN) {
Packit Service d328f3
			connection = vpn_connection_from_file (import_filename, &error);
Packit Service d328f3
		} else {
Packit Service d328f3
			g_set_error (&error, NMA_ERROR, NMA_ERROR_GENERIC,
Packit Service d328f3
			             _("Don’t know how to import “%s” connections"), g_type_name (ctype));
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		if (!connection) {
Packit Service d328f3
			nm_connection_editor_error (NULL, _("Error importing connection"), "%s", error->message);
Packit Service d328f3
			callback (list, user_data);
Packit Service d328f3
			return;
Packit Service d328f3
		}
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (ctype == G_TYPE_INVALID) {
Packit Service d328f3
		nm_connection_editor_error (NULL, _("Error creating connection"), _("Connection type not specified."));
Packit Service d328f3
		callback (list, user_data);
Packit Service d328f3
		return;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	types = get_connection_type_list ();
Packit Service d328f3
	for (i = 0; types[i].name; i++) {
Packit Service d328f3
		if (   types[i].setting_types[0] == ctype
Packit Service d328f3
		    || types[i].setting_types[1] == ctype
Packit Service d328f3
		    || types[i].setting_types[2] == ctype)
Packit Service d328f3
			break;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (!types[i].name) {
Packit Service d328f3
		if (ctype == NM_TYPE_SETTING_VPN) {
Packit Service d328f3
			nm_connection_editor_error (NULL, _("Error creating connection"),
Packit Service d328f3
			                            _("No VPN plugins are installed."));
Packit Service d328f3
		} else {
Packit Service d328f3
			nm_connection_editor_error (NULL, _("Error creating connection"),
Packit Service d328f3
			                            _("Don’t know how to create “%s” connections"), g_type_name (ctype));
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		callback (list, user_data);
Packit Service d328f3
		return;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	data = g_slice_new0 (ConnectionResultData);
Packit Service d328f3
	data->list = list;
Packit Service d328f3
	data->callback = callback;
Packit Service d328f3
	data->user_data = user_data;
Packit Service d328f3
Packit Service d328f3
	new_connection_of_type (GTK_WINDOW (list),
Packit Service d328f3
	                        detail,
Packit Service d328f3
	                        NULL,
Packit Service d328f3
	                        connection,
Packit Service d328f3
	                        priv->client,
Packit Service d328f3
	                        types[i].new_connection_func,
Packit Service d328f3
	                        really_add_connection,
Packit Service d328f3
	                        data);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
void
Packit Service d328f3
nm_connection_list_edit (NMConnectionList *self, const gchar *uuid)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionListPrivate *priv;
Packit Service d328f3
	NMConnection *connection;
Packit Service d328f3
Packit Service d328f3
	g_return_if_fail (NM_IS_CONNECTION_LIST (self));
Packit Service d328f3
	priv = NM_CONNECTION_LIST_GET_PRIVATE (self);
Packit Service d328f3
Packit Service d328f3
	connection = (NMConnection *) nm_client_get_connection_by_uuid (priv->client, uuid);
Packit Service d328f3
	if (!connection) {
Packit Service d328f3
		nm_connection_editor_error (NULL,
Packit Service d328f3
		                            _("Error editing connection"),
Packit Service d328f3
		                            _("Did not find a connection with UUID “%s”"), uuid);
Packit Service d328f3
		return;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	edit_connection (self, connection);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
void
Packit Service d328f3
nm_connection_list_present (NMConnectionList *list)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionListPrivate *priv;
Packit Service d328f3
	const GPtrArray *all_cons;
Packit Service d328f3
	GtkTreePath *path;
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	int i;
Packit Service d328f3
Packit Service d328f3
	g_return_if_fail (NM_IS_CONNECTION_LIST (list));
Packit Service d328f3
	priv = NM_CONNECTION_LIST_GET_PRIVATE (list);
Packit Service d328f3
Packit Service d328f3
	if (!priv->populated) {
Packit Service d328f3
		/* Fill the treeview initially */
Packit Service d328f3
		all_cons = nm_client_get_connections (priv->client);
Packit Service d328f3
		for (i = 0; i < all_cons->len; i++)
Packit Service d328f3
			connection_added (priv->client, all_cons->pdata[i], list);
Packit Service d328f3
		if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->sortable), &iter)) {
Packit Service d328f3
			path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->sortable), &iter);
Packit Service d328f3
			gtk_tree_view_scroll_to_cell (priv->connection_list,
Packit Service d328f3
			                              path, NULL,
Packit Service d328f3
			                              FALSE, 0, 0);
Packit Service d328f3
			gtk_tree_path_free (path);
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		priv->populated = TRUE;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	gtk_window_present (GTK_WINDOW (list));
Packit Service d328f3
}