Blame src/connection-editor/page-team-port.c

Packit Service 639700
// SPDX-License-Identifier: GPL-2.0+
Packit fabffb
/*
Packit fabffb
 * Copyright 2013 Jiri Pirko <jiri@resnulli.us>
Packit fabffb
 * Copyright 2013 - 2017  Red Hat, Inc.
Packit fabffb
 */
Packit fabffb
Packit fabffb
#include "nm-default.h"
Packit fabffb
Packit fabffb
#if WITH_JANSSON
Packit fabffb
#include <jansson.h>
Packit fabffb
#endif
Packit fabffb
Packit fabffb
#include <string.h>
Packit fabffb
Packit fabffb
#include "page-team-port.h"
Packit fabffb
Packit fabffb
G_DEFINE_TYPE (CEPageTeamPort, ce_page_team_port, CE_TYPE_PAGE)
Packit fabffb
Packit fabffb
#define CE_PAGE_TEAM_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CE_TYPE_PAGE_TEAM_PORT, CEPageTeamPortPrivate))
Packit fabffb
Packit fabffb
typedef struct {
Packit fabffb
	NMSettingTeamPort *setting;
Packit fabffb
Packit fabffb
	GtkTextView *json_config_widget;
Packit fabffb
	GtkWidget *import_config_button;
Packit fabffb
Packit fabffb
	GtkButton *advanced_button;
Packit fabffb
	GtkDialog *advanced_dialog;
Packit fabffb
	GtkNotebook *advanced_notebook;
Packit fabffb
Packit fabffb
	/* General */
Packit fabffb
	GtkSpinButton *queue_id;
Packit fabffb
	GtkSpinButton *port_prio;
Packit fabffb
	GtkToggleButton *port_sticky;
Packit fabffb
	GtkSpinButton *lacp_port_prio;
Packit fabffb
	GtkSpinButton *lacp_port_key;
Packit fabffb
Packit fabffb
	/* Link Watch */
Packit fabffb
	GtkComboBox *link_watcher_name;
Packit fabffb
	GtkSpinButton *delay_up;
Packit fabffb
	GtkLabel *delay_up_label;
Packit fabffb
	GtkLabel *delay_up_ms;
Packit fabffb
	GtkSpinButton *delay_down;
Packit fabffb
	GtkLabel *delay_down_label;
Packit fabffb
	GtkLabel *delay_down_ms;
Packit fabffb
	GtkSpinButton *send_interval;
Packit fabffb
	GtkLabel *send_interval_label;
Packit fabffb
	GtkLabel *send_interval_ms;
Packit fabffb
	GtkSpinButton *init_wait;
Packit fabffb
	GtkLabel *init_wait_label;
Packit fabffb
	GtkLabel *init_wait_ms;
Packit fabffb
	GtkSpinButton *missed_max;
Packit fabffb
	GtkLabel *missed_max_label;
Packit fabffb
	GtkEntry *source_host;
Packit fabffb
	GtkLabel *source_host_label;
Packit fabffb
	GtkEntry *target_host;
Packit fabffb
	GtkLabel *target_host_label;
Packit fabffb
	GtkToggleButton *validate_active;
Packit fabffb
	GtkToggleButton *validate_inactive;
Packit fabffb
	GtkToggleButton *send_all;
Packit fabffb
} CEPageTeamPortPrivate;
Packit fabffb
Packit fabffb
/* Get string "type" from a combo box with a ["type", "name"] model. */
Packit fabffb
static gchar *
Packit fabffb
get_combo_box (GtkComboBox *combo)
Packit fabffb
{
Packit fabffb
	GtkTreeModel *model;
Packit fabffb
	GtkTreeIter iter;
Packit fabffb
	gchar *name;
Packit fabffb
Packit fabffb
	if (!gtk_combo_box_get_active_iter (combo, &iter))
Packit fabffb
		g_return_val_if_reached (NULL);
Packit fabffb
Packit fabffb
	model = gtk_combo_box_get_model (combo);
Packit fabffb
	gtk_tree_model_get (model, &iter, 0, &name, -1);
Packit fabffb
Packit fabffb
	return name;
Packit fabffb
}
Packit fabffb
Packit fabffb
#if WITH_JANSSON
Packit fabffb
Packit fabffb
/* Set active item to "type" in a combo box with a ["type", "name"] model. */
Packit fabffb
static gboolean
Packit fabffb
set_combo_box (GtkComboBox *combo, const gchar *value, GError **error)
Packit fabffb
{
Packit fabffb
	GtkTreeModel *model;
Packit fabffb
	GtkTreeIter iter;
Packit fabffb
	gboolean valid;
Packit fabffb
	const gchar *name;
Packit fabffb
	int i = 0;
Packit fabffb
Packit fabffb
	if (!value || !*value) {
Packit fabffb
		gtk_combo_box_set_active (combo, 0);
Packit fabffb
		return TRUE;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	model = gtk_combo_box_get_model (combo);
Packit fabffb
	for (valid = gtk_tree_model_get_iter_first (model, &iter);
Packit fabffb
	     valid;
Packit fabffb
	     valid = gtk_tree_model_iter_next (model, &iter)) {
Packit fabffb
		gtk_tree_model_get (model, &iter, 0, &name, -1);
Packit fabffb
		if (strcmp (name, value) == 0) {
Packit fabffb
			gtk_combo_box_set_active (combo, i);
Packit fabffb
			return TRUE;
Packit fabffb
		}
Packit fabffb
		i++;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC,
Packit fabffb
	             "Value of \"%s\" is not known", value);
Packit fabffb
Packit fabffb
	return FALSE;
Packit fabffb
}
Packit fabffb
Packit fabffb
#endif
Packit fabffb
Packit fabffb
static void
Packit fabffb
team_port_private_init (CEPageTeamPort *self)
Packit fabffb
{
Packit fabffb
	CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self);
Packit fabffb
	GtkBuilder *builder;
Packit fabffb
Packit fabffb
	builder = CE_PAGE (self)->builder;
Packit fabffb
Packit fabffb
	priv->json_config_widget = GTK_TEXT_VIEW (gtk_builder_get_object (builder, "team_port_json_config"));
Packit fabffb
	priv->import_config_button = GTK_WIDGET (gtk_builder_get_object (builder, "import_config_button"));
Packit fabffb
	priv->advanced_button = GTK_BUTTON (gtk_builder_get_object (builder, "advanced_button"));
Packit fabffb
	priv->advanced_dialog = GTK_DIALOG (gtk_builder_get_object (builder, "advanced_dialog"));
Packit fabffb
	gtk_window_set_modal (GTK_WINDOW (priv->advanced_dialog), TRUE);
Packit fabffb
	priv->advanced_notebook = GTK_NOTEBOOK (gtk_builder_get_object (builder, "advanced_notebook"));
Packit fabffb
Packit fabffb
	/* General */
Packit fabffb
	priv->queue_id = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "queue_id"));
