[network-manager-openconnect/th/vpn-service-info-bgo767197: 3/3] change multiprotocol support to use a new "protocol" option



commit d7f0a155227057d399cb2d9cad098df39c9202cf
Author: Thomas Haller <thaller redhat com>
Date:   Wed Jun 8 01:45:20 2016 +0200

    change multiprotocol support to use a new "protocol" option
    
    The recently added Juniper VPN support was realized by adding a
    service-type alias openconnect.nc. Thereby, the protocol was encoded in
    the service-type. That is not great, because traditionally the service-type
    was the D-Bus bus name of the VPN service. Nowadays, with multi-VPN
    support that somewhat changed and it's used as a base to generate the
    real bus name.
    Another important role that the service-type plays is in the connection,
    where the vpn.service-type setting associates a connection with it's plugin.
    
    The service-type should not be hacked to encode the openconnect protocol
    option. Instead, add a NM_OPENCONNECT_KEY_PROTOCOL key.
    
    However, in nm-connection-editor's UI we don't want to show the protocol
    as an option inside the VPN dialog. Instead, the two protocols
    "anyconnect" and "nc" should result in two separate entires in the
    "add-connection" list. This way, the user first selects to create either
    an "anyconnect" or "nc" VPN connection, and then the UI doesn't let
    him switch protocol anymore.
    
    This is realized by exposing the protocol as an "add-detail". When
    populating the list of VPN types, connection-editor can ask the plugin
    whether it supports multiple entires. Later, when adding the connection,
    the protocol field is pre-filled via the "add-detail-key".
    
    Note that nm-openconnect is mostly agnostic to the actual protocol
    value. When openconnect gains support for a new protocol, the plugin
    will just support it for the most part. The only thing that is missing
    is to generate an additional add-connection entry.
    Note that the supported protocols are inside the .name file. So, the
    user could edit the plugin configuration with a new protocol. As a
    result, the new protocol would show up in the list. However, that
    doesn't really fly, because the plugin cannot show a proper name and
    description for the unknown protocol. Also, the .name file is really
    not user-configuration but a part of the plugin's implementation.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=767197

 nm-openconnect-service.name.in       |    4 +-
 properties/Makefile.am               |    1 +
 properties/nm-openconnect.c          |  136 +++++++++++
 shared/Makefile.am                   |    3 +-
 shared/nm-vpn-editor-plugin-call.h   |  407 ++++++++++++++++++++++++++++++++++
 src/nm-openconnect-service-defines.h |    1 +
 src/nm-openconnect-service.c         |   14 +-
 7 files changed, 556 insertions(+), 10 deletions(-)
---
diff --git a/nm-openconnect-service.name.in b/nm-openconnect-service.name.in
index 38adcea..0dde170 100644
--- a/nm-openconnect-service.name.in
+++ b/nm-openconnect-service.name.in
@@ -1,6 +1,5 @@
 [VPN Connection]
 name=openconnect
-aliases=org.freedesktop.NetworkManager.openconnect.anyconnect;org.freedesktop.NetworkManager.openconnect.nc
 service=org.freedesktop.NetworkManager.openconnect
 program= LIBEXECDIR@/nm-openconnect-service
 supports-multiple-connections=true
@@ -11,3 +10,6 @@ plugin= PLUGINDIR@/libnm-vpn-plugin-openconnect.so
 [GNOME]
 auth-dialog= LIBEXECDIR@/nm-openconnect-auth-dialog
 properties= PLUGINDIR@/libnm-openconnect-properties
+
+[openconnect]
+supported-protocols=anyconnect,nc
diff --git a/properties/Makefile.am b/properties/Makefile.am
index f79c5ad..90269f5 100644
--- a/properties/Makefile.am
+++ b/properties/Makefile.am
@@ -20,6 +20,7 @@ common_CFLAGS =                                         \
        $(GLIB_CFLAGS)                                  \
        $(GTK_CFLAGS)                                   \
        $(OPENCONNECT_CFLAGS)                           \
+       -I$(top_srcdir)/shared                          \
        -I$(top_srcdir)/src                             \
        -DICONDIR=\""$(datadir)/pixmaps"\"              \
        -DUIDIR=\""$(uidir)"\"                          \
diff --git a/properties/nm-openconnect.c b/properties/nm-openconnect.c
index ec1a3e8..5ff5954 100644
--- a/properties/nm-openconnect.c
+++ b/properties/nm-openconnect.c
@@ -76,6 +76,10 @@
 #include "nm-openconnect.h"
 #include "auth-helpers.h"
 
