NetworkInador/client-gtk/ni-add-route-dialog.c

782 lines
26 KiB
C
Raw Normal View History

/*
* ni-add-route-dialog.c
* This file is part of Network Inador
*
* Copyright (C) 2021 - Gatuno
*
* Network Inador is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Network Inador is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Network Inador; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include <gtk/gtk.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include "ni-add-route-dialog.h"
#include "ni-route.h"
struct _NIAddRouteGW {
NIAddRouteDialog *dialog;
GtkWidget *hbox;
GtkWidget *hbox_weight;
GtkWidget *label_weight;
GtkWidget *gw, *weight;
GtkWidget *button;
int pos;
};
struct _NIAddRouteDialogPrivate {
int family;
GtkWidget *destination;
GtkWidget *button_add;
GtkWidget *metric;
GList *gws;
GtkWidget *add_gw_button;
GtkSizeGroup *weight_sizer;
int gw_count;
GtkListStore *tables_store;
GtkWidget *entry_tabla;
GtkWidget *entry_protocol;
GtkWidget *check_prefsrc, *entry_prefsrc;
gboolean valid_main_ip, valid_gw;
gboolean valid_metric;
gboolean valid_route_table, valid_route_protocol;
gboolean valid_prefsrc;
};
enum {
PROP_ROUTE_FAMILY = 1,
N_PROPERTIES
};
enum {
COL_TABLE_ID,
COL_TABLE_ID_STR,
COL_TABLE_NAME,
NUM_TABLE_STORE_COLS
};
enum {
COL_ROUTE_PROTOCOL_STR,
COL_ROUTE_PROTOCOL_DESC,
NUM_ROUTE_PROTOCOL_COLS
};
G_DEFINE_TYPE_WITH_PRIVATE (NIAddRouteDialog, ni_add_route_dialog, GTK_TYPE_DIALOG)
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
static void ni_add_route_dialog_add_more_gw_cb (GtkWidget *button, gpointer data);
static void ni_add_route_dialog_remove_gw_row_cb (GtkWidget *button, gpointer data);
static gboolean ni_add_route_dialog_get_ip (NIAddRouteDialog *dialog, struct_addr *addr);
static void split_ip_mask (const char *texto, gchar *ip, int ip_size, gchar *mask, int mask_size) {
gchar *dup;
int g, has_slash = -1;
mask[0] = 0;
dup = g_strdup (texto);
for (g = 0; g < strlen (texto); g++) {
if (texto[g] == '/' && texto[g + 1] != 0) {
has_slash = g;
break;
}
}
if (has_slash >= 0) {
strncpy (mask, &texto[has_slash + 1], mask_size);
strncpy (ip, texto, ip_size);
ip[has_slash] = 0;
} else {
strncpy (ip, texto, ip_size);
}
}
static gboolean ip_valid_ipv4 (const char *ip) {
struct in_addr addr;
if (inet_pton (AF_INET, ip, &addr) == 0) {
return FALSE;
}
return TRUE;
}
static gboolean ip_valid_ipv6 (const char *ip) {
struct in6_addr addr;
if (inet_pton (AF_INET6, ip, &addr) == 0) {
return FALSE;
}
return TRUE;
}
static void ni_add_route_dialog_update_response (NIAddRouteDialog *dialog) {
/*if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_p2p)) && dialog->priv->valid_p2p_ip == FALSE) {
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
return;
}*/
gboolean res;
res = dialog->priv->valid_main_ip && dialog->priv->valid_gw && dialog->priv->valid_metric && dialog->priv->valid_route_table && dialog->priv->valid_route_protocol && dialog->priv->valid_prefsrc;
if (res == FALSE) {
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
return;
}
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
}
static void ni_add_route_dialog_validate_main_ip (GtkEditable *editable, gpointer data) {
NIAddRouteDialog *dialog = NI_ADD_ROUTE_DIALOG (data);
struct_addr addr;
int prefix;
dialog->priv->valid_main_ip = ni_add_route_dialog_get_destination (dialog, &addr, &prefix);
if (dialog->priv->valid_main_ip == FALSE) {
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (editable), GTK_ENTRY_ICON_SECONDARY, "dialog-warning");
} else {
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (editable), GTK_ENTRY_ICON_SECONDARY, NULL);
}
ni_add_route_dialog_update_response (dialog);
}
static void ni_add_route_dialog_validate_gws (GtkWidget *widget, gpointer data) {
NIAddRouteDialog *dialog = NI_ADD_ROUTE_DIALOG (data);
struct _NIAddRouteGW *gw_row;
GList *g;
const gchar *texto;
gboolean valid;
dialog->priv->valid_gw = TRUE;
/* Recorrer cada caja de gateways */
g = dialog->priv->gws;
while (g != NULL) {
gw_row = (struct _NIAddRouteGW *) g->data;
valid = FALSE;
texto = gtk_entry_get_text (GTK_ENTRY (gw_row->gw));
if (dialog->priv->family == AF_INET || dialog->priv->family == AF_UNSPEC) {
valid |= ip_valid_ipv4 (texto);
}
if (dialog->priv->family == AF_INET6 || dialog->priv->family == AF_UNSPEC) {
valid |= ip_valid_ipv6 (texto);
}
dialog->priv->valid_gw = dialog->priv->valid_gw && valid;
if (valid == FALSE) {
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (gw_row->gw), GTK_ENTRY_ICON_SECONDARY, "dialog-warning");
} else {
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (gw_row->gw), GTK_ENTRY_ICON_SECONDARY, NULL);
}
g = g->next;
}
ni_add_route_dialog_update_response (dialog);
}
static void ni_add_route_dialog_validate_metric (GtkSpinButton *spin_button, GtkScrollType scroll, gpointer data) {
NIAddRouteDialog *dialog = NI_ADD_ROUTE_DIALOG (data);
gdouble value;
value = gtk_spin_button_get_value (spin_button);
if (value >= 0.0) {
dialog->priv->valid_metric = TRUE;
} else {
dialog->priv->valid_metric = FALSE;
}
ni_add_route_dialog_update_response (dialog);
}
static void ni_add_route_dialog_validate_route_table (GtkComboBox *combo, gpointer data) {
NIAddRouteDialog *dialog = NI_ADD_ROUTE_DIALOG (data);
const char *texto;
int n, g;
char endptr;
GtkWidget *entry;
entry = gtk_bin_get_child (GTK_BIN (combo));
texto = gtk_entry_get_text (GTK_ENTRY (entry));
n = sscanf (texto, "%i%c", &g, &endptr);
if (n != 1) {
dialog->priv->valid_route_table = FALSE;
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, "dialog-warning");
} else {
dialog->priv->valid_route_table = TRUE;
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, NULL);
}
ni_add_route_dialog_update_response (dialog);
}
static void ni_add_route_dialog_validate_route_protocol (GtkComboBox *combo, gpointer data) {
NIAddRouteDialog *dialog = NI_ADD_ROUTE_DIALOG (data);
const char *texto;
int n, g;
char endptr;
GtkWidget *entry;
entry = gtk_bin_get_child (GTK_BIN (combo));
texto = gtk_entry_get_text (GTK_ENTRY (entry));
n = sscanf (texto, "%i%c", &g, &endptr);
if (n != 1 || g > 255) {
dialog->priv->valid_route_protocol = FALSE;
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, "dialog-warning");
} else {
dialog->priv->valid_route_protocol = TRUE;
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, NULL);
}
ni_add_route_dialog_update_response (dialog);
}
static void ni_add_route_dialog_validate_prefsrc_ip (GtkEditable *editable, gpointer data) {
NIAddRouteDialog *dialog = NI_ADD_ROUTE_DIALOG (data);
const gchar *texto;
int prefix;
texto = gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry_prefsrc));
dialog->priv->valid_prefsrc = FALSE;
if (dialog->priv->family == AF_INET || dialog->priv->family == AF_UNSPEC) {
dialog->priv->valid_prefsrc = ip_valid_ipv4 (texto);
if (dialog->priv->valid_prefsrc) {
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (dialog->priv->entry_prefsrc), GTK_ENTRY_ICON_SECONDARY, NULL);
ni_add_route_dialog_update_response (dialog);
return;
}
}
if (dialog->priv->family == AF_INET6 || dialog->priv->family == AF_UNSPEC) {
dialog->priv->valid_prefsrc = ip_valid_ipv6 (texto);
}
if (dialog->priv->valid_prefsrc) {
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (dialog->priv->entry_prefsrc), GTK_ENTRY_ICON_SECONDARY, NULL);
} else {
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (dialog->priv->entry_prefsrc), GTK_ENTRY_ICON_SECONDARY, "dialog-warning");
}
ni_add_route_dialog_update_response (dialog);
}
void ni_add_route_dialog_toggle_prefsrc_cb (GtkWidget *widget, gpointer data) {
NIAddRouteDialog *dialog = NI_ADD_ROUTE_DIALOG (data);
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) {
gtk_widget_set_sensitive (dialog->priv->entry_prefsrc, TRUE);
ni_add_route_dialog_validate_prefsrc_ip (NULL, dialog);
} else {
gtk_widget_set_sensitive (dialog->priv->entry_prefsrc, FALSE);
dialog->priv->valid_prefsrc = TRUE;
}
ni_add_route_dialog_update_response (dialog);
}
/* Función para renderizar la tabla y el nombre con guion separado */
void ni_add_route_dialog_cell_renderer_table_id (GtkCellLayout *cell_layout, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) {
const gchar *name;
gtk_tree_model_get (tree_model, iter, COL_TABLE_NAME, &name, -1);
if (name == NULL) {
g_object_set (cell, "text", "(Sin nombre)", NULL);
} else {
g_object_set (cell, "text", name, NULL);
}
}
static void ni_add_route_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) {
NIAddRouteDialog *dialog = NI_ADD_ROUTE_DIALOG (object);
g_return_if_fail (NI_IS_ADD_ROUTE_DIALOG (object));
switch (prop_id) {
case PROP_ROUTE_FAMILY:
dialog->priv->family = g_value_get_uint (value);
if (dialog->priv->family == AF_UNSPEC) {
gtk_entry_set_placeholder_text (GTK_ENTRY (dialog->priv->destination), "192.0.2.1/24 or 2001:db8::1/64");
} else if (dialog->priv->family == AF_INET) {
gtk_entry_set_placeholder_text (GTK_ENTRY (dialog->priv->destination), "192.0.2.1/24");
} else if (dialog->priv->family == AF_INET6) {
gtk_entry_set_placeholder_text (GTK_ENTRY (dialog->priv->destination), "2001:db8::1/64");
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void ni_add_route_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
NIAddRouteDialog *dialog = NI_ADD_ROUTE_DIALOG (object);
g_return_if_fail (NI_IS_ADD_ROUTE_DIALOG (object));
switch (prop_id) {
case PROP_ROUTE_FAMILY:
g_value_set_uint (value, dialog->priv->family);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void ni_add_route_dialog_class_init (NIAddRouteDialogClass *klass) {
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWindowClass *window_class = GTK_WINDOW_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
object_class->set_property = ni_add_route_dialog_set_property;
object_class->get_property = ni_add_route_dialog_get_property;
obj_properties[PROP_ROUTE_FAMILY] = g_param_spec_uint (
"family",
"Network family",
"Network family to allow",
0, 10, AF_UNSPEC,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties);
}
static struct _NIAddRouteGW *ni_add_route_dialog_create_gw_row (NIAddRouteDialog *dialog) {
struct _NIAddRouteGW *gw_row;
GtkWidget *label, *button;
gw_row = (struct _NIAddRouteGW *) malloc (sizeof (struct _NIAddRouteGW));
if (gw_row == NULL) return NULL;
gw_row->dialog = dialog;
gw_row->hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
//gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
if (dialog->priv->gw_count > 0) {
button = gtk_button_new_from_icon_name ("list-remove", GTK_ICON_SIZE_BUTTON);
g_signal_connect (button, "clicked", G_CALLBACK (ni_add_route_dialog_remove_gw_row_cb), gw_row);
gtk_box_pack_start (GTK_BOX (gw_row->hbox), button, FALSE, FALSE, 0);
}
label = gtk_label_new ("Puerta de enlace:");
gtk_box_pack_start (GTK_BOX (gw_row->hbox), label, FALSE, FALSE, 0);
gw_row->gw = gtk_entry_new ();
g_signal_connect (gw_row->gw, "changed", G_CALLBACK (ni_add_route_dialog_validate_gws), dialog);
gtk_box_pack_start (GTK_BOX (gw_row->hbox), gw_row->gw, TRUE, TRUE, 0);
gw_row->hbox_weight = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
gtk_box_pack_start (GTK_BOX (gw_row->hbox), gw_row->hbox_weight, FALSE, FALSE, 5);
gtk_size_group_add_widget (dialog->priv->weight_sizer, gw_row->hbox_weight);
gw_row->label_weight = gtk_label_new ("Peso:");
gtk_widget_hide (gw_row->label_weight);
gtk_box_pack_start (GTK_BOX (gw_row->hbox_weight), gw_row->label_weight, FALSE, FALSE, 0);
gw_row->weight = gtk_spin_button_new_with_range (0.0, 9000.0, 10.0);
gtk_widget_hide (gw_row->weight);
gtk_box_pack_start (GTK_BOX (gw_row->hbox_weight), gw_row->weight, TRUE, TRUE, 0);
return gw_row;
}
static void ni_add_route_dialog_remove_gw_row_cb (GtkWidget *button, gpointer data) {
struct _NIAddRouteGW *gw_row = (struct _NIAddRouteGW *) data;
NIAddRouteDialog *dialog = gw_row->dialog;
NIAddRouteDialogPrivate *priv = dialog->priv;
gtk_size_group_remove_widget (priv->weight_sizer, gw_row->hbox_weight);
priv->gws = g_list_remove (priv->gws, gw_row);
priv->gw_count--;
gtk_widget_destroy (gw_row->hbox);
free (gw_row);
if (priv->gw_count == 1) {
/* Volver a ocultar la caja de peso de la única fila */
gw_row = (struct _NIAddRouteGW *) priv->gws->data;
gtk_widget_hide (gw_row->hbox_weight);
}
}
static void ni_add_route_dialog_add_more_gw_cb (GtkWidget *button, gpointer data) {
struct _NIAddRouteGW *gw_row;
NIAddRouteDialog *dialog = NI_ADD_ROUTE_DIALOG (data);
NIAddRouteDialogPrivate *priv = ni_add_route_dialog_get_instance_private (dialog);
GValue gval = G_VALUE_INIT;
gint pos;
GtkWidget *vbox_parent, *image;
/* Si es la única fila, mostrar la caja de peso */
if (priv->gw_count == 1) {
gw_row = (struct _NIAddRouteGW *) priv->gws->data;
gtk_widget_show (gw_row->hbox_weight);
}
/* Desconectar esta señal y conectarla a eliminar */
vbox_parent = gtk_widget_get_parent (priv->add_gw_button);
g_value_init (&gval, G_TYPE_INT);
gtk_container_child_get_property (GTK_CONTAINER (vbox_parent), priv->add_gw_button, "position", &gval);
pos = g_value_get_int (&gval);
/* Ahora, crear una nueva fila */
gw_row = ni_add_route_dialog_create_gw_row (dialog);
if (gw_row != NULL) {
gtk_box_pack_start (GTK_BOX (vbox_parent), gw_row->hbox, FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (vbox_parent), gw_row->hbox, pos);
gtk_widget_show_all (gw_row->hbox);
priv->gws = g_list_append (priv->gws, gw_row);
priv->gw_count++;
gtk_window_set_focus (GTK_WINDOW (dialog), gw_row->gw);
}
}
static void ni_add_route_dialog_init (NIAddRouteDialog *dialog) {
NIAddRouteDialogPrivate *priv = ni_add_route_dialog_get_instance_private (dialog);
GtkWidget *image, *entry;
GtkWidget *vbox, *expander;
GtkWidget *container, *label, *hbox;
GtkTreeIter iter;
GtkCellRenderer *renderer;
struct _NIAddRouteGW *gw_row;
GtkListStore *store;
dialog->priv = priv;
priv->family = AF_UNSPEC;
gtk_window_set_title (GTK_WINDOW (dialog), "Add new Route");
gtk_dialog_add_button (GTK_DIALOG (dialog), "Cancelar", GTK_RESPONSE_CANCEL);
priv->button_add = gtk_dialog_add_button (GTK_DIALOG (dialog), "Agregar", GTK_RESPONSE_OK);
image = gtk_image_new_from_icon_name ("list-add", GTK_ICON_SIZE_BUTTON);
gtk_button_set_image (GTK_BUTTON (priv->button_add), image);
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
container = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_box_pack_start (GTK_BOX (container), vbox, TRUE, TRUE, 0);
label = gtk_label_new ("Ingrese los detalles sobre la ruta:");
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 5);
/* La caja de la ruta */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new ("Destino:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
priv->destination = gtk_entry_new ();
gtk_entry_set_placeholder_text (GTK_ENTRY (priv->destination), "192.0.2.1/24 or 2001:db8::1/64");
g_signal_connect (priv->destination, "changed", G_CALLBACK (ni_add_route_dialog_validate_main_ip), dialog);
gtk_box_pack_start (GTK_BOX (hbox), priv->destination, TRUE, TRUE, 0);
priv->weight_sizer = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
/* Primero crear una sola fila de gateway */
priv->gw_count = 0;
priv->gws = NULL;
gw_row = ni_add_route_dialog_create_gw_row (dialog);
if (gw_row != NULL) {
gtk_box_pack_start (GTK_BOX (vbox), gw_row->hbox, FALSE, FALSE, 0);
priv->gws = g_list_append (NULL, gw_row);
priv->gw_count = 1;
}
priv->add_gw_button = gtk_button_new_with_label ("Agregar un siguiente brinco");
g_signal_connect (priv->add_gw_button, "clicked", G_CALLBACK (ni_add_route_dialog_add_more_gw_cb), dialog);
image = gtk_image_new_from_icon_name ("list-add", GTK_ICON_SIZE_BUTTON);
gtk_button_set_image (GTK_BUTTON (priv->add_gw_button), image);
gtk_box_pack_start (GTK_BOX (vbox), priv->add_gw_button, FALSE, FALSE, 0);
/* La métrica */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new ("Metrica:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
priv->metric = gtk_spin_button_new_with_range (0.0, 9000.0, 10.0);
g_signal_connect (priv->metric, "change-value", G_CALLBACK (ni_add_route_dialog_validate_metric), dialog);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (priv->metric), 0);
// gtk_spin_button_get_value_as_int
gtk_box_pack_start (GTK_BOX (hbox), priv->metric, TRUE, TRUE, 0);
// Las opciones avanzadas
expander = gtk_expander_new_with_mnemonic ("_Opciones avanzadas");
gtk_box_pack_start (GTK_BOX (vbox), expander, FALSE, FALSE, 0);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3);
gtk_container_add (GTK_CONTAINER (expander), vbox);
/* La tabla de ruteo */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 3);
label = gtk_label_new ("Tabla de ruteo:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
priv->tables_store = gtk_list_store_new (NUM_TABLE_STORE_COLS, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
/* TODO: Conseguir esta información desde el NetworkInador */
gtk_list_store_insert_with_values (priv->tables_store, &iter, -1, COL_TABLE_ID, 0, COL_TABLE_ID_STR, "0", COL_TABLE_NAME, "Por defecto", -1);
gtk_list_store_insert_with_values (priv->tables_store, NULL, -1, COL_TABLE_ID, 254, COL_TABLE_ID_STR, "254", COL_TABLE_NAME, "Main", -1);
gtk_list_store_insert_with_values (priv->tables_store, NULL, -1, COL_TABLE_ID, 255, COL_TABLE_ID_STR, "255", COL_TABLE_NAME, "Local", -1);
priv->entry_tabla = gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL (priv->tables_store));
g_signal_connect (priv->entry_tabla, "changed", G_CALLBACK (ni_add_route_dialog_validate_route_table), dialog);
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->entry_tabla), renderer, TRUE);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (priv->entry_tabla), renderer, ni_add_route_dialog_cell_renderer_table_id, NULL, NULL);
gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->entry_tabla), COL_TABLE_ID_STR);
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->entry_tabla), &iter);
g_object_unref (priv->tables_store);
gtk_box_pack_start (GTK_BOX (hbox), priv->entry_tabla, TRUE, TRUE, 0);
/* La opción avanzada de tipo de tipo de ruta */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 3);
label = gtk_label_new ("Tipo de ruta:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
store = gtk_list_store_new (NUM_ROUTE_PROTOCOL_COLS, G_TYPE_STRING, G_TYPE_STRING);
gtk_list_store_insert_with_values (store, NULL, -1, COL_ROUTE_PROTOCOL_STR, "2", COL_ROUTE_PROTOCOL_DESC, "Kernel", -1);
gtk_list_store_insert_with_values (store, NULL, -1, COL_ROUTE_PROTOCOL_STR, "3", COL_ROUTE_PROTOCOL_DESC, "Arranque (Boot)", -1);
gtk_list_store_insert_with_values (store, &iter, -1, COL_ROUTE_PROTOCOL_STR, "4", COL_ROUTE_PROTOCOL_DESC, "Estática", -1);
gtk_list_store_insert_with_values (store, NULL, -1, COL_ROUTE_PROTOCOL_STR, "16", COL_ROUTE_PROTOCOL_DESC, "Por DHCP", -1);
priv->entry_protocol = gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL (store));
g_signal_connect (priv->entry_protocol, "changed", G_CALLBACK (ni_add_route_dialog_validate_route_protocol), dialog);
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->entry_protocol), renderer, TRUE);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (priv->entry_protocol), renderer, "text", COL_ROUTE_PROTOCOL_DESC);
gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->entry_protocol), COL_ROUTE_PROTOCOL_STR);
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->entry_protocol), &iter);
g_object_unref (store);
gtk_box_pack_start (GTK_BOX (hbox), priv->entry_protocol, TRUE, TRUE, 0);
/* Agregar pref-src en las opciones avanzadas */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 3);
priv->check_prefsrc = gtk_check_button_new_with_label ("Pref src:");
g_signal_connect (priv->check_prefsrc, "toggled", G_CALLBACK (ni_add_route_dialog_toggle_prefsrc_cb), dialog);
gtk_box_pack_start (GTK_BOX (hbox), priv->check_prefsrc, FALSE, FALSE, 0);
priv->entry_prefsrc = gtk_entry_new ();
g_signal_connect (priv->entry_prefsrc, "changed", G_CALLBACK (ni_add_route_dialog_validate_prefsrc_ip), dialog);
gtk_box_pack_start (GTK_BOX (hbox), priv->entry_prefsrc, TRUE, TRUE, 0);
gtk_widget_set_sensitive (priv->entry_prefsrc, FALSE);
dialog->priv->valid_main_ip = FALSE;
dialog->priv->valid_gw = FALSE;
dialog->priv->valid_metric = TRUE;
dialog->priv->valid_route_table = TRUE;
dialog->priv->valid_route_protocol = TRUE;
dialog->priv->valid_prefsrc = TRUE;
gtk_widget_show_all (container);
if (gw_row != NULL) {
gtk_widget_hide (gw_row->hbox_weight);
}
}
gboolean ni_add_route_dialog_get_destination (NIAddRouteDialog *dialog, struct_addr *addr, int *prefix) {
const gchar *texto;
gchar *rest, ip[128], mask[32];
int lprefix;
gboolean valid;
texto = gtk_entry_get_text (GTK_ENTRY (dialog->priv->destination));
split_ip_mask (texto, ip, sizeof (ip), mask, sizeof (mask));
if (mask[0] != 0) {
lprefix = g_ascii_strtoll (mask, &rest, 10);
if (rest[0] != 0) {
return FALSE;
}
}
if (dialog->priv->family == AF_INET || dialog->priv->family == AF_UNSPEC) {
valid = ip_valid_ipv4 (ip);
if (valid == FALSE ||
(mask[0] != 0 && (lprefix <= 0 || lprefix > 32))) {
if (dialog->priv->family == AF_INET) {
return FALSE;
}
} else {
*prefix = 32;
if (mask[0] != 0) {
*prefix = lprefix;
}
inet_pton (AF_INET, ip, addr);
return TRUE;
}
}
if (dialog->priv->family == AF_INET6 || dialog->priv->family == AF_UNSPEC) {
valid = ip_valid_ipv6 (ip);
if (valid == FALSE || (mask[0] != 0 && (lprefix <= 0 || lprefix > 128))) {
return FALSE;
} else {
*prefix = 128;
if (mask[0] != 0) {
*prefix = lprefix;
}
inet_pton (AF_INET6, ip, addr);
}
}
return FALSE;
}
GList *ni_add_route_dialog_get_gateways (NIAddRouteDialog *dialog) {
GList *result = NULL, *h;
int g, ret;
struct NIAddRouteDialogGW *gw;
struct _NIAddRouteGW *gw_row;
const char *gw_texto;
for (g = 0; g < dialog->priv->gw_count; g++) {
gw = (struct NIAddRouteDialogGW *) g_malloc (sizeof (struct NIAddRouteDialogGW));
h = g_list_nth (dialog->priv->gws, g);
gw_row = (struct _NIAddRouteGW *) h->data;
gw_texto = gtk_entry_get_text (GTK_ENTRY (gw_row->gw));
if (dialog->priv->family == AF_INET) {
inet_pton (AF_INET, gw_texto, &gw->addr);
} else if (dialog->priv->family == AF_INET6) {
inet_pton (AF_INET6, gw_texto, &gw->addr);
} else {
/* UNSPEC */
ret = inet_pton (AF_INET, gw_texto, &gw->addr);
if (ret == 0) {
inet_pton (AF_INET6, gw_texto, &gw->addr);
}
}
gw_texto = gtk_entry_get_text (GTK_ENTRY (gw_row->weight));
gw->metric = g_ascii_strtoll (gw_texto, NULL, 10);
result = g_list_append (result, gw);
}
return result;
}
int ni_add_route_dialog_get_metric (NIAddRouteDialog *dialog) {
gdouble val;
val = gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->priv->metric));
return (int) val;
}
int ni_add_route_dialog_get_route_table (NIAddRouteDialog *dialog) {
const char *texto;
texto = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (dialog->priv->entry_tabla))));
return g_ascii_strtoll (texto, NULL, 10);
}
int ni_add_route_dialog_get_route_protocol (NIAddRouteDialog *dialog) {
const char *texto;
texto = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (dialog->priv->entry_protocol))));
return g_ascii_strtoll (texto, NULL, 10);
}
gboolean ni_add_route_dialog_has_prefsrc_address (NIAddRouteDialog *dialog) {
return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_prefsrc));
}
gboolean ni_add_route_dialog_get_prefsrc_address (NIAddRouteDialog *dialog, struct_addr *addr) {
gboolean valid;
const gchar *texto;
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_prefsrc)) == FALSE) {
return FALSE;
}
texto = gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry_prefsrc));
if (dialog->priv->family == AF_INET || dialog->priv->family == AF_UNSPEC) {
valid = ip_valid_ipv4 (texto);
if (valid) {
inet_pton (AF_INET, texto, addr);
return TRUE;
}
}
if (dialog->priv->family == AF_INET6 || dialog->priv->family == AF_UNSPEC) {
valid = ip_valid_ipv6 (texto);
if (valid) {
inet_pton (AF_INET6, texto, addr);
return TRUE;
}
}
return FALSE;
}
GtkWidget* ni_add_route_dialog_new (int family) {
NIAddRouteDialog *dialog;
dialog = g_object_new (NI_TYPE_ADD_ROUTE_DIALOG, "family", family, NULL);
return GTK_WIDGET (dialog);
}