static gboolean check_ip_routes (NMConnection *orig, NMConnection *candidate, GHashTable *settings, gint64 default_metric, gboolean v4) { gs_free NMIPRoute **routes1 = NULL, **routes2 = NULL; NMSettingIPConfig *s_ip1, *s_ip2; const char *s_name; GHashTable *props; guint i, num; s_name = v4 ? NM_SETTING_IP4_CONFIG_SETTING_NAME : NM_SETTING_IP6_CONFIG_SETTING_NAME; props = check_property_in_hash (settings, s_name, NM_SETTING_IP_CONFIG_ROUTES); if (!props) return TRUE; s_ip1 = (NMSettingIPConfig *) nm_connection_get_setting_by_name (orig, s_name); s_ip2 = (NMSettingIPConfig *) nm_connection_get_setting_by_name (candidate, s_name); if (!s_ip1 || !s_ip2) return FALSE; num = nm_setting_ip_config_get_num_routes (s_ip1); if (num != nm_setting_ip_config_get_num_routes (s_ip2)) return FALSE; routes1 = g_new (NMIPRoute *, num); routes2 = g_new (NMIPRoute *, num); for (i = 0; i < num; i++) { routes1[i] = nm_setting_ip_config_get_route (s_ip1, i); routes2[i] = nm_setting_ip_config_get_route (s_ip2, i); } qsort (routes1, num, sizeof (NMIPRoute *), route_ptr_compare); qsort (routes2, num, sizeof (NMIPRoute *), route_ptr_compare); for (i = 0; i < num; i++) { if (route_compare (routes1[i], routes2[i], default_metric)) return FALSE; } remove_from_hash (settings, props, s_name, NM_SETTING_IP_CONFIG_ROUTES); return TRUE; }
GtkWidget * ip4_routes_dialog_new (NMSettingIPConfig *s_ip4, gboolean automatic) { GtkBuilder *builder; GtkWidget *dialog, *widget, *ok_button; GtkListStore *store; GtkTreeIter model_iter; GtkTreeSelection *selection; gint offset; GtkTreeViewColumn *column; GtkCellRenderer *renderer; int i; GSList *renderers = NULL; GError* error = NULL; /* Initialize temporary storage vars */ g_free (last_edited); last_edited = NULL; last_path = NULL; g_free (last_path); last_column = -1; builder = gtk_builder_new (); if (!gtk_builder_add_from_file (builder, UIDIR "/ce-ip4-routes.ui", &error)) { g_warning ("Couldn't load builder file: %s", error->message); g_error_free (error); return NULL; } dialog = GTK_WIDGET (gtk_builder_get_object (builder, "ip4_routes_dialog")); if (!dialog) { g_warning ("%s: Couldn't load ip4 routes dialog from .ui file.", __func__); g_object_unref (builder); return NULL; } gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); g_object_set_data_full (G_OBJECT (dialog), "builder", builder, (GDestroyNotify) g_object_unref); ok_button = GTK_WIDGET (gtk_builder_get_object (builder, "ok_button")); store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); /* Add existing routes */ for (i = 0; i < nm_setting_ip_config_get_num_routes (s_ip4); i++) { NMIPRoute *route = nm_setting_ip_config_get_route (s_ip4, i); struct in_addr tmp_addr; char netmask[INET_ADDRSTRLEN], metric[32]; gint64 metric_int; if (!route) { g_warning ("%s: empty IP4 route structure!", __func__); continue; } tmp_addr.s_addr = nm_utils_ip4_prefix_to_netmask (nm_ip_route_get_prefix (route)); if (!inet_ntop (AF_INET, &tmp_addr, netmask, sizeof (netmask))) *netmask = '\0'; metric_int = nm_ip_route_get_metric (route); if (metric_int >= 0 && metric_int <= G_MAXUINT32) g_snprintf (metric, sizeof (metric), "%lu", (unsigned long) metric_int); else { if (metric_int != -1) g_warning ("invalid metric %lld", (long long int) metric_int); metric[0] = 0; } gtk_list_store_append (store, &model_iter); gtk_list_store_set (store, &model_iter, COL_ADDRESS, nm_ip_route_get_dest (route), COL_PREFIX, netmask, COL_NEXT_HOP, nm_ip_route_get_next_hop (route), COL_METRIC, metric, -1); } widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip4_routes")); gtk_tree_view_set_model (GTK_TREE_VIEW (widget), GTK_TREE_MODEL (store)); g_object_unref (store); /* IP Address column */ renderer = gtk_cell_renderer_text_new (); g_object_set (renderer, "editable", TRUE, NULL); g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited), builder); g_object_set_data (G_OBJECT (renderer), "column", GUINT_TO_POINTER (COL_ADDRESS)); g_signal_connect (renderer, "editing-started", G_CALLBACK (ip4_cell_editing_started), ok_button); g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), builder); renderers = g_slist_append (renderers, renderer); offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget), -1, _("Address"), renderer, "text", COL_ADDRESS, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1); gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func, GUINT_TO_POINTER (COL_ADDRESS), NULL); /* Prefix column */ renderer = gtk_cell_renderer_text_new (); g_object_set (renderer, "editable", TRUE, NULL); g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited), builder); g_object_set_data (G_OBJECT (renderer), "column", GUINT_TO_POINTER (COL_PREFIX)); g_signal_connect (renderer, "editing-started", G_CALLBACK (ip4_cell_editing_started), ok_button); g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), builder); renderers = g_slist_append (renderers, renderer); offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget), -1, _("Netmask"), renderer, "text", COL_PREFIX, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1); gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func, GUINT_TO_POINTER (COL_PREFIX), NULL); /* Gateway column */ renderer = gtk_cell_renderer_text_new (); g_object_set (renderer, "editable", TRUE, NULL); g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited), builder); g_object_set_data (G_OBJECT (renderer), "column", GUINT_TO_POINTER (COL_NEXT_HOP)); g_signal_connect (renderer, "editing-started", G_CALLBACK (ip4_cell_editing_started), ok_button); g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), builder); renderers = g_slist_append (renderers, renderer); offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget), -1, _("Gateway"), renderer, "text", COL_NEXT_HOP, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1); gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func, GUINT_TO_POINTER (COL_NEXT_HOP), NULL); /* Metric column */ renderer = gtk_cell_renderer_text_new (); g_object_set (renderer, "editable", TRUE, NULL); g_signal_connect (renderer, "edited", G_CALLBACK (cell_edited), builder); g_object_set_data (G_OBJECT (renderer), "column", GUINT_TO_POINTER (COL_METRIC)); g_signal_connect (renderer, "editing-started", G_CALLBACK (uint_cell_editing_started), ok_button); g_signal_connect (renderer, "editing-canceled", G_CALLBACK (cell_editing_canceled), builder); renderers = g_slist_append (renderers, renderer); offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (widget), -1, _("Metric"), renderer, "text", COL_METRIC, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1); gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func, GUINT_TO_POINTER (COL_METRIC), NULL); g_object_set_data_full (G_OBJECT (dialog), "renderers", renderers, (GDestroyNotify) g_slist_free); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); g_signal_connect (selection, "changed", G_CALLBACK (list_selection_changed), GTK_WIDGET (gtk_builder_get_object (builder, "ip4_route_delete_button"))); g_signal_connect (widget, "button-press-event", G_CALLBACK (tree_view_button_pressed_cb), builder); widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip4_route_add_button")); gtk_widget_set_sensitive (widget, TRUE); g_signal_connect (widget, "clicked", G_CALLBACK (route_add_clicked), builder); widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip4_route_delete_button")); gtk_widget_set_sensitive (widget, FALSE); g_signal_connect (widget, "clicked", G_CALLBACK (route_delete_clicked), builder); widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip4_ignore_auto_routes")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), nm_setting_ip_config_get_ignore_auto_routes (s_ip4)); gtk_widget_set_sensitive (widget, automatic); widget = GTK_WIDGET (gtk_builder_get_object (builder, "ip4_never_default")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), nm_setting_ip_config_get_never_default (s_ip4)); /* Update initial validity */ validate (dialog); return dialog; }