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 a57c23ee3675f7b4f7dbd5bdc6a313b885c8fdb3
Author: [email protected] <[email protected]>
AuthorDate: Sun Jun 21 21:01:00 2026 -0600
networkmanager: prompt for VPN username after import
Capture nmcli stdout, parse the imported connection name, and trigger the
username probe for username-auth VPNs that have no stored username.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
---
src/modules/networkmanager/e_mod_main.c | 14 ++++-
.../networkmanager/e_networkmanager_import.c | 68 ++++++++++++++++++----
.../networkmanager/e_networkmanager_import.h | 7 ++-
3 files changed, 75 insertions(+), 14 deletions(-)
diff --git a/src/modules/networkmanager/e_mod_main.c b/src/modules/networkmanager/e_mod_main.c
index 56bb02991..8d626f4b6 100644
--- a/src/modules/networkmanager/e_mod_main.c
+++ b/src/modules/networkmanager/e_mod_main.c
@@ -3,6 +3,7 @@
#include "e_networkmanager.h"
#include "e_networkmanager_vpn.h"
#include "e_networkmanager_import.h"
+#include "e_networkmanager_vpn_username.h"
E_Module *networkmanager_mod = NULL;
E_NM_Config *networkmanager_config = NULL;
@@ -406,10 +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_UNUSED, Eina_Bool ok, const char *err,
+ const char *conn_name)
{
E_Dialog *err_dlg;
- if (ok) { INF("VPN import succeeded"); return; }
+ if (ok)
+ {
+ INF("VPN import succeeded");
+ if (conn_name) enm_vpn_username_maybe_prompt(conn_name);
+ return;
+ }
ERR("VPN import failed: %s", err ?: "(no output)");
@@ -452,7 +459,8 @@ _enm_vpn_fs_done_cb(void *data, Evas_Object *fs EINA_UNUSED, void *event)
{
_enm_vpn_import_done_cb(NULL, EINA_FALSE,
_("Could not detect VPN type from file extension. "
- "Use a .conf (WireGuard) or .ovpn (OpenVPN) file."));
+ "Use a .conf (WireGuard) or .ovpn (OpenVPN) file."),
+ NULL);
}
else
{
diff --git a/src/modules/networkmanager/e_networkmanager_import.c b/src/modules/networkmanager/e_networkmanager_import.c
index 0b5d2487b..1808c8e39 100644
--- a/src/modules/networkmanager/e_networkmanager_import.c
+++ b/src/modules/networkmanager/e_networkmanager_import.c
@@ -73,11 +73,13 @@ enm_import_detect_type(const char *file_path)
typedef struct _Import_Ctx
{
- Enm_Import_Done_Cb done_cb;
- void *data;
- Ecore_Exe *exe;
- Eina_Strbuf *stderr_buf;
+ Enm_Import_Done_Cb done_cb;
+ void *data;
+ Ecore_Exe *exe;
+ Eina_Strbuf *stderr_buf;
+ Eina_Strbuf *stdout_buf;
Ecore_Event_Handler *handler_err;
+ Ecore_Event_Handler *handler_out;
Ecore_Event_Handler *handler_del;
} Import_Ctx;
@@ -86,8 +88,10 @@ _import_ctx_free(Import_Ctx *ctx)
{
if (!ctx) return;
if (ctx->handler_err) ecore_event_handler_del(ctx->handler_err);
+ if (ctx->handler_out) ecore_event_handler_del(ctx->handler_out);
if (ctx->handler_del) ecore_event_handler_del(ctx->handler_del);
if (ctx->stderr_buf) eina_strbuf_free(ctx->stderr_buf);
+ if (ctx->stdout_buf) eina_strbuf_free(ctx->stdout_buf);
/* exe is already gone by the time _del fires; don't del it here */
free(ctx);
}
@@ -124,6 +128,33 @@ _on_stderr(void *data, int type EINA_UNUSED, void *event)
return ECORE_CALLBACK_DONE;
}
+static Eina_Bool
+_on_stdout(void *data, int type EINA_UNUSED, void *event)
+{
+ Import_Ctx *ctx = data;
+ Ecore_Exe_Event_Data *ev = event;
+
+ if (!ev || !ev->exe || ev->exe != ctx->exe)
+ return ECORE_CALLBACK_PASS_ON;
+ if (ev->data && ev->size > 0)
+ eina_strbuf_append_length(ctx->stdout_buf, ev->data, ev->size);
+ return ECORE_CALLBACK_DONE;
+}
+
+/* Parse `Connection 'NAME' (uuid) successfully added.` -> malloc'd NAME. */
+static char *
+_import_parse_conn_name(const char *out)
+{
+ const char *a, *b;
+ if (!out) return NULL;
+ a = strchr(out, '\'');
+ if (!a) return NULL;
+ a++;
+ b = strchr(a, '\'');
+ if (!b) return NULL;
+ return strndup(a, (size_t)(b - a));
+}
+
static Eina_Bool
_on_del(void *data, int type EINA_UNUSED, void *event)
{
@@ -136,13 +167,18 @@ _on_del(void *data, int type EINA_UNUSED, void *event)
/* Prevent double-free: clear handlers before freeing ctx */
ecore_event_handler_del(ctx->handler_err);
ctx->handler_err = NULL;
+ if (ctx->handler_out)
+ { ecore_event_handler_del(ctx->handler_out); ctx->handler_out = NULL; }
ecore_event_handler_del(ctx->handler_del);
ctx->handler_del = NULL;
Eina_Bool ok = (ev->exited && ev->exit_code == 0);
const char *stderr_text = eina_strbuf_string_get(ctx->stderr_buf);
+ char *conn_name = ok ? _import_parse_conn_name(
+ eina_strbuf_string_get(ctx->stdout_buf)) : NULL;
- ctx->done_cb(ctx->data, ok, stderr_text);
+ ctx->done_cb(ctx->data, ok, stderr_text, conn_name);
+ free(conn_name);
_import_ctx_free(ctx);
return ECORE_CALLBACK_DONE;
@@ -159,7 +195,7 @@ enm_import_run(const char *type, const char *file_path,
const char *nmcli = enm_import_nmcli_path();
if (!nmcli)
{
- done_cb(data, EINA_FALSE, "nmcli not found on PATH");
+ done_cb(data, EINA_FALSE, "nmcli not found on PATH", NULL);
return;
}
@@ -172,7 +208,7 @@ enm_import_run(const char *type, const char *file_path,
free(esc_nmcli);
free(esc_type);
free(esc_filepath);
- done_cb(data, EINA_FALSE, "out of memory");
+ done_cb(data, EINA_FALSE, "out of memory", NULL);
return;
}
@@ -188,7 +224,7 @@ enm_import_run(const char *type, const char *file_path,
Import_Ctx *ctx = calloc(1, sizeof(Import_Ctx));
if (!ctx)
{
- done_cb(data, EINA_FALSE, "out of memory");
+ done_cb(data, EINA_FALSE, "out of memory", NULL);
return;
}
@@ -197,12 +233,22 @@ enm_import_run(const char *type, const char *file_path,
ctx->stderr_buf = eina_strbuf_new();
if (!ctx->stderr_buf)
{
- done_cb(data, EINA_FALSE, "out of memory");
+ done_cb(data, EINA_FALSE, "out of memory", NULL);
+ free(ctx);
+ return;
+ }
+ ctx->stdout_buf = eina_strbuf_new();
+ if (!ctx->stdout_buf)
+ {
+ done_cb(data, EINA_FALSE, "out of memory", NULL);
+ eina_strbuf_free(ctx->stderr_buf);
free(ctx);
return;
}
ctx->exe = ecore_exe_pipe_run(cmd,
+ ECORE_EXE_PIPE_READ |
+ ECORE_EXE_PIPE_READ_LINE_BUFFERED |
ECORE_EXE_PIPE_ERROR |
ECORE_EXE_PIPE_ERROR_LINE_BUFFERED |
ECORE_EXE_NOT_LEADER |
@@ -210,11 +256,13 @@ enm_import_run(const char *type, const char *file_path,
ctx);
if (!ctx->exe)
{
- done_cb(data, EINA_FALSE, "failed to spawn nmcli");
+ done_cb(data, EINA_FALSE, "failed to spawn nmcli", NULL);
_import_ctx_free(ctx);
return;
}
+ ctx->handler_out = ecore_event_handler_add(ECORE_EXE_EVENT_DATA,
+ _on_stdout, ctx);
ctx->handler_err = ecore_event_handler_add(ECORE_EXE_EVENT_ERROR,
_on_stderr, ctx);
ctx->handler_del = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
diff --git a/src/modules/networkmanager/e_networkmanager_import.h b/src/modules/networkmanager/e_networkmanager_import.h
index d34087023..8bf9a11ba 100644
--- a/src/modules/networkmanager/e_networkmanager_import.h
+++ b/src/modules/networkmanager/e_networkmanager_import.h
@@ -28,12 +28,17 @@ const char *enm_import_detect_type(const char *file_path);
* stderr_text points into an internal buffer that is freed immediately
* after the callback returns; copy it if you need to retain.
*
+ * conn_name is the imported connection's name parsed from nmcli stdout
+ * (NULL on failure or when it cannot be parsed); it too is freed right
+ * after the callback returns.
+ *
* data must remain valid until done_cb fires. enm_import_run does not
* return a cancellation handle, so the caller is responsible for
* ensuring it does not deallocate data while a call is in flight.
*/
typedef void (*Enm_Import_Done_Cb)(void *data, Eina_Bool ok,
- const char *stderr_text);
+ const char *stderr_text,
+ const char *conn_name);
/* Run nmcli connection import asynchronously. done_cb is invoked exactly
* once. */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.