Blame src/connection-editor/page-ip6.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
 * Dan Williams <dcbw@redhat.com>
Packit Service d328f3
 *
Packit Service d328f3
 * Copyright 2008 - 2014 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 <errno.h>
Packit Service d328f3
#include <stdlib.h>
Packit Service d328f3
#include <gdk/gdkkeysyms.h>
Packit Service d328f3
#include <sys/socket.h>
Packit Service d328f3
#include <netinet/in.h>
Packit Service d328f3
#include <arpa/inet.h>
Packit Service d328f3
Packit Service d328f3
#include "page-ip6.h"
Packit Service d328f3
#include "ip6-routes-dialog.h"
Packit Service d328f3
#include "ce-utils.h"
Packit Service d328f3
Packit Service d328f3
G_DEFINE_TYPE (CEPageIP6, ce_page_ip6, CE_TYPE_PAGE)
Packit Service d328f3
Packit Service d328f3
#define CE_PAGE_IP6_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CE_TYPE_PAGE_IP6, CEPageIP6Private))
Packit Service d328f3
Packit Service d328f3
#define COL_ADDRESS 0
Packit Service d328f3
#define COL_PREFIX 1
Packit Service d328f3
#define COL_GATEWAY 2
Packit Service d328f3
#define COL_LAST COL_GATEWAY
Packit Service d328f3
Packit Service d328f3
/* Disabled method was added in NM 1.20 */
Packit Service d328f3
#ifndef NM_SETTING_IP6_CONFIG_METHOD_DISABLED
Packit Service d328f3
#define NM_SETTING_IP6_CONFIG_METHOD_DISABLED "disabled"
Packit Service d328f3
#endif
Packit Service d328f3
Packit Service d328f3
typedef struct {
Packit Service d328f3
	NMSettingIPConfig *setting;
Packit Service d328f3
	char *connection_id;
Packit Service d328f3
	GType connection_type;
Packit Service d328f3
Packit Service d328f3
	GtkComboBox *method;
Packit Service d328f3
	GtkListStore *method_store;
Packit Service d328f3
	int normal_method_idx;
Packit Service d328f3
	int hotspot_method_idx;
Packit Service d328f3
Packit Service d328f3
	/* Addresses */
Packit Service d328f3
	GtkWidget *addr_label;
Packit Service d328f3
	GtkButton *addr_add;
Packit Service d328f3
	GtkButton *addr_delete;
Packit Service d328f3
	GtkTreeView *addr_list;
Packit Service d328f3
	GtkCellRenderer *addr_cells[COL_LAST + 1];
Packit Service d328f3
	GtkTreeModel *addr_saved;
Packit Service d328f3
Packit Service d328f3
	/* DNS servers */
Packit Service d328f3
	GtkWidget *dns_servers_label;
Packit Service d328f3
	GtkEntry *dns_servers;
Packit Service d328f3
Packit Service d328f3
	/* Search domains */
Packit Service d328f3
	GtkWidget *dns_searches_label;
Packit Service d328f3
	GtkEntry *dns_searches;
Packit Service d328f3
Packit Service d328f3
	/* Routes */
Packit Service d328f3
	GtkButton *routes_button;
Packit Service d328f3
Packit Service d328f3
	/* IPv6 privacy extensions combo */
Packit Service d328f3
	GtkWidget *ip6_privacy_label;
Packit Service d328f3
	GtkComboBox *ip6_privacy_combo;
Packit Service d328f3
Packit Service d328f3
	GtkWidget *ip6_addr_gen_mode_label;
Packit Service d328f3
	GtkComboBox *ip6_addr_gen_mode_combo;
Packit Service d328f3
Packit Service d328f3
	/* IPv6 required */
Packit Service d328f3
	GtkCheckButton *ip6_required;
Packit Service d328f3
Packit Service d328f3
	GtkWindowGroup *window_group;
Packit Service d328f3
	gboolean window_added;
Packit Service d328f3
Packit Service d328f3
	/* Cached tree view entry for editing-canceled */
Packit Service d328f3
	/* Used also for saving old value when switching between cells via mouse
Packit Service d328f3
	 * clicks - GTK3 produces neither editing-canceled nor editing-done for
Packit Service d328f3
	 * that :( */
Packit Service d328f3
	char *last_edited; /* cell text */
Packit Service d328f3
	char *last_path;   /* row in treeview */
Packit Service d328f3
	int last_column;   /* column in treeview */
Packit Service d328f3
} CEPageIP6Private;
Packit Service d328f3
Packit Service d328f3
#define METHOD_COL_NAME 0
Packit Service d328f3
#define METHOD_COL_NUM  1
Packit Service d328f3
#define METHOD_COL_ENABLED 2
Packit Service d328f3
Packit Service d328f3
#define IP6_METHOD_IGNORE          0
Packit Service d328f3
#define IP6_METHOD_AUTO            1
Packit Service d328f3
#define IP6_METHOD_AUTO_ADDRESSES  2
Packit Service d328f3
#define IP6_METHOD_AUTO_DHCP_ONLY  3
Packit Service d328f3
#define IP6_METHOD_MANUAL          4
Packit Service d328f3
#define IP6_METHOD_LINK_LOCAL      5
Packit Service d328f3
#define IP6_METHOD_SHARED          6
Packit Service d328f3
#define IP6_METHOD_DISABLED        7
Packit Service d328f3
Packit Service d328f3
#define IP6_PRIVACY_DISABLED       0
Packit Service d328f3
#define IP6_PRIVACY_PREFER_PUBLIC  1
Packit Service d328f3
#define IP6_PRIVACY_PREFER_TEMP    2
Packit Service d328f3
Packit Service d328f3
#define IP6_ADDR_GEN_MODE_EUI64    0
Packit Service d328f3
#define IP6_ADDR_GEN_MODE_STABLE   1
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
ip6_private_init (CEPageIP6 *self, NMConnection *connection)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
	GtkBuilder *builder;
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	NMSettingConnection *s_con;
Packit Service d328f3
	const char *connection_type;
Packit Service d328f3
	char *str_auto = NULL, *str_auto_only = NULL;
Packit Service d328f3
	gs_free_list GList *cells = NULL;
Packit Service d328f3
Packit Service d328f3
	builder = CE_PAGE (self)->builder;
Packit Service d328f3
Packit Service d328f3
	s_con = nm_connection_get_setting_connection (connection);
Packit Service d328f3
	g_assert (s_con);
Packit Service d328f3
	connection_type = nm_setting_connection_get_connection_type (s_con);
Packit Service d328f3
	g_assert (connection_type);
Packit Service d328f3
Packit Service d328f3
	priv->connection_type = nm_setting_lookup_type (connection_type);
Packit Service d328f3
Packit Service d328f3
	if (priv->connection_type == NM_TYPE_SETTING_VPN) {
Packit Service d328f3
		str_auto = _("Automatic (VPN)");
Packit Service d328f3
		str_auto_only = _("Automatic (VPN) addresses only");
Packit Service d328f3
	} else if (priv->connection_type == NM_TYPE_SETTING_PPPOE) {
Packit Service d328f3
		str_auto = _("Automatic (PPPoE)");
Packit Service d328f3
		str_auto_only = _("Automatic (PPPoE) addresses only");
Packit Service d328f3
	} else {
Packit Service d328f3
		str_auto = _("Automatic");
Packit Service d328f3
		str_auto_only = _("Automatic, addresses only");
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	priv->method = GTK_COMBO_BOX (gtk_builder_get_object (builder, "ip6_method"));
Packit Service d328f3
	cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (priv->method));
Packit Service d328f3
	gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (priv->method), cells->data,
Packit Service d328f3
	                               "sensitive", METHOD_COL_ENABLED);
Packit Service d328f3
Packit Service d328f3
	priv->method_store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_BOOLEAN);
Packit Service d328f3
Packit Service d328f3
	gtk_list_store_append (priv->method_store, &iter);
Packit Service d328f3
	gtk_list_store_set (priv->method_store, &iter,
Packit Service d328f3
	                    METHOD_COL_NAME, _("Ignore"),
Packit Service d328f3
	                    METHOD_COL_NUM, IP6_METHOD_IGNORE,
Packit Service d328f3
	                    METHOD_COL_ENABLED, TRUE,
Packit Service d328f3
	                    -1);
Packit Service d328f3
Packit Service d328f3
	gtk_list_store_append (priv->method_store, &iter);
Packit Service d328f3
	gtk_list_store_set (priv->method_store, &iter,
Packit Service d328f3
	                    METHOD_COL_NAME, str_auto,
Packit Service d328f3
	                    METHOD_COL_NUM, IP6_METHOD_AUTO,
Packit Service d328f3
	                    METHOD_COL_ENABLED, TRUE,
Packit Service d328f3
	                    -1);
Packit Service d328f3
Packit Service d328f3
	gtk_list_store_append (priv->method_store, &iter);
Packit Service d328f3
	gtk_list_store_set (priv->method_store, &iter,
Packit Service d328f3
	                    METHOD_COL_NAME, str_auto_only,
Packit Service d328f3
	                    METHOD_COL_NUM, IP6_METHOD_AUTO_ADDRESSES,
Packit Service d328f3
	                    METHOD_COL_ENABLED, TRUE,
Packit Service d328f3
	                    -1);
Packit Service d328f3
Packit Service d328f3
	/* DHCP only used on Wi-Fi and ethernet for now */