+#ifndef NM_OPENCONNECT_OLD
+#include "nm-vpn-editor-plugin-call.h"
+#endif
+
 #define OPENCONNECT_PLUGIN_NAME    _("Cisco AnyConnect Compatible VPN (openconnect)")
 #define OPENCONNECT_PLUGIN_DESC    _("Compatible with Cisco AnyConnect SSL VPN.")
 
@@ -94,6 +98,12 @@ G_DEFINE_TYPE_EXTENDED (OpenconnectEditorPlugin, openconnect_editor_plugin, G_TY
                         G_IMPLEMENT_INTERFACE (NM_TYPE_VPN_EDITOR_PLUGIN,
                                                openconnect_editor_plugin_interface_init))
 
+typedef struct {
+       char **supported_protocols;
+} OpenconnectEditorPluginPrivate;
+
+#define OPENCONNECT_EDITOR_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), 
OPENCONNECT_TYPE_EDITOR_PLUGIN, OpenconnectEditorPluginPrivate))
+
 /************** UI widget class **************/
 
 static void openconnect_editor_interface_init (NMVpnEditorInterface *iface_class);
@@ -595,10 +605,18 @@ update_connection (NMVpnEditor *iface,
        GtkTextIter iter_start, iter_end;
        GtkTextBuffer *buffer;
        const char *auth_type = NULL;
+       const char *protocol = NULL;
+
+       s_vpn = nm_connection_get_setting_vpn (connection);
+       if (s_vpn)
+               protocol = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_PROTOCOL);
 
        s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ());
        g_object_set (s_vpn, NM_SETTING_VPN_SERVICE_TYPE, NM_VPN_SERVICE_TYPE_OPENCONNECT, NULL);
 
+       if (protocol)
+               nm_setting_vpn_add_data_item (s_vpn, NM_OPENCONNECT_KEY_PROTOCOL, protocol);
+
        widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "gateway_entry"));
        str = (char *) gtk_entry_get_text (GTK_ENTRY (widget));
        if (str && strlen (str))
@@ -792,6 +810,97 @@ get_capabilities (NMVpnEditorPlugin *iface)
                NM_VPN_EDITOR_PLUGIN_CAPABILITY_IPV6);
 }
 
