417 lines
14 KiB
C
417 lines
14 KiB
C
/*
|
|
* ni-window-interface.c
|
|
* This file is part of NetworkInador
|
|
*
|
|
* Copyright (C) 2021 - Gatuno
|
|
*
|
|
* NetworkInador 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.
|
|
*
|
|
* NetworkInador 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 NetworkInador; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include "ni-window-interface.h"
|
|
|
|
#include "ni-client.h"
|
|
#include "ni-interface.h"
|
|
#include "ni-ip.h"
|
|
|
|
enum {
|
|
IP_FAMILY,
|
|
IP_ADDR,
|
|
IP_PREFIX,
|
|
IP_LOCAL_ADDR,
|
|
|
|
IP_OBJECT,
|
|
|
|
NUM_COLS_IP
|
|
};
|
|
|
|
struct _NIWindowInterfacePrivate {
|
|
NIInterface *ni_interface;
|
|
|
|
GtkWidget *vbox, *notebook;
|
|
GtkWidget *vbox_ipv4, *vbox_ipv6;
|
|
GtkListStore *ipv4_store, *ipv6_store;
|
|
GtkWidget *tree_ipv4, *tree_ipv6;
|
|
};
|
|
|
|
enum {
|
|
PROP_NI_INTERFACE = 1,
|
|
|
|
N_PROPERTIES
|
|
};
|
|
|
|
enum {
|
|
IP_STORE_COL_MAIN_IP,
|
|
IP_STORE_COL_BROADCAST,
|
|
IP_STORE_COL_OBJECT,
|
|
|
|
NUM_IP_STORE_COLS
|
|
};
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (NIWindowInterface, ni_window_interface, GTK_TYPE_WINDOW)
|
|
|
|
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
|
|
|
|
#if 0
|
|
static GObject *ni_interface_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) {
|
|
GObject *obj;
|
|
GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT);
|
|
NIInterface *ni_interface;
|
|
|
|
obj = parent_class->constructor (type, n_construct_properties, construct_properties);
|
|
|
|
ni_interface = NI_INTERFACE (obj);
|
|
{
|
|
int g;
|
|
for (g = 0; g < n_construct_properties; g++) {
|
|
GParamSpec *pspec = construct_properties[g].pspec;
|
|
GValue *value = construct_properties[g].value;
|
|
|
|
/* Manejar el valor */
|
|
if (strcmp (g_param_spec_get_name (pspec), "index") == 0) {
|
|
printf ("Estableciendo sobre el constructor, el index\n");
|
|
ni_interface->priv->index = g_value_get_uint (value);
|
|
|
|
ni_interface_check_and_connect_signal (ni_interface);
|
|
} else if (strcmp (g_param_spec_get_name (pspec), "ni-client") == 0) {
|
|
ni_interface->priv->ni_client = NI_CLIENT (g_value_get_object (value));
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
#endif
|
|
|
|
static void ni_window_interface_ip_addr_add (NIWindowInterface *window_iface, NIIP *ni_ip) {
|
|
GtkTreeIter iter;
|
|
char buffer[256], ip[128], local[128];
|
|
guint prefix, family, family_size;
|
|
|
|
family = ni_ip_get_family (ni_ip);
|
|
inet_ntop (family, ni_ip_get_addr (ni_ip), ip, sizeof (ip));
|
|
prefix = ni_ip_get_prefix (ni_ip);
|
|
|
|
if (family == AF_INET) {
|
|
family_size = sizeof (struct in_addr);
|
|
} else if (family == AF_INET6) {
|
|
family_size = sizeof (struct in6_addr);
|
|
}
|
|
|
|
if (ni_ip_has_local (ni_ip) &&
|
|
memcmp (ni_ip_get_local_addr (ni_ip), ni_ip_get_addr (ni_ip), family_size) != 0) {
|
|
inet_ntop (family, ni_ip_get_local_addr (ni_ip), local, sizeof (local));
|
|
|
|
snprintf (buffer, sizeof (buffer), "%s peer %s/%u", local, ip, prefix);
|
|
} else {
|
|
snprintf (buffer, sizeof (buffer), "%s/%u", ip, prefix);
|
|
}
|
|
|
|
if (family == AF_INET) {
|
|
gtk_list_store_insert (window_iface->priv->ipv4_store, &iter, -1);
|
|
gtk_list_store_set (window_iface->priv->ipv4_store, &iter, IP_STORE_COL_MAIN_IP, buffer, IP_STORE_COL_OBJECT, ni_ip, -1);
|
|
} else if (family == AF_INET6) {
|
|
gtk_list_store_insert (window_iface->priv->ipv6_store, &iter, -1);
|
|
gtk_list_store_set (window_iface->priv->ipv6_store, &iter, IP_STORE_COL_MAIN_IP, buffer, IP_STORE_COL_OBJECT, ni_ip, -1);
|
|
}
|
|
}
|
|
|
|
static void ni_window_interface_ip_add_cb (NIInterface *ni_interface, NIIP *ni_ip, gpointer data) {
|
|
NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (data);
|
|
ni_window_interface_ip_addr_add (window_iface, ni_ip);
|
|
}
|
|
|
|
static void ni_window_interface_ip_del_cb (NIInterface *ni_interface, NIIP *ni_ip, gpointer data) {
|
|
GtkTreeIter iter;
|
|
NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (data);
|
|
gboolean has;
|
|
guint family;
|
|
GtkListStore *p;
|
|
void *iter_obj;
|
|
|
|
family = ni_ip_get_family (ni_ip);
|
|
|
|
if (family == AF_INET) {
|
|
p = window_iface->priv->ipv4_store;
|
|
} else if (family == AF_INET6) {
|
|
p = window_iface->priv->ipv6_store;
|
|
}
|
|
|
|
has = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (p), &iter);
|
|
while (has) {
|
|
gtk_tree_model_get (GTK_TREE_MODEL (p), &iter, IP_STORE_COL_OBJECT, &iter_obj, -1);
|
|
|
|
if (iter_obj == ni_ip) {
|
|
/* Eliminar este objeto */
|
|
gtk_list_store_remove (p, &iter);
|
|
return;
|
|
}
|
|
has = gtk_tree_model_iter_next (GTK_TREE_MODEL (p), &iter);
|
|
}
|
|
}
|
|
|
|
static void ni_window_interface_changed_name_cb (GObject *object, GParamSpec *sp, gpointer data) {
|
|
NIInterface *ni_interface = NI_INTERFACE (object);
|
|
NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (data);
|
|
gchar *name;
|
|
|
|
/* Cambiar el título */
|
|
name = g_strdup_printf ("Interfaz %s", ni_interface_get_name (window_iface->priv->ni_interface));
|
|
gtk_window_set_title (GTK_WINDOW (window_iface), name);
|
|
g_free (name);
|
|
}
|
|
|
|
static void ni_window_interface_constructed (GObject *obj) {
|
|
GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT);
|
|
NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (obj);
|
|
const GList *ip_list, *g;
|
|
NIIP *ni_ip;
|
|
gchar *name;
|
|
|
|
parent_class->constructed (obj);
|
|
|
|
if (window_iface->priv->ni_interface == NULL) return;
|
|
|
|
/* Cambiar el título */
|
|
name = g_strdup_printf ("Interfaz %s", ni_interface_get_name (window_iface->priv->ni_interface));
|
|
gtk_window_set_title (GTK_WINDOW (obj), name);
|
|
g_free (name);
|
|
|
|
/* TODO: Recorrer las ips, y procesar la información */
|
|
ip_list = ni_interface_get_ip_list (window_iface->priv->ni_interface);
|
|
|
|
for (g = ip_list; g != NULL; g = g->next) {
|
|
ni_ip = (NIIP *) g->data;
|
|
|
|
ni_window_interface_ip_addr_add (window_iface, ni_ip);
|
|
}
|
|
|
|
/* Conectar la señal de IP agregada y la señal de IP eliminada */
|
|
g_signal_connect (window_iface->priv->ni_interface, "new-ip", G_CALLBACK (ni_window_interface_ip_add_cb), window_iface);
|
|
g_signal_connect (window_iface->priv->ni_interface, "delete-ip", G_CALLBACK (ni_window_interface_ip_del_cb), window_iface);
|
|
g_signal_connect (window_iface->priv->ni_interface, "notify::name", G_CALLBACK (ni_window_interface_changed_name_cb), window_iface);
|
|
}
|
|
|
|
static void ni_window_interface_dispose (GObject *obj) {
|
|
NIWindowInterface *window_iface;
|
|
GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT);
|
|
|
|
window_iface = NI_WINDOW_INTERFACE (obj);
|
|
|
|
g_object_unref (window_iface->priv->ni_interface);
|
|
|
|
parent_class->dispose (obj);
|
|
}
|
|
|
|
static void ni_window_interface_finalize (GObject *obj) {
|
|
NIWindowInterface *window_iface;
|
|
GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT);
|
|
|
|
window_iface = NI_WINDOW_INTERFACE (obj);
|
|
|
|
/* Nada que hacer, por el momento */
|
|
|
|
parent_class->finalize (obj);
|
|
}
|
|
|
|
static void ni_window_interface_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) {
|
|
NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (object);
|
|
g_return_if_fail (NI_IS_WINDOW_INTERFACE (object));
|
|
|
|
switch (prop_id) {
|
|
case PROP_NI_INTERFACE:
|
|
window_iface->priv->ni_interface = NI_INTERFACE (g_value_get_object (value));
|
|
g_object_ref (window_iface->priv->ni_interface);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void ni_window_interface_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
|
|
NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (object);
|
|
g_return_if_fail (NI_IS_WINDOW_INTERFACE (object));
|
|
|
|
switch (prop_id) {
|
|
case PROP_NI_INTERFACE:
|
|
g_value_set_object (value, window_iface->priv->ni_interface);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void ni_window_interface_class_init (NIWindowInterfaceClass *klass) {
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GtkWindowClass *window_class = GTK_WINDOW_CLASS (klass);
|
|
|
|
object_class->set_property = ni_window_interface_set_property;
|
|
object_class->get_property = ni_window_interface_get_property;
|
|
object_class->constructed = ni_window_interface_constructed;
|
|
object_class->dispose = ni_window_interface_dispose;
|
|
object_class->finalize = ni_window_interface_finalize;
|
|
|
|
obj_properties[PROP_NI_INTERFACE] = g_param_spec_object (
|
|
"ni-interface",
|
|
"Network Inador Client Interface",
|
|
"The interface object",
|
|
NI_TYPE_INTERFACE,
|
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
|
|
|
g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties);
|
|
}
|
|
|
|
GtkWidget *ni_window_interface_create_tree (GtkListStore *store, GtkWidget **tree) {
|
|
GtkWidget *scrolled;
|
|
GtkAdjustment *h, *v;
|
|
GtkTreeViewColumn *column;
|
|
GtkCellRenderer *renderer;
|
|
|
|
*tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
|
|
|
|
h = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (*tree));
|
|
v = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (*tree));
|
|
|
|
scrolled = gtk_scrolled_window_new (h, v);
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
|
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
column = gtk_tree_view_column_new_with_attributes ("Dirección", renderer, "text", IP_STORE_COL_MAIN_IP, NULL);
|
|
gtk_tree_view_append_column (GTK_TREE_VIEW (*tree), column);
|
|
|
|
gtk_container_add (GTK_CONTAINER (scrolled), *tree);
|
|
|
|
return scrolled;
|
|
}
|
|
|
|
static void ni_window_interface_init (NIWindowInterface *window_iface) {
|
|
NIWindowInterfacePrivate *priv = ni_window_interface_get_instance_private (window_iface);
|
|
window_iface->priv = priv;
|
|
GtkWindow *window = GTK_WINDOW (window_iface);
|
|
GtkWidget *hbox, *label, *button, *image;
|
|
GtkWidget *vbox, *scrolled, *vbox2;
|
|
|
|
/* initialize all public and private members to reasonable default values.
|
|
* They are all automatically initialized to 0 to begin with. */
|
|
priv->ni_interface = NULL;
|
|
gtk_window_set_title (window, "Interfaz");
|
|
g_signal_connect (window, "delete-event", G_CALLBACK (gtk_widget_hide_on_delete), NULL);
|
|
|
|
priv->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
|
gtk_container_add (GTK_CONTAINER (window), priv->vbox);
|
|
|
|
priv->notebook = gtk_notebook_new ();
|
|
gtk_box_pack_start (GTK_BOX (priv->vbox), priv->notebook, TRUE, TRUE, 0);
|
|
|
|
/* Página de IPv4 */
|
|
priv->vbox_ipv4 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
|
label = gtk_label_new ("IPv4");
|
|
gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), priv->vbox_ipv4, label);
|
|
gtk_container_set_border_width (GTK_CONTAINER (priv->vbox_ipv4), 5);
|
|
|
|
/* Preparar el list store */
|
|
priv->ipv4_store = gtk_list_store_new (NUM_IP_STORE_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
|
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
|
gtk_box_pack_start (GTK_BOX (priv->vbox_ipv4), vbox, TRUE, TRUE, 5);
|
|
|
|
label = gtk_label_new ("Direcciones:");
|
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
|
|
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
|
|
|
|
scrolled = ni_window_interface_create_tree (priv->ipv4_store, &priv->tree_ipv4);
|
|
gtk_box_pack_start (GTK_BOX (hbox), scrolled, TRUE, TRUE, 0);
|
|
|
|
/* Botonera del tree view */
|
|
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
|
gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
|
|
|
|
button = gtk_button_new_from_icon_name ("list-add", GTK_ICON_SIZE_LARGE_TOOLBAR);
|
|
gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
|
|
|
|
button = gtk_button_new_from_icon_name ("list-remove", GTK_ICON_SIZE_LARGE_TOOLBAR);
|
|
gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
|
|
|
|
|
|
/* Página de IPv6 */
|
|
priv->vbox_ipv6 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
|
label = gtk_label_new ("IPv6");
|
|
gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), priv->vbox_ipv6, label);
|
|
gtk_container_set_border_width (GTK_CONTAINER (priv->vbox_ipv6), 5);
|
|
|
|
/* Preparar el list store */
|
|
priv->ipv6_store = gtk_list_store_new (NUM_IP_STORE_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
|
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
|
gtk_box_pack_start (GTK_BOX (priv->vbox_ipv6), vbox, TRUE, TRUE, 5);
|
|
|
|
label = gtk_label_new ("Direcciones:");
|
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
|
|
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
|
|
|
|
scrolled = ni_window_interface_create_tree (priv->ipv6_store, &priv->tree_ipv6);
|
|
gtk_box_pack_start (GTK_BOX (hbox), scrolled, TRUE, TRUE, 0);
|
|
|
|
/* Botonera del tree view */
|
|
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
|
gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
|
|
|
|
button = gtk_button_new_from_icon_name ("list-add", GTK_ICON_SIZE_LARGE_TOOLBAR);
|
|
gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
|
|
|
|
button = gtk_button_new_from_icon_name ("list-remove", GTK_ICON_SIZE_LARGE_TOOLBAR);
|
|
gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
|
|
|
|
/* La botonera inferior */
|
|
hbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
|
|
gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
|
|
gtk_box_pack_start (GTK_BOX (priv->vbox), hbox, FALSE, FALSE, 0);
|
|
|
|
/* El boton de cerrar */
|
|
button = gtk_button_new_with_label ("Cerrar");
|
|
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_hide_on_delete), window);
|
|
image = gtk_image_new_from_icon_name ("window-close", GTK_ICON_SIZE_BUTTON);
|
|
gtk_button_set_image (GTK_BUTTON (button), image);
|
|
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show_all (priv->vbox);
|
|
}
|
|
|
|
GtkWidget* ni_window_interface_new (NIInterface *ni_interface) {
|
|
NIWindowInterface *window_iface;
|
|
|
|
window_iface = g_object_new (NI_TYPE_WINDOW_INTERFACE, "type", GTK_WINDOW_TOPLEVEL, "ni-interface", ni_interface, NULL);
|
|
|
|
return GTK_WIDGET (window_iface);
|
|
}
|
|
|