Packit fabffb
	priv->port_prio = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "port_prio"));
Packit fabffb
	priv->port_sticky = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "port_sticky"));
Packit fabffb
	priv->lacp_port_prio = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "lacp_port_prio"));
Packit fabffb
	priv->lacp_port_key = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "lacp_port_key"));
Packit fabffb
Packit fabffb
	/* Link Watcher */
Packit fabffb
	priv->link_watcher_name = GTK_COMBO_BOX (gtk_builder_get_object (builder, "link_watcher_name"));
Packit fabffb
	priv->send_interval = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "send_interval"));
Packit fabffb
	priv->send_interval_label = GTK_LABEL (gtk_builder_get_object (builder, "send_interval_label"));
Packit fabffb
	priv->send_interval_ms = GTK_LABEL (gtk_builder_get_object (builder, "send_interval_ms"));
Packit fabffb
	priv->init_wait = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "init_wait"));
Packit fabffb
	priv->init_wait_label = GTK_LABEL (gtk_builder_get_object (builder, "init_wait_label"));
Packit fabffb
	priv->init_wait_ms = GTK_LABEL (gtk_builder_get_object (builder, "init_wait_ms"));
Packit fabffb
	priv->missed_max = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "missed_max"));
Packit fabffb
	priv->missed_max_label = GTK_LABEL (gtk_builder_get_object (builder, "missed_max_label"));
Packit fabffb
	priv->source_host = GTK_ENTRY (gtk_builder_get_object (builder, "source_host"));
Packit fabffb
	priv->source_host_label = GTK_LABEL (gtk_builder_get_object (builder, "source_host_label"));
Packit fabffb
	priv->target_host = GTK_ENTRY (gtk_builder_get_object (builder, "target_host"));
Packit fabffb
	priv->target_host_label = GTK_LABEL (gtk_builder_get_object (builder, "target_host_label"));
Packit fabffb
	priv->validate_active = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "validate_active"));
Packit fabffb
	priv->validate_inactive = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "validate_inactive"));
Packit fabffb
	priv->send_all = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "send_all"));
Packit fabffb
	priv->delay_up = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "delay_up"));
Packit fabffb
	priv->delay_up_label = GTK_LABEL (gtk_builder_get_object (builder, "delay_up_label"));
Packit fabffb
	priv->delay_up_ms = GTK_LABEL (gtk_builder_get_object (builder, "delay_up_ms"));
