Blame src/connection-editor/connection-helpers.c

Packit Service d328f3
// SPDX-License-Identifier: GPL-2.0+
Packit Service d328f3
/* NetworkManager Connection editor -- Connection editor for NetworkManager
Packit Service d328f3
 *
Packit Service d328f3
 * Copyright 2017 Red Hat, Inc.
Packit Service d328f3
 */
Packit Service d328f3
Packit Service d328f3
#include "nm-default.h"
Packit Service d328f3
Packit Service d328f3
#include "connection-helpers.h"
Packit Service d328f3
Packit Service d328f3
#include "nm-connection-list.h"
Packit Service d328f3
#include "nm-connection-editor.h"
Packit Service d328f3
#include "page-ethernet.h"
Packit Service d328f3
#include "page-wifi.h"
Packit Service d328f3
#include "page-mobile.h"
Packit Service d328f3
#include "page-bluetooth.h"
Packit Service d328f3
#include "page-dsl.h"
Packit Service d328f3
#include "page-infiniband.h"
Packit Service d328f3
#include "page-ip-tunnel.h"
Packit Service d328f3
#include "page-macsec.h"
Packit Service d328f3
#include "page-bond.h"
Packit Service d328f3
#include "page-team.h"
Packit Service d328f3
#include "page-bridge.h"
Packit Service d328f3
#include "page-vlan.h"
Packit Service d328f3
#include "page-vpn.h"
Packit Service d328f3
#include "page-wireguard.h"
Packit Service d328f3
#include "vpn-helpers.h"
Packit Service d328f3
#include "nm-utils/nm-vpn-editor-plugin-call.h"
Packit Service d328f3
Packit Service d328f3
#define COL_MARKUP     0
Packit Service d328f3
#define COL_SENSITIVE  1
Packit Service d328f3
#define COL_NEW_FUNC   2
Packit Service d328f3
#define COL_DESCRIPTION 3
Packit Service d328f3
#define COL_VPN_PLUGIN 4
Packit Service d328f3
#define COL_VPN_SERVICE_TYPE 5
Packit Service d328f3
#define COL_VPN_ADD_DETAIL_KEY 6
Packit Service d328f3
#define COL_VPN_ADD_DETAIL_VAL 7
Packit Service d328f3
Packit Service d328f3
static gint
Packit Service d328f3
sort_types (gconstpointer a, gconstpointer b)
Packit Service d328f3
{
Packit Service d328f3
	ConnectionTypeData *typea = (ConnectionTypeData *)a;
Packit Service d328f3
	ConnectionTypeData *typeb = (ConnectionTypeData *)b;
Packit Service d328f3
Packit Service d328f3
	if (typea->virtual && !typeb->virtual)
Packit Service d328f3
		return 1;
Packit Service d328f3
	else if (typeb->virtual && !typea->virtual)
Packit Service d328f3
		return -1;
Packit Service d328f3
Packit Service d328f3
	if (typea->setting_types[0] == NM_TYPE_SETTING_VPN &&
Packit Service d328f3
	    typeb->setting_types[0] != NM_TYPE_SETTING_VPN)
Packit Service d328f3
		return 1;
Packit Service d328f3
	else if (typeb->setting_types[0] == NM_TYPE_SETTING_VPN &&
Packit Service d328f3
	         typea->setting_types[0] != NM_TYPE_SETTING_VPN)
Packit Service d328f3
		return -1;
Packit Service d328f3
Packit Service d328f3
	return g_utf8_collate (typea->name, typeb->name);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
#define add_type_data_full(a, n, new_func, type0, type1, type2, v) \
Packit Service d328f3
{ \
Packit Service d328f3
	ConnectionTypeData data; \
Packit Service d328f3
 \
Packit Service d328f3
	memset (&data, 0, sizeof (data)); \
Packit Service d328f3
	data.name = n; \
Packit Service d328f3
	data.new_connection_func = new_func; \
Packit Service d328f3
	data.setting_types[0] = type0; \
Packit Service d328f3
	data.setting_types[1] = type1; \
Packit Service d328f3
	data.setting_types[2] = type2; \
Packit Service d328f3
	data.setting_types[3] = G_TYPE_INVALID; \
Packit Service d328f3
	data.virtual = v; \
Packit Service d328f3
	g_array_append_val (a, data); \
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
#define add_type_data_real(a, n, new_func, type0) \
Packit Service d328f3
	add_type_data_full(a, n, new_func, type0, G_TYPE_INVALID, G_TYPE_INVALID, FALSE)
Packit Service d328f3
Packit Service d328f3
#define add_type_data_virtual(a, n, new_func, type0) \
Packit Service d328f3
	add_type_data_full(a, n, new_func, type0, G_TYPE_INVALID, G_TYPE_INVALID, TRUE)
Packit Service d328f3
Packit Service d328f3
ConnectionTypeData *
Packit Service d328f3
get_connection_type_list (void)
Packit Service d328f3
{
Packit Service d328f3
	GArray *array;
Packit Service d328f3
	static ConnectionTypeData *list;
Packit Service d328f3
Packit Service d328f3
	if (list)
Packit Service d328f3
		return list;
Packit Service d328f3
Packit Service d328f3
	array = g_array_new (TRUE, FALSE, sizeof (ConnectionTypeData));
Packit Service d328f3
Packit Service d328f3
	add_type_data_real (array, _("Ethernet"), ethernet_connection_new, NM_TYPE_SETTING_WIRED);
Packit Service d328f3
	add_type_data_real (array, _("Wi-Fi"), wifi_connection_new, NM_TYPE_SETTING_WIRELESS);
Packit Service d328f3
	add_type_data_full (array,
Packit Service d328f3
	                    _("Mobile Broadband"),
Packit Service d328f3
	                    mobile_connection_new,
Packit Service d328f3
	                    NM_TYPE_SETTING_GSM,
Packit Service d328f3
	                    NM_TYPE_SETTING_CDMA,
Packit Service d328f3
	                    NM_TYPE_SETTING_BLUETOOTH,
Packit Service d328f3
	                    FALSE);
Packit Service d328f3
	add_type_data_real (array, _("Bluetooth"), bluetooth_connection_new, NM_TYPE_SETTING_BLUETOOTH);
Packit Service d328f3
	add_type_data_real (array, _("DSL/PPPoE"), dsl_connection_new, NM_TYPE_SETTING_PPPOE);
Packit Service d328f3
	add_type_data_real (array, _("InfiniBand"), infiniband_connection_new, NM_TYPE_SETTING_INFINIBAND);
Packit Service d328f3
	add_type_data_virtual (array, _("Bond"), bond_connection_new, NM_TYPE_SETTING_BOND);
Packit Service d328f3
	add_type_data_virtual (array, _("Team"), team_connection_new, NM_TYPE_SETTING_TEAM);
Packit Service d328f3
	add_type_data_virtual (array, _("Bridge"), bridge_connection_new, NM_TYPE_SETTING_BRIDGE);
Packit Service d328f3
	add_type_data_virtual (array, _("VLAN"), vlan_connection_new, NM_TYPE_SETTING_VLAN);
Packit Service d328f3
	add_type_data_virtual (array, _("IP tunnel"), ip_tunnel_connection_new, NM_TYPE_SETTING_IP_TUNNEL);
Packit Service d328f3
	add_type_data_virtual (array, _("MACsec"), macsec_connection_new, NM_TYPE_SETTING_MACSEC);
Packit Service d328f3
	add_type_data_virtual (array, _("WireGuard"), wireguard_connection_new, NM_TYPE_SETTING_WIREGUARD);
Packit Service d328f3
Packit Service d328f3
	add_type_data_virtual (array, _("VPN"), vpn_connection_new, NM_TYPE_SETTING_VPN);
Packit Service d328f3
Packit Service d328f3
	g_array_sort (array, sort_types);
Packit Service d328f3
Packit Service d328f3
	return (ConnectionTypeData *)g_array_free (array, FALSE);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
combo_row_separator_func (GtkTreeModel *model,
Packit Service d328f3
                          GtkTreeIter  *iter,
Packit Service d328f3
                          gpointer      data)
Packit Service d328f3
{
Packit Service d328f3
	char *label;
Packit Service d328f3
Packit Service d328f3
	gtk_tree_model_get (model, iter,
Packit Service d328f3
	                    COL_MARKUP, &label,
Packit Service d328f3
	                    -1);
Packit Service d328f3
	if (label) {
Packit Service d328f3
		g_free (label);
Packit Service d328f3
		return FALSE;
Packit Service d328f3
	} else
Packit Service d328f3
		return TRUE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
combo_changed_cb (GtkComboBox *combo, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	GtkLabel *label = GTK_LABEL (user_data);
Packit Service d328f3
	GtkTreeModel *model;
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	gs_free char *description = NULL;
Packit Service d328f3
Packit Service d328f3
	if (!gtk_combo_box_get_active_iter (combo, &iter))
Packit Service d328f3
		goto no_description;
Packit Service d328f3
	model = gtk_combo_box_get_model (combo);
Packit Service d328f3
	if (!model)
Packit Service d328f3
		goto no_description;
Packit Service d328f3
Packit Service d328f3
	gtk_tree_model_get (model, &iter,
Packit Service d328f3
	                    COL_DESCRIPTION, &description,
Packit Service d328f3
	                    -1);
Packit Service d328f3
	if (description) {
Packit Service d328f3
		gs_free char *markup = NULL;
Packit Service d328f3
Packit Service d328f3
		markup = g_markup_printf_escaped ("%s", description);
Packit Service d328f3
		gtk_label_set_markup (label, markup);
Packit Service d328f3
		return;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
no_description:
Packit Service d328f3
	gtk_label_set_text (label, "");
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
NMConnection *
Packit Service d328f3
vpn_connection_from_file (const char *filename, GError **error)
Packit Service d328f3
{
Packit Service d328f3
	NMConnection *connection = NULL;
Packit Service d328f3
	GSList *iter;
Packit Service d328f3
Packit Service d328f3
	for (iter = vpn_get_plugin_infos (); !connection && iter; iter = iter->next) {
Packit Service d328f3
		NMVpnEditorPlugin *plugin;
Packit Service d328f3
Packit Service d328f3
		plugin = nm_vpn_plugin_info_get_editor_plugin (iter->data);
Packit Service d328f3
		g_clear_error (error);
Packit Service d328f3
		connection = nm_vpn_editor_plugin_import (plugin, filename, error);
Packit Service d328f3
		if (connection)
Packit Service d328f3
			break;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (connection) {
Packit Service d328f3
		NMSettingVpn *s_vpn;
Packit Service d328f3
		const char *service_type;
Packit Service d328f3
Packit Service d328f3
		s_vpn = nm_connection_get_setting_vpn (connection);
Packit Service d328f3
		service_type = s_vpn ? nm_setting_vpn_get_service_type (s_vpn) : NULL;
Packit Service d328f3
Packit Service d328f3
		/* Check connection sanity. */
Packit Service d328f3
		if (!service_type || !strlen (service_type)) {
Packit Service d328f3
			g_object_unref (connection);
Packit Service d328f3
			connection = NULL;
Packit Service d328f3
			g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("No VPN service type."));
Packit Service d328f3
		}
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (!connection)
Packit Service d328f3
		g_prefix_error (error, _("The VPN plugin failed to import the VPN connection correctly: "));
Packit Service d328f3
Packit Service d328f3
	return connection;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
typedef struct {
Packit Service d328f3
	GtkWindow *parent;
Packit Service d328f3
	NMClient *client;
Packit Service d328f3
	PageNewConnectionResultFunc result_func;
Packit Service d328f3
	gpointer user_data;
Packit Service d328f3
} ImportVpnInfo;
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
import_vpn_from_file_cb (GtkWidget *dialog, gint response, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	char *filename = NULL;
Packit Service d328f3
	ImportVpnInfo *info = (ImportVpnInfo *) user_data;
Packit Service d328f3
	NMConnection *connection = NULL;
Packit Service d328f3
	GError *error = NULL;
Packit Service d328f3
	gboolean canceled = TRUE;
Packit Service d328f3
Packit Service d328f3
	if (response != GTK_RESPONSE_ACCEPT)
Packit Service d328f3
		goto out;
Packit Service d328f3
Packit Service d328f3
	filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
Packit Service d328f3
	if (!filename) {
Packit Service d328f3
		g_warning ("%s: didn't get a filename back from the chooser!", __func__);
Packit Service d328f3
		goto out;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	canceled = FALSE;
Packit Service d328f3
	connection = vpn_connection_from_file (filename, &error);
Packit Service d328f3
	if (connection) {
Packit Service d328f3
		/* Wrap around the actual new function so that the page can complete
Packit Service d328f3
		 * the missing parts, such as UUID or make up the connection name. */
Packit Service d328f3
		vpn_connection_new (FUNC_TAG_PAGE_NEW_CONNECTION_CALL,
Packit Service d328f3
		                    info->parent,
Packit Service d328f3
		                    NULL,
Packit Service d328f3
		                    NULL,
Packit Service d328f3
		                    connection,
Packit Service d328f3
		                    info->client,
Packit Service d328f3
		                    info->result_func,
Packit Service d328f3
		                    info->user_data);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	g_free (filename);
Packit Service d328f3
Packit Service d328f3
out:
Packit Service d328f3
	if (!connection) {
Packit Service d328f3
		info->result_func (FUNC_TAG_PAGE_NEW_CONNECTION_RESULT_CALL,
Packit Service d328f3
		                   connection, canceled, error, info->user_data);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	gtk_widget_hide (dialog);
Packit Service d328f3
	gtk_widget_destroy (dialog);
Packit Service d328f3
	g_object_unref (info->parent);
Packit Service d328f3
	g_object_unref (info->client);
Packit Service d328f3
	g_slice_free (ImportVpnInfo, info);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
vpn_connection_import (FUNC_TAG_PAGE_NEW_CONNECTION_IMPL,
Packit Service d328f3
                       GtkWindow *parent,
Packit Service d328f3
                       const char *detail,
Packit Service d328f3
                       gpointer detail_data,
Packit Service d328f3
                       NMConnection *connection,
Packit Service d328f3
                       NMClient *client,
Packit Service d328f3
                       PageNewConnectionResultFunc result_func,
Packit Service d328f3
                       gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	ImportVpnInfo *info;
Packit Service d328f3
	GtkWidget *dialog;
Packit Service d328f3
	const char *home_folder;
Packit Service d328f3
Packit Service d328f3
	/* The import function decides about the type. */
Packit Service d328f3
	g_return_if_fail (!detail);
Packit Service d328f3
	g_warn_if_fail (!connection);
Packit Service d328f3
Packit Service d328f3
	info = g_slice_new (ImportVpnInfo);
Packit Service d328f3
	info->parent = g_object_ref (parent);
Packit Service d328f3
	info->result_func = result_func;
Packit Service d328f3
	info->client = g_object_ref (client);
Packit Service d328f3
	info->user_data = user_data;
Packit Service d328f3
Packit Service d328f3
	dialog = gtk_file_chooser_dialog_new (_("Select file to import"),
Packit Service d328f3
	                                      NULL,
Packit Service d328f3
	                                      GTK_FILE_CHOOSER_ACTION_OPEN,
Packit Service d328f3
	                                      _("_Cancel"), GTK_RESPONSE_CANCEL,
Packit Service d328f3
	                                      _("_Open"), GTK_RESPONSE_ACCEPT,
Packit Service d328f3
	                                      NULL);
Packit Service d328f3
	home_folder = g_get_home_dir ();
Packit Service d328f3
	gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), home_folder);
Packit Service d328f3
Packit Service d328f3
	g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (import_vpn_from_file_cb), info);
Packit Service d328f3
	gtk_widget_show_all (dialog);
Packit Service d328f3
	gtk_window_present (GTK_WINDOW (dialog));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
set_up_connection_type_combo (GtkComboBox *combo,
Packit Service d328f3
                              GtkLabel *description_label,
Packit Service d328f3
                              NewConnectionTypeFilterFunc type_filter_func,
Packit Service d328f3
                              gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	GtkListStore *model = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
Packit Service d328f3
	ConnectionTypeData *list = get_connection_type_list ();
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	GSList *p;
Packit Service d328f3
	int i, vpn_index = -1, active = 0, added = 0;
Packit Service d328f3
	gboolean import_supported = FALSE;
Packit Service d328f3
	gboolean added_virtual_header = FALSE;
Packit Service d328f3
	gboolean show_headers = (type_filter_func == NULL);
Packit Service d328f3
	char *markup;
Packit Service d328f3
	GSList *vpn_plugins;
Packit Service d328f3
Packit Service d328f3
	gtk_combo_box_set_row_separator_func (combo, combo_row_separator_func, NULL, NULL);
Packit Service d328f3
	g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (combo_changed_cb), description_label);
Packit Service d328f3
Packit Service d328f3
	if (show_headers) {
Packit Service d328f3
		markup = g_strdup_printf ("<big>%s</big>", _("Hardware"));
Packit Service d328f3
		gtk_list_store_append (model, &iter);
Packit Service d328f3
		gtk_list_store_set (model, &iter,
Packit Service d328f3
		                    COL_MARKUP, markup,
Packit Service d328f3
		                    COL_SENSITIVE, FALSE,
Packit Service d328f3
		                    -1);
Packit Service d328f3
		g_free (markup);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	for (i = 0; list[i].name; i++) {
Packit Service d328f3
		if (type_filter_func) {
Packit Service d328f3
			if (   (   list[i].setting_types[0] == G_TYPE_INVALID
Packit Service d328f3
			        || !type_filter_func (FUNC_TAG_NEW_CONNECTION_TYPE_FILTER_CALL, list[i].setting_types[0], user_data))
Packit Service d328f3
			    && (   list[i].setting_types[1] == G_TYPE_INVALID
Packit Service d328f3
			        || !type_filter_func (FUNC_TAG_NEW_CONNECTION_TYPE_FILTER_CALL, list[i].setting_types[1], user_data))
Packit Service d328f3
			    && (   list[i].setting_types[2] == G_TYPE_INVALID
Packit Service d328f3
			        || !type_filter_func (FUNC_TAG_NEW_CONNECTION_TYPE_FILTER_CALL, list[i].setting_types[2], user_data)))
Packit Service d328f3
				continue;
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		if (list[i].setting_types[0] == NM_TYPE_SETTING_VPN) {
Packit Service d328f3
			vpn_index = i;
Packit Service d328f3
			continue;
Packit Service d328f3
		} else if (list[i].setting_types[0] == NM_TYPE_SETTING_WIRED)
Packit Service d328f3
			active = added;
Packit Service d328f3
Packit Service d328f3
		if (list[i].virtual && !added_virtual_header && show_headers) {
Packit Service d328f3
			markup = g_strdup_printf ("<big>%s</big>", _("Virtual"));
Packit Service d328f3
			gtk_list_store_append (model, &iter);
Packit Service d328f3
			gtk_list_store_set (model, &iter,
Packit Service d328f3
			                    COL_MARKUP, markup,
Packit Service d328f3
			                    COL_SENSITIVE, FALSE,
Packit Service d328f3
			                    -1);
Packit Service d328f3
			g_free (markup);
Packit Service d328f3
			added_virtual_header = TRUE;
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		if (show_headers)
Packit Service d328f3
			markup = g_markup_printf_escaped ("    %s", list[i].name);
Packit Service d328f3
		else
Packit Service d328f3
			markup = g_markup_escape_text (list[i].name, -1);
Packit Service d328f3
		gtk_list_store_append (model, &iter);
Packit Service d328f3
		gtk_list_store_set (model, &iter,
Packit Service d328f3
		                    COL_MARKUP, markup,
Packit Service d328f3
		                    COL_SENSITIVE, TRUE,
Packit Service d328f3
		                    COL_NEW_FUNC, list[i].new_connection_func,
Packit Service d328f3
		                    -1);
Packit Service d328f3
		g_free (markup);
Packit Service d328f3
		added++;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	vpn_plugins = vpn_get_plugin_infos ();
Packit Service d328f3
	if (!vpn_plugins || vpn_index == -1) {
Packit Service d328f3
		gtk_combo_box_set_active (combo, show_headers ? active + 1 : active);
Packit Service d328f3
		return;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (show_headers) {
Packit Service d328f3
		markup = g_strdup_printf ("<big>%s</big>", _("VPN"));
Packit Service d328f3
		gtk_list_store_append (model, &iter);
Packit Service d328f3
		gtk_list_store_set (model, &iter,
Packit Service d328f3
		                    COL_MARKUP, markup,
Packit Service d328f3
		                    COL_SENSITIVE, FALSE,
Packit Service d328f3
		                    -1);
Packit Service d328f3
		g_free (markup);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	for (p = vpn_plugins; p; p = p->next) {
Packit Service d328f3
		NMVpnPluginInfo *plugin_info = p->data;
Packit Service d328f3
		NMVpnEditorPlugin *plugin;
Packit Service d328f3
		const char *const*aliases;
Packit Service d328f3
		const char *service_type;
Packit Service d328f3
		gboolean is_alias = FALSE;
Packit Service d328f3
Packit Service d328f3
		plugin = nm_vpn_plugin_info_get_editor_plugin (plugin_info);
Packit Service d328f3
		if (!plugin)
Packit Service d328f3
			continue;
Packit Service d328f3
Packit Service d328f3
		service_type = nm_vpn_plugin_info_get_service (plugin_info);
Packit Service d328f3
		aliases = nm_vpn_plugin_info_get_aliases (plugin_info);
Packit Service d328f3
Packit Service d328f3
		for (;;) {
Packit Service d328f3
			gs_free char *pretty_name = NULL;
Packit Service d328f3
			gs_free char *description = NULL;
Packit Service d328f3
			NMVpnEditorPluginServiceFlags flags;
Packit Service d328f3
			gs_strfreev char **add_details_free = NULL;
Packit Service d328f3
			char **add_details;
Packit Service d328f3
			const char *i_add_detail;
Packit Service d328f3
Packit Service d328f3
			if (!nm_vpn_editor_plugin_get_service_info (plugin, service_type, NULL, &pretty_name, &description, &flags)) {
Packit Service d328f3
				if (is_alias)
Packit Service d328f3
					goto next;
Packit Service d328f3
				g_object_get (plugin,
Packit Service d328f3
				              NM_VPN_EDITOR_PLUGIN_NAME, &pretty_name,
Packit Service d328f3
				              NM_VPN_EDITOR_PLUGIN_DESCRIPTION, &description,
Packit Service d328f3
				              NULL);
Packit Service d328f3
				flags = NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_CAN_ADD;
Packit Service d328f3
			}
Packit Service d328f3
			if (!pretty_name)
Packit Service d328f3
				goto next;
Packit Service d328f3
			if (!NM_FLAGS_HAS (flags, NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_CAN_ADD))
Packit Service d328f3
				goto next;
Packit Service d328f3
Packit Service d328f3
			add_details_free = nm_vpn_editor_plugin_get_service_add_details (plugin, service_type);
Packit Service d328f3
			add_details = add_details_free;
Packit Service d328f3
			i_add_detail = add_details ? add_details[0] : NULL;
Packit Service d328f3
			do {
Packit Service d328f3
				const char *i_pretty_name, *i_description;
Packit Service d328f3
				gs_free char *i_pretty_name_free = NULL;
Packit Service d328f3
				gs_free char *i_description_free = NULL;
Packit Service d328f3
				gs_free char *i_add_detail_key = NULL;
Packit Service d328f3
				gs_free char *i_add_detail_val = NULL;
Packit Service d328f3
Packit Service d328f3
				if (i_add_detail) {
Packit Service d328f3
					if (i_add_detail[0] == '\0')
Packit Service d328f3
						goto i_next;
Packit Service d328f3
					if (!nm_vpn_editor_plugin_get_service_add_detail (plugin, service_type, i_add_detail,
Packit Service d328f3
					                                                  &i_pretty_name_free, &i_description_free,
Packit Service d328f3
					                                                  &i_add_detail_key, &i_add_detail_val, NULL))
Packit Service d328f3
						goto i_next;
Packit Service d328f3
					if (!i_pretty_name_free)
Packit Service d328f3
						goto i_next;
Packit Service d328f3
					if (i_add_detail_key && !i_add_detail_key[0])
Packit Service d328f3
						goto i_next;
Packit Service d328f3
					if (i_add_detail_val && !i_add_detail_val[0])
Packit Service d328f3
						goto next;
Packit Service d328f3
					if (!i_add_detail_key ^ !i_add_detail_val)
Packit Service d328f3
						goto next;
Packit Service d328f3
					i_pretty_name = i_pretty_name_free;
Packit Service d328f3
					i_description = i_description_free;
Packit Service d328f3
				} else {
Packit Service d328f3
					i_pretty_name = pretty_name;
Packit Service d328f3
					i_description = description;
Packit Service d328f3
				}
Packit Service d328f3
Packit Service d328f3
				if (show_headers)
Packit Service d328f3
					markup = g_markup_printf_escaped ("    %s", i_pretty_name);
Packit Service d328f3
				else
Packit Service d328f3
					markup = g_markup_escape_text (i_pretty_name, -1);
Packit Service d328f3
Packit Service d328f3
				gtk_list_store_append (model, &iter);
Packit Service d328f3
				gtk_list_store_set (model, &iter,
Packit Service d328f3
				                    COL_MARKUP, markup,
Packit Service d328f3
				                    COL_SENSITIVE, TRUE,
Packit Service d328f3
				                    COL_NEW_FUNC, list[vpn_index].new_connection_func,
Packit Service d328f3
				                    COL_DESCRIPTION, i_description,
Packit Service d328f3
				                    COL_VPN_PLUGIN, plugin,
Packit Service d328f3
				                    COL_VPN_SERVICE_TYPE, service_type,
Packit Service d328f3
				                    COL_VPN_ADD_DETAIL_KEY, i_add_detail_key,
Packit Service d328f3
				                    COL_VPN_ADD_DETAIL_VAL, i_add_detail_val,
Packit Service d328f3
				                    -1);
Packit Service d328f3
				g_free (markup);
Packit Service d328f3
Packit Service d328f3
i_next:
Packit Service d328f3
				if (!i_add_detail)
Packit Service d328f3
					break;
Packit Service d328f3
				i_add_detail = (++add_details)[0];
Packit Service d328f3
			} while (i_add_detail);
Packit Service d328f3
Packit Service d328f3
next:
Packit Service d328f3
			if (!aliases || !aliases[0])
Packit Service d328f3
				break;
Packit Service d328f3
			is_alias = TRUE;
Packit Service d328f3
			service_type = aliases[0];
Packit Service d328f3
			aliases++;
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		if (nm_vpn_editor_plugin_get_capabilities (plugin) & NM_VPN_EDITOR_PLUGIN_CAPABILITY_IMPORT)
Packit Service d328f3
			import_supported = TRUE;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (import_supported) {
Packit Service d328f3
		/* Separator */
Packit Service d328f3
		gtk_list_store_append (model, &iter);
Packit Service d328f3
Packit Service d328f3
		if (show_headers)
Packit Service d328f3
			markup = g_strdup_printf ("    %s", _("Import a saved VPN configuration…"));
Packit Service d328f3
		else
Packit Service d328f3
			markup = g_strdup (_("Import a saved VPN configuration…"));
Packit Service d328f3
		gtk_list_store_append (model, &iter);
Packit Service d328f3
		gtk_list_store_set (model, &iter,
Packit Service d328f3
		                    COL_MARKUP, markup,
Packit Service d328f3
		                    COL_SENSITIVE, TRUE,
Packit Service d328f3
		                    COL_NEW_FUNC, vpn_connection_import,
Packit Service d328f3
		                    -1);
Packit Service d328f3
		g_free (markup);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	gtk_combo_box_set_active (combo, show_headers ? active + 1 : active);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
typedef struct {
Packit Service d328f3
	GtkWindow *parent_window;
Packit Service d328f3
	NMClient *client;
Packit Service d328f3
	NewConnectionResultFunc result_func;
Packit Service d328f3
	gpointer user_data;
Packit Service d328f3
} NewConnectionData;
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
new_connection_result (FUNC_TAG_PAGE_NEW_CONNECTION_RESULT_IMPL,
Packit Service d328f3
                       NMConnection *connection, /* allow-none, don't transfer reference, allow-keep */
Packit Service d328f3
                       gboolean canceled,
Packit Service d328f3
                       GError *error,
Packit Service d328f3
                       gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NewConnectionData *ncd = user_data;
Packit Service d328f3
	NewConnectionResultFunc result_func;
Packit Service d328f3
	GtkWindow *parent_window;
Packit Service d328f3
	const char *default_message = _("The connection editor dialog could not be initialized due to an unknown error.");
Packit Service d328f3
Packit Service d328f3
	result_func = ncd->result_func;
Packit Service d328f3
	user_data = ncd->user_data;
Packit Service d328f3
	parent_window = ncd->parent_window;
Packit Service d328f3
	g_slice_free (NewConnectionData, ncd);
Packit Service d328f3
Packit Service d328f3
	if (!connection && !canceled) {
Packit Service d328f3
		nm_connection_editor_error (parent_window,
Packit Service d328f3
		                            _("Could not create new connection"),
Packit Service d328f3
		                            "%s",
Packit Service d328f3
		                            (error && error->message) ? error->message : default_message);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	result_func (FUNC_TAG_NEW_CONNECTION_RESULT_CALL, connection, user_data);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
void
Packit Service d328f3
new_connection_of_type (GtkWindow *parent_window,
Packit Service d328f3
                        const char *detail,
Packit Service d328f3
                        gpointer detail_data,
Packit Service d328f3
                        NMConnection *connection,
Packit Service d328f3
                        NMClient *client,
Packit Service d328f3
                        PageNewConnectionFunc new_func,
Packit Service d328f3
                        NewConnectionResultFunc result_func,
Packit Service d328f3
                        gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NewConnectionData *ncd;
Packit Service d328f3
Packit Service d328f3
	ncd = g_slice_new (NewConnectionData);
Packit Service d328f3
	ncd->parent_window = parent_window;
Packit Service d328f3
	ncd->client = client;
Packit Service d328f3
	ncd->result_func = result_func;
Packit Service d328f3
	ncd->user_data = user_data;
Packit Service d328f3
Packit Service d328f3
	new_func (FUNC_TAG_PAGE_NEW_CONNECTION_CALL,
Packit Service d328f3
	          parent_window,
Packit Service d328f3
	          detail,
Packit Service d328f3
	          detail_data,
Packit Service d328f3
	          connection,
Packit Service d328f3
	          client,
Packit Service d328f3
	          new_connection_result,
Packit Service d328f3
	          ncd);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
void
Packit Service d328f3
new_connection_dialog (GtkWindow *parent_window,
Packit Service d328f3
                       NMClient *client,
Packit Service d328f3
                       NewConnectionTypeFilterFunc type_filter_func,
Packit Service d328f3
                       NewConnectionResultFunc result_func,
Packit Service d328f3
                       gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	new_connection_dialog_full (parent_window, client,
Packit Service d328f3
	                            NULL, NULL,
Packit Service d328f3
	                            type_filter_func,
Packit Service d328f3
	                            result_func,
Packit Service d328f3
	                            user_data);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
void
Packit Service d328f3
new_connection_dialog_full (GtkWindow *parent_window,
Packit Service d328f3
                            NMClient *client,
Packit Service d328f3
                            const char *primary_label,
Packit Service d328f3
                            const char *secondary_label,
Packit Service d328f3
                            NewConnectionTypeFilterFunc type_filter_func,
Packit Service d328f3
                            NewConnectionResultFunc result_func,
Packit Service d328f3
                            gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
Packit Service d328f3
	GtkBuilder *gui;
Packit Service d328f3
	GtkDialog *type_dialog;
Packit Service d328f3
	GtkComboBox *combo;
Packit Service d328f3
	GtkLabel *label;
Packit Service d328f3
	GtkTreeIter iter;
Packit Service d328f3
	int response;
Packit Service d328f3
	PageNewConnectionFunc new_func = NULL;
Packit Service d328f3
	gs_free char *vpn_service_type = NULL;
Packit Service d328f3
	gs_free char *vpn_add_detail_key = NULL;
Packit Service d328f3
	gs_free char *vpn_add_detail_val = NULL;
Packit Service d328f3
	const char *detail = NULL;
Packit Service d328f3
	gpointer detail_data = NULL;
Packit Service d328f3
	GError *error = NULL;
Packit Service d328f3
	CEPageVpnDetailData vpn_data;
Packit Service d328f3
	GtkButton *create_button;
Packit Service d328f3
Packit Service d328f3
	/* load GUI */
Packit Service d328f3
	gui = gtk_builder_new ();
Packit Service d328f3
	if (!gtk_builder_add_from_resource (gui,
Packit Service d328f3
	                                    "/org/gnome/nm_connection_editor/ce-new-connection.ui",
Packit Service d328f3
	                                    &error)) {
Packit Service d328f3
		g_warning ("Couldn't load builder resource: %s", error->message);
Packit Service d328f3
		g_error_free (error);
Packit Service d328f3
		g_object_unref (gui);
Packit Service d328f3
		return;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	type_dialog = GTK_DIALOG (gtk_builder_get_object (gui, "new_connection_type_dialog"));
Packit Service d328f3
	gtk_window_set_transient_for (GTK_WINDOW (type_dialog), parent_window);
Packit Service d328f3
Packit Service d328f3
	combo = GTK_COMBO_BOX (gtk_builder_get_object (gui, "new_connection_type_combo"));
Packit Service d328f3
	label = GTK_LABEL (gtk_builder_get_object (gui, "new_connection_desc_label"));
Packit Service d328f3
	create_button = GTK_BUTTON (gtk_builder_get_object (gui, "create_button"));
Packit Service d328f3
	set_up_connection_type_combo (combo, label, type_filter_func, user_data);
Packit Service d328f3
Packit Service d328f3
	/* Disable "Create" button if no item is available */
Packit Service d328f3
	if (!gtk_tree_model_iter_n_children (gtk_combo_box_get_model (combo), NULL))
Packit Service d328f3
		gtk_widget_set_sensitive (GTK_WIDGET (create_button), FALSE);
Packit Service d328f3
Packit Service d328f3
	if (primary_label) {
Packit Service d328f3
		label = GTK_LABEL (gtk_builder_get_object (gui, "new_connection_primary_label"));
Packit Service d328f3
		gtk_label_set_text (label, primary_label);
Packit Service d328f3
	}
Packit Service d328f3
	if (secondary_label) {
Packit Service d328f3
		label = GTK_LABEL (gtk_builder_get_object (gui, "new_connection_secondary_label"));
Packit Service d328f3
		gtk_label_set_text (label, secondary_label);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	response = gtk_dialog_run (type_dialog);
Packit Service d328f3
	if (response == GTK_RESPONSE_OK) {
Packit Service d328f3
		if (gtk_combo_box_get_active_iter (combo, &iter)) {
Packit Service d328f3
			gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
Packit Service d328f3
			                    COL_NEW_FUNC, &new_func,
Packit Service d328f3
			                    COL_VPN_SERVICE_TYPE, &vpn_service_type,
Packit Service d328f3
			                    COL_VPN_ADD_DETAIL_KEY, &vpn_add_detail_key,
Packit Service d328f3
			                    COL_VPN_ADD_DETAIL_VAL, &vpn_add_detail_val,
Packit Service d328f3
			                    -1);
Packit Service d328f3
			if (vpn_service_type) {
Packit Service d328f3
				memset (&vpn_data, 0, sizeof (vpn_data));
Packit Service d328f3
				vpn_data.add_detail_key = vpn_add_detail_key;
Packit Service d328f3
				vpn_data.add_detail_val = vpn_add_detail_val;
Packit Service d328f3
Packit Service d328f3
				detail = vpn_service_type;
Packit Service d328f3
				detail_data = &vpn_data;
Packit Service d328f3
			}
Packit Service d328f3
		}
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	gtk_widget_destroy (GTK_WIDGET (type_dialog));
Packit Service d328f3
	g_object_unref (gui);
Packit Service d328f3
Packit Service d328f3
	if (new_func) {
Packit Service d328f3
		new_connection_of_type (parent_window,
Packit Service d328f3
		                        detail,
Packit Service d328f3
		                        detail_data,
Packit Service d328f3
		                        NULL,
Packit Service d328f3
		                        client,
Packit Service d328f3
		                        new_func,
Packit Service d328f3
		                        result_func,
Packit Service d328f3
		                        user_data);
Packit Service d328f3
	} else
Packit Service d328f3
		result_func (FUNC_TAG_NEW_CONNECTION_RESULT_CALL, NULL, user_data);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
typedef struct {
Packit Service d328f3
	GtkWindow *parent_window;
Packit Service d328f3
	NMConnectionEditor *editor;
Packit Service d328f3
	DeleteConnectionResultFunc result_func;
Packit Service d328f3
	gpointer user_data;
Packit Service d328f3
} DeleteInfo;
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
delete_cb (GObject *connection,
Packit Service d328f3
           GAsyncResult *result,
Packit Service d328f3
           gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	DeleteInfo *info = user_data;
Packit Service d328f3
	DeleteConnectionResultFunc result_func;
Packit Service d328f3
	GError *error = NULL;
Packit Service d328f3
Packit Service d328f3
	nm_remote_connection_delete_finish (NM_REMOTE_CONNECTION (connection), result, &error);
Packit Service d328f3
	if (error) {
Packit Service d328f3
		nm_connection_editor_error (info->parent_window,
Packit Service d328f3
		                            _("Connection delete failed"),
Packit Service d328f3
		                            "%s", error->message);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (info->editor) {
Packit Service d328f3
		nm_connection_editor_set_busy (info->editor, FALSE);
Packit Service d328f3
		g_object_unref (info->editor);
Packit Service d328f3
	}
Packit Service d328f3
	if (info->parent_window)
Packit Service d328f3
		g_object_unref (info->parent_window);
Packit Service d328f3
Packit Service d328f3
	result_func = info->result_func;
Packit Service d328f3
	user_data = info->user_data;
Packit Service d328f3
	g_free (info);
Packit Service d328f3
	g_clear_error (&error);
Packit Service d328f3
Packit Service d328f3
	if (result_func)
Packit Service d328f3
		(*result_func) (FUNC_TAG_DELETE_CONNECTION_RESULT_CALL, NM_REMOTE_CONNECTION (connection), error == NULL, user_data);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
void
Packit Service d328f3
delete_connection (GtkWindow *parent_window,
Packit Service d328f3
                   NMRemoteConnection *connection,
Packit Service d328f3
                   DeleteConnectionResultFunc result_func,
Packit Service d328f3
                   gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMConnectionEditor *editor;
Packit Service d328f3
	NMSettingConnection *s_con;
Packit Service d328f3
	GtkWidget *dialog;
Packit Service d328f3
	const char *id;
Packit Service d328f3
	guint result;
Packit Service d328f3
	DeleteInfo *info;
Packit Service d328f3
Packit Service d328f3
	editor = nm_connection_editor_get (NM_CONNECTION (connection));
Packit Service d328f3
	if (editor && nm_connection_editor_get_busy (editor)) {
Packit Service d328f3
		/* Editor already has an operation in progress, raise it */
Packit Service d328f3
		nm_connection_editor_present (editor);
Packit Service d328f3
		return;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
Packit Service d328f3
	g_assert (s_con);
Packit Service d328f3
	id = nm_setting_connection_get_id (s_con);
Packit Service d328f3
Packit Service d328f3
	dialog = gtk_message_dialog_new (parent_window,
Packit Service d328f3
	                                 GTK_DIALOG_DESTROY_WITH_PARENT,
Packit Service d328f3
	                                 GTK_MESSAGE_QUESTION,
Packit Service d328f3
	                                 GTK_BUTTONS_NONE,
Packit Service d328f3
	                                 _("Are you sure you wish to delete the connection %s?"),
Packit Service d328f3
	                                 id);
Packit Service d328f3
	gtk_dialog_add_buttons (GTK_DIALOG (dialog),
Packit Service d328f3
	                        _("_Cancel"), GTK_RESPONSE_CANCEL,
Packit Service d328f3
	                        _("_Delete"), GTK_RESPONSE_YES,
Packit Service d328f3
	                        NULL);
Packit Service d328f3
Packit Service d328f3
	result = gtk_dialog_run (GTK_DIALOG (dialog));
Packit Service d328f3
	gtk_widget_destroy (dialog);
Packit Service d328f3
Packit Service d328f3
	if (result != GTK_RESPONSE_YES)
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	info = g_malloc0 (sizeof (DeleteInfo));
Packit Service d328f3
	info->editor = editor ? g_object_ref (editor) : NULL;
Packit Service d328f3
	info->parent_window = parent_window ? g_object_ref (parent_window) : NULL;
Packit Service d328f3
	info->result_func = result_func;
Packit Service d328f3
	info->user_data = user_data;
Packit Service d328f3
Packit Service d328f3
	if (editor)
Packit Service d328f3
		nm_connection_editor_set_busy (editor, TRUE);
Packit Service d328f3
Packit Service d328f3
	nm_remote_connection_delete_async (connection, NULL, delete_cb, info);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
gboolean
Packit Service d328f3
connection_supports_proxy (NMConnection *connection)
Packit Service d328f3
{
Packit Service d328f3
	NMSettingConnection *s_con;
Packit Service d328f3
Packit Service d328f3
	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
Packit Service d328f3
Packit Service d328f3
	s_con = nm_connection_get_setting_connection (connection);
Packit Service d328f3
	return (nm_setting_connection_get_slave_type (s_con) == NULL);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
gboolean
Packit Service d328f3
connection_supports_ip4 (NMConnection *connection)
Packit Service d328f3
{
Packit Service d328f3
	NMSettingConnection *s_con;
Packit Service d328f3
Packit Service d328f3
	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
Packit Service d328f3
Packit Service d328f3
	s_con = nm_connection_get_setting_connection (connection);
Packit Service d328f3
	return (nm_setting_connection_get_slave_type (s_con) == NULL);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
gboolean
Packit Service d328f3
connection_supports_ip6 (NMConnection *connection)
Packit Service d328f3
{
Packit Service d328f3
	NMSettingConnection *s_con;
Packit Service d328f3
	const char *connection_type;
Packit Service d328f3
Packit Service d328f3
	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
Packit Service d328f3
Packit Service d328f3
	s_con = nm_connection_get_setting_connection (connection);
Packit Service d328f3
	if (nm_setting_connection_get_slave_type (s_con) != NULL)
Packit Service d328f3
		return FALSE;
Packit Service d328f3
Packit Service d328f3
	connection_type = nm_setting_connection_get_connection_type (s_con);
Packit Service d328f3
	if (!strcmp (connection_type, NM_SETTING_VPN_SETTING_NAME))
Packit Service d328f3
		return vpn_supports_ipv6 (connection);
Packit Service d328f3
	else if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME))
Packit Service d328f3
		return FALSE;
Packit Service d328f3
	else
Packit Service d328f3
		return TRUE;
Packit Service d328f3
}