This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch nm-vpn-username-capture
in repository enlightenment.

View the commit online.

commit 877d64d3a28b4730772d7fb388ba7c608ee602d7
Author: [email protected] <[email protected]>
AuthorDate: Sun Jun 21 21:05:29 2026 -0600

    networkmanager: inject VPN username field at connect time
    
    Detect a missing username for username-auth VPNs from the already-parsed
    vpn.data, add a Username row to the secrets dialog, and persist it to
    vpn.data on OK (as a property, not a secret).
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
---
 src/modules/networkmanager/agent.c            | 60 ++++++++++++++++++++++++---
 src/modules/networkmanager/e_networkmanager.c | 19 ++++++++-
 src/modules/networkmanager/e_networkmanager.h |  3 +-
 3 files changed, 73 insertions(+), 9 deletions(-)

diff --git a/src/modules/networkmanager/agent.c b/src/modules/networkmanager/agent.c
index c1c85e058..0e1505a2b 100644
--- a/src/modules/networkmanager/agent.c
+++ b/src/modules/networkmanager/agent.c
@@ -9,6 +9,7 @@
 
 #include "e.h"
 #include "e_networkmanager.h"
+#include "e_networkmanager_vpn_username.h"
 #include "e_mod_main.h"
 
 /*
@@ -37,6 +38,11 @@ struct _E_NM_Agent_Dialog
    char               **field_names;
    Evas_Object        **field_entries;
    unsigned int         n_fields;
+   /* VPN mode: when set, username_entry holds a username *property* (not a
+    * secret) — persisted to vpn.data on OK instead of returned via reply. */
+   Eina_Bool            has_username_field;
+   Evas_Object         *username_entry;
+   char                *conn_name;   /* strdup; for username persistence */
 };
 
 static E_NM_Agent_Dialog *_current_dialog = NULL;
@@ -64,6 +70,17 @@ _dialog_send_ok(E_NM_Agent_Dialog *ad)
      }
    else
      {
+        /* The username is a connection property, not a secret: persist it to
+         * vpn.data instead of returning it through the secrets reply. */
+        if (ad->has_username_field && ad->username_entry)
+          {
+             char *user = elm_entry_markup_to_utf8(
+                             elm_entry_entry_get(ad->username_entry));
+             if (user && user[0] && ad->conn_name)
+               enm_vpn_username_set(ad->conn_name, user, NULL, NULL);
+             free(user);
+          }
+
         const char **values = calloc(ad->n_fields, sizeof(*values));
         char **utf8 = calloc(ad->n_fields, sizeof(*utf8));
         if (!values || !utf8)
@@ -158,6 +175,7 @@ _dialog_del_cb(void *data)
         free(ad->field_names);
      }
    free(ad->field_entries);
+   free(ad->conn_name);
    free(ad);
 }
 