Packit fabffb
	priv->delay_down = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "delay_down"));
Packit fabffb
	priv->delay_down_label = GTK_LABEL (gtk_builder_get_object (builder, "delay_down_label"));
Packit fabffb
	priv->delay_down_ms = GTK_LABEL (gtk_builder_get_object (builder, "delay_down_ms"));
Packit fabffb
Packit fabffb
	ce_spin_default_val (priv->queue_id, -1);
Packit fabffb
	ce_spin_default_val (priv->port_prio, -1);
Packit fabffb
	ce_spin_default_val (priv->lacp_port_prio, -1);
Packit fabffb
	ce_spin_default_val (priv->lacp_port_key, -1);
Packit fabffb
	ce_spin_default_val (priv->send_interval, -1);
Packit fabffb
	ce_spin_default_val (priv->init_wait, -1);
Packit fabffb
	ce_spin_default_val (priv->missed_max, -1);
Packit fabffb
	ce_spin_default_val (priv->delay_up, -1);
Packit fabffb
	ce_spin_default_val (priv->delay_down, -1);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
import_button_clicked_cb (GtkWidget *widget, CEPageTeamPort *self)
Packit fabffb
{
Packit fabffb
	CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self);
Packit fabffb
	GtkWidget *dialog;
Packit fabffb
	GtkTextBuffer *buffer;
Packit fabffb
	char *filename;
Packit fabffb
	char *buf = NULL;
Packit fabffb
	gsize buf_len;
Packit fabffb
	GtkWidget *toplevel;
Packit fabffb
Packit fabffb
	toplevel = gtk_widget_get_toplevel (CE_PAGE (self)->page);
Packit fabffb
	g_return_if_fail (toplevel);
Packit fabffb
	g_return_if_fail (gtk_widget_is_toplevel (toplevel));
Packit fabffb
Packit fabffb
	dialog = gtk_file_chooser_dialog_new (_("Select file to import"),
Packit fabffb
	                                      GTK_WINDOW (toplevel),
Packit fabffb
	                                      GTK_FILE_CHOOSER_ACTION_OPEN,
Packit fabffb
	                                      _("_Cancel"), GTK_RESPONSE_CANCEL,
Packit fabffb
	                                      _("_Open"), GTK_RESPONSE_ACCEPT,
Packit fabffb
	                                      NULL);
Packit fabffb
	gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
Packit fabffb
Packit fabffb
	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
Packit fabffb
		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
Packit fabffb
		if (!filename) {
Packit fabffb
			g_warning ("%s: didn't get a filename back from the chooser!", __func__);
Packit fabffb
			goto out;
Packit fabffb
		}
Packit fabffb
Packit fabffb
		/* Put the file content into JSON config text view. */
Packit fabffb
		// FIXME: do a cleverer file validity check
Packit fabffb
		g_file_get_contents (filename, &buf, &buf_len, NULL);
Packit fabffb
		if (buf_len > 100000) {
Packit fabffb
			g_free (buf);
Packit fabffb
			buf = g_strdup (_("Error: file doesn’t contain a valid JSON configuration"));
Packit fabffb
		}
Packit fabffb
Packit fabffb
		buffer = gtk_text_view_get_buffer (priv->json_config_widget);
Packit fabffb
		gtk_text_buffer_set_text (buffer, buf ? buf : "", -1);
Packit fabffb
Packit fabffb
		g_free (filename);
Packit fabffb
		g_free (buf);
Packit fabffb
	}
Packit fabffb
Packit fabffb
out:
Packit fabffb
	gtk_widget_destroy (dialog);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
link_watcher_changed (GtkComboBox *combo, gpointer user_data)
Packit fabffb
{
Packit fabffb
	CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (user_data);
Packit fabffb
	gchar *name;
Packit fabffb
Packit fabffb
	/* First hide everything and then show just what we need. */
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->delay_up));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->delay_up_label));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->delay_up_ms));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->delay_down));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->delay_down_label));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->delay_down_ms));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->send_interval));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->send_interval_label));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->send_interval_ms));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->init_wait));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->init_wait_label));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->init_wait_ms));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->missed_max));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->missed_max_label));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->source_host));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->source_host_label));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->target_host));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->target_host_label));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->validate_active));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->validate_inactive));
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->send_all));
Packit fabffb
Packit fabffb
	name = get_combo_box (combo);
