[network-manager-applet/th/vpn-service-info-bgo767197: 7/7] c-e: support multiple "Add VPN connection" entires per service-type



commit db8057c3174ed73cee1baaac2235bfe00257b6a6
Author: Thomas Haller <thaller redhat com>
Date:   Wed Jun 8 13:23:49 2016 +0200

    c-e: support multiple "Add VPN connection" entires per service-type
    
    For one given service-type, the UI shall be able to show multiple
    entires in the list for creating a new connection.
    
    This works by asking the plugin whether it supports multiple
    "add-details". And if so, create an entry for each add-detail.
    
    When adding a VPN connection, the editor creates a NMConnection
    with initializing vpn.service-type and setting the add-detail to a
    key according to the plugin's instruction.
    
    For example, nm-openvpn supports multiple "vpn.connection-type" such as
    "tls", "static-key", "password", "password-tls". With this change, it could
    generate an entry for each type in nm-c-e's connection-add list. To do
    that, it should announce add-details to be "tls", "static-key",
    "password", "password-tls", and the "add-detail-key" to be "connection-type".
    
    It also works to specify the add-detail on command line to create a
    particular VPN connection:
    
      $ nm-connection-editor -c -t vpn:<SERVICE_TYPE>:<ADD_DETAIL>
    
    For example:
    
      $ nm-connection-editor -c -t vpn:openconnect:nc

 src/connection-editor/ce-new-connection.ui |    6 ++
 src/connection-editor/connection-helpers.c |  105 +++++++++++++++++++++++-----
 src/connection-editor/nm-connection-list.c |   26 +++++--
 src/connection-editor/page-vpn.c           |   52 +++++++++++++-
 src/connection-editor/page-vpn.h           |    6 ++
 5 files changed, 168 insertions(+), 27 deletions(-)
---
diff --git a/src/connection-editor/ce-new-connection.ui b/src/connection-editor/ce-new-connection.ui
index c9dfa54..66e9ae8 100644
--- a/src/connection-editor/ce-new-connection.ui
+++ b/src/connection-editor/ce-new-connection.ui
@@ -16,6 +16,12 @@
       <column type="GObject"/>
       <!-- column-name vpn_service_type, COL_VPN_SERVICE_TYPE -->
       <column type="gchararray"/>
+      <!-- column-name add_detail, COL_VPN_ADD_DETAIL -->
+      <column type="gchararray"/>
+      <!-- column-name add_detail_key, COL_VPN_ADD_DETAIL_KEY -->
+      <column type="gchararray"/>
+      <!-- column-name add_detail_val, COL_VPN_ADD_DETAIL_VAL -->
+      <column type="gchararray"/>
     </columns>
   </object>
   <object class="GtkDialog" id="new_connection_type_dialog">
diff --git a/src/connection-editor/connection-helpers.c b/src/connection-editor/connection-helpers.c
index 44921b1..d840cc2 100644
--- a/src/connection-editor/connection-helpers.c
+++ b/src/connection-editor/connection-helpers.c
@@ -43,6 +43,9 @@
 #define COL_DESCRIPTION 3
 #define COL_VPN_PLUGIN 4
 #define COL_VPN_SERVICE_TYPE 5
+#define COL_VPN_ADD_DETAIL 6
+#define COL_VPN_ADD_DETAIL_KEY 7
+#define COL_VPN_ADD_DETAIL_VAL 8
 
 static gint
 sort_types (gconstpointer a, gconstpointer b)
