|
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 <netinet/in.h>
|
|
Packit Service |
d328f3 |
#include <sys/types.h>
|
|
Packit Service |
d328f3 |
#include <sys/socket.h>
|
|
Packit Service |
d328f3 |
#include <arpa/inet.h>
|
|
Packit Service |
d328f3 |
#include <errno.h>
|
|
Packit Service |
d328f3 |
#include <stdlib.h>
|
|
Packit Service |
d328f3 |
#include <string.h>
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
#include <gdk/gdkkeysyms.h>
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
#include <NetworkManager.h>
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
#include "ip6-routes-dialog.h"
|
|
Packit Service |
d328f3 |
#include "utils.h"
|
|
Packit Service |
d328f3 |
#include "ce-utils.h"
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
#define COL_ADDRESS 0
|
|
Packit Service |
d328f3 |
#define COL_PREFIX 1
|
|
Packit Service |
d328f3 |
#define COL_NEXT_HOP 2
|
|
Packit Service |
d328f3 |
#define COL_METRIC 3
|
|
Packit Service |
d328f3 |
#define COL_LAST COL_METRIC
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Variables to temporarily save last edited cell value
|
|
Packit Service |
d328f3 |
* from routes treeview (cancelling issues) */
|
|
Packit Service |
d328f3 |
static char *last_edited = NULL; /* cell text */
|
|
Packit Service |
d328f3 |
static char *last_path = NULL; /* row in treeview */
|
|
Packit Service |
d328f3 |
static int last_column = -1; /* column in treeview */
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
static gboolean
|
|
Packit Service |
d328f3 |
get_one_int64 (GtkTreeModel *model,
|
|
Packit Service |
d328f3 |
GtkTreeIter *iter,
|
|
Packit Service |
d328f3 |
int column,
|
|
Packit Service |
d328f3 |
gint64 min_value,
|
|
Packit Service |
d328f3 |
gint64 max_value,
|
|
Packit Service |
d328f3 |
gboolean fail_if_missing,
|
|
Packit Service |
d328f3 |
gint64 *out,
|
|
Packit Service |
d328f3 |
char **out_raw)
|
|
Packit Service |
d328f3 |
{
|
|
Packit Service |
d328f3 |
char *item = NULL;
|
|
Packit Service |
d328f3 |
gboolean success = FALSE;
|
|
Packit Service |
d328f3 |
long long int tmp_int;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
gtk_tree_model_get (model, iter, column, &item, -1);
|
|
Packit Service |
d328f3 |
if (out_raw)
|
|
Packit Service |
d328f3 |
*out_raw = item;
|
|
Packit Service |
d328f3 |
if (!item || !strlen (item)) {
|
|
Packit Service |
d328f3 |
if (!out_raw)
|
|
Packit Service |
d328f3 |
g_free (item);
|
|
Packit Service |
d328f3 |
return fail_if_missing ? FALSE : TRUE;
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
errno = 0;
|
|
Packit Service |
d328f3 |
tmp_int = strtoll (item, NULL, 10);
|
|
Packit Service |
d328f3 |
if (errno || tmp_int < min_value || tmp_int > max_value)
|
|
Packit Service |
d328f3 |
goto out;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
*out = (gint64) tmp_int;
|
|
Packit Service |
d328f3 |
success = TRUE;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
out:
|
|
Packit Service |
d328f3 |
if (!out_raw)
|
|
Packit Service |
d328f3 |
g_free (item);
|
|
Packit Service |
d328f3 |
return success;
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
static void
|
|
Packit Service |
d328f3 |
validate (GtkWidget *dialog)
|
|
Packit Service |
d328f3 |
{
|
|
Packit Service |
d328f3 |
GtkBuilder *builder;
|
|
Packit Service |
d328f3 |
GtkWidget *widget;
|
|
Packit Service |
d328f3 |
GtkTreeModel *model;
|
|
Packit Service |
d328f3 |
GtkTreeIter tree_iter;
|
|
Packit Service |
d328f3 |
gboolean valid = FALSE, iter_valid = FALSE;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
g_return_if_fail (dialog != NULL);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
builder = g_object_get_data (G_OBJECT (dialog), "builder");
|
|
Packit Service |
d328f3 |
g_return_if_fail (builder != NULL);
|
|
Packit Service |
d328f3 |
g_return_if_fail (GTK_IS_BUILDER (builder));
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes"));
|
|
Packit Service |
d328f3 |
model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
|
|
Packit Service |
d328f3 |
iter_valid = gtk_tree_model_get_iter_first (model, &tree_iter);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
while (iter_valid) {
|
|
Packit Service |
d328f3 |
char *dest = NULL, *next_hop = NULL;
|
|
Packit Service |
d328f3 |
gint64 prefix = 0, metric = -1;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Address */
|
|
Packit Service |
d328f3 |
if (!utils_tree_model_get_address (model, &tree_iter, COL_ADDRESS, AF_INET6, TRUE, &dest, NULL))
|
|
Packit Service |
d328f3 |
goto done;
|
|
Packit Service |
d328f3 |
g_free (dest);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Prefix */
|
|
Packit Service |
d328f3 |
if (!utils_tree_model_get_int64 (model, &tree_iter, COL_PREFIX, 1, 128, TRUE, &prefix, NULL))
|
|
Packit Service |
d328f3 |
goto done;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Next hop (optional) */
|
|
Packit Service |
d328f3 |
if (!utils_tree_model_get_address (model, &tree_iter, COL_NEXT_HOP, AF_INET6, FALSE, &next_hop, NULL))
|
|
Packit Service |
d328f3 |
goto done;
|
|
Packit Service |
d328f3 |
g_free (next_hop);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Metric (optional) */
|
|
Packit Service |
d328f3 |
if (!get_one_int64 (model, &tree_iter, COL_METRIC, 0, G_MAXUINT32, FALSE, &metric, NULL))
|
|
Packit Service |
d328f3 |
goto done;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
iter_valid = gtk_tree_model_iter_next (model, &tree_iter);
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
valid = TRUE;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
done:
|
|
Packit Service |
d328f3 |
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ok_button"));
|
|
Packit Service |
d328f3 |
gtk_widget_set_sensitive (widget, valid);
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
static void
|
|
Packit Service |
d328f3 |
route_add_clicked (GtkButton *button, gpointer user_data)
|
|
Packit Service |
d328f3 |
{
|
|
Packit Service |
d328f3 |
GtkBuilder *builder = GTK_BUILDER (user_data);
|
|
Packit Service |
d328f3 |
GtkWidget *widget;
|
|
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 |
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes"));
|
|
Packit Service |
d328f3 |
store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (widget)));
|
|
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 (GTK_TREE_VIEW (widget));
|
|
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 (GTK_TREE_VIEW (widget), 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 (GTK_TREE_VIEW (widget), 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 |
validate (GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes_dialog")));
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
static void
|
|
Packit Service |
d328f3 |
route_delete_clicked (GtkButton *button, gpointer user_data)
|
|
Packit Service |
d328f3 |
{
|
|
Packit Service |
d328f3 |
GtkBuilder *builder = GTK_BUILDER (user_data);
|
|
Packit Service |
d328f3 |
GtkTreeView *treeview;
|
|
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 |
treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "ip6_routes"));
|
|
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 |
validate (GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes_dialog")));
|
|
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 |
GtkBuilder *builder = GTK_BUILDER (user_data);
|
|
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 |
if (last_edited) {
|
|
Packit Service |
d328f3 |
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (gtk_builder_get_object (builder, "ip6_routes")));
|
|
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, last_edited, -1);
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
g_free (last_edited);
|
|
Packit Service |
d328f3 |
last_edited = NULL;
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
g_free (last_path);
|
|
Packit Service |
d328f3 |
last_path = NULL;
|
|
Packit Service |
d328f3 |
last_column = -1;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
validate (GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes_dialog")));
|
|
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 |
GtkBuilder *builder = GTK_BUILDER (user_data);
|
|
Packit Service |
d328f3 |
GtkWidget *widget, *dialog;
|
|
Packit Service |
d328f3 |
GtkListStore *store;
|
|
Packit Service |
d328f3 |
GtkTreePath *path;
|
|
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 (last_edited);
|
|
Packit Service |
d328f3 |
last_edited = NULL;
|
|
Packit Service |
d328f3 |
g_free (last_path);
|
|
Packit Service |
d328f3 |
last_path = NULL;
|
|
Packit Service |
d328f3 |
last_column = -1;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes"));
|
|
Packit Service |
d328f3 |
store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (widget)));
|
|
Packit Service |
d328f3 |
path = gtk_tree_path_new_from_string (path_string);
|
|
Packit Service |
d328f3 |
column = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (cell), "column"));
|
|
Packit Service |
d328f3 |
|
|
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 (GTK_TREE_VIEW (widget), column);
|
|
Packit Service |
d328f3 |
dialog = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes_dialog"));
|
|
Packit Service |
d328f3 |
next_cell = g_slist_nth_data (g_object_get_data (G_OBJECT (dialog), "renderers"), column);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (widget), path, next_col, next_cell, TRUE);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
gtk_tree_path_free (path);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
validate (dialog);
|
|
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 |
GtkWidget *ok_button = user_data;
|
|
Packit Service |
d328f3 |
gboolean changed;
|
|
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 |
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 (last_edited);
|
|
Packit Service |
d328f3 |
last_edited = gtk_editable_get_chars (editable, 0, -1);
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Desensitize the OK button during input to simplify input validation.
|
|
Packit Service |
d328f3 |
* All routes will be validated on focus-out, which will then re-enable
|
|
Packit Service |
d328f3 |
* the OK button if the routes are valid.
|
|
Packit Service |
d328f3 |
*/
|
|
Packit Service |
d328f3 |
gtk_widget_set_sensitive (ok_button, FALSE);
|
|
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 |
GtkWidget *ok_button = user_data;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Keep last_edited up-to-date */
|
|
Packit Service |
d328f3 |
g_free (last_edited);
|
|
Packit Service |
d328f3 |
last_edited = gtk_editable_get_chars (editable, 0, -1);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Desensitize the OK button during input to simplify input validation.
|
|
Packit Service |
d328f3 |
* All routes will be validated on focus-out, which will then re-enable
|
|
Packit Service |
d328f3 |
* the OK button if the routes are valid.
|
|
Packit Service |
d328f3 |
*/
|
|
Packit Service |
d328f3 |
gtk_widget_set_sensitive (ok_button, FALSE);
|
|
Packit Service |
d328f3 |
}
|
|
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 |
char *cell_text;
|
|
Packit Service |
d328f3 |
guint column;
|
|
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 |
column = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (user_data), "column"));
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
if (column == COL_PREFIX) {
|
|
Packit Service |
d328f3 |
long int tmp_int;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
errno = 0;
|
|
Packit Service |
d328f3 |
tmp_int = strtol (cell_text, NULL, 10);
|
|
Packit Service |
d328f3 |
if (!*cell_text || errno || tmp_int < 1 || tmp_int > 128)
|
|
Packit Service |
d328f3 |
value_valid = FALSE;
|
|
Packit Service |
d328f3 |
else
|
|
Packit Service |
d328f3 |
value_valid = TRUE;
|
|
Packit Service |
d328f3 |
} else if (column == COL_METRIC) {
|
|
Packit Service |
d328f3 |
long int tmp_int;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
errno = 0;
|
|
Packit Service |
d328f3 |
tmp_int = strtol (cell_text, NULL, 10);
|
|
Packit Service |
d328f3 |
if (errno || tmp_int < 0 || tmp_int > G_MAXUINT32)
|
|
Packit Service |
d328f3 |
value_valid = FALSE;
|
|
Packit Service |
d328f3 |
else
|
|
Packit Service |
d328f3 |
value_valid = TRUE;
|
|
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) > 0)
|
|
Packit Service |
d328f3 |
value_valid = TRUE;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* :: is not accepted for address */
|
|
Packit Service |
d328f3 |
if (column == COL_ADDRESS && IN6_IS_ADDR_UNSPECIFIED (&tmp_addr))
|
|
Packit Service |
d328f3 |
value_valid = FALSE;
|
|
Packit Service |
d328f3 |
/* Consider empty next_hop as valid */
|
|
Packit Service |
d328f3 |
if (!*cell_text && column == COL_NEXT_HOP)
|
|
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 |
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 |
ip6_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 |
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 (last_edited);
|
|
Packit Service |
d328f3 |
last_edited = NULL;
|
|
Packit Service |
d328f3 |
g_free (last_path);
|
|
Packit Service |
d328f3 |
last_path = g_strdup (path);
|
|
Packit Service |
d328f3 |
last_column = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (cell), "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 |
g_signal_connect (G_OBJECT (editable), "changed",
|
|
Packit Service |
d328f3 |
(GCallback) cell_changed_cb,
|
|
Packit Service |
d328f3 |
cell);
|
|
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 |
uint_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 |
GtkWidget *ok_button = user_data;
|
|
Packit Service |
d328f3 |
gboolean changed;
|
|
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 |
utils_char_is_ascii_digit,
|
|
Packit Service |
d328f3 |
uint_filter_cb);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
if (changed) {
|
|
Packit Service |
d328f3 |
g_free (last_edited);
|
|
Packit Service |
d328f3 |
last_edited = gtk_editable_get_chars (editable, 0, -1);
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Desensitize the OK button during input to simplify input validation.
|
|
Packit Service |
d328f3 |
* All routes will be validated on focus-out, which will then re-enable
|
|
Packit Service |
d328f3 |
* the OK button if the routes are valid.
|
|
Packit Service |
d328f3 |
*/
|
|
Packit Service |
d328f3 |
gtk_widget_set_sensitive (ok_button, FALSE);
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
static void
|
|
Packit Service |
d328f3 |
uint_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 |
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 (last_edited);
|
|
Packit Service |
d328f3 |
last_edited = NULL;
|
|
Packit Service |
d328f3 |
g_free (last_path);
|
|
Packit Service |
d328f3 |
last_path = g_strdup (path);
|
|
Packit Service |
d328f3 |
last_column = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (cell), "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) uint_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 |
g_signal_connect (G_OBJECT (editable), "changed",
|
|
Packit Service |
d328f3 |
(GCallback) cell_changed_cb,
|
|
Packit Service |
d328f3 |
cell);
|
|
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 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 |
GtkBuilder *builder = GTK_BUILDER (user_data);
|
|
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 (last_edited && last_path) {
|
|
Packit Service |
d328f3 |
GtkTreeIter iter;
|
|
Packit Service |
d328f3 |
GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (widget)));
|
|
Packit Service |
d328f3 |
GtkTreePath *last_treepath = gtk_tree_path_new_from_string (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, last_column, last_edited, -1);
|
|
Packit Service |
d328f3 |
gtk_tree_path_free (last_treepath);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
g_free (last_edited);
|
|
Packit Service |
d328f3 |
last_edited = NULL;
|
|
Packit Service |
d328f3 |
g_free (last_path);
|
|
Packit Service |
d328f3 |
last_path = NULL;
|
|
Packit Service |
d328f3 |
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 (widget));
|
|
Packit Service |
d328f3 |
validate (GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes_dialog")));
|
|
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 |
char *addr, *next_hop;
|
|
Packit Service |
d328f3 |
gint64 prefix, metric;
|
|
Packit Service |
d328f3 |
const char *color = "red";
|
|
Packit Service |
d328f3 |
gboolean invalid = FALSE;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
if (col == COL_ADDRESS)
|
|
Packit Service |
d328f3 |
invalid = !utils_tree_model_get_address (tree_model, iter, COL_ADDRESS, AF_INET6, TRUE, &addr, &value);
|
|
Packit Service |
d328f3 |
else if (col == COL_PREFIX)
|
|
Packit Service |
d328f3 |
invalid = !utils_tree_model_get_int64 (tree_model, iter, COL_PREFIX, 1, 128, TRUE, &prefix, &value);
|
|
Packit Service |
d328f3 |
else if (col == COL_NEXT_HOP)
|
|
Packit Service |
d328f3 |
invalid = !utils_tree_model_get_address (tree_model, iter, COL_NEXT_HOP, AF_INET6, FALSE, &next_hop, &value);
|
|
Packit Service |
d328f3 |
else if (col == COL_METRIC)
|
|
Packit Service |
d328f3 |
invalid = !utils_tree_model_get_int64 (tree_model, iter, COL_METRIC, 0, G_MAXUINT32, FALSE, &metric, &value);
|
|
Packit Service |
d328f3 |
else
|
|
Packit Service |
d328f3 |
g_warn_if_reached ();
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
if (invalid)
|
|
Packit Service |
d328f3 |
utils_set_cell_background (cell, color, value);
|
|
Packit Service |
d328f3 |
else
|
|
Packit Service |
d328f3 |
utils_set_cell_background (cell, NULL, NULL);
|
|
Packit Service |
d328f3 |
g_free (value);
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
GtkWidget *
|
|
Packit Service |
d328f3 |
ip6_routes_dialog_new (NMSettingIPConfig *s_ip6, gboolean automatic)
|
|
Packit Service |
d328f3 |
{
|
|
Packit Service |
d328f3 |
GtkBuilder *builder;
|
|
Packit Service |
d328f3 |
GtkWidget *dialog, *widget, *ok_button;
|
|
Packit Service |
d328f3 |
GtkListStore *store;
|
|
Packit Service |
d328f3 |
GtkTreeIter model_iter;
|
|
Packit Service |
d328f3 |
GtkTreeSelection *selection;
|
|
Packit Service |
d328f3 |
gint offset;
|
|
Packit Service |
d328f3 |
GtkTreeViewColumn *column;
|
|
Packit Service |
d328f3 |
GtkCellRenderer *renderer;
|
|
Packit Service |
d328f3 |
int i;
|
|
Packit Service |
d328f3 |
GSList *renderers = NULL;
|
|
Packit Service |
d328f3 |
GError* error = NULL;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Initialize temporary storage vars */
|
|
Packit Service |
d328f3 |
g_free (last_edited);
|
|
Packit Service |
d328f3 |
last_edited = NULL;
|
|
Packit Service |
d328f3 |
last_path = NULL;
|
|
Packit Service |
d328f3 |
g_free (last_path);
|
|
Packit Service |
d328f3 |
last_column = -1;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
builder = gtk_builder_new ();
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
if (!gtk_builder_add_from_resource (builder, "/org/gnome/nm_connection_editor/ce-ip6-routes.ui", &error)) {
|
|
Packit Service |
d328f3 |
g_warning ("Couldn't load builder resource: %s", error->message);
|
|
Packit Service |
d328f3 |
g_error_free (error);
|
|
Packit Service |
d328f3 |
return NULL;
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
dialog = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes_dialog"));
|
|
Packit Service |
d328f3 |
if (!dialog) {
|
|
Packit Service |
d328f3 |
g_warning ("%s: Couldn't load ip6 routes dialog from .ui file.", __func__);
|
|
Packit Service |
d328f3 |
g_object_unref (builder);
|
|
Packit Service |
d328f3 |
return NULL;
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
g_object_set_data_full (G_OBJECT (dialog), "builder",
|
|
Packit Service |
d328f3 |
builder, (GDestroyNotify) g_object_unref);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
ok_button = GTK_WIDGET (gtk_builder_get_object (builder, "ok_button"));
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Add existing routes */
|
|
Packit Service |
d328f3 |
for (i = 0; i < nm_setting_ip_config_get_num_routes (s_ip6); i++) {
|
|
Packit Service |
d328f3 |
NMIPRoute *route = nm_setting_ip_config_get_route (s_ip6, i);
|
|
Packit Service |
d328f3 |
char prefix[32], metric[32];
|
|
Packit Service |
d328f3 |
gint64 metric_int;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
if (!route) {
|
|
Packit Service |
d328f3 |
g_warning ("%s: empty IP6 route structure!", __func__);
|
|
Packit Service |
d328f3 |
continue;
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
g_snprintf (prefix, sizeof (prefix), "%u", nm_ip_route_get_prefix (route));
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
metric_int = nm_ip_route_get_metric (route);
|
|
Packit Service |
d328f3 |
if (metric_int >= 0 && metric_int <= G_MAXUINT32)
|
|
Packit Service |
d328f3 |
g_snprintf (metric, sizeof (metric), "%lu", (unsigned long) metric_int);
|
|
Packit Service |
d328f3 |
else {
|
|
Packit Service |
d328f3 |
if (metric_int != -1)
|
|
Packit Service |
d328f3 |
g_warning ("invalid metric %lld", (long long int) metric_int);
|
|
Packit Service |
d328f3 |
metric[0] = 0;
|
|
Packit Service |
d328f3 |
}
|
|
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_route_get_dest (route),
|
|
Packit Service |
d328f3 |
COL_PREFIX, prefix,
|
|
Packit Service |
d328f3 |
COL_NEXT_HOP, nm_ip_route_get_next_hop (route),
|
|
Packit Service |
d328f3 |
COL_METRIC, metric,
|
|
Packit Service |
d328f3 |
-1);
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes"));
|
|
Packit Service |
d328f3 |
gtk_tree_view_set_model (GTK_TREE_VIEW (widget), GTK_TREE_MODEL (store));
|
|
Packit Service |
d328f3 |
g_object_unref (store);
|
|
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), builder);
|
|
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 (ip6_cell_editing_started), ok_button);
|
|
Packit Service |
d328f3 |
g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), builder);
|
|
Packit Service |
d328f3 |
renderers = g_slist_append (renderers, renderer);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget),
|
|
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 (widget), 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), builder);
|
|
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 (uint_cell_editing_started), ok_button);
|
|
Packit Service |
d328f3 |
g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), builder);
|
|
Packit Service |
d328f3 |
renderers = g_slist_append (renderers, renderer);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget),
|
|
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 (widget), 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), builder);
|
|
Packit Service |
d328f3 |
g_object_set_data (G_OBJECT (renderer), "column", GUINT_TO_POINTER (COL_NEXT_HOP));
|
|
Packit Service |
d328f3 |
g_signal_connect (renderer, "editing-started", G_CALLBACK (ip6_cell_editing_started), ok_button);
|
|
Packit Service |
d328f3 |
g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), builder);
|
|
Packit Service |
d328f3 |
renderers = g_slist_append (renderers, renderer);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget),
|
|
Packit Service |
d328f3 |
-1, _("Gateway"), renderer,
|
|
Packit Service |
d328f3 |
"text", COL_NEXT_HOP,
|
|
Packit Service |
d328f3 |
NULL);
|
|
Packit Service |
d328f3 |
column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), 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_NEXT_HOP), NULL);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Metric 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), builder);
|
|
Packit Service |
d328f3 |
g_object_set_data (G_OBJECT (renderer), "column", GUINT_TO_POINTER (COL_METRIC));
|
|
Packit Service |
d328f3 |
g_signal_connect (renderer, "editing-started", G_CALLBACK (uint_cell_editing_started), ok_button);
|
|
Packit Service |
d328f3 |
g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), builder);
|
|
Packit Service |
d328f3 |
renderers = g_slist_append (renderers, renderer);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget),
|
|
Packit Service |
d328f3 |
-1, _("Metric"), renderer,
|
|
Packit Service |
d328f3 |
"text", COL_METRIC,
|
|
Packit Service |
d328f3 |
NULL);
|
|
Packit Service |
d328f3 |
column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), 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_METRIC), NULL);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
g_object_set_data_full (G_OBJECT (dialog), "renderers", renderers, (GDestroyNotify) g_slist_free);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
|
|
Packit Service |
d328f3 |
g_signal_connect (selection, "changed",
|
|
Packit Service |
d328f3 |
G_CALLBACK (list_selection_changed),
|
|
Packit Service |
d328f3 |
GTK_WIDGET (gtk_builder_get_object (builder, "ip6_route_delete_button")));
|
|
Packit Service |
d328f3 |
g_signal_connect (widget, "button-press-event", G_CALLBACK (tree_view_button_pressed_cb), builder);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_route_add_button"));
|
|
Packit Service |
d328f3 |
gtk_widget_set_sensitive (widget, TRUE);
|
|
Packit Service |
d328f3 |
g_signal_connect (widget, "clicked", G_CALLBACK (route_add_clicked), builder);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_route_delete_button"));
|
|
Packit Service |
d328f3 |
gtk_widget_set_sensitive (widget, FALSE);
|
|
Packit Service |
d328f3 |
g_signal_connect (widget, "clicked", G_CALLBACK (route_delete_clicked), builder);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_ignore_auto_routes"));
|
|
Packit Service |
d328f3 |
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget),
|
|
Packit Service |
d328f3 |
nm_setting_ip_config_get_ignore_auto_routes (s_ip6));
|
|
Packit Service |
d328f3 |
gtk_widget_set_sensitive (widget, automatic);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_never_default"));
|
|
Packit Service |
d328f3 |
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget),
|
|
Packit Service |
d328f3 |
nm_setting_ip_config_get_never_default (s_ip6));
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Update initial validity */
|
|
Packit Service |
d328f3 |
validate (dialog);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
return dialog;
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
void
|
|
Packit Service |
d328f3 |
ip6_routes_dialog_update_setting (GtkWidget *dialog, NMSettingIPConfig *s_ip6)
|
|
Packit Service |
d328f3 |
{
|
|
Packit Service |
d328f3 |
GtkBuilder *builder;
|
|
Packit Service |
d328f3 |
GtkWidget *widget;
|
|
Packit Service |
d328f3 |
GtkTreeModel *model;
|
|
Packit Service |
d328f3 |
GtkTreeIter tree_iter;
|
|
Packit Service |
d328f3 |
gboolean iter_valid;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
g_return_if_fail (dialog != NULL);
|
|
Packit Service |
d328f3 |
g_return_if_fail (s_ip6 != NULL);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
builder = g_object_get_data (G_OBJECT (dialog), "builder");
|
|
Packit Service |
d328f3 |
g_return_if_fail (builder != NULL);
|
|
Packit Service |
d328f3 |
g_return_if_fail (GTK_IS_BUILDER (builder));
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_routes"));
|
|
Packit Service |
d328f3 |
model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
|
|
Packit Service |
d328f3 |
iter_valid = gtk_tree_model_get_iter_first (model, &tree_iter);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
nm_setting_ip_config_clear_routes (s_ip6);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
while (iter_valid) {
|
|
Packit Service |
d328f3 |
char *dest = NULL, *next_hop = NULL;
|
|
Packit Service |
d328f3 |
gint64 prefix = 0, metric = -1;
|
|
Packit Service |
d328f3 |
NMIPRoute *route;
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Address */
|
|
Packit Service |
d328f3 |
if (!utils_tree_model_get_address (model, &tree_iter, COL_ADDRESS, AF_INET6, TRUE, &dest, NULL)) {
|
|
Packit Service |
d328f3 |
g_warning ("%s: IPv6 address missing or invalid!", __func__);
|
|
Packit Service |
d328f3 |
goto next;
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Prefix */
|
|
Packit Service |
d328f3 |
if (!utils_tree_model_get_int64 (model, &tree_iter, COL_PREFIX, 1, 128, TRUE, &prefix, NULL)) {
|
|
Packit Service |
d328f3 |
g_warning ("%s: IPv6 prefix missing or invalid!", __func__);
|
|
Packit Service |
d328f3 |
g_free (dest);
|
|
Packit Service |
d328f3 |
goto next;
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Next hop (optional) */
|
|
Packit Service |
d328f3 |
if (!utils_tree_model_get_address (model, &tree_iter, COL_NEXT_HOP, AF_INET6, FALSE, &next_hop, NULL)) {
|
|
Packit Service |
d328f3 |
g_warning ("%s: IPv6 next hop invalid!", __func__);
|
|
Packit Service |
d328f3 |
g_free (dest);
|
|
Packit Service |
d328f3 |
goto next;
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
/* Metric (optional) */
|
|
Packit Service |
d328f3 |
if (!utils_tree_model_get_int64 (model, &tree_iter, COL_METRIC, 0, G_MAXUINT32, FALSE, &metric, NULL)) {
|
|
Packit Service |
d328f3 |
g_warning ("%s: IPv6 metric invalid!", __func__);
|
|
Packit Service |
d328f3 |
g_free (dest);
|
|
Packit Service |
d328f3 |
g_free (next_hop);
|
|
Packit Service |
d328f3 |
goto next;
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
route = nm_ip_route_new (AF_INET6, dest, prefix, next_hop, metric, NULL);
|
|
Packit Service |
d328f3 |
nm_setting_ip_config_add_route (s_ip6, route);
|
|
Packit Service |
d328f3 |
nm_ip_route_unref (route);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
next:
|
|
Packit Service |
d328f3 |
iter_valid = gtk_tree_model_iter_next (model, &tree_iter);
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_ignore_auto_routes"));
|
|
Packit Service |
d328f3 |
g_object_set (s_ip6, NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES,
|
|
Packit Service |
d328f3 |
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)),
|
|
Packit Service |
d328f3 |
NULL);
|
|
Packit Service |
d328f3 |
|
|
Packit Service |
d328f3 |
widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip6_never_default"));
|
|
Packit Service |
d328f3 |
g_object_set (s_ip6, NM_SETTING_IP_CONFIG_NEVER_DEFAULT,
|
|
Packit Service |
d328f3 |
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)),
|
|
Packit Service |
d328f3 |
NULL);
|
|
Packit Service |
d328f3 |
}
|
|
Packit Service |
d328f3 |
|