+#ifndef NM_OPENCONNECT_OLD
+static void
+notify_plugin_info_set (NMVpnEditorPlugin *plugin,
+                        NMVpnPluginInfo *plugin_info)
+{
+       OpenconnectEditorPluginPrivate *priv = OPENCONNECT_EDITOR_PLUGIN_GET_PRIVATE (plugin);
+       const char *supported_protocols;
+       guint i, j;
+
+       if (!plugin_info)
+               return;
+
+       supported_protocols = nm_vpn_plugin_info_lookup_property (plugin_info, "openconnect", 
"supported-protocols");
+
+       g_strfreev (priv->supported_protocols);
+       priv->supported_protocols = supported_protocols
+           ? g_strsplit_set (supported_protocols, ",", -1)
+           : g_new0 (char *, 1);
+
+       /*remove empty entries and whitespace */
+       for (i = 0, j = 0; priv->supported_protocols[j]; j++) {
+               g_strstrip (priv->supported_protocols[j]);
+               if (priv->supported_protocols[j][0] == '\0')
+                       g_free (priv->supported_protocols[j]);
+               else
+                       priv->supported_protocols[i++] = priv->supported_protocols[j];
+       }
+       priv->supported_protocols[i] = NULL;
+}
+
+static gboolean
+_impl_get_service_add_details (NMVpnEditorPlugin *plugin,
+                               const char *service_type,
+                               char ***out_add_details)
+{
+       *out_add_details = g_strdupv (OPENCONNECT_EDITOR_PLUGIN_GET_PRIVATE (plugin)->supported_protocols);
+       return TRUE;
+}
+NM_VPN_EDITOR_PLUGIN_CALL_SET_GET_SERVICE_ADD_DETAILS (_impl_get_service_add_details);
+
+static gboolean
+_impl_get_service_add_detail (NMVpnEditorPlugin *plugin,
+                              const char *service_type,
+                              const char *add_detail,
+                              char **out_pretty_name,
+                              char **out_description,
+                              char **out_add_detail_key,
+                              guint *out_flags,
+                              GError **error)
+{
+       OpenconnectEditorPluginPrivate *priv;
+       guint i;
+
+       if (!nm_streq (service_type, NM_VPN_SERVICE_TYPE_OPENCONNECT))
+               return FALSE;
+
+       priv = OPENCONNECT_EDITOR_PLUGIN_GET_PRIVATE (plugin);
+
+       if (   nm_streq (add_detail, "anyconnect")
+           && g_strv_contains ((const char *const*) priv->supported_protocols, add_detail)) {
+               *out_pretty_name = g_strdup (OPENCONNECT_PLUGIN_NAME);
+               *out_description = g_strdup (OPENCONNECT_PLUGIN_DESC);
+               *out_add_detail_key = g_strdup (NM_OPENCONNECT_KEY_PROTOCOL);
+               return TRUE;
+       }
+       if (   nm_streq (add_detail, "nc")
+           && g_strv_contains ((const char*const*) priv->supported_protocols, add_detail)) {
+               *out_pretty_name = g_strdup (_("Juniper Network Connect (openconnect)"));
+               *out_description = g_strdup (_("Compatible with Juniper Network Connect / Pulse Secure SSL 
VPN"));
+               *out_add_detail_key = g_strdup (NM_OPENCONNECT_KEY_PROTOCOL);
+               return TRUE;
+       }
+       for (i = 0; priv->supported_protocols[i]; i++) {
+               if (strcmp (add_detail, priv->supported_protocols[i]))
+                       continue;
+               /* we don't know this protocol by name, but it's configured in the .name file,
+                * so just take it. */
+               *out_pretty_name = g_strdup_printf (_("Openconnect VPN (%s)"), add_detail);
+               *out_description = g_strdup_printf (_("Openconnect SSL VPN with %s protocol"), add_detail);
+               *out_add_detail_key = g_strdup (NM_OPENCONNECT_KEY_PROTOCOL);
+               return TRUE;
+       }
+
+       g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+                    _("add-detail '%s' for '%s' does not support add-details"), add_detail, service_type);
+       return FALSE;
+}
+NM_VPN_EDITOR_PLUGIN_CALL_SET_GET_SERVICE_ADD_DETAIL (_impl_get_service_add_detail);
+
+#endif
+
 static NMVpnEditor *
 get_editor (NMVpnEditorPlugin *iface, NMConnection *connection, GError **error)
 {
@@ -819,11 +928,26 @@ get_property (GObject *object, guint prop_id,
 }
 
 static void
+openconnect_editor_plugin_dispose (GObject *object)
+{
+       OpenconnectEditorPlugin *plugin = OPENCONNECT_EDITOR_PLUGIN (object);
+       OpenconnectEditorPluginPrivate *priv = OPENCONNECT_EDITOR_PLUGIN_GET_PRIVATE (plugin);
+
+       g_strfreev (priv->supported_protocols);
+       priv->supported_protocols = NULL;
+
+       G_OBJECT_CLASS (openconnect_editor_plugin_parent_class)->dispose (object);
+}
+
+static void
 openconnect_editor_plugin_class_init (OpenconnectEditorPluginClass *req_class)
 {
        GObjectClass *object_class = G_OBJECT_CLASS (req_class);
 
+       g_type_class_add_private (req_class, sizeof (OpenconnectEditorPluginPrivate));
+
        object_class->get_property = get_property;
+       object_class->dispose = openconnect_editor_plugin_dispose;
 
        g_object_class_override_property (object_class,
                                          PROP_NAME,
@@ -841,6 +965,14 @@ openconnect_editor_plugin_class_init (OpenconnectEditorPluginClass *req_class)
 static void
 openconnect_editor_plugin_init (OpenconnectEditorPlugin *plugin)
 {
+       OpenconnectEditorPluginPrivate *priv = OPENCONNECT_EDITOR_PLUGIN_GET_PRIVATE (plugin);
+       char *dflt[] = {
+               "anyconnect",
+               "nc",
+               NULL,
+       };
+
+       priv->supported_protocols = g_strdupv (dflt);
 }
 
 static void
@@ -851,6 +983,10 @@ openconnect_editor_plugin_interface_init (NMVpnEditorPluginInterface *iface_clas
        iface_class->get_capabilities = get_capabilities;
        iface_class->import_from_file = import;
        iface_class->export_to_file = export;
+#ifndef NM_OPENCONNECT_OLD
+       iface_class->notify_plugin_info_set = notify_plugin_info_set;
+       NM_VPN_EDITOR_PLUGIN_CALL_SETUP (iface_class);
+#endif
 }
 
 G_MODULE_EXPORT NMVpnEditorPlugin *
diff --git a/shared/Makefile.am b/shared/Makefile.am
index 4101bef..ff2c8bc 100644
--- a/shared/Makefile.am
+++ b/shared/Makefile.am
@@ -1,3 +1,4 @@
 EXTRA_DIST = \
     gsystem-local-alloc.h \
-    nm-macros-internal.h
+    nm-macros-internal.h \
+    nm-vpn-editor-plugin-call.h
diff --git a/shared/nm-vpn-editor-plugin-call.h b/shared/nm-vpn-editor-plugin-call.h
new file mode 100644
index 0000000..cad8143
--- /dev/null
+++ b/shared/nm-vpn-editor-plugin-call.h
@@ -0,0 +1,407 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2016 Red Hat, Inc.
+ */
+
+#ifndef __NM_VPN_EDITOR_PLUGIN_CALL_H__
+#define __NM_VPN_EDITOR_PLUGIN_CALL_H__
+
+/* This header is an internal, header-only file that can be copied to
+ * other projects to call well-known service functions on VPN plugins. */
+
+#include <NetworkManager.h>
+
+/* we make use of otherinternal header files, you need those too. */
+#include "gsystem-local-alloc.h"
+#include "nm-macros-internal.h"
+
+/*****************************************************************************/
+
+/**
+ * NMVpnEditorPluginServiceFlags:
+ * @NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_NONE: no flags
+ * @NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_CAN_ADD: whether the plugin can
+ *   add a new connection for the given service-type.
+ **/
+typedef enum { /*< skip >*/
+       NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_NONE     = 0x00,
+       NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_CAN_ADD  = 0x01,
+} NMVpnEditorPluginServiceFlags;
+
+/*****************************************************************************/
+
+/**
+ * NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_INFO: name of call "get-service-info".
+ *   This call has 1 input argument:
+ *     service-type (string): analog to NM_VPN_EDITOR_PLUGIN_SERVICE
+ *     it specifies for which service-type the information is requested.
+ *     This can either be the main service-type or an alias.
+ *   This call has 3 output arguments:
+ *     short-name (string): for the main service-type, this shall return [VPN Connection].name.
+ *        Otherwise, it is a short-name to refer to service-type.
+ *     pretty-name (string): for the main service-type, this shall return NM_VPN_EDITOR_PLUGIN_NAME.
+ *        It's a localized, pretty name of the service-type.
+ *     description (string): for the main service-type, this shall return NM_VPN_EDITOR_PLUGIN_DESCRIPTION
+ *        It's a localized, description for the service-type.
+ *     service flags (uint): flags for the service-type.
+ */
+#define NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_INFO "get-service-info"
+
+/**
+ * NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_ADD_DETAILS: name of call "get-service-add-details".
+ *   For one particular service-type, the UI might want to show multiple "Add new connection"
+ *   entires. That is controlled by passing around "add-details".
+ *   The "get-service-add-details" returns optionally a list of "add-details" if it wishes
+ *   to generate multiple add entries.
+ *   This call has 1 input argument:
+ *     service-type: string: analog to NM_VPN_EDITOR_PLUGIN_SERVICE or an service-type
+ *        alias.
+ *   This call has 1 output argument:
+ *     add-details: strv: a list of details that can be passed to "get-service-add-detail"
+ *        call.
+ */
+#define NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_ADD_DETAILS "get-service-add-details"
+
+/**
+ * NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_ADD_DETAIL: if the plugin supports "add-details"
+ *   as indicated by "get-service-add-details", return more information.
+ *   This call has 2 input arguments:
+ *     service-name: string: analog to NM_VPN_EDITOR_PLUGIN_SERVICE or an service-type
+ *        alias. This was passed to "get-service-add-details" call.
+ *     add-detail: a detail for which the information is requested.
+ *   This call has 1 output argument:
+ *     pretty-name: (string), a localized name for what is to be added. Similar to
+ *       NM_VPN_EDITOR_PLUGIN_NAME.
+ *     description: (string), a localized descirption, similar to NM_VPN_EDITOR_PLUGIN_DESCRIPTION.
+ *     add-detail-key: (string), when creating such a connection of type "service-type","add-detail",
+ *       the user shall create a NMConnection with setting "service-type". It also sets the VPN
+ *       key "add-detail-key" to the value "add-detail", so that the plugin knows which connection
+ *       is to be created.
+ *     flags: (uint), additional flags, currently unused.
+ */
+#define NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_ADD_DETAIL "get-service-add-detail"
+
+/*****************************************************************************
+ * Call
+ *
+ * The following wrap the calling of generic functions for a VPN plugin.
+ * They are used by callers (for example nm-connection-editor).
+ *****************************************************************************/
+
+static inline gboolean
+nm_vpn_editor_plugin_get_service_info (NMVpnEditorPlugin *plugin,
+                                       const char *service_type,
+                                       char **out_short_name,
+                                       char **out_pretty_name,
+                                       char **out_description,
+                                       NMVpnEditorPluginServiceFlags *out_flags)
+{
+       gs_free char *short_name_local = NULL;
+       gs_free char *pretty_name_local = NULL;
+       gs_free char *description_local = NULL;
+       guint flags_local = 0;
+
+       g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), FALSE);
+       g_return_val_if_fail (service_type, FALSE);
+
+       if (!nm_vpn_editor_plugin_call (plugin,
+                                       NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_INFO,
+                                       NULL,
+                                       G_TYPE_STRING, &service_type,
+                                       G_TYPE_INVALID,
+                                       G_TYPE_STRING, &short_name_local,
+                                       G_TYPE_STRING, &pretty_name_local,
+                                       G_TYPE_STRING, &description_local,
+                                       G_TYPE_UINT,   &flags_local,
+                                       G_TYPE_INVALID))
+               return FALSE;
+       NM_SET_OUT (out_short_name, g_steal_pointer (&short_name_local));
+       NM_SET_OUT (out_pretty_name, g_steal_pointer (&pretty_name_local));
+       NM_SET_OUT (out_description, g_steal_pointer (&description_local));
+       NM_SET_OUT (out_flags, flags_local);
+       return TRUE;
+}
+
+static inline char **
+nm_vpn_editor_plugin_get_service_add_details (NMVpnEditorPlugin *plugin,
+                                              const char *service_name)
+{
+       char **details = NULL;
+
+       g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), FALSE);
+       g_return_val_if_fail (service_name, FALSE);
+
+       if (!nm_vpn_editor_plugin_call (plugin,
+                                       NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_ADD_DETAILS,
+                                       NULL,
+                                       G_TYPE_STRING, service_name,
+                                       G_TYPE_INVALID,
+                                       G_TYPE_STRV,   &details,
+                                       G_TYPE_INVALID))
+               g_clear_pointer (&details, g_strfreev);
+       else if (!details)
+               return g_new0 (char *, 1);
+       return details;
+}
+
+static inline gboolean
+nm_vpn_editor_plugin_get_service_add_detail (NMVpnEditorPlugin *plugin,
+                                             const char *service_type,
+                                             const char *add_detail,
+                                             char **out_pretty_name,
+                                             char **out_description,
+                                             char **out_add_detail_key,
+                                             guint *out_flags)
+{
+       gs_free char *pretty_name_local = NULL;
+       gs_free char *description_local = NULL;
+       gs_free char *add_detail_key_local = NULL;
+       guint flags_local = 0;
+
+       g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), FALSE);
+       g_return_val_if_fail (service_type, FALSE);
+       g_return_val_if_fail (add_detail, FALSE);
+
+       if (!nm_vpn_editor_plugin_call (plugin,
+                                       NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_ADD_DETAIL,
+                                       NULL,
+                                       G_TYPE_STRING, service_type,
+                                       G_TYPE_STRING, add_detail,
+                                       G_TYPE_INVALID,
+                                       G_TYPE_STRING, &pretty_name_local,
+                                       G_TYPE_STRING, &description_local,
+                                       G_TYPE_STRING, &add_detail_key_local,
+                                       G_TYPE_UINT,   out_flags ?: &flags_local,
+                                       G_TYPE_INVALID))
+               return FALSE;
+       NM_SET_OUT (out_pretty_name, g_steal_pointer (&pretty_name_local));
+       NM_SET_OUT (out_description, g_steal_pointer (&description_local));
+       NM_SET_OUT (out_add_detail_key, g_steal_pointer (&add_detail_key_local));
+       return TRUE;
+}
+
+/*****************************************************************************
+ * Implementation
+ *
+ * The following glue code can be used to implement calls in a VPN plugin.
+ * Register your hocks via NM_VPN_EDITOR_PLUGIN_CALL_SET_*() and
+ * NM_VPN_EDITOR_PLUGIN_CALL_SETUP().
+ *****************************************************************************/
+
+static gboolean (*const _nm_vpn_editor_plugin_call_impl_get_service_info) (NMVpnEditorPlugin *plugin,
+                                                                           const char *service_type,
+                                                                           char **out_short_name,
+                                                                           char **out_pretty_name,
+                                                                           char **out_description,
+                                                                           NMVpnEditorPluginServiceFlags 
*out_flags,
+                                                                           GError **error);
+
+#define NM_VPN_EDITOR_PLUGIN_CALL_SET_GET_SERVICE_INFO(fcn) \
+static gboolean (*const _nm_vpn_editor_plugin_call_impl_get_service_info) (NMVpnEditorPlugin *plugin, \
+                                                                           const char *service_type, \
+                                                                           char **out_short_name, \
+                                                                           char **out_pretty_name, \
+                                                                           char **out_description, \
+                                                                           NMVpnEditorPluginServiceFlags 
*out_flags, \
+                                                                           GError **error) = (fcn)
+
+static gboolean (*const _nm_vpn_editor_plugin_call_impl_get_service_add_details) (NMVpnEditorPlugin *plugin,
+                                                                                  const char *service_type,
+                                                                                  char ***out_add_details,
+                                                                                  GError **error);
+
+#define NM_VPN_EDITOR_PLUGIN_CALL_SET_GET_SERVICE_ADD_DETAILS(fcn) \
+static gboolean (*const _nm_vpn_editor_plugin_call_impl_get_service_add_details) (NMVpnEditorPlugin *plugin, 
\
+                                                                                  const char *service_type, \
+                                                                                  char ***out_add_details, \
+                                                                                  GError **error) = (fcn)
+
+static gboolean (*const _nm_vpn_editor_plugin_call_impl_get_service_add_detail) (NMVpnEditorPlugin *plugin,
+                                                                                 const char *service_type,
+                                                                                 const char *add_detail,
+                                                                                 char **out_pretty_name,
+                                                                                 char **out_description,
+                                                                                 char **out_add_detail_key,
+                                                                                 guint *out_flags,
+                                                                                 GError **error);
+
+#define NM_VPN_EDITOR_PLUGIN_CALL_SET_GET_SERVICE_ADD_DETAIL(fcn) \
+static gboolean (*const _nm_vpn_editor_plugin_call_impl_get_service_add_detail) (NMVpnEditorPlugin *plugin, \
+                                                                                 const char *service_type, \
+                                                                                 const char *add_detail, \
+                                                                                 char **out_pretty_name, \
+                                                                                 char **out_description, \
+                                                                                 char **out_add_detail_key, \
+                                                                                 guint *out_flags, \
+                                                                                 GError **error) = (fcn)
+
+static inline gboolean
+_nm_vpn_editor_plugin_call_get_signature (NMVpnEditorPlugin *plugin,
+                                          const char *request,
+                                          gboolean *free_types,
+                                          GType **types_in,
+                                          GType **types_out)
+{
+       if (   _nm_vpn_editor_plugin_call_impl_get_service_info
+           && nm_streq (request, NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_INFO)) {
+               static GType t_in[] = { G_TYPE_STRING, 0 };
+               static GType t_out[] = { G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, 0 };
+
+               *types_in = t_in;
+               *types_out = t_out;
+               return TRUE;
+       }
+       if (   _nm_vpn_editor_plugin_call_impl_get_service_add_details
+           && nm_streq (request, NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_ADD_DETAILS)) {
+               static GType t_in[] = { G_TYPE_STRING, 0 };
+               static GType t_out[] = { 0, 0 };
+
+               if (G_UNLIKELY (t_out[0] == 0))
+                       t_out[0] = G_TYPE_STRV;
+
+               *types_in = t_in;
+               *types_out = t_out;
+               return TRUE;
+       }
+       if (   _nm_vpn_editor_plugin_call_impl_get_service_add_detail
+           && nm_streq (request, NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_ADD_DETAIL)) {
+               static GType t_in[] = { G_TYPE_STRING, G_TYPE_STRING, 0 };
+               static GType t_out[] = { G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, 0 };
+
+               *types_in = t_in;
+               *types_out = t_out;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+static inline gboolean
+_nm_vpn_editor_plugin_call_fail_unknown_service_type (GError **error, const char *service_type)
+{
+       if (error && !*error) {
+               g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_CALL_INVALID_ARGUMENT,
+                            _("Unknown service-type %s%s%s"), NM_PRINT_FMT_QUOTE_STRING (service_type));
+       }
+       return FALSE;
+}
+
+static inline gboolean
+_nm_vpn_editor_plugin_call (NMVpnEditorPlugin *plugin,
+                            const char *request,
+                            GError **error,
+                            const GValue *const*args_in,
+                            GValue *const*args_out)
+{
+       if (   _nm_vpn_editor_plugin_call_impl_get_service_info
+           && nm_streq (request, NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_INFO)) {
+               const char *service_type;
+               gs_free char *short_name = NULL;
+               gs_free char *pretty_name = NULL;
+               gs_free char *description = NULL;
+               NMVpnEditorPluginServiceFlags flags = 0;
+
+               service_type = g_value_get_string (args_in[0]);
+
+               if (!service_type)
+                       return _nm_vpn_editor_plugin_call_fail_unknown_service_type (error, service_type);
+
+               if (_nm_vpn_editor_plugin_call_impl_get_service_info (plugin,
+                                                                     service_type,
+                                                                     &short_name,
+                                                                     &pretty_name,
+                                                                     &description,
+                                                                     &flags,
+                                                                        error)) {
+                       g_value_take_string (args_out[0], g_steal_pointer (&short_name));
+                       g_value_take_string (args_out[1], g_steal_pointer (&pretty_name));
+                       g_value_take_string (args_out[2], g_steal_pointer (&description));
+                       g_value_set_uint (args_out[3], flags);
+                       return TRUE;
+               }
+               return _nm_vpn_editor_plugin_call_fail_unknown_service_type (error, service_type);
+       }
+
+       if (   _nm_vpn_editor_plugin_call_impl_get_service_add_details
+           && nm_streq (request, NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_ADD_DETAILS)) {
+               const char *service_type;
+
+               service_type = g_value_get_string (args_in[0]);
+               if (service_type) {
+                       gs_strfreev char **add_details = NULL;
+
+                       if (_nm_vpn_editor_plugin_call_impl_get_service_add_details (plugin,
+                                                                                    service_type,
+                                                                                    &add_details,
+                                                                                    error)) {
+                               g_value_take_boxed (args_out[0], g_steal_pointer (&add_details));
+                               return TRUE;
+                       }
+               }
+               return _nm_vpn_editor_plugin_call_fail_unknown_service_type (error, service_type);
+       }
+
+       if (   _nm_vpn_editor_plugin_call_impl_get_service_add_detail
+           && nm_streq (request, NM_VPN_EDITOR_PLUGIN_CALL_GET_SERVICE_ADD_DETAIL)) {
+               const char *service_type;
+               const char *add_detail;
+               gs_free char *pretty_name = NULL;
+               gs_free char *description = NULL;
+               gs_free char *add_detail_key = NULL;
+               guint flags = 0;
+
+               service_type = g_value_get_string (args_in[0]);
+               add_detail = g_value_get_string (args_in[1]);
+
+               if (!service_type)
+                       return _nm_vpn_editor_plugin_call_fail_unknown_service_type (error, service_type);
+
+               if (!add_detail) {
+                       g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_CALL_INVALID_ARGUMENT,
+                                    _("missing add_detail argument"));
+                       return FALSE;
+               }
+               if (_nm_vpn_editor_plugin_call_impl_get_service_add_detail (plugin,
+                                                                           service_type,
+                                                                           add_detail,
+                                                                           &pretty_name,
+                                                                           &description,
+                                                                           &add_detail_key,
+                                                                           &flags,
+                                                                           error)) {
+                       g_value_take_string (args_out[0], g_steal_pointer (&pretty_name));
+                       g_value_take_string (args_out[1], g_steal_pointer (&description));
+                       g_value_take_string (args_out[2], g_steal_pointer (&add_detail_key));
+                       g_value_set_uint (args_out[3], flags);
+                       return TRUE;
+               }
+               return _nm_vpn_editor_plugin_call_fail_unknown_service_type (error, service_type);
+       }
+
+       g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_CALL_INVALID_ARGUMENT,
+                    _("Unknown request %s"), request);
+       return FALSE;
+}
+
+static inline void
+NM_VPN_EDITOR_PLUGIN_CALL_SETUP (NMVpnEditorPluginInterface *iface_class)
+{
+       iface_class->call_get_signature = _nm_vpn_editor_plugin_call_get_signature;
+       iface_class->call = _nm_vpn_editor_plugin_call;
+}
+
+#endif /* __NM_VPN_EDITOR_PLUGIN_CALL_H__ */
diff --git a/src/nm-openconnect-service-defines.h b/src/nm-openconnect-service-defines.h
index 8bc2626..6853505 100644
--- a/src/nm-openconnect-service-defines.h
+++ b/src/nm-openconnect-service-defines.h
@@ -40,6 +40,7 @@
 #define NM_OPENCONNECT_KEY_PRIVKEY "userkey"
 #define NM_OPENCONNECT_KEY_MTU "mtu"
 #define NM_OPENCONNECT_KEY_PEM_PASSPHRASE_FSID "pem_passphrase_fsid"