@@ -357,7 +375,8 @@ _dialog_new(E_NM_Agent_Request *req, const char *ssid)
 static E_NM_Agent_Dialog *
 _vpn_dialog_new(E_NM_Agent_Request *req, const char *conn_name,
                 const char *service_type, const char *message,
-                const char *const *fields, unsigned int n_fields)
+                const char *const *fields, unsigned int n_fields,
+                Eina_Bool need_username)
 {
    E_NM_Agent_Dialog *ad;
    Evas_Object *frame, *box, *table;
@@ -374,6 +393,8 @@ _vpn_dialog_new(E_NM_Agent_Request *req, const char *conn_name,
    ad->req    = req;
    ad->is_vpn = EINA_TRUE;
    ad->n_fields = n_fields;
+   ad->has_username_field = need_username;
+   ad->conn_name = conn_name ? strdup(conn_name) : NULL;
    ad->field_names = calloc(n_fields ?: 1, sizeof(*ad->field_names));
    ad->field_entries = calloc(n_fields ?: 1, sizeof(*ad->field_entries));
    used = calloc(n_fields ?: 1, sizeof(*used));
@@ -437,6 +458,31 @@ _vpn_dialog_new(E_NM_Agent_Request *req, const char *conn_name,
    evas_object_show(table);
    _field_column_min_width_set(table, 1);
 
+   unsigned int base = 0;
+   if (need_username)
+     {
+        Evas_Object *label, *entry;
+
+        label = elm_label_add(table);
+        elm_object_text_set(label, _("Username"));
+        evas_object_size_hint_weight_set(label, 0, 0);
+        evas_object_size_hint_align_set(label, 1.0, 0.5);
+        elm_table_pack(table, label, 0, 0, 1, 1);
+        evas_object_show(label);
+
+        entry = elm_entry_add(table);
+        elm_entry_single_line_set(entry, EINA_TRUE);
+        elm_entry_scrollable_set(entry, EINA_TRUE);
+        evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, 0);
+        evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, 0.5);
+        evas_object_smart_callback_add(entry, "activated",
+                                       _entry_activated_cb, ad);
+        elm_table_pack(table, entry, 1, 0, 1, 1);
+        evas_object_show(entry);
+        ad->username_entry = entry;
+        base = 1;
+     }
+
    for (unsigned int i = 0; i < n_fields; i++)
      {
         Evas_Object *label, *entry;
@@ -446,7 +492,7 @@ _vpn_dialog_new(E_NM_Agent_Request *req, const char *conn_name,
         elm_object_text_set(label, _vpn_field_label_get(field));
         evas_object_size_hint_weight_set(label, 0, 0);
         evas_object_size_hint_align_set(label, 1.0, 0.5);
-        elm_table_pack(table, label, 0, i, 1, 1);
+        elm_table_pack(table, label, 0, base + i, 1, 1);
         evas_object_show(label);
 
         entry = elm_entry_add(table);
@@ -457,7 +503,7 @@ _vpn_dialog_new(E_NM_Agent_Request *req, const char *conn_name,
         evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, 0.5);
         evas_object_smart_callback_add(entry, "activated",
                                        _entry_activated_cb, ad);
-        elm_table_pack(table, entry, 1, i, 1, 1);
+        elm_table_pack(table, entry, 1, base + i, 1, 1);
         evas_object_show(entry);
 
         ad->field_entries[i] = entry;
@@ -471,7 +517,8 @@ _vpn_dialog_new(E_NM_Agent_Request *req, const char *conn_name,
                                   _dialog_key_down_cb, ad);
    e_object_del_attach_func_set(E_OBJECT(dialog), _dialog_del_cb);
    e_object_data_set(E_OBJECT(dialog), ad);
-   if (n_fields > 0) elm_object_focus_set(ad->field_entries[0], EINA_TRUE);
+   if (ad->username_entry) elm_object_focus_set(ad->username_entry, EINA_TRUE);
+   else if (n_fields > 0) elm_object_focus_set(ad->field_entries[0], EINA_TRUE);
    elm_win_center(dialog->win, 1, 1);
    return ad;
 }
@@ -521,7 +568,8 @@ static void
 _agent_ui_vpn_request_cb(void *data EINA_UNUSED, E_NM_Agent_Request *req,
                          const char *conn_name, const char *service_type,
                          const char *message,
-                         const char *const *fields, unsigned int n_fields)
+                         const char *const *fields, unsigned int n_fields,
+                         Eina_Bool need_username)
 {
    if (_current_dialog)
      {
@@ -531,7 +579,7 @@ _agent_ui_vpn_request_cb(void *data EINA_UNUSED, E_NM_Agent_Request *req,
      }
    _current_dialog = _vpn_dialog_new(req, conn_name, service_type,
                                      message,
-                                     fields, n_fields);
+                                     fields, n_fields, need_username);
    if (!_current_dialog) { e_nm_agent_reply_cancel(req); return; }
 }
 
diff --git a/src/modules/networkmanager/e_networkmanager.c b/src/modules/networkmanager/e_networkmanager.c
index b7dccbef0..560553d4e 100644
--- a/src/modules/networkmanager/e_networkmanager.c
+++ b/src/modules/networkmanager/e_networkmanager.c
@@ -1,5 +1,6 @@
 #include "e_mod_main.h"
 #include "e_networkmanager_vpn.h"
+#include "e_networkmanager_vpn_username.h"
 #include <ctype.h>
 
 /* -------------------------------------------------------------------------- */
@@ -3618,7 +3619,19 @@ _agent_get_secrets(const Eldbus_Service_Interface *iface,
              return NULL;
           }
 
-        if (fields.len == 0)
+        /* The username is a connection *property* (vpn.data["username"]), never
+         * a secret, so NM never prompts for it.  When it is missing for a
+         * username-auth VPN, inject a username field into the dialog and
+         * persist it back to vpn.data on OK.  Pointers returned by
+         * _agent_vpn_data_find alias into `info`, valid until the clear below. */
+        {
+           const char *short_name = _agent_vpn_service_short_name(info.svc_type);
+           const char *conn_type  = _agent_vpn_data_find(&info, "connection-type");
+           const char *cur_user   = _agent_vpn_data_find(&info, "username");
+           Eina_Bool need_username =
+              enm_vpn_username_needed(short_name, conn_type, cur_user);
+
+        if (fields.len == 0 && !need_username)
           {
   printf("NM: _agent_get_secrets() fields.len == 0\n");
              WRN("GetSecrets: no VPN secrets requested by hints or flags");
@@ -3635,13 +3648,15 @@ _agent_get_secrets(const Eldbus_Service_Interface *iface,
                                     info.conn_id ?: "VPN", info.svc_type,
                                     fields.message,
                                     (const char *const *)fields.items,
-                                    fields.len);
+                                    fields.len,
+                                    need_username);
           }
         else
           {
              WRN("No VPN SecretAgent UI callback; cancelling");
              e_nm_agent_reply_cancel(req);
           }
+        }
 
         _agent_vpn_field_list_clear(&fields);
         _agent_vpn_conn_info_clear(&info);
diff --git a/src/modules/networkmanager/e_networkmanager.h b/src/modules/networkmanager/e_networkmanager.h
index 9ed81d26f..46579890e 100644
--- a/src/modules/networkmanager/e_networkmanager.h
+++ b/src/modules/networkmanager/e_networkmanager.h
@@ -44,7 +44,8 @@ typedef void (*E_NM_Agent_VPN_Secrets_Request_Cb)(void *data,
         const char *service_type,
         const char *message,
         const char *const *fields,
-        unsigned int n_fields);
+        unsigned int n_fields,
+        Eina_Bool need_username);
 
 typedef struct _E_NM_Agent_Callbacks E_NM_Agent_Callbacks;
 struct _E_NM_Agent_Callbacks

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to