Packit Service d328f3
	if (   priv->connection_type == NM_TYPE_SETTING_WIRED
Packit Service d328f3
	    || priv->connection_type == NM_TYPE_SETTING_WIRELESS) {
Packit Service d328f3
		gtk_list_store_append (priv->method_store, &iter);
Packit Service d328f3
		gtk_list_store_set (priv->method_store, &iter,
Packit Service d328f3
		                    METHOD_COL_NAME, _("Automatic, DHCP only"),
Packit Service d328f3
		                    METHOD_COL_NUM, IP6_METHOD_AUTO_DHCP_ONLY,
Packit Service d328f3
		                    METHOD_COL_ENABLED, TRUE,
Packit Service d328f3
		                    -1);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* Manual is pointless for Mobile Broadband */
Packit Service d328f3
	if (   priv->connection_type != NM_TYPE_SETTING_GSM
Packit Service d328f3
	    && priv->connection_type != NM_TYPE_SETTING_CDMA
Packit Service d328f3
	    && priv->connection_type != NM_TYPE_SETTING_VPN) {
Packit Service d328f3
		gtk_list_store_append (priv->method_store, &iter);
Packit Service d328f3
		gtk_list_store_set (priv->method_store, &iter,
Packit Service d328f3
		                    METHOD_COL_NAME, _("Manual"),
Packit Service d328f3
		                    METHOD_COL_NUM, IP6_METHOD_MANUAL,
Packit Service d328f3
		                    METHOD_COL_ENABLED, TRUE,
Packit Service d328f3
		                    -1);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* Link-local is pointless for VPNs, Mobile Broadband, and PPPoE */
Packit Service d328f3
	if (   priv->connection_type != NM_TYPE_SETTING_VPN
Packit Service d328f3
	    && priv->connection_type != NM_TYPE_SETTING_PPPOE
Packit Service d328f3
	    && priv->connection_type != NM_TYPE_SETTING_GSM
Packit Service d328f3
	    && priv->connection_type != NM_TYPE_SETTING_CDMA) {
Packit Service d328f3
		gtk_list_store_append (priv->method_store, &iter);
Packit Service d328f3
		gtk_list_store_set (priv->method_store, &iter,
Packit Service d328f3
		                    METHOD_COL_NAME, _("Link-Local Only"),
Packit Service d328f3
		                    METHOD_COL_NUM, IP6_METHOD_LINK_LOCAL,
Packit Service d328f3
		                    METHOD_COL_ENABLED, TRUE,
Packit Service d328f3
		                    -1);
Packit Service d328f3
Packit Service d328f3
		gtk_list_store_append (priv->method_store, &iter);
Packit Service d328f3
		gtk_list_store_set (priv->method_store, &iter,
Packit Service d328f3
		                    METHOD_COL_NAME, _("Shared to other computers"),
Packit Service d328f3
		                    METHOD_COL_NUM, IP6_METHOD_SHARED,
Packit Service d328f3
		                    METHOD_COL_ENABLED, TRUE,
Packit Service d328f3
		                    -1);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	gtk_list_store_append (priv->method_store, &iter);
Packit Service d328f3
	gtk_list_store_set (priv->method_store, &iter,
Packit Service d328f3
	                    METHOD_COL_NAME, _("Disabled"),
Packit Service d328f3
	                    METHOD_COL_NUM, IP6_METHOD_DISABLED,
Packit Service d328f3
	                    METHOD_COL_ENABLED, TRUE,
Packit Service d328f3
	                    -1);
Packit Service d328f3
Packit Service d328f3
	gtk_combo_box_set_model (priv->method, GTK_TREE_MODEL (priv->method_store));
Packit Service d328f3
Packit Service d328f3
	priv->addr_label = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_addr_label"));
Packit Service d328f3
	priv->addr_add = GTK_BUTTON (gtk_builder_get_object (builder, "ip6_addr_add_button"));
Packit Service d328f3
	priv->addr_delete = GTK_BUTTON (gtk_builder_get_object (builder, "ip6_addr_delete_button"));
Packit Service d328f3
	priv->addr_list = GTK_TREE_VIEW (gtk_builder_get_object (builder, "ip6_addresses"));
Packit Service d328f3
Packit Service d328f3
	priv->dns_servers_label = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_dns_servers_label"));
Packit Service d328f3
	priv->dns_servers = GTK_ENTRY (gtk_builder_get_object (builder, "ip6_dns_servers_entry"));
Packit Service d328f3
Packit Service d328f3
	priv->dns_searches_label = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_dns_searches_label"));
Packit Service d328f3
	priv->dns_searches = GTK_ENTRY (gtk_builder_get_object (builder, "ip6_dns_searches_entry"));
Packit Service d328f3
Packit Service d328f3
	priv->ip6_privacy_label = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_privacy_label"));
Packit Service d328f3
	priv->ip6_privacy_combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, "ip6_privacy_combo"));
Packit Service d328f3
Packit Service d328f3
	priv->ip6_addr_gen_mode_label = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_addr_gen_mode_label"));
Packit Service d328f3
	priv->ip6_addr_gen_mode_combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, "ip6_addr_gen_mode_combo"));
Packit Service d328f3
Packit Service d328f3
	priv->ip6_required = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "ip6_required_checkbutton"));
Packit Service d328f3
	/* Hide IP6-require button if it'll never be used for a particular method */
Packit Service d328f3
	if (   priv->connection_type == NM_TYPE_SETTING_VPN
Packit Service d328f3
	    || priv->connection_type == NM_TYPE_SETTING_GSM
Packit Service d328f3
	    || priv->connection_type == NM_TYPE_SETTING_CDMA
Packit Service d328f3
	    || priv->connection_type == NM_TYPE_SETTING_PPPOE)
Packit Service d328f3
		gtk_widget_hide (GTK_WIDGET (priv->ip6_required));
Packit Service d328f3
Packit Service d328f3
	priv->routes_button = GTK_BUTTON (gtk_builder_get_object (builder, "ip6_routes_button"));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