@@ -273,9 +276,12 @@ set_up_connection_type_combo (GtkComboBox *combo,
                        gs_free char *pretty_name = NULL;
                        gs_free char *description = NULL;
                        NMVpnEditorPluginServiceFlags flags;
+                       gs_strfreev char **add_details_free = NULL;
+                       char **add_details;
+                       const char *i_add_detail;
 
                        if (!nm_vpn_editor_plugin_get_service_info (plugin, service_type, NULL, &pretty_name, 
&description, &flags)) {
-                               if (!is_alias)
+                               if (is_alias)
                                        goto next;
                                g_object_get (plugin,
                                              NM_VPN_EDITOR_PLUGIN_NAME, &pretty_name,
@@ -288,21 +294,70 @@ set_up_connection_type_combo (GtkComboBox *combo,
                        if (!NM_FLAGS_HAS (flags, NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_CAN_ADD))
                                goto next;
 
-                       if (show_headers)
-                               markup = g_markup_printf_escaped ("    %s", pretty_name);
-                       else
-                               markup = g_markup_escape_text (pretty_name, -1);
-
-                       gtk_list_store_append (model, &iter);
-                       gtk_list_store_set (model, &iter,
-                                           COL_MARKUP, markup,
-                                           COL_SENSITIVE, TRUE,
-                                           COL_NEW_FUNC, list[vpn_index].new_connection_func,
-                                           COL_DESCRIPTION, description,
-                                           COL_VPN_PLUGIN, plugin,
-                                           COL_VPN_SERVICE_TYPE, service_type,
-                                           -1);
-                       g_free (markup);
+                       add_details_free = nm_vpn_editor_plugin_get_service_add_details (plugin, 
service_type);
+                       add_details = add_details_free;
+                       i_add_detail = add_details ? add_details[0] : NULL;
+                       do {
+                               const char *i_pretty_name, *i_description;
+                               gs_free char *i_pretty_name_free = NULL;
+                               gs_free char *i_description_free = NULL;
+                               gs_free char *i_add_detail_key = NULL;
+                               gs_free char *i_add_detail_val = NULL;
+
+                               if (i_add_detail) {
+                                       if (i_add_detail[0] == '\0')
+                                               goto i_next;
+                                       if (!nm_vpn_editor_plugin_get_service_add_detail (plugin, 
service_type, i_add_detail,
+                                                                                         
&i_pretty_name_free, &i_description_free,
+                                                                                         &i_add_detail_key, 
&i_add_detail_val, NULL))
+                                               goto i_next;
+                                       if (!i_add_detail_key || !i_add_detail_key[0]) {
+                                               /* currently, the only way for a plugin to know the 
add-detail of a new connection
+                                                * is by returning an "add-detail-key", which then is set in 
the VPN connection.
+                                                *
+                                                * We could imaging other schemes, to notify the plugin which 
connection is to be
+                                                * created. This one is sufficient for now, so as is, a 
plugin must return an
+                                                * "add-detail-key", otherwise it cannot work. */
+                                               goto i_next;
+                                       }
+                                       if (!i_add_detail_val || !i_add_detail_val[0]) {
+                                               /* we require a value, also because 
nm_setting_vpn_add_data_item()
+                                                * doesn't allow even empty strings (??). */
+                                               goto i_next;
+                                       }
+                                       if (!i_pretty_name_free)
+                                               goto i_next;
+                                       i_pretty_name = i_pretty_name_free;
+                                       i_description = i_description_free;
+                               } else {
+                                       i_pretty_name = pretty_name;
+                                       i_description = description;
+                               }
+
+                               if (show_headers)
+                                       markup = g_markup_printf_escaped ("    %s", i_pretty_name);
+                               else
+                                       markup = g_markup_escape_text (i_pretty_name, -1);
+
+                               gtk_list_store_append (model, &iter);
+                               gtk_list_store_set (model, &iter,
+                                                   COL_MARKUP, markup,
+                                                   COL_SENSITIVE, TRUE,
+                                                   COL_NEW_FUNC, list[vpn_index].new_connection_func,
+                                                   COL_DESCRIPTION, i_description,
+                                                   COL_VPN_PLUGIN, plugin,
+                                                   COL_VPN_SERVICE_TYPE, service_type,
+                                                   COL_VPN_ADD_DETAIL, i_add_detail,
+                                                   COL_VPN_ADD_DETAIL_KEY, i_add_detail_key,
+                                                   COL_VPN_ADD_DETAIL_VAL, i_add_detail_val,
+                                                   -1);
+                               g_free (markup);
+
+i_next:
+                               if (!add_details)
+                                       break;
+                               i_add_detail = (++add_details)[0];
+                       } while (i_add_detail);
 
 next:
                        if (!aliases || !aliases[0])
@@ -426,8 +481,13 @@ new_connection_dialog_full (GtkWindow *parent_window,
        int response;
        PageNewConnectionFunc new_func = NULL;
        gs_free char *vpn_service_type = NULL;
+       gs_free char *vpn_add_detail = NULL;
+       gs_free char *vpn_add_detail_key = NULL;
+       gs_free char *vpn_add_detail_val = NULL;
        const char *detail = NULL;
+       gpointer detail_data = NULL;
        GError *error = NULL;
+       CEPageVpnDetailData vpn_data;
 
        /* load GUI */
        gui = gtk_builder_new ();
@@ -462,16 +522,25 @@ new_connection_dialog_full (GtkWindow *parent_window,
                gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
                                    COL_NEW_FUNC, &new_func,
                                    COL_VPN_SERVICE_TYPE, &vpn_service_type,
+                                   COL_VPN_ADD_DETAIL, &vpn_add_detail,
+                                   COL_VPN_ADD_DETAIL_KEY, &vpn_add_detail_key,
+                                   COL_VPN_ADD_DETAIL_VAL, &vpn_add_detail_val,
                                    -1);
-               if (vpn_service_type)
+               if (vpn_service_type) {
+                       memset (&vpn_data, 0, sizeof (vpn_data));
+                       vpn_data.add_detail_key = vpn_add_detail_key;
+                       vpn_data.add_detail_val = vpn_add_detail_val;
+
                        detail = vpn_service_type;
+                       detail_data = &vpn_data;
+               }
        }
 
        gtk_widget_destroy (GTK_WIDGET (type_dialog));
        g_object_unref (gui);
 
        if (new_func)
-               new_connection_of_type (parent_window, detail, NULL, client, new_func, result_func, 
user_data);
+               new_connection_of_type (parent_window, detail, detail_data, client, new_func, result_func, 
user_data);
        else
                result_func (NULL, user_data);
 }
diff --git a/src/connection-editor/nm-connection-list.c b/src/connection-editor/nm-connection-list.c
index 5c092dc..ea1f8a8 100644
--- a/src/connection-editor/nm-connection-list.c
+++ b/src/connection-editor/nm-connection-list.c
@@ -33,6 +33,7 @@
 #include "nm-connection-list.h"
 #include "ce-polkit-button.h"
 #include "connection-helpers.h"
+#include "page-vpn.h"
 
 extern gboolean nm_ce_keep_above;
 
@@ -895,6 +896,8 @@ void
 nm_connection_list_create (NMConnectionList *self, GType ctype, const char *detail)
 {
        ConnectionTypeData *types;
+       gpointer detail_data = NULL;
+       CEPageVpnDetailData vpn_data;
        int i;
 
        g_return_if_fail (NM_IS_CONNECTION_LIST (self));
@@ -914,15 +917,22 @@ nm_connection_list_create (NMConnectionList *self, GType ctype, const char *deta
                        nm_connection_editor_error (NULL, _("Error creating connection"),
                                                    _("Don't know how to create '%s' connections"), 
g_type_name (ctype));
                }
-       } else {
-               new_connection_of_type (GTK_WINDOW (self->dialog),
-                                       detail,
-                                       NULL,
-                                       self->client,
-                                       types[i].new_connection_func,
-                                       really_add_connection,
-                                       self);
+               return;
        }
+
+       if (ctype == NM_TYPE_SETTING_VPN) {
+               memset (&vpn_data, 0, sizeof (vpn_data));
+               vpn_data.parse_detail = TRUE;
+               detail_data = &vpn_data;
+       }
+
+       new_connection_of_type (GTK_WINDOW (self->dialog),
+                               detail,
+                               detail_data,
+                               self->client,
+                               types[i].new_connection_func,
+                               really_add_connection,
+                               self);
 }
 
 void
diff --git a/src/connection-editor/page-vpn.c b/src/connection-editor/page-vpn.c
index 4b4a45d..2c2d71d 100644
--- a/src/connection-editor/page-vpn.c
+++ b/src/connection-editor/page-vpn.c
@@ -28,6 +28,7 @@
 #include "connection-helpers.h"
 #include "nm-connection-editor.h"
 #include "vpn-helpers.h"
+#include "nm-vpn-editor-plugin-call.h"
 
 G_DEFINE_TYPE (CEPageVpn, ce_page_vpn, CE_TYPE_PAGE)
 
@@ -290,6 +291,12 @@ vpn_connection_new (GtkWindow *parent,
        NMSetting *s_vpn;
        const char *service_type;
        gs_free char *service_type_free = NULL;
+       gs_free char *add_detail_key_free = NULL;
+       gs_free char *add_detail_val_free = NULL;
+       const CEPageVpnDetailData *vpn_data = detail_data;
+       gssize split_idx, l;
+       const char *add_detail_key = NULL;
+       const char *add_detail_val = NULL;
 
        if (!detail) {
                NewVpnInfo *info;
@@ -309,8 +316,47 @@ vpn_connection_new (GtkWindow *parent,
                return;
        }
 
+       service_type = detail;
+       add_detail_key = vpn_data ? vpn_data->add_detail_key : NULL;
+       add_detail_val = vpn_data ? vpn_data->add_detail_val : NULL;
+
        service_type_free = nm_vpn_plugin_info_list_find_service_type (vpn_get_plugin_infos (), detail);
-       service_type = service_type_free ?: detail;
+       if (service_type_free)
+               service_type = service_type_free;
+       else if (   vpn_data
+                && vpn_data->parse_detail
+                && (l = strlen (detail)) >= 3) {
+
+               /* "detail" was not found as a shortname for a service-type. It might contain 
"<SERVICE_TYPE>:<ADD_DETAIL>".
+                * Try to parse that by spliting @detail at the colons. */
+               for (split_idx = 1; split_idx < l - 1; split_idx++) {
+                       if (detail[split_idx] == ':') {
+                               gs_free char *detail_main = g_strndup (detail, split_idx);
+                               NMVpnEditorPlugin *plugin;
+
+                               service_type_free = nm_vpn_plugin_info_list_find_service_type 
(vpn_get_plugin_infos (), detail_main);
+                               if (!service_type_free)
+                                       continue;
+                               plugin = vpn_get_plugin_by_service (service_type_free);
+                               if (!plugin) {
+                                       g_clear_pointer (&service_type_free, g_free);
+                                       continue;
+                               }
+
+                               /* we found a service_type. The try to use the remainder as add-detail. */
+                               service_type = service_type_free;
+                               if (nm_vpn_editor_plugin_get_service_add_detail (plugin, service_type, 
&detail[split_idx + 1],
+                                                                                NULL, NULL,
+                                                                                &add_detail_key_free, 
&add_detail_val_free, NULL)
+                                   && add_detail_key_free && add_detail_key_free[0]
+                                   && add_detail_val_free && add_detail_val_free[0]) {
+                                       add_detail_key = add_detail_key_free;
+                                       add_detail_val = add_detail_val_free;
+                               }
+                               break;
+                       }
+               }
+       }
 
        connection = ce_page_new_connection (_("VPN connection %d"),
                                             NM_SETTING_VPN_SETTING_NAME,
@@ -319,6 +365,10 @@ vpn_connection_new (GtkWindow *parent,
                                             user_data);
        s_vpn = nm_setting_vpn_new ();
        g_object_set (s_vpn, NM_SETTING_VPN_SERVICE_TYPE, service_type, NULL);
+
+       if (add_detail_key)
+               nm_setting_vpn_add_data_item ((NMSettingVpn *) s_vpn, add_detail_key, add_detail_val);
+
        nm_connection_add_setting (connection, s_vpn);
 
        (*result_func) (connection, FALSE, NULL, user_data);
diff --git a/src/connection-editor/page-vpn.h b/src/connection-editor/page-vpn.h
index e8dddf0..c3e7210 100644
--- a/src/connection-editor/page-vpn.h
+++ b/src/connection-editor/page-vpn.h
@@ -43,6 +43,12 @@ typedef struct {
        CEPageClass parent;
 } CEPageVpnClass;
 
+typedef struct {
+       gboolean parse_detail;
+       char *add_detail_key;
+       char *add_detail_val;
+} CEPageVpnDetailData;
+
 GType ce_page_vpn_get_type (void);
 
 CEPage *ce_page_vpn_new (NMConnectionEditor *editor,


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