/* * 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 #include #include #include #include #include #include #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); }