method_changed (GtkComboBox *combo, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (user_data);
Packit Service d328f3
	guint32 method = IP6_METHOD_AUTO;
Packit Service d328f3
	gboolean addr_enabled = FALSE;
Packit Service d328f3
	gboolean dns_enabled = FALSE;
Packit Service d328f3
	gboolean routes_enabled = FALSE;
Packit Service d328f3
	gboolean ip6_privacy_enabled = FALSE;
Packit Service d328f3
	gboolean ip6_addr_gen_mode_enabled = TRUE;
Packit Service d328f3
	gboolean ip6_required_enabled = TRUE;
Packit Service d328f3
	gboolean method_auto = FALSE;
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	GtkListStore *store;
Packit Service d328f3
	const char *tooltip = NULL, *label = NULL;
Packit Service d328f3
Packit Service d328f3
	if (gtk_combo_box_get_active_iter (priv->method, &iter)) {
Packit Service d328f3
		gtk_tree_model_get (GTK_TREE_MODEL (priv->method_store), &iter,
Packit Service d328f3
		                    METHOD_COL_NUM, &method, -1);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	switch (method) {
Packit Service d328f3
	case IP6_METHOD_AUTO:
Packit Service d328f3
		addr_enabled = TRUE;
Packit Service d328f3
		routes_enabled = TRUE;
Packit Service d328f3
		dns_enabled = TRUE;
Packit Service d328f3
		method_auto = TRUE;
Packit Service d328f3
		ip6_privacy_enabled = TRUE;
Packit Service d328f3
		tooltip = CE_TOOLTIP_ADDR_AUTO;
Packit Service d328f3
		label = CE_LABEL_ADDR_AUTO;
Packit Service d328f3
		break;
Packit Service d328f3
	case IP6_METHOD_AUTO_ADDRESSES:
Packit Service d328f3
		addr_enabled = TRUE;
Packit Service d328f3
		dns_enabled = routes_enabled = TRUE;
Packit Service d328f3
		ip6_privacy_enabled = TRUE;
Packit Service d328f3
		tooltip = CE_TOOLTIP_ADDR_AUTO;
Packit Service d328f3
		label = CE_LABEL_ADDR_AUTO;
Packit Service d328f3
		break;
Packit Service d328f3
	case IP6_METHOD_AUTO_DHCP_ONLY:
Packit Service d328f3
		addr_enabled = TRUE;
Packit Service d328f3
		routes_enabled = TRUE;
Packit Service d328f3
		tooltip = CE_TOOLTIP_ADDR_AUTO;
Packit Service d328f3
		label = CE_LABEL_ADDR_AUTO;
Packit Service d328f3
		break;
Packit Service d328f3
	case IP6_METHOD_MANUAL:
Packit Service d328f3
		addr_enabled = dns_enabled = routes_enabled = TRUE;
Packit Service d328f3
		tooltip = CE_TOOLTIP_ADDR_MANUAL;
Packit Service d328f3
		label = CE_LABEL_ADDR_MANUAL;
Packit Service d328f3
		break;
Packit Service d328f3
	case IP6_METHOD_SHARED:
Packit Service d328f3
		addr_enabled = dns_enabled = routes_enabled = TRUE;
Packit Service d328f3
		tooltip = CE_TOOLTIP_ADDR_SHARED;
Packit Service d328f3
		label = CE_LABEL_ADDR_SHARED;
Packit Service d328f3
		break;
Packit Service d328f3
	case IP6_METHOD_IGNORE:
Packit Service d328f3
	case IP6_METHOD_DISABLED:
Packit Service d328f3
		ip6_required_enabled = FALSE;
Packit Service d328f3
		ip6_addr_gen_mode_enabled = FALSE;
Packit Service d328f3
		break;
Packit Service d328f3
	default:
Packit Service d328f3
		break;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	gtk_widget_set_tooltip_text (GTK_WIDGET (priv->addr_list), tooltip);
Packit Service d328f3
	gtk_label_set_text (GTK_LABEL (priv->addr_label), label);
Packit Service d328f3
Packit Service d328f3
	gtk_widget_set_sensitive (priv->addr_label, addr_enabled);
Packit Service d328f3
	gtk_widget_set_sensitive (GTK_WIDGET (priv->addr_add), addr_enabled);
Packit Service d328f3
	gtk_widget_set_sensitive (GTK_WIDGET (priv->addr_delete), addr_enabled);
Packit Service d328f3
	gtk_widget_set_sensitive (GTK_WIDGET (priv->addr_list), addr_enabled);
Packit Service d328f3
Packit Service d328f3
	if (addr_enabled) {
Packit Service d328f3
		if (priv->addr_saved) {
Packit Service d328f3
			/* Restore old entries */
Packit Service d328f3
			gtk_tree_view_set_model (priv->addr_list, priv->addr_saved);
Packit Service d328f3
			g_clear_object (&priv->addr_saved);
Packit Service d328f3
		}
Packit Service d328f3
	} else {
Packit Service d328f3
		if (!priv->addr_saved) {
Packit Service d328f3
			/* Save current entries, set empty list */
Packit Service d328f3
			priv->addr_saved = g_object_ref (gtk_tree_view_get_model (priv->addr_list));
Packit Service d328f3
			store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
Packit Service d328f3
			gtk_tree_view_set_model (priv->addr_list, GTK_TREE_MODEL (store));
Packit Service d328f3
			g_object_unref (store);
Packit Service d328f3
		}
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	gtk_widget_set_sensitive (priv->dns_servers_label, dns_enabled);
Packit Service d328f3
	if (method_auto)
Packit Service d328f3
		gtk_label_set_text_with_mnemonic (GTK_LABEL (priv->dns_servers_label), _("Additional DNS ser_vers"));
Packit Service d328f3
	else
Packit Service d328f3
		gtk_label_set_text_with_mnemonic (GTK_LABEL (priv->dns_servers_label), _("DNS ser_vers"));
Packit Service d328f3
	gtk_widget_set_sensitive (GTK_WIDGET (priv->dns_servers), dns_enabled);
Packit Service d328f3
	if (!dns_enabled)
Packit Service d328f3
		gtk_entry_set_text (priv->dns_servers, "");
Packit Service d328f3
Packit Service d328f3
	gtk_widget_set_sensitive (priv->dns_searches_label, dns_enabled);
Packit Service d328f3
	if (method_auto)
Packit Service d328f3
		gtk_label_set_text_with_mnemonic (GTK_LABEL (priv->dns_searches_label), _("Additional s_earch domains"));
Packit Service d328f3
	else
Packit Service d328f3
		gtk_label_set_text_with_mnemonic (GTK_LABEL (priv->dns_searches_label), _("S_earch domains"));
Packit Service d328f3
	gtk_widget_set_sensitive (GTK_WIDGET (priv->dns_searches), dns_enabled);
Packit Service d328f3
	if (!dns_enabled)
Packit Service d328f3
		gtk_entry_set_text (priv->dns_searches, "");
Packit Service d328f3
Packit Service d328f3
	gtk_widget_set_sensitive (priv->ip6_privacy_label, ip6_privacy_enabled);
Packit Service d328f3
	gtk_widget_set_sensitive (GTK_WIDGET (priv->ip6_privacy_combo), ip6_privacy_enabled);
Packit Service d328f3
Packit Service d328f3
	gtk_widget_set_sensitive (priv->ip6_addr_gen_mode_label, ip6_addr_gen_mode_enabled);
Packit Service d328f3
	gtk_widget_set_sensitive (GTK_WIDGET (priv->ip6_addr_gen_mode_combo), ip6_addr_gen_mode_enabled);
Packit Service d328f3
Packit Service d328f3
	gtk_widget_set_sensitive (GTK_WIDGET (priv->ip6_required), ip6_required_enabled);
Packit Service d328f3
Packit Service d328f3
	gtk_widget_set_sensitive (GTK_WIDGET (priv->routes_button), routes_enabled);
Packit Service d328f3
Packit Service d328f3
	ce_page_changed (CE_PAGE (user_data));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
typedef struct {
Packit Service d328f3
	int method;
Packit Service d328f3
	GtkComboBox *combo;
Packit Service d328f3
} SetMethodInfo;
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
set_method (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	SetMethodInfo *info = (SetMethodInfo *) user_data;
Packit Service d328f3
	int method = 0;
Packit Service d328f3
Packit Service d328f3
	gtk_tree_model_get (model, iter, METHOD_COL_NUM, &method, -1);
Packit Service d328f3
	if (method == info->method) {
Packit Service d328f3
		gtk_combo_box_set_active_iter (info->combo, iter);
Packit Service d328f3
		return TRUE;
Packit Service d328f3
	}
Packit Service d328f3
	return FALSE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
populate_ui (CEPageIP6 *self)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
	NMSettingIPConfig *setting = priv->setting;
Packit Service d328f3
	GtkListStore *store;
Packit Service d328f3
	GtkTreeIter model_iter;
Packit Service d328f3
	int method = IP6_METHOD_AUTO;
Packit Service d328f3
	NMSettingIP6ConfigPrivacy ip6_privacy;
Packit Service d328f3
	int ip6_privacy_idx = IP6_PRIVACY_DISABLED;
Packit Service d328f3
	NMSettingIP6ConfigAddrGenMode ip6_addr_gen_mode;
Packit Service d328f3
	int ip6_addr_gen_mode_idx;
Packit Service d328f3
	GString *string = NULL;
Packit Service d328f3
	SetMethodInfo info;
Packit Service d328f3
	const char *str_method;
Packit Service d328f3
	int i;
Packit Service d328f3
Packit Service d328f3
	/* Method */
Packit Service d328f3
	gtk_combo_box_set_active (priv->method, 0);
Packit Service d328f3
	str_method = nm_setting_ip_config_get_method (setting);
Packit Service d328f3
	if (str_method) {
Packit Service d328f3
		if (!strcmp (str_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE))
Packit Service d328f3
			method = IP6_METHOD_IGNORE;
Packit Service d328f3
		if (!strcmp (str_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO))
Packit Service d328f3
			method = IP6_METHOD_AUTO;
Packit Service d328f3
		if (!strcmp (str_method, NM_SETTING_IP6_CONFIG_METHOD_DHCP))
Packit Service d328f3
			method = IP6_METHOD_AUTO_DHCP_ONLY;
Packit Service d328f3
		else if (!strcmp (str_method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL))
Packit Service d328f3
			method = IP6_METHOD_LINK_LOCAL;
Packit Service d328f3
		else if (!strcmp (str_method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL))
Packit Service d328f3
			method = IP6_METHOD_MANUAL;
Packit Service d328f3
		else if (!strcmp (str_method, NM_SETTING_IP6_CONFIG_METHOD_SHARED))
Packit Service d328f3
			method = IP6_METHOD_SHARED;
Packit Service d328f3
		else if (!strcmp (str_method, NM_SETTING_IP6_CONFIG_METHOD_DISABLED))
Packit Service d328f3
			method = IP6_METHOD_DISABLED;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (method == IP6_METHOD_AUTO && nm_setting_ip_config_get_ignore_auto_dns (setting))
Packit Service d328f3
		method = IP6_METHOD_AUTO_ADDRESSES;
Packit Service d328f3
Packit Service d328f3
	info.method = method;
Packit Service d328f3
	info.combo = priv->method;
Packit Service d328f3
	gtk_tree_model_foreach (GTK_TREE_MODEL (priv->method_store), set_method, &info;;
Packit Service d328f3
Packit Service d328f3
	/* Addresses */
Packit Service d328f3
	store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
Packit Service d328f3
	for (i = 0; i < nm_setting_ip_config_get_num_addresses (setting); i++) {
Packit Service d328f3
		NMIPAddress *addr = nm_setting_ip_config_get_address (setting, i);
Packit Service d328f3
		char buf[32];
Packit Service d328f3
Packit Service d328f3
		if (!addr) {
Packit Service d328f3
			g_warning ("%s: empty IP6 Address structure!", __func__);
Packit Service d328f3
			continue;
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		snprintf (buf, sizeof (buf), "%u", nm_ip_address_get_prefix (addr));
Packit Service d328f3
Packit Service d328f3
		gtk_list_store_append (store, &model_iter);
Packit Service d328f3
		gtk_list_store_set (store, &model_iter,
Packit Service d328f3
		                    COL_ADDRESS, nm_ip_address_get_address (addr),
Packit Service d328f3
		                    COL_PREFIX, buf,
Packit Service d328f3
		                    /* FIXME */
Packit Service d328f3
		                    COL_GATEWAY, i == 0 ? nm_setting_ip_config_get_gateway (setting) : NULL,
Packit Service d328f3
		                    -1);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	gtk_tree_view_set_model (priv->addr_list, GTK_TREE_MODEL (store));
Packit Service d328f3
	g_signal_connect_swapped (store, "row-inserted", G_CALLBACK (ce_page_changed), self);
Packit Service d328f3
	g_signal_connect_swapped (store, "row-deleted", G_CALLBACK (ce_page_changed), self);
Packit Service d328f3
	g_object_unref (store);
Packit Service d328f3
Packit Service d328f3
	/* DNS servers */
Packit Service d328f3
	string = g_string_new ("");
Packit Service d328f3
	for (i = 0; i < nm_setting_ip_config_get_num_dns (setting); i++) {
Packit Service d328f3
		const char *dns;
Packit Service d328f3
Packit Service d328f3
		dns = nm_setting_ip_config_get_dns (setting, i);
Packit Service d328f3
		if (!dns)
Packit Service d328f3
			continue;
Packit Service d328f3
Packit Service d328f3
		if (string->len)
Packit Service d328f3
			g_string_append (string, ", ");
Packit Service d328f3
		g_string_append (string, dns);
Packit Service d328f3
	}
Packit Service d328f3
	gtk_entry_set_text (priv->dns_servers, string->str);
Packit Service d328f3
	g_string_free (string, TRUE);
Packit Service d328f3
Packit Service d328f3
	/* DNS searches */
Packit Service d328f3
	string = g_string_new ("");
Packit Service d328f3
	for (i = 0; i < nm_setting_ip_config_get_num_dns_searches (setting); i++) {
Packit Service d328f3
		if (string->len)
Packit Service d328f3
			g_string_append (string, ", ");
Packit Service d328f3
		g_string_append (string, nm_setting_ip_config_get_dns_search (setting, i));
Packit Service d328f3
	}
Packit Service d328f3
	gtk_entry_set_text (priv->dns_searches, string->str);
Packit Service d328f3
	g_string_free (string, TRUE);
Packit Service d328f3
Packit Service d328f3
	/* IPv6 privacy extensions */
Packit Service d328f3
	ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (setting));
Packit Service d328f3
	switch (ip6_privacy) {
Packit Service d328f3
	case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED:
Packit Service d328f3
		ip6_privacy_idx = IP6_PRIVACY_DISABLED;
Packit Service d328f3
		break;
Packit Service d328f3
	case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR:
Packit Service d328f3
		ip6_privacy_idx = IP6_PRIVACY_PREFER_PUBLIC;
Packit Service d328f3
		break;
Packit Service d328f3
	case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR:
Packit Service d328f3
		ip6_privacy_idx = IP6_PRIVACY_PREFER_TEMP;
Packit Service d328f3
		break;
Packit Service d328f3
	default:
Packit Service d328f3
		ip6_privacy_idx = IP6_PRIVACY_DISABLED;
Packit Service d328f3
		break;
Packit Service d328f3
	}
Packit Service d328f3
	gtk_combo_box_set_active (priv->ip6_privacy_combo, ip6_privacy_idx);
Packit Service d328f3
Packit Service d328f3
	ip6_addr_gen_mode = nm_setting_ip6_config_get_addr_gen_mode (NM_SETTING_IP6_CONFIG (setting));
Packit Service d328f3
	if (ip6_addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64)
Packit Service d328f3
		ip6_addr_gen_mode_idx = IP6_ADDR_GEN_MODE_EUI64;
Packit Service d328f3
	else
Packit Service d328f3
		ip6_addr_gen_mode_idx = IP6_ADDR_GEN_MODE_STABLE;
Packit Service d328f3
	gtk_combo_box_set_active (priv->ip6_addr_gen_mode_combo, ip6_addr_gen_mode_idx);
Packit Service d328f3
Packit Service d328f3
	/* IPv6 required */
Packit Service d328f3
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->ip6_required),
Packit Service d328f3
	                              !nm_setting_ip_config_get_may_fail (setting));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
is_prefix_valid (const char *prefix_str, guint32 *out_prefix)
Packit Service d328f3
{
Packit Service d328f3
	guint32 prefix;
Packit Service d328f3
	char *end;
Packit Service d328f3
Packit Service d328f3
	if (!prefix_str || !*prefix_str)
Packit Service d328f3
		return FALSE;
Packit Service d328f3
Packit Service d328f3
	prefix = strtoul (prefix_str, &end, 10);
Packit Service d328f3
	if (!end || *end || prefix == 0 || prefix > 128)
Packit Service d328f3
		return FALSE;
Packit Service d328f3
	else {
Packit Service d328f3
		if (out_prefix)
Packit Service d328f3
			*out_prefix = prefix;
Packit Service d328f3
		return TRUE;
Packit Service d328f3
	}
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
is_address_unspecified (const char *str)
Packit Service d328f3
{
Packit Service d328f3
	struct in6_addr addr;
Packit Service d328f3
Packit Service d328f3
	if (!str)
Packit Service d328f3
		return FALSE;
Packit Service d328f3
Packit Service d328f3
	return (   inet_pton (AF_INET6, str, &addr) == 1
Packit Service d328f3
	        && IN6_IS_ADDR_UNSPECIFIED (&addr));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
addr_add_clicked (GtkButton *button, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (user_data);
Packit Service d328f3
	GtkListStore *store;
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	GtkTreeSelection *selection;
Packit Service d328f3
	GtkTreeViewColumn *column;
Packit Service d328f3
	GtkTreePath *path;
Packit Service d328f3
	GList *cells;
Packit Service d328f3
Packit Service d328f3
	store = GTK_LIST_STORE (gtk_tree_view_get_model (priv->addr_list));
Packit Service d328f3
	gtk_list_store_append (store, &iter);
Packit Service d328f3
	gtk_list_store_set (store, &iter, COL_ADDRESS, "", -1);
Packit Service d328f3
Packit Service d328f3
	selection = gtk_tree_view_get_selection (priv->addr_list);
Packit Service d328f3
	gtk_tree_selection_select_iter (selection, &iter);
Packit Service d328f3
Packit Service d328f3
	path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
Packit Service d328f3
	column = gtk_tree_view_get_column (priv->addr_list, COL_ADDRESS);
Packit Service d328f3
Packit Service d328f3
	/* FIXME: using cells->data is pretty fragile but GTK apparently doesn't
Packit Service d328f3
	 * have a way to get a cell renderer from a column based on path or iter
Packit Service d328f3
	 * or whatever.
Packit Service d328f3
	 */
Packit Service d328f3
	cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
Packit Service d328f3
	gtk_tree_view_set_cursor_on_cell (priv->addr_list, path, column, cells->data, TRUE);
Packit Service d328f3
Packit Service d328f3
	g_list_free (cells);
Packit Service d328f3
	gtk_tree_path_free (path);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
addr_delete_clicked (GtkButton *button, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	GtkTreeView *treeview = GTK_TREE_VIEW (user_data);
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
	int num_rows;
Packit Service d328f3
Packit Service d328f3
	selection = gtk_tree_view_get_selection (treeview);
Packit Service d328f3
	if (gtk_tree_selection_count_selected_rows (selection) != 1)
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
Packit Service d328f3
	if (!selected_rows)
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	if (gtk_tree_model_get_iter (model, &iter, (GtkTreePath *) selected_rows->data))
Packit Service d328f3
		gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
Packit Service d328f3
Packit Service d328f3
	g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
Packit Service d328f3
Packit Service d328f3
	num_rows = gtk_tree_model_iter_n_children (model, NULL);
Packit Service d328f3
	if (num_rows && gtk_tree_model_iter_nth_child (model, &iter, NULL, num_rows - 1)) {
Packit Service d328f3
		selection = gtk_tree_view_get_selection (treeview);
Packit Service d328f3
		gtk_tree_selection_select_iter (selection, &iter);
Packit Service d328f3
	}
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
list_selection_changed (GtkTreeSelection *selection, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	GtkWidget *button = GTK_WIDGET (user_data);
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	GtkTreeModel *model = NULL;
Packit Service d328f3
Packit Service d328f3
	if (gtk_tree_selection_get_selected (selection, &model, &iter))
Packit Service d328f3
		gtk_widget_set_sensitive (button, TRUE);
Packit Service d328f3
	else
Packit Service d328f3
		gtk_widget_set_sensitive (button, FALSE);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
cell_editing_canceled (GtkCellRenderer *renderer, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self;
Packit Service d328f3
	CEPageIP6Private *priv;
Packit Service d328f3
	GtkTreeModel *model = NULL;
Packit Service d328f3
	GtkTreeSelection *selection;
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	guint32 column;
Packit Service d328f3
Packit Service d328f3
	/* user_data disposed? */
Packit Service d328f3
	if (GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (renderer), "ce-page-not-valid")))
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	self = CE_PAGE_IP6 (user_data);
Packit Service d328f3
	priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
Packit Service d328f3
	if (priv->last_edited) {
Packit Service d328f3
		selection = gtk_tree_view_get_selection (priv->addr_list);
Packit Service d328f3
		if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
Packit Service d328f3
			column = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (renderer), "column"));
Packit Service d328f3
			gtk_list_store_set (GTK_LIST_STORE (model), &iter, column, priv->last_edited, -1);
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		g_free (priv->last_edited);
Packit Service d328f3
		priv->last_edited = NULL;
Packit Service d328f3
Packit Service d328f3
		ce_page_changed (CE_PAGE (self));
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	g_free (priv->last_path);
Packit Service d328f3
	priv->last_path = NULL;
Packit Service d328f3
	priv->last_column = -1;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
#define DO_NOT_CYCLE_TAG "do-not-cycle"
Packit Service d328f3
#define DIRECTION_TAG    "direction"
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
cell_edited (GtkCellRendererText *cell,
Packit Service d328f3
             const gchar *path_string,
Packit Service d328f3
             const gchar *new_text,
Packit Service d328f3
             gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self = CE_PAGE_IP6 (user_data);
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
	GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (priv->addr_list));
Packit Service d328f3
	GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	guint32 column;
Packit Service d328f3
	GtkTreeViewColumn *next_col;
Packit Service d328f3
	GtkCellRenderer *next_cell;
Packit Service d328f3
	gboolean can_cycle;
Packit Service d328f3
	int direction, tmp;
Packit Service d328f3
Packit Service d328f3
	/* Free auxiliary stuff */
Packit Service d328f3
	g_free (priv->last_edited);
Packit Service d328f3
	priv->last_edited = NULL;
Packit Service d328f3
	g_free (priv->last_path);
Packit Service d328f3
	priv->last_path = NULL;
Packit Service d328f3
	priv->last_column = -1;
Packit Service d328f3
Packit Service d328f3
	column = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (cell), "column"));
Packit Service d328f3
	gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
Packit Service d328f3
	gtk_list_store_set (store, &iter, column, new_text, -1);
Packit Service d328f3
Packit Service d328f3
	/* Move focus to the next/previous column */
Packit Service d328f3
	can_cycle = g_object_get_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG) == NULL;
Packit Service d328f3
	direction = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), DIRECTION_TAG));
Packit Service d328f3
	g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, NULL);
Packit Service d328f3
	g_object_set_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG, NULL);
Packit Service d328f3
	if (direction == 0)  /* Move forward by default */
Packit Service d328f3
		direction = 1;
Packit Service d328f3
Packit Service d328f3
	tmp = column + direction;
Packit Service d328f3
	if (can_cycle)
Packit Service d328f3
		column = tmp < 0 ? COL_LAST : tmp > COL_LAST ? 0 : tmp;
Packit Service d328f3
	else
Packit Service d328f3
		column = tmp;
Packit Service d328f3
	next_col = gtk_tree_view_get_column (priv->addr_list, column);
Packit Service d328f3
	next_cell = column <= COL_LAST ? priv->addr_cells[column] : NULL;
Packit Service d328f3
	gtk_tree_view_set_cursor_on_cell (priv->addr_list, path, next_col, next_cell, TRUE);
Packit Service d328f3
Packit Service d328f3
	gtk_tree_path_free (path);
Packit Service d328f3
	ce_page_changed (CE_PAGE (self));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
ip_address_filter_cb (GtkEditable *editable,
Packit Service d328f3
                      gchar *text,
Packit Service d328f3
                      gint length,
Packit Service d328f3
                      gint *position,
Packit Service d328f3
                      gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self = CE_PAGE_IP6 (user_data);
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
	guint column;
Packit Service d328f3
	gboolean changed;
Packit Service d328f3
Packit Service d328f3
Packit Service d328f3
	/* The prefix column only allows numbers, no ':' */
Packit Service d328f3
	column = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (editable), "column"));