Packit fabffb
	if (g_strcmp0 (name, "master") == 0) {
Packit fabffb
		/* Leave everything disabled. */
Packit fabffb
	} else if (g_strcmp0 (name, "ethtool") == 0) {
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->delay_up));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->delay_up_label));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->delay_up_ms));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->delay_down));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->delay_down_label));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->delay_down_ms));
Packit fabffb
	} else if (g_strcmp0 (name, "arp_ping") == 0) {
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->send_interval));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->send_interval_label));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->send_interval_ms));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->init_wait));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->init_wait_label));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->init_wait_ms));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->missed_max));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->missed_max_label));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->source_host));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->source_host_label));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->target_host));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->target_host_label));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->validate_active));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->validate_inactive));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->send_all));
Packit fabffb
	} else if (g_strcmp0 (name, "nsna_ping") == 0) {
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->send_interval));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->send_interval_label));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->send_interval_ms));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->init_wait));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->init_wait_label));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->init_wait_ms));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->missed_max));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->missed_max_label));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->target_host));
Packit fabffb
		gtk_widget_show (GTK_WIDGET (priv->target_host_label));
Packit fabffb
	} else {
Packit fabffb
		g_return_if_reached ();
Packit fabffb
	}
Packit fabffb
	g_free (name);
Packit fabffb
}
Packit fabffb
Packit fabffb
#if WITH_JANSSON
Packit fabffb
Packit fabffb
static gboolean
Packit fabffb
json_to_dialog (CEPageTeamPort *self)
Packit fabffb
{
Packit fabffb
	CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self);
Packit fabffb
	char *json_config;
Packit fabffb
	json_t *json;
Packit fabffb
	json_error_t json_error;
Packit fabffb
	int ret;
Packit fabffb
	gboolean success = TRUE;
Packit fabffb
	GtkTextIter start, end;
Packit fabffb
	GtkTextBuffer *buffer;
Packit fabffb
	GError *error = NULL;
Packit fabffb
	/* General */
Packit fabffb
	int queue_id = -1;
Packit fabffb
	int port_prio = -1;
Packit fabffb
	int port_sticky = FALSE;
Packit fabffb
	int lacp_port_prio = -1;
Packit fabffb
	int lacp_port_key = -1;
Packit fabffb
	/* Link Watch */
Packit fabffb
	const char *link_watch_name = "";
Packit fabffb
	int link_watch_delay_up = -1;
Packit fabffb
	int link_watch_delay_down = -1;
Packit fabffb
	int link_watch_interval = -1;
Packit fabffb
	int link_watch_init_wait = -1;
Packit fabffb
	int link_watch_missed_max = -1;
Packit fabffb
	const char *link_watch_source_host = "";
Packit fabffb
	const char *link_watch_target_host = "";
Packit fabffb
	int link_watch_validate_active = FALSE;
Packit fabffb
	int link_watch_validate_inactive = FALSE;
Packit fabffb
	int link_watch_send_always = FALSE;
Packit fabffb
Packit fabffb
	buffer = gtk_text_view_get_buffer (priv->json_config_widget);
Packit fabffb
	gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
Packit fabffb
	gtk_text_buffer_get_iter_at_offset (buffer, &end, -1);
Packit fabffb
	json_config = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