+#define NM_OPENCONNECT_KEY_PROTOCOL "protocol"
 #define NM_OPENCONNECT_KEY_PROXY "proxy"
 #define NM_OPENCONNECT_KEY_CSD_ENABLE "enable_csd_trojan"
 #define NM_OPENCONNECT_KEY_CSD_WRAPPER "csd_wrapper"
diff --git a/src/nm-openconnect-service.c b/src/nm-openconnect-service.c
index 7e8be4f..4fccba2 100644
--- a/src/nm-openconnect-service.c
+++ b/src/nm-openconnect-service.c
@@ -364,7 +364,7 @@ nm_openconnect_start_openconnect_binary (NMOpenconnectPlugin *plugin,
        GSource *openconnect_watch;
        gint    stdin_fd;
        const char *props_vpn_gw, *props_cookie, *props_cacert, *props_mtu, *props_gwcert, *props_proxy;
-       const char *service;
+       const char *protocol;
 
        /* Find openconnect */
        openconnect_binary = openconnect_binary_paths;
@@ -410,20 +410,18 @@ nm_openconnect_start_openconnect_binary (NMOpenconnectPlugin *plugin,
        props_mtu = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_MTU);
 
        props_proxy = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_PROXY);
-       service = nm_setting_vpn_get_service_type (s_vpn);
 
        openconnect_argv = g_ptr_array_new ();
        g_ptr_array_add (openconnect_argv, (gpointer) (*openconnect_binary));
 