Packit Service d328f3
Packit Service d328f3
	changed = utils_filter_editable_on_insert_text (editable,
Packit Service d328f3
	                                                text, length, position, user_data,
Packit Service d328f3
	                                                column == COL_PREFIX ? utils_char_is_ascii_digit : utils_char_is_ascii_ip6_address,
Packit Service d328f3
	                                                ip_address_filter_cb);
Packit Service d328f3
Packit Service d328f3
	if (changed) {
Packit Service d328f3
		g_free (priv->last_edited);
Packit Service d328f3
		priv->last_edited = gtk_editable_get_chars (editable, 0, -1);
Packit Service d328f3
	}
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
_char_is_ascii_dns_servers (char character)
Packit Service d328f3
{
Packit Service d328f3
	return utils_char_is_ascii_ip6_address (character) ||
Packit Service d328f3
	       character == ' ' ||
Packit Service d328f3
	       character == ',' ||
Packit Service d328f3
	       character == ';';
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
dns_servers_filter_cb (GtkEditable *editable,
Packit Service d328f3
                       gchar *text,
Packit Service d328f3
                       gint length,
Packit Service d328f3
                       gint *position,
Packit Service d328f3
                       gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	utils_filter_editable_on_insert_text (editable,
Packit Service d328f3
	                                      text, length, position, user_data,
Packit Service d328f3
	                                      _char_is_ascii_dns_servers,
Packit Service d328f3
	                                      dns_servers_filter_cb);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
delete_text_cb (GtkEditable *editable,
Packit Service d328f3
                    gint start_pos,
Packit Service d328f3
                    gint end_pos,
Packit Service d328f3
                    gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self = CE_PAGE_IP6 (user_data);
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
Packit Service d328f3
	/* Keep last_edited up-to-date */
Packit Service d328f3
	g_free (priv->last_edited);
Packit Service d328f3
	priv->last_edited = gtk_editable_get_chars (editable, 0, -1);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
gateway_matches_address (const char *gw_str, const char *addr_str, guint32 prefix)
Packit Service d328f3
{
Packit Service d328f3
	struct in6_addr gw, addr;
Packit Service d328f3
	guint32 x, y, mask;
Packit Service d328f3
	int i;
Packit Service d328f3
Packit Service d328f3
	if (!gw_str || inet_pton (AF_INET6, gw_str, &gw) != 1)
Packit Service d328f3
		return FALSE;
Packit Service d328f3
	if (!addr_str || inet_pton (AF_INET6, addr_str, &addr) != 1)
Packit Service d328f3
		return FALSE;
Packit Service d328f3
Packit Service d328f3
	x = prefix / 32;
Packit Service d328f3
	y = prefix % 32;
Packit Service d328f3
	mask = ~htonl (0xFFFFFFFF >> y);
Packit Service d328f3
	for (i = 0; i < x; i++) {
Packit Service d328f3
		if (addr.s6_addr32[i] != gw.s6_addr32[i])
Packit Service d328f3
			return FALSE;
Packit Service d328f3
	}
Packit Service d328f3
	if ((addr.s6_addr32[i] & mask) != (gw.s6_addr32[i] & mask))
Packit Service d328f3
		return FALSE;
Packit Service d328f3
	return TRUE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
possibly_wrong_gateway (GtkTreeModel *model, GtkTreeIter *iter, const char *gw_str)
Packit Service d328f3
{
Packit Service d328f3
	char *addr_str, *prefix_str;
Packit Service d328f3
	gboolean addr_valid;
Packit Service d328f3
	guint32 prefix;
Packit Service d328f3
Packit Service d328f3
	gtk_tree_model_get (model, iter, COL_ADDRESS, &addr_str, -1);
Packit Service d328f3
	gtk_tree_model_get (model, iter, COL_PREFIX, &prefix_str, -1);
Packit Service d328f3
	addr_valid =   addr_str && *addr_str && nm_utils_ipaddr_valid (AF_INET6, addr_str) && !is_address_unspecified (addr_str)
Packit Service d328f3
	            && is_prefix_valid (prefix_str, &prefix);
Packit Service d328f3
Packit Service d328f3
	if (addr_valid && !gateway_matches_address (gw_str, addr_str, prefix))
Packit Service d328f3
		return TRUE;
Packit Service d328f3
	else
Packit Service d328f3
		return FALSE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
typedef struct {
Packit Service d328f3
	GtkTreeModel *model;
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	guint column;
Packit Service d328f3
} AddressLineInfo;
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
cell_changed_cb (GtkEditable *editable,
Packit Service d328f3
                 gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	AddressLineInfo *info = (AddressLineInfo *) user_data;
Packit Service d328f3
	char *cell_text;
Packit Service d328f3
	GdkRGBA rgba;
Packit Service d328f3
	gboolean value_valid = FALSE;
Packit Service d328f3
	const char *colorname = NULL;
Packit Service d328f3
Packit Service d328f3
	cell_text = gtk_editable_get_chars (editable, 0, -1);
Packit Service d328f3
Packit Service d328f3
	/* The Prefix column is 1..128 */
Packit Service d328f3
	if (info->column == COL_PREFIX)
Packit Service d328f3
		value_valid = is_prefix_valid (cell_text, NULL);
Packit Service d328f3
	else {
Packit Service d328f3
		struct in6_addr tmp_addr;
Packit Service d328f3
Packit Service d328f3
		if (inet_pton (AF_INET6, cell_text, &tmp_addr))
Packit Service d328f3
			value_valid = TRUE;
Packit Service d328f3
Packit Service d328f3
		/* :: is not accepted for address */
Packit Service d328f3
		if (info->column == COL_ADDRESS && IN6_IS_ADDR_UNSPECIFIED (&tmp_addr))
Packit Service d328f3
                        value_valid = FALSE;
Packit Service d328f3
		/* Consider empty gateway as valid */
Packit Service d328f3
		if (!*cell_text && info->column == COL_GATEWAY)
Packit Service d328f3
			value_valid = TRUE;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* Change cell's background color while editing */
Packit Service d328f3
	colorname = value_valid ? "lightgreen" : "red";
Packit Service d328f3
Packit Service d328f3
	/* Check gateway against address and prefix */
Packit Service d328f3
	if (   info->column == COL_GATEWAY
Packit Service d328f3
	    && value_valid
Packit Service d328f3
	    && possibly_wrong_gateway (info->model, &info->iter, cell_text))
Packit Service d328f3
		colorname = "yellow";
Packit Service d328f3
Packit Service d328f3
	gdk_rgba_parse (&rgba, colorname);
Packit Service d328f3
	utils_override_bg_color (GTK_WIDGET (editable), &rgba);
Packit Service d328f3
Packit Service d328f3
	g_free (cell_text);
Packit Service d328f3
	return FALSE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
key_pressed_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	GdkModifierType modifiers;
Packit Service d328f3
	GtkCellRenderer *cell = (GtkCellRenderer *) user_data;
Packit Service d328f3
Packit Service d328f3
	modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
Packit Service d328f3
Packit Service d328f3
	/*
Packit Service d328f3
	 * Change some keys so that they work properly:
Packit Service d328f3
	 * We want:
Packit Service d328f3
	 *   - Tab should behave the same way as Enter (cycling on cells),
Packit Service d328f3
	 *   - Shift-Tab should move in backwards direction.
Packit Service d328f3
	 *   - Down arrow moves as Enter, but we have to handle Down arrow on
Packit Service d328f3
	 *     key pad.
Packit Service d328f3
	 *   - Up arrow should move backwards and we also have to handle Up arrow
Packit Service d328f3
	 *     on key pad.
Packit Service d328f3
	 *   - Enter should end editing when pressed on last column.
Packit Service d328f3
	 *
Packit Service d328f3
	 * Note: gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (widget)) cannot be called
Packit Service d328f3
	 * in this function, because it would crash with XIM input (GTK_IM_MODULE=xim), see
Packit Service d328f3
	 * https://bugzilla.redhat.com/show_bug.cgi?id=747368
Packit Service d328f3
	 */
Packit Service d328f3
Packit Service d328f3
	if (event->keyval == GDK_KEY_Tab && modifiers == 0) {
Packit Service d328f3
		/* Tab */
Packit Service d328f3
		g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (1));
Packit Service d328f3
		utils_fake_return_key (event);
Packit Service d328f3
	} else if (event->keyval == GDK_KEY_ISO_Left_Tab && modifiers == GDK_SHIFT_MASK) {
Packit Service d328f3
		/* Shift-Tab */
Packit Service d328f3
		g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (-1));
Packit Service d328f3
		utils_fake_return_key (event);
Packit Service d328f3
	} else if (event->keyval == GDK_KEY_KP_Down)
Packit Service d328f3
		event->keyval = GDK_KEY_Down;
Packit Service d328f3
	else if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up) {
Packit Service d328f3
		event->keyval = GDK_KEY_Up;
Packit Service d328f3
		g_object_set_data (G_OBJECT (cell), DIRECTION_TAG, GINT_TO_POINTER (-1));
Packit Service d328f3
	} else if (   event->keyval == GDK_KEY_Return
Packit Service d328f3
	           || event->keyval == GDK_KEY_ISO_Enter
Packit Service d328f3
	           || event->keyval == GDK_KEY_KP_Enter)
Packit Service d328f3
		g_object_set_data (G_OBJECT (cell), DO_NOT_CYCLE_TAG, GUINT_TO_POINTER (TRUE));
Packit Service d328f3
Packit Service d328f3
	return FALSE; /* Allow default handler to be called */
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
address_line_info_destroy (gpointer data, GClosure *closure)
Packit Service d328f3
{
Packit Service d328f3
	g_slice_free (AddressLineInfo, data);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
cell_editing_started (GtkCellRenderer *cell,
Packit Service d328f3
                      GtkCellEditable *editable,
Packit Service d328f3
                      const gchar     *path,
Packit Service d328f3
                      gpointer         user_data)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self = CE_PAGE_IP6 (user_data);
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
	guint column;
Packit Service d328f3
	GtkTreeModel *model;
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	AddressLineInfo *info;
Packit Service d328f3
Packit Service d328f3
	if (!GTK_IS_ENTRY (editable)) {
Packit Service d328f3
		g_warning ("%s: Unexpected cell editable type.", __func__);
Packit Service d328f3
		return;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* Initialize last_path and last_column, last_edited is initialized when the cell is edited */
Packit Service d328f3
	g_free (priv->last_edited);
Packit Service d328f3
	priv->last_edited = NULL;
Packit Service d328f3
	g_free (priv->last_path);
Packit Service d328f3
	priv->last_path = g_strdup (path);
Packit Service d328f3
	priv->last_column = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (cell), "column"));
Packit Service d328f3
Packit Service d328f3
	/* Need to pass column # to the editable's insert-text function */	
Packit Service d328f3
	column = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (cell), "column"));
Packit Service d328f3
	g_object_set_data (G_OBJECT (editable), "column", GUINT_TO_POINTER (column));
Packit Service d328f3
Packit Service d328f3
	/* Set up the entry filter */
Packit Service d328f3
	g_signal_connect (G_OBJECT (editable), "insert-text",
Packit Service d328f3
	                  (GCallback) ip_address_filter_cb,
Packit Service d328f3
	                  user_data);
Packit Service d328f3
Packit Service d328f3
	g_signal_connect_after (G_OBJECT (editable), "delete-text",
Packit Service d328f3
	                        (GCallback) delete_text_cb,
Packit Service d328f3
	                        user_data);
Packit Service d328f3
Packit Service d328f3
	/* Set up handler for value verifying and changing cell background */
Packit Service d328f3
	model = gtk_tree_view_get_model (priv->addr_list);
Packit Service d328f3
	gtk_tree_model_get_iter_from_string (model, &iter, priv->last_path);
Packit Service d328f3
	info = g_slice_new0 (AddressLineInfo);
Packit Service d328f3
	info->model = model;
Packit Service d328f3
	info->iter = iter;
Packit Service d328f3
	info->column = priv->last_column;
Packit Service d328f3
	g_signal_connect_data (G_OBJECT (editable), "changed",
Packit Service d328f3
	                       (GCallback) cell_changed_cb,
Packit Service d328f3
	                       info,
Packit Service d328f3
	                       address_line_info_destroy, 0);
Packit Service d328f3
Packit Service d328f3
	/* Set up key pressed handler - need to handle Tab key */
Packit Service d328f3
	g_signal_connect (G_OBJECT (editable), "key-press-event",
Packit Service d328f3
	                  (GCallback) key_pressed_cb,
Packit Service d328f3
	                  cell);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
routes_dialog_close_cb (GtkWidget *dialog, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	gtk_widget_hide (dialog);
Packit Service d328f3
	/* gtk_widget_destroy() will remove the window from the window group */
Packit Service d328f3
	gtk_widget_destroy (dialog);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
routes_dialog_response_cb (GtkWidget *dialog, gint response, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self = CE_PAGE_IP6 (user_data);
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
Packit Service d328f3
	if (response == GTK_RESPONSE_OK)
Packit Service d328f3
		ip6_routes_dialog_update_setting (dialog, priv->setting);
Packit Service d328f3
Packit Service d328f3
	routes_dialog_close_cb (dialog, NULL);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
routes_button_clicked_cb (GtkWidget *button, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self = CE_PAGE_IP6 (user_data);
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
	GtkWidget *dialog, *toplevel;
Packit Service d328f3
	gboolean automatic = FALSE;
Packit Service d328f3
	const char *method;
Packit Service d328f3
	char *tmp;
Packit Service d328f3
Packit Service d328f3
	toplevel = gtk_widget_get_toplevel (CE_PAGE (self)->page);
Packit Service d328f3
	g_return_if_fail (gtk_widget_is_toplevel (toplevel));
Packit Service d328f3
Packit Service d328f3
	method = nm_setting_ip_config_get_method (priv->setting);
Packit Service d328f3
	if (!method || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO))
Packit Service d328f3
		automatic = TRUE;
Packit Service d328f3
Packit Service d328f3
	dialog = ip6_routes_dialog_new (priv->setting, automatic);
Packit Service d328f3
	if (!dialog) {
Packit Service d328f3
		g_warning ("%s: failed to create the routes dialog!", __func__);
Packit Service d328f3
		return;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	gtk_window_group_add_window (priv->window_group, GTK_WINDOW (dialog));
Packit Service d328f3
	if (!priv->window_added) {
Packit Service d328f3
		gtk_window_group_add_window (priv->window_group, GTK_WINDOW (toplevel));
Packit Service d328f3
		priv->window_added = TRUE;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (toplevel));
Packit Service d328f3
	tmp = g_strdup_printf (_("Editing IPv6 routes for %s"), priv->connection_id);
Packit Service d328f3
	gtk_window_set_title (GTK_WINDOW (dialog), tmp);
Packit Service d328f3
	g_free (tmp);
Packit Service d328f3
Packit Service d328f3
	g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (routes_dialog_response_cb), self);
Packit Service d328f3
Packit Service d328f3
	gtk_widget_show_all (dialog);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
tree_view_button_pressed_cb (GtkWidget *widget,
Packit Service d328f3
                             GdkEvent *event,
Packit Service d328f3
                             gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self = CE_PAGE_IP6 (user_data);
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
Packit Service d328f3
	/* last_edited can be set e.g. when we get here by clicking an cell while
Packit Service d328f3
	 * editing another cell. GTK3 issue neither editing-canceled nor editing-done
Packit Service d328f3
	 * for cell renderer. Thus the previous cell value isn't saved. Store it now. */
Packit Service d328f3
	if (priv->last_edited && priv->last_path) {
Packit Service d328f3
		GtkTreeIter iter;
Packit Service d328f3
		GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (priv->addr_list));
Packit Service d328f3
		GtkTreePath *last_treepath = gtk_tree_path_new_from_string (priv->last_path);
Packit Service d328f3
Packit Service d328f3
		gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, last_treepath);
Packit Service d328f3
		gtk_list_store_set (store, &iter, priv->last_column, priv->last_edited, -1);
Packit Service d328f3
		gtk_tree_path_free (last_treepath);
Packit Service d328f3
Packit Service d328f3
		g_free (priv->last_edited);
Packit Service d328f3
		priv->last_edited = NULL;
Packit Service d328f3
		g_free (priv->last_path);
Packit Service d328f3
		priv->last_path = NULL;
Packit Service d328f3
		priv->last_column = -1;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* Ignore double clicks events. (They are issued after the single clicks, see GdkEventButton) */
Packit Service d328f3
	if (event->type == GDK_2BUTTON_PRESS)
Packit Service d328f3
		return TRUE;
Packit Service d328f3
Packit Service d328f3
	gtk_widget_grab_focus (GTK_WIDGET (priv->addr_list));
Packit Service d328f3
	return FALSE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
cell_error_data_func (GtkTreeViewColumn *tree_column,
Packit Service d328f3
                      GtkCellRenderer *cell,
Packit Service d328f3
                      GtkTreeModel *tree_model,
Packit Service d328f3
                      GtkTreeIter *iter,
Packit Service d328f3
                      gpointer data)
Packit Service d328f3
{
Packit Service d328f3
	guint32 col = GPOINTER_TO_UINT (data);
Packit Service d328f3
	char *value = NULL;
Packit Service d328f3
	const char *color = NULL;
Packit Service d328f3
	gboolean invalid = FALSE;
Packit Service d328f3
Packit Service d328f3
	gtk_tree_model_get (tree_model, iter, col, &value, -1);
Packit Service d328f3
Packit Service d328f3
	if (col == COL_ADDRESS)
Packit Service d328f3
		invalid =    !value || !*value || !nm_utils_ipaddr_valid (AF_INET6, value)
Packit Service d328f3
		          || is_address_unspecified (value);
Packit Service d328f3
	else if (col == COL_PREFIX)
Packit Service d328f3
		invalid = !is_prefix_valid (value, NULL);
Packit Service d328f3
	else if (col == COL_GATEWAY) {
Packit Service d328f3
		invalid = value && *value && !nm_utils_ipaddr_valid (AF_INET6, value);
Packit Service d328f3
Packit Service d328f3
		/* Check gateway against address and prefix */
Packit Service d328f3
		if (!invalid && possibly_wrong_gateway (tree_model, iter, value))
Packit Service d328f3
			color = "#DDC000"; /* darker than "yellow", else selected text is hard to read */
Packit Service d328f3
	} else
Packit Service d328f3
		g_warn_if_reached ();
Packit Service d328f3
Packit Service d328f3
	if (invalid)
Packit Service d328f3
		color = "red";
Packit Service d328f3
	utils_set_cell_background (cell, color, color ? value : NULL);
Packit Service d328f3
	g_free (value);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
finish_setup (CEPageIP6 *self, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
	GtkTreeSelection *selection;
Packit Service d328f3
	gint offset;
Packit Service d328f3
	GtkTreeViewColumn *column;
Packit Service d328f3
	GtkCellRenderer *renderer;
Packit Service d328f3
Packit Service d328f3
	populate_ui (self);
Packit Service d328f3
Packit Service d328f3
	/* IP Address column */
Packit Service d328f3
	renderer = gtk_cell_renderer_text_new ();
Packit Service d328f3
	g_object_set (renderer, "editable", TRUE, NULL);
Packit Service d328f3
	g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited), self);
Packit Service d328f3
	g_object_set_data (G_OBJECT (renderer), "column", GUINT_TO_POINTER (COL_ADDRESS));
Packit Service d328f3
	g_signal_connect (renderer, "editing-started", G_CALLBACK (cell_editing_started), self);
Packit Service d328f3
	g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), self);
Packit Service d328f3
	priv->addr_cells[COL_ADDRESS] = GTK_CELL_RENDERER (renderer);
Packit Service d328f3
Packit Service d328f3
	offset = gtk_tree_view_insert_column_with_attributes (priv->addr_list,
Packit Service d328f3
	                                                      -1, _("Address"), renderer,
Packit Service d328f3
	                                                      "text", COL_ADDRESS,
Packit Service d328f3
	                                                      NULL);
Packit Service d328f3
	column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->addr_list), offset - 1);