Packit fabffb
Packit fabffb
	if (strcmp (json_config, "") == 0) {
Packit fabffb
		/* Initial empty configuration */
Packit fabffb
		json = json_object ();
Packit fabffb
	} else {
Packit fabffb
		json = json_loads (json_config, 0, &json_error);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	if (!json) {
Packit fabffb
		g_message ("Failed to parse JSON: %s on line %d", json_error.text, json_error.line);
Packit fabffb
		success = FALSE;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	/* For simplicity, we proceed with json==NULL. The attempt to
Packit fabffb
	 * unpack will produce an error which we'll ignore. */
Packit fabffb
	g_free (json_config);
Packit fabffb
	ret = json_unpack_ex (json, &json_error, 0,
Packit fabffb
	                      "{"
Packit fabffb
	                      " s?:i,"
Packit fabffb
	                      " s?:i,"
Packit fabffb
	                      " s?:b,"
Packit fabffb
	                      " s?:i,"
Packit fabffb
	                      " s?:i,"
Packit fabffb
	                      " s?:{s?:s, s?:i, s?:i, s?:i, s?:i, s?:i, s?:s, s?:s, s?:b, s?:b, s?:b !}"
Packit fabffb
	                      "!}",
Packit fabffb
	                      "queue_id", &queue_id,
Packit fabffb
	                      "prio", &port_prio,
Packit fabffb
	                      "sticky", &port_sticky,
Packit fabffb
	                      "lacp_prio", &lacp_port_prio,
Packit fabffb
	                      "lacp_key", &lacp_port_key,
Packit fabffb
	                      "link_watch",
Packit fabffb
	                          "name", &link_watch_name,
Packit fabffb
	                          "delay_up", &link_watch_delay_up,
Packit fabffb
	                          "delay_down", &link_watch_delay_down,
Packit fabffb
	                          "interval", &link_watch_interval,
Packit fabffb
	                          "init_wait", &link_watch_init_wait,
Packit fabffb
	                          "missed_max", &link_watch_missed_max,
Packit fabffb
	                          "source_host", &link_watch_source_host,
Packit fabffb
	                          "target_host", &link_watch_target_host,
Packit fabffb
	                          "validate_active", &link_watch_validate_active,
Packit fabffb
	                          "validate_inactive", &link_watch_validate_inactive,
Packit fabffb
	                          "send_always", &link_watch_send_always);
Packit fabffb
Packit fabffb
	if (success == TRUE && ret == -1) {
Packit fabffb
		g_message ("Failed to parse JSON: %s on line %d", json_error.text, json_error.line);
Packit fabffb
		success = FALSE;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	/* We proceed setting the form fields even in case we couldn't unpack.
Packit fabffb
	 * That way we'll get at least sensible default values. Editing will
Packit fabffb
	 * be disabled anyway. */
Packit fabffb
	gtk_spin_button_set_value (priv->queue_id, queue_id);
Packit fabffb
	gtk_spin_button_set_value (priv->port_prio, port_prio);
Packit fabffb
	gtk_toggle_button_set_active (priv->port_sticky, port_sticky);
Packit fabffb
	gtk_spin_button_set_value (priv->lacp_port_prio, lacp_port_prio);
Packit fabffb
	gtk_spin_button_set_value (priv->lacp_port_key, lacp_port_key);
Packit fabffb
	if (!set_combo_box (priv->link_watcher_name, link_watch_name, &error)) {
Packit fabffb
		g_message ("Cannot read link watcher name: %s", error->message);
Packit fabffb
		g_clear_error (&error);
Packit fabffb
		success = FALSE;
Packit fabffb
	}
Packit fabffb
	gtk_spin_button_set_value (priv->delay_up, link_watch_delay_up);
Packit fabffb
	gtk_spin_button_set_value (priv->delay_down, link_watch_delay_down);
Packit fabffb
	gtk_spin_button_set_value (priv->send_interval, link_watch_interval);
Packit fabffb
	gtk_spin_button_set_value (priv->init_wait, link_watch_init_wait);
Packit fabffb
	gtk_spin_button_set_value (priv->missed_max, link_watch_missed_max);
Packit fabffb
	gtk_entry_set_text (priv->source_host, link_watch_source_host);
Packit fabffb
	gtk_entry_set_text (priv->target_host, link_watch_target_host);
Packit fabffb
	gtk_toggle_button_set_active (priv->validate_active, link_watch_validate_active);
Packit fabffb
	gtk_toggle_button_set_active (priv->validate_inactive, link_watch_validate_inactive);
Packit fabffb
	gtk_toggle_button_set_active (priv->send_all, link_watch_send_always);
Packit fabffb
Packit fabffb
	if (success) {
Packit fabffb
		/* Enable editing. */
Packit fabffb
		gtk_widget_set_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 0), 1);
Packit fabffb
		gtk_widget_set_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 1), 1);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	json_decref (json);
Packit fabffb
	return success;
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
maybe_set_str (json_t *json, const char *key, const char *str)
Packit fabffb
{
Packit fabffb
	if (str && *str)
Packit fabffb
		json_object_set_new(json, key, json_string (str));
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
maybe_set_int (json_t *json, const char *key, int num)
Packit fabffb
{
Packit fabffb
	if (num != -1)
Packit fabffb
		json_object_set_new(json, key, json_integer (num));
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
maybe_set_json (json_t *json, const char *key, json_t *val)
Packit fabffb
{
Packit fabffb
	if (   (json_is_object (val) && json_object_size (val))
Packit fabffb
	    || (json_is_array (val) && json_array_size (val))) {
Packit fabffb
		json_object_set_new (json, key, val);
Packit fabffb
	} else {
Packit fabffb
		json_decref (val);
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
maybe_set_true (json_t *json, const char *key, int set)
Packit fabffb
{
Packit fabffb
	if (set)
Packit fabffb
		json_object_set_new(json, key, json_true ());
Packit fabffb
	else
Packit fabffb
		json_object_set_new(json, key, json_false ());
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
dialog_to_json (CEPageTeamPort *self)
Packit fabffb
{
Packit fabffb
	CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self);
Packit fabffb
	json_t *json;
Packit fabffb
	json_t *obj;
Packit fabffb
	gchar *tmp;
Packit fabffb
	char *json_config;
Packit fabffb
	GtkTextBuffer *buffer;
Packit fabffb
Packit fabffb
	/* If the JSON is being edited, don't overwrite it. */
Packit fabffb
	if (!gtk_widget_get_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 0)))
Packit fabffb
		return;
Packit fabffb
Packit fabffb
	/* Disable editing via form, until converted back from JSON. */
Packit fabffb
	gtk_widget_set_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 0), 0);
Packit fabffb
	gtk_widget_set_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 1), 0);
