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;
}