Packit Service d328f3
	gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
Packit Service d328f3
	gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
Packit Service d328f3
	gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
Packit Service d328f3
	                                         GUINT_TO_POINTER (COL_ADDRESS), NULL);
Packit Service d328f3
Packit Service d328f3
	/* Prefix column */
Packit Service d328f3
	renderer = gtk_cell_renderer_text_new ();
Packit Service d328f3
	g_object_set (renderer, "editable", TRUE, NULL);
Packit Service d328f3
	g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited), self);
Packit Service d328f3
	g_object_set_data (G_OBJECT (renderer), "column", GUINT_TO_POINTER (COL_PREFIX));
Packit Service d328f3
	g_signal_connect (renderer, "editing-started", G_CALLBACK (cell_editing_started), self);
Packit Service d328f3
	g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), self);
Packit Service d328f3
	priv->addr_cells[COL_PREFIX] = GTK_CELL_RENDERER (renderer);
Packit Service d328f3
Packit Service d328f3
	offset = gtk_tree_view_insert_column_with_attributes (priv->addr_list,
Packit Service d328f3
	                                                      -1, _("Prefix"), renderer,
Packit Service d328f3
	                                                      "text", COL_PREFIX,
Packit Service d328f3
	                                                      NULL);
Packit Service d328f3
	column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->addr_list), offset - 1);