-       if (service && g_str_has_prefix(service, NM_DBUS_SERVICE_OPENCONNECT ".")) {
-               service += strlen(NM_DBUS_SERVICE_OPENCONNECT ".");
-
+       protocol = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_PROTOCOL);
+       if (protocol && strcmp (protocol, "anyconnect")) {
                /* Special case for OpenConnect 7.06 which had --juniper but not --protocol */
-               if (!strcmp(service, "juniper"))
+               if (!strcmp (protocol, "juniper"))
                        g_ptr_array_add (openconnect_argv, (gpointer) "--juniper");
                else {
                        g_ptr_array_add (openconnect_argv, (gpointer) "--protocol");
-                       g_ptr_array_add (openconnect_argv, (gpointer) service);
+                       g_ptr_array_add (openconnect_argv, (gpointer) protocol);
                }
        }
 
@@ -444,7 +442,7 @@ nm_openconnect_start_openconnect_binary (NMOpenconnectPlugin *plugin,
                g_ptr_array_add (openconnect_argv, (gpointer) "--proxy");
                g_ptr_array_add (openconnect_argv, (gpointer) props_proxy);
        }
-               
+
        g_ptr_array_add (openconnect_argv, (gpointer) "--syslog");
        g_ptr_array_add (openconnect_argv, (gpointer) "--cookie-on-stdin");
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]