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 776def9935c5dc27c9f0afa9e26544d87f82aa0f
Author: [email protected] <[email protected]>
AuthorDate: Sun Jun 21 22:38:38 2026 -0600
networkmanager: fix post-import username probe (single-line query)
Root cause of the missing dialog: the probe queried three fields
(connection.id, vpn.service-type, vpn.data) producing multi-line nmcli
output, but ecore_exe delivered the process-exit event after only the first
DATA line, so the parser saw just 20 bytes (the name) -> needed=0 -> no
dialog. Query ONLY vpn.data (a single comma-joined line, immune to the
race) and take the service short name from the import type instead. Thread
the import type through enm_vpn_username_maybe_prompt.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
---
src/modules/networkmanager/e_mod_main.c | 11 +--
.../networkmanager/e_networkmanager_vpn_username.c | 83 +++++++++-------------
.../networkmanager/e_networkmanager_vpn_username.h | 7 +-
3 files changed, 45 insertions(+), 56 deletions(-)
diff --git a/src/modules/networkmanager/e_mod_main.c b/src/modules/networkmanager/e_mod_main.c
index 326fcff0e..62e90fbf4 100644
--- a/src/modules/networkmanager/e_mod_main.c
+++ b/src/modules/networkmanager/e_mod_main.c
@@ -407,15 +407,16 @@ _enm_itc_bt_content_get(void *data, Evas_Object *obj, const char *part)
/* ---- VPN item class callbacks --------------------------------------------- */
static void
-_enm_vpn_import_done_cb(void *data EINA_UNUSED, Eina_Bool ok, const char *err,
+_enm_vpn_import_done_cb(void *data, Eina_Bool ok, const char *err,
const char *conn_name)
{
+ const char *type = data; /* import VPN type ("openvpn", ...); may be NULL */
E_Dialog *err_dlg;
if (ok)
{
- fprintf(stderr, "ENM-DBG import_done ok: conn(uuid)=%s\n",
- conn_name ?: "(null)"); fflush(stderr);
- if (conn_name) enm_vpn_username_maybe_prompt(conn_name);
+ fprintf(stderr, "ENM-DBG import_done ok: conn(uuid)=%s type=%s\n",
+ conn_name ?: "(null)", type ?: "(null)"); fflush(stderr);
+ if (conn_name) enm_vpn_username_maybe_prompt(conn_name, type);
return;
}
@@ -465,7 +466,7 @@ _enm_vpn_fs_done_cb(void *data, Evas_Object *fs EINA_UNUSED, void *event)
}
else
{
- enm_import_run(type, file, _enm_vpn_import_done_cb, NULL);
+ enm_import_run(type, file, _enm_vpn_import_done_cb, (void *)type);
}
e_object_del(E_OBJECT(dialog));
}
diff --git a/src/modules/networkmanager/e_networkmanager_vpn_username.c b/src/modules/networkmanager/e_networkmanager_vpn_username.c
index 2ec911140..2ec3f7f5a 100644
--- a/src/modules/networkmanager/e_networkmanager_vpn_username.c
+++ b/src/modules/networkmanager/e_networkmanager_vpn_username.c
@@ -304,7 +304,8 @@ _nmcli_kv_find(const char *blob, const char *key)
typedef struct _Username_Probe_Ctx
{
- char *conn_name;
+ char *conn_uuid; /* unique id for nmcli ops */
+ char *svc; /* service short name, from import type */
Ecore_Exe *exe;
Eina_Strbuf *out;
Ecore_Event_Handler *h_data;
@@ -335,8 +336,7 @@ _probe_on_del(void *data, int type EINA_UNUSED, void *event)
{
Username_Probe_Ctx *ctx = data;
Ecore_Exe_Event_Del *ev = event;
- char *id = NULL, *svc = NULL, *conn_type = NULL, *username = NULL;
- const char *short_name = NULL;
+ char *conn_type = NULL, *username = NULL;
const char *blob;
Eina_Bool needed;
@@ -345,85 +345,72 @@ _probe_on_del(void *data, int type EINA_UNUSED, void *event)
if (ctx->h_data) ecore_event_handler_del(ctx->h_data);
if (ctx->h_del) ecore_event_handler_del(ctx->h_del);
+ /* Single line: the vpn.data list (queried alone to avoid a multi-line
+ * ecore_exe data/exit race). The service short name comes from the import
+ * type, so we never need vpn.service-type here. */
blob = eina_strbuf_string_get(ctx->out);
- /* Three lines: connection.id, vpn.service-type, then the vpn.data list. */
- {
- const char *l1 = blob;
- const char *nl1 = strchr(l1, '\n');
- if (nl1)
- {
- const char *l2 = nl1 + 1;
- const char *nl2 = strchr(l2, '\n');
- id = strndup(l1, (size_t)(nl1 - l1));
- if (nl2)
- {
- const char *l3 = nl2 + 1;
- svc = strndup(l2, (size_t)(nl2 - l2));
- conn_type = _nmcli_kv_find(l3, "connection-type");
- username = _nmcli_kv_find(l3, "username");
- }
- }
- }
- if (svc) { char *d = strrchr(svc, '.'); short_name = d ? d + 1 : svc; }
+ conn_type = _nmcli_kv_find(blob, "connection-type");
+ username = _nmcli_kv_find(blob, "username");
- needed = enm_vpn_username_needed(short_name, conn_type, username);
- fprintf(stderr, "ENM-DBG probe result: id=%s svc=%s conn_type=%s "
+ needed = enm_vpn_username_needed(ctx->svc, conn_type, username);
+ fprintf(stderr, "ENM-DBG probe result: svc=%s conn_type=%s "
"username=%s needed=%d blob_len=%zu\n",
- id ?: "(null)", short_name ?: "(null)", conn_type ?: "(null)",
+ ctx->svc ?: "(null)", conn_type ?: "(null)",
username ?: "(null)", (int)needed, strlen(blob));
fflush(stderr);
if (needed)
{
- char *uuid_copy = strdup(ctx->conn_name); /* ctx->conn_name is the UUID */
+ char *uuid_copy = strdup(ctx->conn_uuid);
if (uuid_copy)
- enm_vpn_username_dialog(id ?: ctx->conn_name, /* display name */
- short_name, /* type label */
+ enm_vpn_username_dialog(NULL, /* generic "VPN" header */
+ ctx->svc, /* type label */
username,
_probe_username_entered,
uuid_copy);
}
- free(id); free(svc); free(conn_type); free(username);
- free(ctx->conn_name);
+ free(conn_type); free(username);
+ free(ctx->conn_uuid); free(ctx->svc);
eina_strbuf_free(ctx->out);
free(ctx);
return ECORE_CALLBACK_DONE;
}
void
-enm_vpn_username_maybe_prompt(const char *conn_name)
+enm_vpn_username_maybe_prompt(const char *conn_uuid, const char *svc_short)
{
const char *nmcli;
- char *esc_nmcli, *esc_name, cmd[4096];
+ char *esc_nmcli, *esc_uuid, cmd[4096];
Username_Probe_Ctx *ctx;
- fprintf(stderr, "ENM-DBG maybe_prompt: id=%s\n", conn_name ?: "(null)");
- fflush(stderr);
- if (!conn_name) return;
+ fprintf(stderr, "ENM-DBG maybe_prompt: uuid=%s svc=%s\n",
+ conn_uuid ?: "(null)", svc_short ?: "(null)"); fflush(stderr);
+ if (!conn_uuid) return;
nmcli = enm_import_nmcli_path();
if (!nmcli) { fprintf(stderr, "ENM-DBG maybe_prompt: nmcli NULL\n"); fflush(stderr); return; }
esc_nmcli = _username_shell_escape(nmcli);
- esc_name = _username_shell_escape(conn_name);
- if (!esc_nmcli || !esc_name) { free(esc_nmcli); free(esc_name); return; }
+ esc_uuid = _username_shell_escape(conn_uuid);
+ if (!esc_nmcli || !esc_uuid) { free(esc_nmcli); free(esc_uuid); return; }
- /* Query by UUID (conn_name here is the connection UUID — unique, unlike the
- * display name). LC_ALL=C for stable, non-localized -g output. Fields:
- * line1 connection.id (display name), line2 service-type, line3 vpn.data. */
+ /* Query ONLY vpn.data, by UUID (unique). vpn.data prints as a single
+ * comma-joined line, which avoids the multi-line ecore_exe data/exit race
+ * that drops trailing lines. The service short name comes from the import
+ * type, so vpn.service-type is not needed. */
snprintf(cmd, sizeof(cmd),
- "LC_ALL=C '%s' -g connection.id,vpn.service-type,vpn.data "
- "connection show '%s'",
- esc_nmcli, esc_name);
- free(esc_nmcli); free(esc_name);
+ "LC_ALL=C '%s' -g vpn.data connection show '%s'",
+ esc_nmcli, esc_uuid);
+ free(esc_nmcli); free(esc_uuid);
fprintf(stderr, "ENM-DBG probe spawn: %s\n", cmd); fflush(stderr);
ctx = calloc(1, sizeof(*ctx));
if (!ctx) return;
- ctx->conn_name = strdup(conn_name);
+ ctx->conn_uuid = strdup(conn_uuid);
+ ctx->svc = svc_short ? strdup(svc_short) : NULL;
ctx->out = eina_strbuf_new();
- if (!ctx->conn_name || !ctx->out)
- { free(ctx->conn_name); if (ctx->out) eina_strbuf_free(ctx->out); free(ctx); return; }
+ if (!ctx->conn_uuid || !ctx->out)
+ { free(ctx->conn_uuid); free(ctx->svc); if (ctx->out) eina_strbuf_free(ctx->out); free(ctx); return; }
ctx->exe = ecore_exe_pipe_run(cmd,
ECORE_EXE_PIPE_READ |
@@ -431,7 +418,7 @@ enm_vpn_username_maybe_prompt(const char *conn_name)
ECORE_EXE_NOT_LEADER |
ECORE_EXE_TERM_WITH_PARENT, ctx);
if (!ctx->exe)
- { free(ctx->conn_name); eina_strbuf_free(ctx->out); free(ctx); return; }
+ { free(ctx->conn_uuid); free(ctx->svc); eina_strbuf_free(ctx->out); free(ctx); return; }
ctx->h_data = ecore_event_handler_add(ECORE_EXE_EVENT_DATA, _probe_on_data, ctx);
ctx->h_del = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _probe_on_del, ctx);
}
diff --git a/src/modules/networkmanager/e_networkmanager_vpn_username.h b/src/modules/networkmanager/e_networkmanager_vpn_username.h
index 24b77b1e1..0335d1b87 100644
--- a/src/modules/networkmanager/e_networkmanager_vpn_username.h
+++ b/src/modules/networkmanager/e_networkmanager_vpn_username.h
@@ -44,8 +44,9 @@ void enm_vpn_username_dialog(const char *conn_name, const char *type_label,
const char *initial,
Enm_Username_Entered_Cb cb, void *data);
-/* Post-import orchestrator: query the connection, and if it needs a username,
- * prompt for one and persist it. Fire-and-forget. */
-void enm_vpn_username_maybe_prompt(const char *conn_name);
+/* Post-import orchestrator: query the connection (by UUID), and if it needs a
+ * username, prompt for one and persist it. svc_short is the VPN service short
+ * name ("openvpn", "vpnc", ...) from the import type. Fire-and-forget. */
+void enm_vpn_username_maybe_prompt(const char *conn_uuid, const char *svc_short);
#endif
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.