Packit Service d328f3
	gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
Packit Service d328f3
	gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
Packit Service d328f3
	gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
Packit Service d328f3
	                                         GUINT_TO_POINTER (COL_PREFIX), NULL);
Packit Service d328f3
Packit Service d328f3
	/* Gateway column */
Packit Service d328f3
	renderer = gtk_cell_renderer_text_new ();
Packit Service d328f3
	g_object_set (renderer, "editable", TRUE, NULL);
Packit Service d328f3
	g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited), self);
Packit Service d328f3
	g_object_set_data (G_OBJECT (renderer), "column", GUINT_TO_POINTER (COL_GATEWAY));
Packit Service d328f3
	g_signal_connect (renderer, "editing-started", G_CALLBACK (cell_editing_started), self);
Packit Service d328f3
	g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), self);
Packit Service d328f3
	priv->addr_cells[COL_GATEWAY] = GTK_CELL_RENDERER (renderer);
Packit Service d328f3
Packit Service d328f3
	offset = gtk_tree_view_insert_column_with_attributes (priv->addr_list,
Packit Service d328f3
	                                                      -1, _("Gateway"), renderer,
Packit Service d328f3
	                                                      "text", COL_GATEWAY,
Packit Service d328f3
	                                                      NULL);
Packit Service d328f3
	column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->addr_list), offset - 1);
Packit Service d328f3
	gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
Packit Service d328f3
	gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
Packit Service d328f3
	gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
Packit Service d328f3
	                                         GUINT_TO_POINTER (COL_GATEWAY), NULL);
Packit Service d328f3
Packit Service d328f3
	g_signal_connect (priv->addr_list, "button-press-event", G_CALLBACK (tree_view_button_pressed_cb), self);
Packit Service d328f3
Packit Service d328f3
	gtk_widget_set_sensitive (GTK_WIDGET (priv->addr_add), TRUE);