Packit fabffb
Packit fabffb
	json = json_object ();
Packit fabffb
	maybe_set_int (json, "queue_id", gtk_spin_button_get_value_as_int (priv->queue_id));
Packit fabffb
	maybe_set_int (json, "prio", gtk_spin_button_get_value_as_int (priv->port_prio));
Packit fabffb
	if (gtk_toggle_button_get_active (priv->port_sticky))
Packit fabffb
		json_object_set_new(json, "sticky", json_true ());
Packit fabffb
	maybe_set_int (json, "lacp_prio", gtk_spin_button_get_value_as_int (priv->lacp_port_prio));
Packit fabffb
	maybe_set_int (json, "lacp_key", gtk_spin_button_get_value_as_int (priv->lacp_port_key));
Packit fabffb
Packit fabffb
	obj = json_object ();
Packit fabffb
	tmp = get_combo_box (priv->link_watcher_name);
Packit fabffb
	if (g_strcmp0 (tmp, "master") != 0) {
Packit fabffb
		maybe_set_str (obj, "name", tmp);
Packit fabffb
		if (g_strcmp0 (tmp, "ethtool") == 0) {
Packit fabffb
			maybe_set_int (obj, "delay_up", gtk_spin_button_get_value (priv->delay_up));
Packit fabffb
			maybe_set_int (obj, "delay_down", gtk_spin_button_get_value (priv->delay_down));
Packit fabffb
		} else if (g_strcmp0 (tmp, "arp_ping") == 0) {
Packit fabffb
			maybe_set_int (obj, "interval", gtk_spin_button_get_value (priv->send_interval));
Packit fabffb
			maybe_set_int (obj, "init_wait", gtk_spin_button_get_value (priv->init_wait));
Packit fabffb
			maybe_set_int (obj, "missed_max", gtk_spin_button_get_value (priv->missed_max));
Packit fabffb
			maybe_set_str (obj, "source_host", gtk_entry_get_text (priv->source_host));
Packit fabffb
			maybe_set_str (obj, "target_host", gtk_entry_get_text (priv->target_host));
Packit fabffb
			maybe_set_true (obj, "validate_active", gtk_toggle_button_get_active (priv->validate_active));
Packit fabffb
			maybe_set_true (obj, "validate_inactive", gtk_toggle_button_get_active (priv->validate_inactive));
Packit fabffb
			maybe_set_true (obj, "send_always", gtk_toggle_button_get_active (priv->send_all));
Packit fabffb
		} else if (g_strcmp0 (tmp, "nsna_ping") == 0) {
Packit fabffb
			maybe_set_int (obj, "interval", gtk_spin_button_get_value (priv->send_interval));
Packit fabffb
			maybe_set_int (obj, "init_wait", gtk_spin_button_get_value (priv->init_wait));
Packit fabffb
			maybe_set_int (obj, "missed_max", gtk_spin_button_get_value (priv->missed_max));
Packit fabffb
			maybe_set_str (obj, "target_host", gtk_entry_get_text (priv->target_host));
Packit fabffb
		} else {
Packit fabffb
			g_return_if_reached ();
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
	maybe_set_json (json, "link_watch", obj);
Packit fabffb
	g_free (tmp);
Packit fabffb
Packit fabffb
	json_config = json_dumps (json, JSON_INDENT (4));
Packit fabffb
	json_decref (json);
Packit fabffb
Packit fabffb
	buffer = gtk_text_view_get_buffer (priv->json_config_widget);
Packit fabffb
	gtk_text_buffer_set_text (buffer, json_config, -1);
Packit fabffb
	free (json_config);
Packit fabffb
}
Packit fabffb
Packit fabffb
#else /* WITH_JANSSON */
Packit fabffb
Packit fabffb
static gboolean
Packit fabffb
json_to_dialog (CEPageTeamPort *self)
Packit fabffb
{
Packit fabffb
	return FALSE;
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
dialog_to_json (CEPageTeamPort *self)
Packit fabffb
{
Packit fabffb
}
Packit fabffb
Packit fabffb
#endif /* WITH_JANSSON */
Packit fabffb
Packit fabffb
static void
Packit fabffb
advanced_button_clicked_cb (GtkWidget *button, gpointer user_data)
Packit fabffb
{
Packit fabffb
	CEPageTeamPort *self = CE_PAGE_TEAM_PORT (user_data);
Packit fabffb
	CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self);
Packit fabffb
	NMSettingTeamPort *s_port = priv->setting;
Packit fabffb
	GtkWidget *toplevel;
Packit fabffb
	GtkTextBuffer *buffer;
Packit fabffb
	GtkTextIter start, end;
Packit fabffb
	char *json_config = NULL;
Packit fabffb
Packit fabffb
	toplevel = gtk_widget_get_toplevel (CE_PAGE (self)->page);
Packit fabffb
	g_return_if_fail (toplevel);
Packit fabffb
	gtk_window_set_transient_for (GTK_WINDOW (priv->advanced_dialog), GTK_WINDOW (toplevel));
Packit fabffb
	g_return_if_fail (gtk_widget_is_toplevel (toplevel));
Packit fabffb
Packit fabffb
	/* Load in the JSON from settings to dialog. */
Packit fabffb
	buffer = gtk_text_view_get_buffer (priv->json_config_widget);
Packit fabffb
	gtk_text_buffer_set_text (buffer, nm_setting_team_port_get_config (s_port) ?: "", -1);
Packit fabffb
Packit fabffb
	/* Fill in the form fields. */
Packit fabffb
	if (json_to_dialog (self)) {
Packit fabffb
		gtk_notebook_set_current_page (priv->advanced_notebook, 0);
Packit fabffb
	} else {
Packit fabffb
		/* First disable the pages, so that potentially
Packit fabffb
		 * inconsistent changes are not propageated to JSON. */
Packit fabffb
		gtk_widget_set_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 0), 0);
Packit fabffb
		gtk_widget_set_sensitive (gtk_notebook_get_nth_page (priv->advanced_notebook, 1), 0);
Packit fabffb
		gtk_notebook_set_current_page (priv->advanced_notebook, 2);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	link_watcher_changed (priv->link_watcher_name, self);
Packit fabffb
Packit fabffb
	if (gtk_dialog_run (priv->advanced_dialog) == GTK_RESPONSE_OK) {
Packit fabffb
		dialog_to_json (self);
Packit fabffb
Packit fabffb
		/* Set the JSON from the dialog to setting. */
Packit fabffb
		gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
Packit fabffb
		gtk_text_buffer_get_iter_at_offset (buffer, &end, -1);
Packit fabffb
		json_config = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
Packit fabffb
Packit fabffb
		g_object_set (priv->setting,
Packit fabffb
		              NM_SETTING_TEAM_CONFIG,
Packit fabffb
		              g_strcmp0 (json_config, "") == 0 ? NULL : json_config,
Packit fabffb
		              NULL);
Packit fabffb
		g_free (json_config);
Packit fabffb
		ce_page_changed (CE_PAGE (self));
Packit fabffb
	}
Packit fabffb
	gtk_widget_hide (GTK_WIDGET (priv->advanced_dialog));
Packit fabffb
}
Packit fabffb
Packit fabffb
static gboolean
Packit fabffb
switch_page (GtkNotebook *notebook,
Packit fabffb
             GtkWidget   *page,
Packit fabffb
             guint        page_num,
Packit fabffb
             gpointer     user_data)
