/* * ni-add-ip-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 #include #include #include #include #include "ni-ip-add-dialog.h" #include "ni-ip.h" struct _NIIPAddDialogPrivate { int family; GtkWidget *entry; GtkWidget *button_add; GtkWidget *check_p2p, *entry_p2p; GtkWidget *check_noprefix; gboolean valid_main_ip, valid_p2p_ip; }; enum { PROP_IP_FAMILY = 1, N_PROPERTIES }; G_DEFINE_TYPE_WITH_PRIVATE (NIIPAddDialog, ni_ip_add_dialog, GTK_TYPE_DIALOG) static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; 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); } } gboolean ip_valid_ipv4 (const char *ip) { struct in_addr addr; if (inet_pton (AF_INET, ip, &addr) == 0) { return FALSE; } return TRUE; } 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_ip_add_dialog_update_response (NIIPAddDialog *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; } if (dialog->priv->valid_main_ip == 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_ip_add_dialog_validate_main_ip (GtkEditable *editable, gpointer data) { NIIPAddDialog *dialog = NI_IP_ADD_DIALOG (data); struct_addr addr; int prefix; dialog->priv->valid_main_ip = ni_ip_add_dialog_get_address (dialog, &addr, &prefix); ni_ip_add_dialog_update_response (dialog); } static void ni_ip_add_dialog_validate_p2p_ip (GtkEditable *editable, gpointer data) { NIIPAddDialog *dialog = NI_IP_ADD_DIALOG (data); const gchar *texto; int prefix; texto = gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry_p2p)); dialog->priv->valid_p2p_ip = FALSE; if (dialog->priv->family == AF_INET || dialog->priv->family == AF_UNSPEC) { dialog->priv->valid_p2p_ip = ip_valid_ipv4 (texto); if (dialog->priv->valid_p2p_ip) { ni_ip_add_dialog_update_response (dialog); return; } } if (dialog->priv->family == AF_INET6 || dialog->priv->family == AF_UNSPEC) { dialog->priv->valid_p2p_ip = ip_valid_ipv6 (texto); } ni_ip_add_dialog_update_response (dialog); } void ni_ip_add_dialog_toggle_p2p_cb (GtkWidget *widget, gpointer data) { NIIPAddDialog *dialog = NI_IP_ADD_DIALOG (data); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) { gtk_widget_set_sensitive (dialog->priv->entry_p2p, TRUE); } else { gtk_widget_set_sensitive (dialog->priv->entry_p2p, FALSE); } ni_ip_add_dialog_update_response (dialog); } static void ni_ip_add_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NIIPAddDialog *dialog = NI_IP_ADD_DIALOG (object); g_return_if_fail (NI_IS_IP_ADD_DIALOG (object)); switch (prop_id) { case PROP_IP_FAMILY: dialog->priv->family = g_value_get_uint (value); if (dialog->priv->family == AF_UNSPEC) { gtk_entry_set_placeholder_text (GTK_ENTRY (dialog->priv->entry), "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->entry), "192.0.2.1/24"); } else if (dialog->priv->family == AF_INET6) { gtk_entry_set_placeholder_text (GTK_ENTRY (dialog->priv->entry), "2001:db8::1/64"); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void ni_ip_add_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NIIPAddDialog *dialog = NI_IP_ADD_DIALOG (object); g_return_if_fail (NI_IS_IP_ADD_DIALOG (object)); switch (prop_id) { case PROP_IP_FAMILY: g_value_set_uint (value, dialog->priv->family); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void ni_ip_add_dialog_class_init (NIIPAddDialogClass *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_ip_add_dialog_set_property; object_class->get_property = ni_ip_add_dialog_get_property; obj_properties[PROP_IP_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 void ni_ip_add_dialog_init (NIIPAddDialog *dialog) { NIIPAddDialogPrivate *priv = ni_ip_add_dialog_get_instance_private (dialog); GtkWidget *image; GtkWidget *vbox, *expander; GtkWidget *container, *label, *hbox; dialog->priv = priv; priv->family = AF_UNSPEC; gtk_window_set_title (GTK_WINDOW (dialog), "Add new IP"); 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_LARGE_TOOLBAR); 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 dirección IP:"); gtk_label_set_xalign (GTK_LABEL (label), 0.0); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 5); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new ("IP:"); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); priv->entry = gtk_entry_new (); gtk_entry_set_placeholder_text (GTK_ENTRY (priv->entry), "192.0.2.1/24 or 2001:db8::1/64"); g_signal_connect (priv->entry, "changed", G_CALLBACK (ni_ip_add_dialog_validate_main_ip), dialog); gtk_box_pack_start (GTK_BOX (hbox), priv->entry, TRUE, TRUE, 0); 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 posible dirección peer-to-peer */ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 3); priv->check_p2p = gtk_check_button_new_with_label ("Point-to-point address:"); g_signal_connect (priv->check_p2p, "toggled", G_CALLBACK (ni_ip_add_dialog_toggle_p2p_cb), dialog); gtk_box_pack_start (GTK_BOX (hbox), priv->check_p2p, FALSE, FALSE, 0); priv->entry_p2p = gtk_entry_new (); g_signal_connect (priv->entry_p2p, "changed", G_CALLBACK (ni_ip_add_dialog_validate_p2p_ip), dialog); gtk_box_pack_start (GTK_BOX (hbox), priv->entry_p2p, TRUE, TRUE, 0); gtk_widget_set_sensitive (priv->entry_p2p, FALSE); priv->check_noprefix = gtk_check_button_new_with_label ("No prefix route"); gtk_box_pack_start (GTK_BOX (vbox), priv->check_noprefix, FALSE, FALSE, 3); dialog->priv->valid_main_ip = FALSE; dialog->priv->valid_p2p_ip = FALSE; gtk_widget_show_all (container); } gboolean ni_ip_add_dialog_get_address (NIIPAddDialog *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->entry)); 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))) { dialog->priv->valid_main_ip = FALSE; return FALSE; } else { *prefix = 128; if (mask[0] != 0) { *prefix = lprefix; } inet_pton (AF_INET6, ip, addr); } } return FALSE; } gboolean ni_ip_add_dialog_has_p2p_address (NIIPAddDialog *dialog) { return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_p2p)); } gboolean ni_ip_add_dialog_get_p2p_address (NIIPAddDialog *dialog, struct_addr *addr) { gboolean valid; const gchar *texto; if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_p2p)) == FALSE) { return FALSE; } texto = gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry_p2p)); 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; } gboolean ni_ip_add_dialog_get_noprefix (NIIPAddDialog *dialog) { return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_noprefix)); } GtkWidget* ni_ip_add_dialog_new (int family) { NIIPAddDialog *dialog; dialog = g_object_new (NI_TYPE_IP_ADD_DIALOG, "family", family, NULL); return GTK_WIDGET (dialog); }