Packit Service d328f3
	gtk_widget_set_sensitive (GTK_WIDGET (priv->addr_delete), FALSE);
Packit Service d328f3
Packit Service d328f3
	g_signal_connect (priv->addr_add, "clicked", G_CALLBACK (addr_add_clicked), self);
Packit Service d328f3
	g_signal_connect (priv->addr_delete, "clicked", G_CALLBACK (addr_delete_clicked), priv->addr_list);
Packit Service d328f3
	selection = gtk_tree_view_get_selection (priv->addr_list);
Packit Service d328f3
	g_signal_connect (selection, "changed", G_CALLBACK (list_selection_changed), priv->addr_delete);
Packit Service d328f3
Packit Service d328f3
	g_signal_connect_swapped (priv->dns_servers, "changed", G_CALLBACK (ce_page_changed), self);
Packit Service d328f3
	g_signal_connect (priv->dns_servers, "insert-text", G_CALLBACK (dns_servers_filter_cb), self);
Packit Service d328f3
	g_signal_connect_swapped (priv->dns_searches, "changed", G_CALLBACK (ce_page_changed), self);
Packit Service d328f3
	g_signal_connect_swapped (priv->ip6_privacy_combo, "changed", G_CALLBACK (ce_page_changed), self);
Packit Service d328f3
	g_signal_connect_swapped (priv->ip6_addr_gen_mode_combo, "changed", G_CALLBACK (ce_page_changed), self);
Packit Service d328f3
Packit Service d328f3
	method_changed (priv->method, self);
Packit Service d328f3
	g_signal_connect (priv->method, "changed", G_CALLBACK (method_changed), self);
Packit Service d328f3
Packit Service d328f3
	g_signal_connect_swapped (priv->ip6_required, "toggled", G_CALLBACK (ce_page_changed), self);
Packit Service d328f3
Packit Service d328f3
	g_signal_connect (priv->routes_button, "clicked", G_CALLBACK (routes_button_clicked_cb), self);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
CEPage *
Packit Service d328f3
ce_page_ip6_new (NMConnectionEditor *editor,
Packit Service d328f3
                 NMConnection *connection,
Packit Service d328f3
                 GtkWindow *parent_window,
Packit Service d328f3
                 NMClient *client,
Packit Service d328f3
                 const char **out_secrets_setting_name,
Packit Service d328f3
                 GError **error)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self;
Packit Service d328f3
	CEPageIP6Private *priv;
Packit Service d328f3
	NMSettingConnection *s_con;
Packit Service d328f3
Packit Service d328f3
	self = CE_PAGE_IP6 (ce_page_new (CE_TYPE_PAGE_IP6,
Packit Service d328f3
	                                 editor,
Packit Service d328f3
	                                 connection,
Packit Service d328f3
	                                 parent_window,
Packit Service d328f3
	                                 client,
Packit Service d328f3
	                                 "/org/gnome/nm_connection_editor/ce-page-ip6.ui",
Packit Service d328f3
	                                 "IP6Page",
Packit Service d328f3
	                                 _("IPv6 Settings")));
Packit Service d328f3
	if (!self) {
Packit Service d328f3
		g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("Could not load IPv6 user interface."));
Packit Service d328f3
		return NULL;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	ip6_private_init (self, connection);
Packit Service d328f3
	priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
Packit Service d328f3
	priv->window_group = gtk_window_group_new ();
Packit Service d328f3
Packit Service d328f3
	s_con = nm_connection_get_setting_connection (connection);
Packit Service d328f3
	g_assert (s_con);
Packit Service d328f3
	priv->connection_id = g_strdup (nm_setting_connection_get_id (s_con));
Packit Service d328f3
Packit Service d328f3
	priv->setting = nm_connection_get_setting_ip6_config (connection);
Packit Service d328f3
	g_assert (priv->setting);
Packit Service d328f3
Packit Service d328f3
	g_signal_connect (self, CE_PAGE_INITIALIZED, G_CALLBACK (finish_setup), NULL);
Packit Service d328f3
Packit Service d328f3
	return CE_PAGE (self);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
ui_to_setting (CEPageIP6 *self, GError **error)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
	GtkTreeModel *model;
Packit Service d328f3
	GtkTreeIter tree_iter;
Packit Service d328f3
	int int_method = IP6_METHOD_AUTO;
Packit Service d328f3
	const char *method;
Packit Service d328f3
	char *gateway = NULL;
Packit Service d328f3
	gboolean valid = FALSE, iter_valid;
Packit Service d328f3
	const char *text;
Packit Service d328f3
	gboolean ignore_auto_dns = FALSE;
Packit Service d328f3
	char **items = NULL, **iter;
Packit Service d328f3
	gboolean may_fail;
Packit Service d328f3
	NMSettingIP6ConfigPrivacy ip6_privacy;
Packit Service d328f3
	NMSettingIP6ConfigAddrGenMode ip6_addr_gen_mode;
Packit Service d328f3
Packit Service d328f3
	/* Method */
