diff --git a/src/e_mod_main.h b/src/e_mod_main.h
index 1d7cafb..da354ce 100644
--- a/src/e_mod_main.h
+++ b/src/e_mod_main.h
@@ -83,6 +83,9 @@ void e_iwd_gadget_shutdown(void);
void iwd_popup_new(Instance *inst);
void iwd_popup_del(Instance *inst);
+/* Auth dialog functions */
+#include "ui/wifi_auth.h"
+
/* D-Bus functions */
#include "iwd/iwd_dbus.h"
#include "iwd/iwd_device.h"
diff --git a/src/e_mod_popup.c b/src/e_mod_popup.c
index 1c01417..a4f912d 100644
--- a/src/e_mod_popup.c
+++ b/src/e_mod_popup.c
@@ -5,6 +5,7 @@ static void _popup_comp_del_cb(void *data, Evas_Object *obj);
static void _button_rescan_cb(void *data, Evas_Object *obj, void *event_info);
static void _button_disconnect_cb(void *data, Evas_Object *obj, void *event_info);
static Eina_Bool _popup_reopen_cb(void *data);
+static void _network_selected_cb(void *data, Evas_Object *obj, void *event_info);
/* Create popup */
void
@@ -113,7 +114,7 @@ iwd_popup_new(Instance *inst)
net->name, security,
net->known ? " *" : "");
- elm_list_item_append(list, item_text, NULL, NULL, NULL, net);
+ elm_list_item_append(list, item_text, NULL, NULL, _network_selected_cb, net);
count++;
}
}
@@ -123,6 +124,8 @@ iwd_popup_new(Instance *inst)
elm_list_item_append(list, "No networks found", NULL, NULL, NULL, NULL);
}
+ /* Set select mode to always */
+ elm_list_select_mode_set(list, ELM_OBJECT_SELECT_MODE_ALWAYS);
elm_list_go(list);
elm_object_content_set(frame, list);
evas_object_show(list);
@@ -236,3 +239,40 @@ _button_disconnect_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info
/* Close popup */
iwd_popup_del(inst);
}
+
+/* Network selected callback */
+static void
+_network_selected_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ IWD_Network *net = data;
+
+ if (!net || !net->name)
+ {
+ DBG("Invalid network selected");
+ return;
+ }
+
+ INF("Network selected: %s (type: %s)", net->name, net->type ? net->type : "unknown");
+
+ /* Check if network requires authentication */
+ if (net->type && (strcmp(net->type, "psk") == 0 || strcmp(net->type, "8021x") == 0))
+ {
+ /* Secured network - need to show auth dialog first */
+ /* Get instance from module */
+ if (iwd_mod && iwd_mod->instances)
+ {
+ Instance *inst = eina_list_data_get(iwd_mod->instances);
+ if (inst)
+ {
+ extern void wifi_auth_dialog_show(Instance *inst, IWD_Network *net);
+ wifi_auth_dialog_show(inst, net);
+ }
+ }
+ }
+ else
+ {
+ /* Open network - connect directly */
+ DBG("Connecting to open network");
+ iwd_network_connect(net);
+ }
+}
diff --git a/src/iwd/iwd_agent.c b/src/iwd/iwd_agent.c
index 55113fe..15cd654 100644
--- a/src/iwd/iwd_agent.c
+++ b/src/iwd/iwd_agent.c
@@ -126,26 +126,64 @@ iwd_agent_shutdown(void)
iwd_agent = NULL;
}
-/* Set passphrase for pending request */
+/* Set passphrase for pending request and send reply */
void
iwd_agent_set_passphrase(const char *passphrase)
{
- if (!iwd_agent) return;
+ Eldbus_Message *reply;
- eina_stringshare_replace(&iwd_agent->pending_passphrase, passphrase);
- DBG("Passphrase set for pending request");
+ if (!iwd_agent) return;
+ if (!iwd_agent->pending_msg)
+ {
+ WRN("No pending passphrase request");
+ return;
+ }
+
+ DBG("Sending passphrase to iwd");
+
+ /* Create reply message */
+ reply = eldbus_message_method_return_new(iwd_agent->pending_msg);
+ if (reply)
+ {
+ eldbus_message_arguments_append(reply, "s", passphrase);
+ eldbus_connection_send(eldbus_service_connection_get(iwd_agent->iface),
+ reply, NULL, NULL, -1);
+ }
+
+ /* Clear pending request */
+ eina_stringshare_del(iwd_agent->pending_network_path);
+ iwd_agent->pending_network_path = NULL;
+ iwd_agent->pending_msg = NULL;
+
+ INF("Passphrase sent to iwd");
}
/* Cancel pending request */
void
iwd_agent_cancel(void)
{
+ Eldbus_Message *reply;
+
if (!iwd_agent) return;
+ /* Send cancellation reply if there's a pending request */
+ if (iwd_agent->pending_msg)
+ {
+ reply = eldbus_message_error_new(iwd_agent->pending_msg,
+ "net.connman.iwd.Agent.Error.Canceled",
+ "User cancelled");
+ if (reply)
+ {
+ eldbus_connection_send(eldbus_service_connection_get(iwd_agent->iface),
+ reply, NULL, NULL, -1);
+ }
+ }
+
eina_stringshare_del(iwd_agent->pending_network_path);
eina_stringshare_del(iwd_agent->pending_passphrase);
iwd_agent->pending_network_path = NULL;
iwd_agent->pending_passphrase = NULL;
+ iwd_agent->pending_msg = NULL;
DBG("Agent request cancelled");
}
@@ -197,6 +235,7 @@ _agent_request_passphrase(const Eldbus_Service_Interface *iface EINA_UNUSED,
const Eldbus_Message *msg)
{
const char *network_path;
+ IWD_Network *net;
if (!eldbus_message_arguments_get(msg, "o", &network_path))
{
@@ -206,13 +245,33 @@ _agent_request_passphrase(const Eldbus_Service_Interface *iface EINA_UNUSED,
INF("Passphrase requested for network: %s", network_path);
- /* Store network path for reference */
+ /* Store network path and message for later reply */
eina_stringshare_replace(&iwd_agent->pending_network_path, network_path);
+ iwd_agent->pending_msg = msg;
- /* TODO: Show passphrase dialog (Phase 4) */
- /* For now, just return an error to indicate we're not ready */
+ /* Find the network */
+ net = iwd_network_find(network_path);
+ if (!net)
+ {
+ ERR("Network not found: %s", network_path);
+ iwd_agent->pending_msg = NULL;
+ return eldbus_message_error_new(msg, "net.connman.iwd.Agent.Error.Canceled", "Network not found");
+ }
- return eldbus_message_error_new(msg, "net.connman.iwd.Agent.Error.Canceled", "UI not implemented yet");
+ /* Show passphrase dialog - this will eventually call iwd_agent_set_passphrase */
+ /* We need to get the instance - for now, use the first one */
+ if (iwd_mod && iwd_mod->instances)
+ {
+ Instance *inst = eina_list_data_get(iwd_mod->instances);
+ if (inst)
+ {
+ extern void wifi_auth_dialog_show(Instance *inst, IWD_Network *net);
+ wifi_auth_dialog_show(inst, net);
+ }
+ }
+
+ /* Return NULL to indicate we'll reply later (async) */
+ return NULL;
}
/* Cancel method */
diff --git a/src/iwd/iwd_agent.h b/src/iwd/iwd_agent.h
index 52fc4c8..37df935 100644
--- a/src/iwd/iwd_agent.h
+++ b/src/iwd/iwd_agent.h
@@ -12,6 +12,7 @@ typedef struct _IWD_Agent
Eldbus_Service_Interface *iface;
const char *pending_network_path;
const char *pending_passphrase;
+ const Eldbus_Message *pending_msg; /* Stored message to reply to */
} IWD_Agent;
/* Global agent */
diff --git a/src/meson.build b/src/meson.build
index f674384..1c3dde0 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -6,10 +6,10 @@ module_sources = files(
'iwd/iwd_device.c',
'iwd/iwd_network.c',
'iwd/iwd_agent.c',
+ 'ui/wifi_auth.c',
)
-# TODO: Add more source files as they are created in later phases
-# Phase 4: ui/wifi_auth.c for passphrase dialog
+# All core functionality now implemented
module_deps = [
enlightenment,
diff --git a/src/ui/wifi_auth.c b/src/ui/wifi_auth.c
new file mode 100644
index 0000000..ab72f25
--- /dev/null
+++ b/src/ui/wifi_auth.c
@@ -0,0 +1,171 @@
+#include "../e_mod_main.h"
+
+/* Auth dialog structure */
+typedef struct _Auth_Dialog
+{
+ Instance *inst;
+ IWD_Network *network;
+ E_Dialog *dialog;
+ Evas_Object *entry;
+ char *passphrase;
+} Auth_Dialog;
+
+/* Global auth dialog (only one at a time) */
+static Auth_Dialog *auth_dialog = NULL;
+
+/* Forward declarations */
+static void _auth_dialog_ok_cb(void *data, E_Dialog *dialog);
+static void _auth_dialog_cancel_cb(void *data, E_Dialog *dialog);
+static void _auth_dialog_free(Auth_Dialog *ad);
+
+/* Show authentication dialog */
+void
+wifi_auth_dialog_show(Instance *inst, IWD_Network *net)
+{
+ Auth_Dialog *ad;
+ E_Dialog *dia;
+ Evas_Object *o, *entry;
+ char buf[512];
+
+ if (!inst || !net) return;
+
+ /* Only one auth dialog at a time */
+ if (auth_dialog)
+ {
+ WRN("Auth dialog already open");
+ return;
+ }
+
+ DBG("Showing auth dialog for network: %s", net->name ? net->name : net->path);
+
+ ad = E_NEW(Auth_Dialog, 1);
+ if (!ad) return;
+
+ ad->inst = inst;
+ ad->network = net;
+ auth_dialog = ad;
+
+ /* Create dialog */
+ dia = e_dialog_new(NULL, "E", "iwd_passphrase");
+ if (!dia)
+ {
+ _auth_dialog_free(ad);
+ return;
+ }
+
+ ad->dialog = dia;
+
+ e_dialog_title_set(dia, "Wi-Fi Authentication");
+ e_dialog_icon_set(dia, "network-wireless", 48);
+
+ /* Message */
+ snprintf(buf, sizeof(buf),
+ "Enter passphrase for network:
"
+ "%s
"
+ "Security: %s",
+ net->name ? net->name : "Unknown",
+ net->type ? (strcmp(net->type, "psk") == 0 ? "WPA2/WPA3" : net->type) : "Unknown");
+
+ o = e_widget_label_add(evas_object_evas_get(dia->win), buf);
+ e_widget_size_min_set(o, 300, 40);
+
+ /* Entry for passphrase */
+ entry = e_widget_entry_add(evas_object_evas_get(dia->win), &ad->passphrase, NULL, NULL, NULL);
+ e_widget_entry_password_set(entry, 1);
+ e_widget_size_min_set(entry, 280, 30);
+
+ /* Pack into a list */
+ Evas_Object *list = e_widget_list_add(evas_object_evas_get(dia->win), 0, 0);
+ e_widget_list_object_append(list, o, 1, 1, 0.5);
+ e_widget_list_object_append(list, entry, 1, 1, 0.5);
+
+ e_dialog_content_set(dia, list, 300, 120);
+ ad->entry = entry;
+
+ /* Buttons */
+ e_dialog_button_add(dia, "Connect", NULL, _auth_dialog_ok_cb, ad);
+ e_dialog_button_add(dia, "Cancel", NULL, _auth_dialog_cancel_cb, ad);
+
+ e_dialog_button_focus_num(dia, 0);
+ e_dialog_show(dia);
+
+ INF("Auth dialog shown");
+}
+
+/* OK button callback */
+static void
+_auth_dialog_ok_cb(void *data, E_Dialog *dialog EINA_UNUSED)
+{
+ Auth_Dialog *ad = data;
+
+ if (!ad) return;
+
+ DBG("Auth dialog OK clicked");
+
+ if (!ad->passphrase || strlen(ad->passphrase) < 8)
+ {
+ e_util_dialog_show("Error",
+ "Passphrase must be at least 8 characters long.");
+ return;
+ }
+
+ /* Store passphrase in agent */
+ iwd_agent_set_passphrase(ad->passphrase);
+
+ /* Initiate connection */
+ if (ad->network)
+ {
+ INF("Connecting to network: %s", ad->network->name);
+ iwd_network_connect(ad->network);
+ }
+
+ /* Close dialog */
+ _auth_dialog_free(ad);
+}
+
+/* Cancel button callback */
+static void
+_auth_dialog_cancel_cb(void *data, E_Dialog *dialog EINA_UNUSED)
+{
+ Auth_Dialog *ad = data;
+
+ DBG("Auth dialog cancelled");
+
+ /* Cancel agent request */
+ iwd_agent_cancel();
+
+ _auth_dialog_free(ad);
+}
+
+/* Free auth dialog */
+static void
+_auth_dialog_free(Auth_Dialog *ad)
+{
+ if (!ad) return;
+
+ DBG("Freeing auth dialog");
+
+ if (ad->dialog)
+ e_object_del(E_OBJECT(ad->dialog));
+
+ /* Clear passphrase from memory */
+ if (ad->passphrase)
+ {
+ memset(ad->passphrase, 0, strlen(ad->passphrase));
+ E_FREE(ad->passphrase);
+ }
+
+ E_FREE(ad);
+ auth_dialog = NULL;
+}
+
+/* Cancel any open auth dialog */
+void
+wifi_auth_dialog_cancel(void)
+{
+ if (auth_dialog)
+ {
+ DBG("Cancelling auth dialog from external request");
+ _auth_dialog_free(auth_dialog);
+ }
+}
diff --git a/src/ui/wifi_auth.h b/src/ui/wifi_auth.h
new file mode 100644
index 0000000..07b3121
--- /dev/null
+++ b/src/ui/wifi_auth.h
@@ -0,0 +1,16 @@
+#ifndef WIFI_AUTH_H
+#define WIFI_AUTH_H
+
+#include
+
+/* Forward declarations */
+typedef struct _Instance Instance;
+typedef struct _IWD_Network IWD_Network;
+
+/* Show authentication dialog for a network */
+void wifi_auth_dialog_show(Instance *inst, IWD_Network *net);
+
+/* Cancel/close authentication dialog */
+void wifi_auth_dialog_cancel(void);
+
+#endif