Packit fabffb
{
Packit fabffb
	CEPageTeamPort *self = CE_PAGE_TEAM_PORT (user_data);
Packit fabffb
Packit fabffb
	/* Keep the JSON and the form in sync if possible. */
Packit fabffb
	if (gtk_notebook_get_current_page (notebook) == 2)
Packit fabffb
		json_to_dialog (self);
Packit fabffb
	else if (page_num == 2)
Packit fabffb
		dialog_to_json (self);
Packit fabffb
Packit fabffb
	return TRUE;
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
populate_ui (CEPageTeamPort *self)
Packit fabffb
{
Packit fabffb
	CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self);
Packit fabffb
	NMSettingTeamPort *s_port = priv->setting;
Packit fabffb
	GtkTextBuffer *buffer;
Packit fabffb
	const char *json_config;
Packit fabffb
Packit fabffb
	buffer = gtk_text_view_get_buffer (priv->json_config_widget);
Packit fabffb
	json_config = nm_setting_team_port_get_config (s_port);
Packit fabffb
	gtk_text_buffer_set_text (buffer, json_config ? json_config : "", -1);
Packit fabffb
Packit fabffb
	g_signal_connect (priv->import_config_button, "clicked", G_CALLBACK (import_button_clicked_cb), self);
Packit fabffb
	g_signal_connect (priv->link_watcher_name, "changed", G_CALLBACK (link_watcher_changed), self);
Packit fabffb
	g_signal_connect (priv->advanced_button, "clicked", G_CALLBACK (advanced_button_clicked_cb), self);
Packit fabffb
	g_signal_connect (priv->advanced_notebook, "switch-page", G_CALLBACK (switch_page), self);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
finish_setup (CEPageTeamPort *self, gpointer user_data)
Packit fabffb
{
Packit fabffb
	populate_ui (self);
Packit fabffb
}
Packit fabffb
Packit fabffb
CEPage *
Packit fabffb
ce_page_team_port_new (NMConnectionEditor *editor,
Packit fabffb
                       NMConnection *connection,
Packit fabffb
                       GtkWindow *parent_window,
Packit fabffb
                       NMClient *client,
Packit fabffb
                       const char **out_secrets_setting_name,
Packit fabffb
                       GError **error)
Packit fabffb
{
Packit fabffb
	CEPageTeamPort *self;
Packit fabffb
	CEPageTeamPortPrivate *priv;
Packit fabffb
Packit fabffb
	self = CE_PAGE_TEAM_PORT (ce_page_new (CE_TYPE_PAGE_TEAM_PORT,
Packit fabffb
	                                       editor,
Packit fabffb
	                                       connection,
Packit fabffb
	                                       parent_window,
Packit fabffb
	                                       client,
Packit fabffb
	                                       "/org/gnome/nm_connection_editor/ce-page-team-port.ui",
Packit fabffb
	                                       "TeamPortPage",
Packit fabffb
	                                       /* Translators: a "Team Port" is a network
Packit fabffb
	                                        * device that is part of a team.
Packit fabffb
	                                        */
Packit fabffb
	                                       _("Team Port")));
Packit fabffb
	if (!self) {
Packit fabffb
		g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("Could not load team port user interface."));
Packit fabffb
		return NULL;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	team_port_private_init (self);
Packit fabffb
	priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self);
Packit fabffb
Packit fabffb
	priv->setting = nm_connection_get_setting_team_port (connection);
Packit fabffb
	if (!priv->setting) {
Packit fabffb
		priv->setting = NM_SETTING_TEAM_PORT (nm_setting_team_port_new ());
Packit fabffb
		nm_connection_add_setting (connection, NM_SETTING (priv->setting));
Packit fabffb
	}
Packit fabffb
Packit fabffb
	g_signal_connect (self, CE_PAGE_INITIALIZED, G_CALLBACK (finish_setup), NULL);
Packit fabffb
Packit fabffb
	return CE_PAGE (self);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
ui_to_setting (CEPageTeamPort *self)
Packit fabffb
{
Packit fabffb
	CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self);
Packit fabffb
	GtkTextBuffer *buffer;
Packit fabffb
	GtkTextIter start, end;
Packit fabffb
	char *json_config;
Packit fabffb
Packit fabffb
	buffer = gtk_text_view_get_buffer (priv->json_config_widget);
Packit fabffb
	gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
Packit fabffb
	gtk_text_buffer_get_iter_at_offset (buffer, &end, -1);
Packit fabffb
	json_config = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
Packit fabffb
Packit fabffb
	if (g_strcmp0 (json_config, "") == 0)
Packit fabffb
		json_config = NULL;
Packit fabffb
	g_object_set (priv->setting,
Packit fabffb
	              NM_SETTING_TEAM_PORT_CONFIG, json_config,
Packit fabffb
	              NULL);
Packit fabffb
	g_free (json_config);
Packit fabffb
}
Packit fabffb
Packit fabffb
static gboolean
Packit fabffb
ce_page_validate_v (CEPage *page, NMConnection *connection, GError **error)
Packit fabffb
{
Packit fabffb
	CEPageTeamPort *self = CE_PAGE_TEAM_PORT (page);
Packit fabffb
	CEPageTeamPortPrivate *priv = CE_PAGE_TEAM_PORT_GET_PRIVATE (self);
Packit fabffb
Packit fabffb
	ui_to_setting (self);
Packit fabffb
	return nm_setting_verify (NM_SETTING (priv->setting), NULL, error);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
ce_page_team_port_init (CEPageTeamPort *self)
Packit fabffb
{
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
ce_page_team_port_class_init (CEPageTeamPortClass *team_port_class)
Packit fabffb
{
Packit fabffb
	GObjectClass *object_class = G_OBJECT_CLASS (team_port_class);
Packit fabffb
	CEPageClass *parent_class = CE_PAGE_CLASS (team_port_class);
Packit fabffb
Packit fabffb
	g_type_class_add_private (object_class, sizeof (CEPageTeamPortPrivate));
Packit fabffb
Packit fabffb
	/* virtual methods */
Packit fabffb
	parent_class->ce_page_validate_v = ce_page_validate_v;
Packit fabffb
}