Packit Service d328f3
	if (gtk_combo_box_get_active_iter (priv->method, &tree_iter)) {
Packit Service d328f3
		gtk_tree_model_get (GTK_TREE_MODEL (priv->method_store), &tree_iter,
Packit Service d328f3
		                    METHOD_COL_NUM, &int_method, -1);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	switch (int_method) {
Packit Service d328f3
	case IP6_METHOD_IGNORE:
Packit Service d328f3
		method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE;
Packit Service d328f3
		break;
Packit Service d328f3
	case IP6_METHOD_DISABLED:
Packit Service d328f3
		method = NM_SETTING_IP6_CONFIG_METHOD_DISABLED;
Packit Service d328f3
		break;
Packit Service d328f3
	case IP6_METHOD_LINK_LOCAL:
Packit Service d328f3
		method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL;
Packit Service d328f3
		break;
Packit Service d328f3
	case IP6_METHOD_MANUAL:
Packit Service d328f3
		method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
Packit Service d328f3
		break;
Packit Service d328f3
	case IP6_METHOD_SHARED:
Packit Service d328f3
		method = NM_SETTING_IP6_CONFIG_METHOD_SHARED;
Packit Service d328f3
		break;
Packit Service d328f3
	case IP6_METHOD_AUTO_DHCP_ONLY:
Packit Service d328f3
		method = NM_SETTING_IP6_CONFIG_METHOD_DHCP;
Packit Service d328f3
		break;
Packit Service d328f3
	case IP6_METHOD_AUTO_ADDRESSES:
Packit Service d328f3
		ignore_auto_dns = TRUE;
Packit Service d328f3
		/* fall through */
Packit Service d328f3
	default:
Packit Service d328f3
		method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
Packit Service d328f3
		break;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	g_object_freeze_notify (G_OBJECT (priv->setting));
Packit Service d328f3
	g_object_set (priv->setting,
Packit Service d328f3
	              NM_SETTING_IP_CONFIG_METHOD, method,
Packit Service d328f3
	              NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, ignore_auto_dns,
Packit Service d328f3
	              NULL);
Packit Service d328f3
Packit Service d328f3
	/* IP addresses */
Packit Service d328f3
	nm_setting_ip_config_clear_addresses (priv->setting);
Packit Service d328f3
	model = gtk_tree_view_get_model (priv->addr_list);
Packit Service d328f3
	iter_valid = gtk_tree_model_get_iter_first (model, &tree_iter);
Packit Service d328f3
	while (iter_valid) {
Packit Service d328f3
		char *addr_str = NULL, *prefix_str = NULL, *addr_gw_str = NULL;
Packit Service d328f3
		NMIPAddress *addr;
Packit Service d328f3
		guint32 prefix;
Packit Service d328f3
Packit Service d328f3
		gtk_tree_model_get (model, &tree_iter,
Packit Service d328f3
		                    COL_ADDRESS, &addr_str,
Packit Service d328f3
		                    COL_PREFIX, &prefix_str,
Packit Service d328f3
		                    COL_GATEWAY, &addr_gw_str,
Packit Service d328f3
		                    -1);
Packit Service d328f3
Packit Service d328f3
		if (   !addr_str
Packit Service d328f3
		    || !nm_utils_ipaddr_valid (AF_INET6, addr_str)
Packit Service d328f3
		    || is_address_unspecified (addr_str)) {
Packit Service d328f3
			g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("IPv6 address “%s” invalid"), addr_str ? addr_str : "");
Packit Service d328f3
			g_free (addr_str);
Packit Service d328f3
			g_free (prefix_str);
Packit Service d328f3
			g_free (addr_gw_str);
Packit Service d328f3
			goto out;
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		if (!is_prefix_valid (prefix_str, &prefix)) {
Packit Service d328f3
			g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("IPv6 prefix “%s” invalid"), prefix_str ? prefix_str : "");
Packit Service d328f3
			g_free (addr_str);
Packit Service d328f3
			g_free (prefix_str);
Packit Service d328f3
			g_free (addr_gw_str);
Packit Service d328f3
			goto out;
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		/* Gateway is optional... */
Packit Service d328f3
		if (addr_gw_str && *addr_gw_str && !nm_utils_ipaddr_valid (AF_INET6, addr_gw_str)) {
Packit Service d328f3
			g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("IPv6 gateway “%s” invalid"), addr_gw_str);
Packit Service d328f3
			g_free (addr_str);
Packit Service d328f3
			g_free (prefix_str);
Packit Service d328f3
			g_free (addr_gw_str);
Packit Service d328f3
			goto out;
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		addr = nm_ip_address_new (AF_INET6, addr_str, prefix, NULL);
Packit Service d328f3
		nm_setting_ip_config_add_address (priv->setting, addr);
Packit Service d328f3
		nm_ip_address_unref (addr);
Packit Service d328f3
Packit Service d328f3
		if (nm_setting_ip_config_get_num_addresses (priv->setting) == 1 && addr_gw_str && *addr_gw_str) {
Packit Service d328f3
			gateway = addr_gw_str;
Packit Service d328f3
			addr_gw_str = NULL;
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		g_free (addr_str);
Packit Service d328f3
		g_free (prefix_str);
Packit Service d328f3
		g_free (addr_gw_str);
Packit Service d328f3
Packit Service d328f3
		iter_valid = gtk_tree_model_iter_next (model, &tree_iter);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	g_object_set (G_OBJECT (priv->setting),
Packit Service d328f3
	              NM_SETTING_IP_CONFIG_GATEWAY, gateway,
Packit Service d328f3
	              NULL);
Packit Service d328f3
Packit Service d328f3
	/* DNS servers */
Packit Service d328f3
	nm_setting_ip_config_clear_dns (priv->setting);
Packit Service d328f3
	text = gtk_entry_get_text (GTK_ENTRY (priv->dns_servers));
Packit Service d328f3
	if (text && strlen (text)) {
Packit Service d328f3
		items = g_strsplit_set (text, ", ;", 0);
Packit Service d328f3
		for (iter = items; *iter; iter++) {
Packit Service d328f3
			struct in6_addr tmp_addr;
Packit Service d328f3
			char *stripped = g_strstrip (*iter);
Packit Service d328f3
Packit Service d328f3
			if (!strlen (stripped))
Packit Service d328f3
				continue;
Packit Service d328f3
Packit Service d328f3
			if (inet_pton (AF_INET6, stripped, &tmp_addr)) {
Packit Service d328f3
				nm_setting_ip_config_add_dns (priv->setting, stripped);
Packit Service d328f3
			} else {
Packit Service d328f3
				g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("IPv6 DNS server “%s” invalid"), stripped);
Packit Service d328f3
				g_strfreev (items);
Packit Service d328f3
				goto out;
Packit Service d328f3
			}
Packit Service d328f3
		}
Packit Service d328f3
		g_strfreev (items);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* Search domains */
Packit Service d328f3
	nm_setting_ip_config_clear_dns_searches (priv->setting);
Packit Service d328f3
	text = gtk_entry_get_text (GTK_ENTRY (priv->dns_searches));
Packit Service d328f3
	if (text && strlen (text)) {
Packit Service d328f3
		items = g_strsplit_set (text, ", ;:", 0);
Packit Service d328f3
		for (iter = items; *iter; iter++) {
Packit Service d328f3
			char *stripped = g_strstrip (*iter);
Packit Service d328f3
Packit Service d328f3
			if (strlen (stripped))
Packit Service d328f3
				nm_setting_ip_config_add_dns_search (priv->setting, stripped);
Packit Service d328f3
		}
Packit Service d328f3
		g_strfreev (items);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* IPv6 Privacy */
Packit Service d328f3
	switch (gtk_combo_box_get_active (priv->ip6_privacy_combo)) {
Packit Service d328f3
	case IP6_PRIVACY_DISABLED:
Packit Service d328f3
		ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED;
Packit Service d328f3
		break;
Packit Service d328f3
	case IP6_PRIVACY_PREFER_PUBLIC:
Packit Service d328f3
		ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR;
Packit Service d328f3
		break;
Packit Service d328f3
	case IP6_PRIVACY_PREFER_TEMP:
Packit Service d328f3
		ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR;
Packit Service d328f3
		break;
Packit Service d328f3
	default:
Packit Service d328f3
		ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
Packit Service d328f3
		break;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (gtk_combo_box_get_active (priv->ip6_addr_gen_mode_combo) == IP6_ADDR_GEN_MODE_EUI64)
Packit Service d328f3
		ip6_addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64;
Packit Service d328f3
	else
Packit Service d328f3
		ip6_addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY;
Packit Service d328f3
Packit Service d328f3
	may_fail = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->ip6_required));
Packit Service d328f3
	g_object_set (G_OBJECT (priv->setting),
Packit Service d328f3
	              NM_SETTING_IP_CONFIG_MAY_FAIL, may_fail,
Packit Service d328f3
	              NM_SETTING_IP6_CONFIG_IP6_PRIVACY, ip6_privacy,
Packit Service d328f3
	              NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, (int) ip6_addr_gen_mode,
Packit Service d328f3
	              NULL);
Packit Service d328f3
Packit Service d328f3
	valid = TRUE;
Packit Service d328f3
Packit Service d328f3
out:
Packit Service d328f3
	g_object_thaw_notify (G_OBJECT (priv->setting));
Packit Service d328f3
Packit Service d328f3
	return valid;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
ce_page_validate_v (CEPage *page, NMConnection *connection, GError **error)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self = CE_PAGE_IP6 (page);
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
Packit Service d328f3
	if (!ui_to_setting (self, error))
Packit Service d328f3
		return FALSE;
Packit Service d328f3
	return nm_setting_verify (NM_SETTING (priv->setting), NULL, error);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
get_iter_for_method (GtkTreeModel *model, int column, GtkTreeIter *iter)
Packit Service d328f3
{
Packit Service d328f3
	int col;
Packit Service d328f3
Packit Service d328f3
	if (gtk_tree_model_get_iter_first (model, iter)) {
Packit Service d328f3
		do {
Packit Service d328f3
			gtk_tree_model_get (model, iter, METHOD_COL_NUM, &col, -1);
Packit Service d328f3
			if (col == column)
Packit Service d328f3
				return TRUE;
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 void
Packit Service d328f3
toggle_method_sensitivity (CEPage *page, int column, gboolean sensitive)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self = CE_PAGE_IP6 (page);
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
	GtkTreeModel *model = GTK_TREE_MODEL (priv->method_store);
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
Packit Service d328f3
	if (get_iter_for_method (model, column, &iter))
Packit Service d328f3
		gtk_list_store_set (priv->method_store, &iter, METHOD_COL_ENABLED, sensitive, -1);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
get_method_sensitivity (CEPage *page, int column)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self = CE_PAGE_IP6 (page);
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
	GtkTreeModel *model = GTK_TREE_MODEL (priv->method_store);
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	gboolean sensitive = FALSE;
Packit Service d328f3
Packit Service d328f3
	if (get_iter_for_method (model, column, &iter))
Packit Service d328f3
		gtk_tree_model_get (GTK_TREE_MODEL (priv->method_store), &iter, METHOD_COL_ENABLED, &sensitive, -1);
Packit Service d328f3
	return sensitive;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
change_method_combo (CEPage *page, gboolean is_hotspot)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self = CE_PAGE_IP6 (page);
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
Packit Service d328f3
	/* Store previous active method */
Packit Service d328f3
	if (get_method_sensitivity (page, IP6_METHOD_AUTO))
Packit Service d328f3
		priv->normal_method_idx = gtk_combo_box_get_active (priv->method);
Packit Service d328f3
	else
Packit Service d328f3
		priv->hotspot_method_idx = gtk_combo_box_get_active (priv->method);
Packit Service d328f3
Packit Service d328f3
	/* Set active method */
Packit Service d328f3
	if (is_hotspot) {
Packit Service d328f3
		if (priv->hotspot_method_idx == -1) {
Packit Service d328f3
			int method = IP6_METHOD_SHARED;
Packit Service d328f3
			if (nm_streq0 (nm_setting_ip_config_get_method (priv->setting),
Packit Service d328f3
			               NM_SETTING_IP6_CONFIG_METHOD_IGNORE))
Packit Service d328f3
				method = IP6_METHOD_IGNORE;
Packit Service d328f3
			else if (nm_streq0 (nm_setting_ip_config_get_method (priv->setting),
Packit Service d328f3
			                    NM_SETTING_IP6_CONFIG_METHOD_DISABLED))
Packit Service d328f3
				method = IP6_METHOD_DISABLED;
Packit Service d328f3
			gtk_combo_box_set_active (priv->method, method);
Packit Service d328f3
		} else
Packit Service d328f3
			gtk_combo_box_set_active (priv->method, priv->hotspot_method_idx);
Packit Service d328f3
	} else {
Packit Service d328f3
		if (priv->normal_method_idx != -1)
Packit Service d328f3
			gtk_combo_box_set_active (priv->method, priv->normal_method_idx);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	toggle_method_sensitivity (page, IP6_METHOD_AUTO, !is_hotspot);
Packit Service d328f3
	toggle_method_sensitivity (page, IP6_METHOD_AUTO_ADDRESSES, !is_hotspot);
Packit Service d328f3
	toggle_method_sensitivity (page, IP6_METHOD_AUTO_DHCP_ONLY, !is_hotspot);
Packit Service d328f3
	toggle_method_sensitivity (page, IP6_METHOD_MANUAL, !is_hotspot);
Packit Service d328f3
	toggle_method_sensitivity (page, IP6_METHOD_LINK_LOCAL, !is_hotspot);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
inter_page_change (CEPage *page)
Packit Service d328f3
{
Packit Service d328f3
	gpointer wifi_mode_ap;
Packit Service d328f3
Packit Service d328f3
	if (nm_connection_editor_inter_page_get_value (page->editor, INTER_PAGE_CHANGE_WIFI_MODE, &wifi_mode_ap)) {
Packit Service d328f3
		/* For Wi-Fi AP mode restrict IPv6 methods to ignore */
Packit Service d328f3
		if (GPOINTER_TO_UINT (wifi_mode_ap))
Packit Service d328f3
			change_method_combo (page, TRUE);
Packit Service d328f3
		else
Packit Service d328f3
			change_method_combo (page, FALSE);
Packit Service d328f3
	}
Packit Service d328f3
	return TRUE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
ce_page_ip6_init (CEPageIP6 *self)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
Packit Service d328f3
	priv->last_column = -1;
Packit Service d328f3
	priv->normal_method_idx = -1;
Packit Service d328f3
	priv->hotspot_method_idx = -1;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
dispose (GObject *object)
Packit Service d328f3
{
Packit Service d328f3
	CEPageIP6 *self = CE_PAGE_IP6 (object);
Packit Service d328f3
	CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
Packit Service d328f3
	int i;
Packit Service d328f3
Packit Service d328f3
	g_clear_object (&priv->window_group);
Packit Service d328f3
Packit Service d328f3
	/* Mark CEPageIP6 object as invalid; store this indication to cells to be usable in callbacks */
Packit Service d328f3
	for (i = 0; i <= COL_LAST; i++)
Packit Service d328f3
		g_object_set_data (G_OBJECT (priv->addr_cells[i]), "ce-page-not-valid", GUINT_TO_POINTER (1));
Packit Service d328f3
Packit Service d328f3
	g_clear_pointer (&priv->connection_id, g_free);
Packit Service d328f3
Packit Service d328f3
	G_OBJECT_CLASS (ce_page_ip6_parent_class)->dispose (object);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
ce_page_ip6_class_init (CEPageIP6Class *ip6_class)
Packit Service d328f3
{
Packit Service d328f3
	GObjectClass *object_class = G_OBJECT_CLASS (ip6_class);
Packit Service d328f3
	CEPageClass *parent_class = CE_PAGE_CLASS (ip6_class);
Packit Service d328f3
Packit Service d328f3
	g_type_class_add_private (object_class, sizeof (CEPageIP6Private));
Packit Service d328f3
Packit Service d328f3
	/* virtual methods */
Packit Service d328f3
	parent_class->ce_page_validate_v = ce_page_validate_v;
Packit Service d328f3
	parent_class->inter_page_change = inter_page_change;
Packit Service d328f3
	object_class->dispose = dispose;
Packit Service d328f3
}