diff --git a/meson.build b/meson.build index 6d929ef..718947c 100644 --- a/meson.build +++ b/meson.build @@ -13,12 +13,8 @@ module_arch = enlightenment.get_variable(pkgconfig: 'module_arch', default_value: 'linux-gnu-@0@'.format(host_machine.cpu())) module_dir = join_paths(get_option('libdir'), 'enlightenment', 'modules', 'iwd') -utf8_args = cc.get_supported_arguments(['-finput-charset=UTF-8', - '-fexec-charset=UTF-8']) - add_project_arguments('-DPACKAGE="e_iwd"', '-DPACKAGE_VERSION="@0@"'.format(meson.project_version()), - utf8_args, language : 'c') subdir('src') diff --git a/src/e_mod_config.c b/src/e_mod_config.c index 255fc0e..50bfdd6 100644 --- a/src/e_mod_config.c +++ b/src/e_mod_config.c @@ -30,8 +30,9 @@ e_iwd_config_load(void) /* Missing or out-of-date — start fresh with defaults. */ if (e_iwd_config) { - eina_stringshare_replace(&e_iwd_config->preferred_adapter, NULL); - E_FREE(e_iwd_config); + if (e_iwd_config->preferred_adapter) + eina_stringshare_del(e_iwd_config->preferred_adapter); + free(e_iwd_config); } e_iwd_config = E_NEW(E_Iwd_Config, 1); e_iwd_config->version = CONFIG_VERSION; diff --git a/src/e_mod_gadget.c b/src/e_mod_gadget.c index 62cac2c..45d278f 100644 --- a/src/e_mod_gadget.c +++ b/src/e_mod_gadget.c @@ -5,9 +5,7 @@ #include "iwd/iwd_manager.h" #include "iwd/iwd_device.h" #include "iwd/iwd_network.h" -#include "iwd/iwd_labels.h" #include -#include /* ----- per-instance gadget data --------------------------------------- */ @@ -76,6 +74,30 @@ _icon_name_for_state(Iwd_State s) return "network-wireless"; } +static const char * +_state_label(Iwd_State s) +{ + switch (s) + { + case IWD_STATE_OFF: return "Wi-Fi disabled"; + case IWD_STATE_IDLE: return "Disconnected"; + case IWD_STATE_SCANNING: return "Scanning"; + case IWD_STATE_CONNECTING: return "Connecting"; + case IWD_STATE_CONNECTED: return "Connected"; + case IWD_STATE_ERROR: return "Error"; + } + return ""; +} + +static const char * +_sec_label(int s) +{ + /* Iwd_Security values, kept in sync with iwd_network.h. */ + switch (s) { case 0: return "open"; case 1: return "WPA"; + case 2: return "802.1X"; case 3: return "WEP"; } + return "?"; +} + static void _build_tooltip(Instance *inst, Iwd_State s) { @@ -86,13 +108,13 @@ _build_tooltip(Instance *inst, Iwd_State s) if (n) snprintf(buf, sizeof(buf), "Wi-Fi: %s — %s — signal %d/4", n->ssid ? n->ssid : "?", - iwd_security_label(n->security), + _sec_label(n->security), iwd_network_signal_tier(n)); else snprintf(buf, sizeof(buf), "Wi-Fi: connected"); } else - snprintf(buf, sizeof(buf), "Wi-Fi: %s", iwd_state_label(s)); + snprintf(buf, sizeof(buf), "Wi-Fi: %s", _state_label(s)); elm_object_tooltip_text_set(inst->o_base, buf); } @@ -151,12 +173,14 @@ _on_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, vo /* ----- helpers --------------------------------------------------------- */ -static Eina_Bool -_theme_path(char *buf, size_t len) +static char * +_theme_path(void) { - if (!e_iwd || !e_iwd->module) return EINA_FALSE; - snprintf(buf, len, "%s/e-module-iwd.edj", e_module_dir_get(e_iwd->module)); - return EINA_TRUE; + static char buf[4096]; + if (!e_iwd || !e_iwd->module) return NULL; + snprintf(buf, sizeof(buf), "%s/e-module-iwd.edj", + e_module_dir_get(e_iwd->module)); + return buf; } /* ----- gadcon class ---------------------------------------------------- */ @@ -165,8 +189,7 @@ static E_Gadcon_Client * _gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style) { Instance *inst = E_NEW(Instance, 1); - char path[PATH_MAX]; - if (!_theme_path(path, sizeof(path))) path[0] = '\0'; + const char *path = _theme_path(); /* themed edje is the gadcon o_base — its intrinsic min comes from the * theme group, just like the backlight module. */ @@ -201,9 +224,6 @@ _gc_shutdown(E_Gadcon_Client *gcc) Instance *inst = gcc->data; if (!inst) return; _instances = eina_list_remove(_instances, inst); - if (inst->o_base) - evas_object_event_callback_del_full(inst->o_base, EVAS_CALLBACK_MOUSE_DOWN, - _on_mouse_down, inst); if (inst->o_icon) evas_object_del(inst->o_icon); if (inst->o_base) evas_object_del(inst->o_base); E_FREE(inst); @@ -230,20 +250,19 @@ _gc_label(const E_Gadcon_Client_Class *cc EINA_UNUSED) { return "iwd"; } static Evas_Object * _gc_icon(const E_Gadcon_Client_Class *cc EINA_UNUSED, Evas *evas) { - char path[PATH_MAX]; + const char *path = _theme_path(); Evas_Object *o = edje_object_add(evas); - if (_theme_path(path, sizeof(path))) - edje_object_file_set(o, path, "icon"); + if (path) edje_object_file_set(o, path, "icon"); return o; } static const char * _gc_id_new(const E_Gadcon_Client_Class *cc) { - char buf[128]; + static char buf[128]; snprintf(buf, sizeof(buf), "%s.%d", cc->name, eina_list_count(_instances) + 1); - return eina_stringshare_add(buf); + return buf; } static const E_Gadcon_Client_Class _gadcon_class = diff --git a/src/e_mod_main.c b/src/e_mod_main.c index bcd8f60..160316a 100644 --- a/src/e_mod_main.c +++ b/src/e_mod_main.c @@ -42,7 +42,6 @@ e_modapi_shutdown(E_Module *m EINA_UNUSED) if (!e_iwd) return 1; e_iwd_gadget_shutdown(); - e_iwd_popup_shutdown(); if (e_iwd->manager) iwd_manager_free(e_iwd->manager); e_iwd_config_save(); if (e_iwd->conn) eldbus_connection_unref(e_iwd->conn); diff --git a/src/e_mod_popup.c b/src/e_mod_popup.c index c8ef68a..c987cf2 100644 --- a/src/e_mod_popup.c +++ b/src/e_mod_popup.c @@ -4,7 +4,6 @@ #include "iwd/iwd_device.h" #include "iwd/iwd_network.h" #include "iwd/iwd_agent.h" -#include "iwd/iwd_labels.h" #include "ui/wifi_auth.h" #include "ui/wifi_hidden.h" #include @@ -31,42 +30,38 @@ static Popup *_popup = NULL; static Iwd_Agent_Request *_pending_req = NULL; /* Tracked so iwd's Cancel(reason) can tear down the dialog. */ static Evas_Object *_pending_dialog = NULL; -/* One-shot passphrase pre-armed by the hidden-network dialog. Bound to the - * SSID it was entered for, with a timeout that wipes it if iwd never comes - * asking — so a stashed passphrase can never leak to an unrelated network. */ -static char *_hidden_pending_pass = NULL; -static char *_hidden_pending_ssid = NULL; -static Ecore_Timer *_hidden_pending_timer = NULL; -#define HIDDEN_PASS_TIMEOUT 30.0 /* seconds */ - -static void -_hidden_pending_clear(void) -{ - if (_hidden_pending_pass) - { - explicit_bzero(_hidden_pending_pass, strlen(_hidden_pending_pass)); - free(_hidden_pending_pass); - _hidden_pending_pass = NULL; - } - free(_hidden_pending_ssid); - _hidden_pending_ssid = NULL; - if (_hidden_pending_timer) - { - ecore_timer_del(_hidden_pending_timer); - _hidden_pending_timer = NULL; - } -} - -static Eina_Bool -_hidden_pending_timeout(void *data EINA_UNUSED) -{ - _hidden_pending_timer = NULL; - _hidden_pending_clear(); - return ECORE_CALLBACK_CANCEL; -} +/* One-shot passphrase pre-armed by the hidden-network dialog. */ +static char *_hidden_pending_pass = NULL; /* ----- helpers --------------------------------------------------------- */ +static const char * +_state_label(Iwd_State s) +{ + switch (s) { + case IWD_STATE_OFF: return "Wi-Fi disabled"; + case IWD_STATE_IDLE: return "Disconnected"; + case IWD_STATE_SCANNING: return "Scanning…"; + case IWD_STATE_CONNECTING: return "Connecting…"; + case IWD_STATE_CONNECTED: return "Connected"; + case IWD_STATE_ERROR: return "Error"; + } + return ""; +} + +static const char * +_sec_label(Iwd_Security s) +{ + switch (s) { + case IWD_SEC_OPEN: return "open"; + case IWD_SEC_PSK: return "WPA"; + case IWD_SEC_8021X: return "802.1X"; + case IWD_SEC_WEP: return "WEP"; + case IWD_SEC_UNKNOWN: return "?"; + } + return ""; +} + static int _net_cmp(const void *a, const void *b) { @@ -117,95 +112,20 @@ _active_device(void) /* ----- list rendering -------------------------------------------------- */ -/* Click data is a strdup'd object path, freed via the row's EVAS_CALLBACK_DEL. - * Holding the Iwd_Network * directly would UAF if iwd vanished (its hash is - * cleared in _on_name_vanished) between row paint and click. */ -static void -_row_path_free(void *data, Evas *e EINA_UNUSED, - Evas_Object *o EINA_UNUSED, void *ev EINA_UNUSED) -{ free(data); } - static void _on_net_clicked(void *data, Evas_Object *obj EINA_UNUSED, void *ev EINA_UNUSED) { - const char *netpath = data; - if (!netpath || !e_iwd || !e_iwd->manager) return; - const Eina_Hash *h = iwd_manager_networks(e_iwd->manager); - Iwd_Network *n = h ? eina_hash_find(h, netpath) : NULL; + Iwd_Network *n = data; if (!n) return; - iwd_manager_clear_error(e_iwd->manager); iwd_network_connect(n); } -/* The Iwd_Network captured when the confirmation popup was opened may have - * disappeared (scan refresh, iwd restart) by the time the user clicks. We - * stash its object path on the popup and re-resolve through the live hash - * at click time so a stale pointer is never dereferenced. */ -static void _forget_confirm_free(void *data, Evas *e EINA_UNUSED, - Evas_Object *o EINA_UNUSED, void *ev EINA_UNUSED) -{ free(data); } - -static void _forget_confirm_yes(void *data, Evas_Object *obj, void *ev EINA_UNUSED) -{ - const char *netpath = data; - Evas_Object *pp = evas_object_data_get(obj, "_eiwd_confirm_popup"); - if (netpath && e_iwd && e_iwd->manager) - { - const Eina_Hash *h = iwd_manager_networks(e_iwd->manager); - Iwd_Network *n = h ? eina_hash_find(h, netpath) : NULL; - if (n) iwd_network_forget(n); - } - if (pp) evas_object_del(pp); -} - -static void _forget_confirm_no(void *data EINA_UNUSED, Evas_Object *obj, void *ev EINA_UNUSED) -{ - Evas_Object *pp = evas_object_data_get(obj, "_eiwd_confirm_popup"); - if (pp) evas_object_del(pp); -} - static void _on_net_forget(void *data, Evas_Object *obj EINA_UNUSED, void *ev EINA_UNUSED) { - const char *netpath = data; - if (!netpath || !e_iwd || !e_iwd->manager) return; - const Eina_Hash *h = iwd_manager_networks(e_iwd->manager); - Iwd_Network *n = h ? eina_hash_find(h, netpath) : NULL; + Iwd_Network *n = data; if (!n) return; - - /* Forget destroys the saved passphrase irreversibly — confirm first. - * A stray click on the ✕ next to a known network would otherwise wipe - * credentials with no recovery. */ - Evas_Object *parent = _popup ? _popup->box : e_comp->elm; - Evas_Object *pp = elm_popup_add(parent); - char msg[256]; - snprintf(msg, sizeof(msg), - "Forget saved network %s?
" - "The passphrase will be permanently deleted.", - n->ssid ? n->ssid : "(hidden)"); - elm_object_part_text_set(pp, "title,text", "Forget network"); - elm_object_text_set(pp, msg); - - /* Weak ref by netpath — looked up at click time. Freed when the popup - * is destroyed (either button or the user closing the window). */ - char *netpath_ref = n->path ? strdup(n->path) : NULL; - if (netpath_ref) - evas_object_event_callback_add(pp, EVAS_CALLBACK_DEL, - _forget_confirm_free, netpath_ref); - - Evas_Object *yes = elm_button_add(pp); - elm_object_text_set(yes, "Forget"); - evas_object_data_set(yes, "_eiwd_confirm_popup", pp); - evas_object_smart_callback_add(yes, "clicked", _forget_confirm_yes, netpath_ref); - elm_object_part_content_set(pp, "button1", yes); - - Evas_Object *no = elm_button_add(pp); - elm_object_text_set(no, "Cancel"); - evas_object_data_set(no, "_eiwd_confirm_popup", pp); - evas_object_smart_callback_add(no, "clicked", _forget_confirm_no, NULL); - elm_object_part_content_set(pp, "button2", no); - - evas_object_show(pp); + iwd_network_forget(n); } static void @@ -238,23 +158,13 @@ _rebuild_list(Popup *p) evas_object_size_hint_align_set(row, EVAS_HINT_FILL, 0); Evas_Object *btn = elm_button_add(row); - /* Truncate long SSIDs so the row never forces horizontal scrolling. - * Count codepoints, not bytes — SSIDs may contain UTF-8 and naive - * byte truncation would split a multi-byte sequence. */ + /* Truncate long SSIDs so the row never forces horizontal scrolling. */ const char *raw_ssid = n->ssid ? n->ssid : "(hidden)"; - char ssid_buf[64]; - const int max_chars = 21; - int iindex = 0, prev = 0, chars = 0; - while (chars < max_chars - && eina_unicode_utf8_next_get(raw_ssid, &iindex)) - { prev = iindex; chars++; } - if (eina_unicode_utf8_next_get(raw_ssid, &iindex)) + char ssid_buf[32]; + const int max_ssid = 22; + if ((int)strlen(raw_ssid) > max_ssid) { - /* more remains — truncate at `prev` and append U+2026 */ - int copy = prev < (int)sizeof(ssid_buf) - 4 - ? prev : (int)sizeof(ssid_buf) - 4; - memcpy(ssid_buf, raw_ssid, copy); - memcpy(ssid_buf + copy, "\xe2\x80\xa6", 4); /* "…" + NUL */ + snprintf(ssid_buf, sizeof(ssid_buf), "%.*s…", max_ssid - 1, raw_ssid); raw_ssid = ssid_buf; } char label[256]; @@ -262,32 +172,12 @@ _rebuild_list(Popup *p) _signal_bars(iwd_network_signal_tier(n)), n->known_path ? "★ " : " ", raw_ssid, - iwd_security_label(n->security), + _sec_label(n->security), n->connected ? " ✔" : ""); elm_object_text_set(btn, label); - /* Spoken label: avoids the ▂▄▆█ glyphs and ★/✔ markers which - * screen readers announce as raw Unicode. */ - char access[256]; - snprintf(access, sizeof(access), - "%s, signal %d of 4, %s%s%s", - raw_ssid, - iwd_network_signal_tier(n), - iwd_security_label(n->security), - n->known_path ? ", saved" : "", - n->connected ? ", connected" : ""); - elm_object_access_info_set(btn, access); evas_object_size_hint_weight_set(btn, EVAS_HINT_EXPAND, 0); evas_object_size_hint_align_set(btn, EVAS_HINT_FILL, 0); - /* Pass a copy of the object path, not the Iwd_Network *: the network - * may disappear (iwd_dbus name-vanished, scan refresh) before the - * user clicks, freeing the struct. The path is re-resolved through - * the live hash at click time. The buffer is freed via the button's - * EVAS_CALLBACK_DEL when the row is rebuilt or popup torn down. */ - char *click_path = n->path ? strdup(n->path) : NULL; - if (click_path) - evas_object_event_callback_add(btn, EVAS_CALLBACK_DEL, - _row_path_free, click_path); - evas_object_smart_callback_add(btn, "clicked", _on_net_clicked, click_path); + evas_object_smart_callback_add(btn, "clicked", _on_net_clicked, n); elm_box_pack_end(row, btn); evas_object_show(btn); @@ -296,14 +186,7 @@ _rebuild_list(Popup *p) Evas_Object *fb = elm_button_add(row); elm_object_text_set(fb, "✕"); elm_object_tooltip_text_set(fb, "Forget network"); - char facc[128]; - snprintf(facc, sizeof(facc), "Forget %s", raw_ssid); - elm_object_access_info_set(fb, facc); - char *forget_path = n->path ? strdup(n->path) : NULL; - if (forget_path) - evas_object_event_callback_add(fb, EVAS_CALLBACK_DEL, - _row_path_free, forget_path); - evas_object_smart_callback_add(fb, "clicked", _on_net_forget, forget_path); + evas_object_smart_callback_add(fb, "clicked", _on_net_forget, n); elm_box_pack_end(row, fb); evas_object_show(fb); } @@ -319,21 +202,8 @@ _refresh(Popup *p) { if (!p || !e_iwd || !e_iwd->manager) return; Iwd_State s = iwd_manager_state(e_iwd->manager); - /* Radio went off: the stash can no longer be useful (iwd won't ask) - * and we'd rather not keep a passphrase resident across a toggle. */ - if (s == IWD_STATE_OFF) _hidden_pending_clear(); if (p->status_lbl) - { - const char *err = iwd_manager_last_error(e_iwd->manager); - if (err) - { - char buf[320]; - snprintf(buf, sizeof(buf), "%s — %s", iwd_state_label(s), err); - elm_object_text_set(p->status_lbl, buf); - } - else - elm_object_text_set(p->status_lbl, iwd_state_label(s)); - } + elm_object_text_set(p->status_lbl, _state_label(s)); if (p->btn_toggle) elm_object_text_set(p->btn_toggle, s == IWD_STATE_OFF ? "Enable" : "Disable"); if (p->btn_scan) @@ -359,23 +229,18 @@ _on_manager_change(void *data, Iwd_Manager *m EINA_UNUSED) static void _on_rescan (void *d EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *e EINA_UNUSED) { - if (!e_iwd || !e_iwd->manager) return; - iwd_manager_clear_error(e_iwd->manager); - iwd_manager_scan_request(e_iwd->manager); + if (e_iwd && e_iwd->manager) iwd_manager_scan_request(e_iwd->manager); } static void _on_toggle(void *d EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *e EINA_UNUSED) { if (!e_iwd || !e_iwd->manager) return; - iwd_manager_clear_error(e_iwd->manager); Eina_Bool off = (iwd_manager_state(e_iwd->manager) == IWD_STATE_OFF); iwd_manager_set_powered(e_iwd->manager, off); } static void _on_disconnect(void *d EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *e EINA_UNUSED) { Iwd_Device *dev = _active_device(); - if (!dev) return; - if (e_iwd && e_iwd->manager) iwd_manager_clear_error(e_iwd->manager); - iwd_device_disconnect(dev); + if (dev) iwd_device_disconnect(dev); } static void @@ -384,19 +249,10 @@ _on_hidden_done(void *data EINA_UNUSED, const char *ssid, const char *pass, Eina if (!ok || !ssid || !*ssid) return; Iwd_Device *dev = _active_device(); if (!dev) return; - /* Pre-arm the agent reply so the next RequestPassphrase from iwd for - * *this SSID* is answered automatically. The stash is bound to the SSID - * and self-clears after HIDDEN_PASS_TIMEOUT seconds — so a typo'd or - * out-of-range SSID cannot cause the passphrase to leak to a later, - * unrelated network whose RequestPassphrase happens to land first. */ - _hidden_pending_clear(); - if (pass && *pass) - { - _hidden_pending_pass = strdup(pass); - _hidden_pending_ssid = strdup(ssid); - _hidden_pending_timer = ecore_timer_add(HIDDEN_PASS_TIMEOUT, - _hidden_pending_timeout, NULL); - } + /* Pre-arm the agent reply so the next RequestPassphrase from iwd is + * answered automatically. If the network turns out to be open, the + * stashed passphrase is simply never consumed. */ + if (pass && *pass) _hidden_pending_pass = strdup(pass); iwd_device_connect_hidden(dev, ssid); } @@ -411,12 +267,7 @@ static void _on_auth_done(void *data EINA_UNUSED, const char *pass, Eina_Bool ok) { _pending_dialog = NULL; - if (!_pending_req) - { - /* Request was already canceled by iwd; nothing to do. The caller - * (wifi_auth) wipes its own copy of `pass` after we return. */ - return; - } + if (!_pending_req) return; if (ok) iwd_agent_reply (_pending_req, pass ? pass : ""); else iwd_agent_cancel(_pending_req); _pending_req = NULL; @@ -452,27 +303,15 @@ e_iwd_popup_install_passphrase_handler(void) static void _on_passphrase_request(void *data EINA_UNUSED, Iwd_Agent_Request *req, const char *netpath) { - /* Resolve netpath -> network so we can both match the hidden stash - * against the requested SSID *and* show a friendly label in the dialog. */ - Iwd_Network *n = NULL; - if (e_iwd && e_iwd->manager) - { - const Eina_Hash *h = iwd_manager_networks(e_iwd->manager); - if (h) n = eina_hash_find(h, netpath); - } - const char *req_ssid = (n && n->ssid) ? n->ssid : NULL; - - /* Use the hidden-network stash *only* if iwd is asking for the same - * SSID we entered it for. Anything else: drop the stash on the floor - * and prompt normally. */ - if (_hidden_pending_pass && _hidden_pending_ssid && - req_ssid && !strcmp(req_ssid, _hidden_pending_ssid)) + /* If the user just kicked off a hidden-network connect with a passphrase, + * answer this request automatically without prompting. */ + if (_hidden_pending_pass) { iwd_agent_reply(req, _hidden_pending_pass); - _hidden_pending_clear(); + free(_hidden_pending_pass); + _hidden_pending_pass = NULL; return; } - if (_pending_req) { iwd_agent_cancel(req); @@ -480,8 +319,27 @@ _on_passphrase_request(void *data EINA_UNUSED, Iwd_Agent_Request *req, const cha } _pending_req = req; - const char *ssid = req_ssid ? req_ssid : "network"; - const char *sec = n ? iwd_security_label(n->security) : NULL; + /* Look up the network for a friendly SSID, if we have it. */ + const char *ssid = "network"; + if (e_iwd && e_iwd->manager) + { + const Eina_Hash *h = iwd_manager_networks(e_iwd->manager); + if (h) + { + Iwd_Network *n = eina_hash_find(h, netpath); + if (n && n->ssid) ssid = n->ssid; + } + } + const char *sec = NULL; + if (e_iwd && e_iwd->manager) + { + const Eina_Hash *h = iwd_manager_networks(e_iwd->manager); + if (h) + { + Iwd_Network *n = eina_hash_find(h, netpath); + if (n) sec = _sec_label(n->security); + } + } _pending_dialog = wifi_auth_prompt(_popup ? _popup->box : e_comp->elm, ssid, sec, _on_auth_done, NULL); } @@ -497,17 +355,6 @@ _destroy(void) if (_popup->gp) e_object_del(E_OBJECT(_popup->gp)); free(_popup); _popup = NULL; - /* Drop any pre-armed hidden-network passphrase: if the user closes the - * popup before iwd asks, the stash would otherwise sit in the heap until - * the 30 s timer fires. The stash is process-global, not popup-scoped. */ - _hidden_pending_clear(); -} - -void -e_iwd_popup_shutdown(void) -{ - _destroy(); - _hidden_pending_clear(); } void @@ -523,7 +370,6 @@ e_iwd_popup_toggle(E_Gadcon_Client *gcc) if (!gcc || !e_iwd) return; Popup *p = calloc(1, sizeof(*p)); - if (!p) return; _popup = p; p->gp = e_gadcon_popup_new(gcc, EINA_FALSE); diff --git a/src/e_mod_popup.h b/src/e_mod_popup.h index a053212..33717a9 100644 --- a/src/e_mod_popup.h +++ b/src/e_mod_popup.h @@ -4,9 +4,8 @@ #include void e_iwd_popup_install_passphrase_handler(void); -void e_iwd_popup_toggle (E_Gadcon_Client *gcc); -void e_iwd_popup_close (void); -void e_iwd_popup_refresh (void); -void e_iwd_popup_shutdown(void); +void e_iwd_popup_toggle (E_Gadcon_Client *gcc); +void e_iwd_popup_close (void); +void e_iwd_popup_refresh(void); #endif diff --git a/src/iwd/iwd_adapter.c b/src/iwd/iwd_adapter.c index 8cce39d..4747dad 100644 --- a/src/iwd/iwd_adapter.c +++ b/src/iwd/iwd_adapter.c @@ -61,28 +61,6 @@ iwd_adapter_free(Iwd_Adapter *a) free(a); } -/* Reply context captures the *manager* (which outlives all sub-objects) and - * a strdup'd adapter path, never the Iwd_Adapter — on iwd disconnect the - * adapter hash is freed, and a raw back-ref would UAF when the local-error - * reply lands. Mirrors the pattern in iwd_network.c / iwd_device.c. */ -typedef struct -{ - Iwd_Manager *m; - char *path; -} _Adapter_Reply_Ctx; - -static void -_on_set_powered_reply(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED) -{ - _Adapter_Reply_Ctx *ctx = data; - const char *en, *em; - if (eldbus_message_error_get(msg, &en, &em) && ctx->m) - iwd_manager_report_error(ctx->m, - "Set Adapter.Powered failed: %s", em ? em : en); - free(ctx->path); - free(ctx); -} - void iwd_adapter_set_powered(Iwd_Adapter *a, Eina_Bool on) { @@ -105,13 +83,7 @@ iwd_adapter_set_powered(Iwd_Adapter *a, Eina_Bool on) eldbus_message_iter_basic_append(variant, 'b', v); eldbus_message_iter_container_close(iter, variant); - _Adapter_Reply_Ctx *ctx = calloc(1, sizeof(*ctx)); - if (ctx) - { - ctx->m = a->manager; - ctx->path = a->path ? strdup(a->path) : NULL; - } - eldbus_proxy_send(props, msg, _on_set_powered_reply, ctx, -1); + eldbus_proxy_send(props, msg, NULL, NULL, -1); /* Keep the props proxy alive on the adapter so the call isn't canceled. */ if (a->_props_proxy_keepalive) eldbus_proxy_unref(a->_props_proxy_keepalive); a->_props_proxy_keepalive = props; diff --git a/src/iwd/iwd_agent.c b/src/iwd/iwd_agent.c index e378039..6947f90 100644 --- a/src/iwd/iwd_agent.c +++ b/src/iwd/iwd_agent.c @@ -1,7 +1,5 @@ #include "iwd_agent.h" #include "iwd_dbus.h" -#include "iwd_manager.h" -#include #include #include @@ -73,9 +71,6 @@ _request_passphrase_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, "No UI handler"); Iwd_Agent_Request *req = calloc(1, sizeof(*req)); - if (!req) - return eldbus_message_error_new(msg, "net.connman.iwd.Agent.Error.Canceled", - "Out of memory"); req->agent = _self; req->msg = eldbus_message_ref((Eldbus_Message *)msg); _self->cb(_self->data, req, path); @@ -118,12 +113,6 @@ void iwd_agent_reply(Iwd_Agent_Request *req, const char *passphrase) { if (!req) return; - /* The passphrase is copied into the eldbus/libdbus marshalled message - * buffer here. We can't wipe that buffer ourselves — eldbus owns it and - * frees it asynchronously after the call is sent. Callers are expected - * to explicit_bzero their own copy of `passphrase` after this returns; - * the residue inside the outbound D-Bus message is unavoidable at this - * boundary. */ Eldbus_Message *r = eldbus_message_method_return_new(req->msg); eldbus_message_arguments_append(r, "s", passphrase ? passphrase : ""); eldbus_connection_send(req->agent->conn, r, NULL, NULL, -1); @@ -146,29 +135,14 @@ iwd_agent_cancel(Iwd_Agent_Request *req) /* ----- Registration with iwd ------------------------------------------ */ static void -_on_register(void *data, const Eldbus_Message *msg, +_on_register(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED) { - /* `data` is the manager — same pointer the trampoline carries. */ - Iwd_Manager *m = data; const char *en, *em; - if (!eldbus_message_error_get(msg, &en, &em)) return; - if (m) - iwd_manager_report_error(m, - "Wi-Fi agent registration refused (another agent running?): %s", - em ? em : en); - else + if (eldbus_message_error_get(msg, &en, &em)) fprintf(stderr, "e_iwd: agent register failed: %s: %s\n", en, em); } -void -iwd_agent_register(Iwd_Agent *a) -{ - if (!a || !a->am_proxy) return; - eldbus_proxy_call(a->am_proxy, "RegisterAgent", _on_register, a->data, -1, - "o", IWD_AGENT_PATH); -} - Iwd_Agent * iwd_agent_new(Eldbus_Connection *conn, Iwd_Agent_Passphrase_Cb cb, void *data) { @@ -184,8 +158,12 @@ iwd_agent_new(Eldbus_Connection *conn, Iwd_Agent_Passphrase_Cb cb, void *data) a->am_obj = eldbus_object_get(conn, IWD_BUS_NAME, "/net/connman/iwd"); if (a->am_obj) - a->am_proxy = eldbus_proxy_get(a->am_obj, IWD_IFACE_AGENT_MANAGER); - iwd_agent_register(a); + { + a->am_proxy = eldbus_proxy_get(a->am_obj, IWD_IFACE_AGENT_MANAGER); + if (a->am_proxy) + eldbus_proxy_call(a->am_proxy, "RegisterAgent", _on_register, NULL, -1, + "o", IWD_AGENT_PATH); + } return a; } @@ -201,13 +179,6 @@ void iwd_agent_free(Iwd_Agent *a) { if (!a) return; - /* Politely deregister so iwd doesn't keep dispatching to a dead service - * during shutdown. Fire-and-forget: the connection may already be torn - * down by the time the call would land, and there's nothing to do with - * the reply anyway. */ - if (a->am_proxy) - eldbus_proxy_call(a->am_proxy, "UnregisterAgent", NULL, NULL, -1, - "o", IWD_AGENT_PATH); if (a->svc) eldbus_service_interface_unregister(a->svc); if (a->am_proxy) eldbus_proxy_unref(a->am_proxy); if (a->am_obj) eldbus_object_unref(a->am_obj); diff --git a/src/iwd/iwd_agent.h b/src/iwd/iwd_agent.h index 49e6b65..9fcc168 100644 --- a/src/iwd/iwd_agent.h +++ b/src/iwd/iwd_agent.h @@ -21,10 +21,6 @@ Iwd_Agent *iwd_agent_new (Eldbus_Connection *conn, Iwd_Agent_Passphrase_Cb cb, void *data); void iwd_agent_set_cancel_cb(Iwd_Agent *a, Iwd_Agent_Cancel_Cb cb, void *data); -/* Re-issue RegisterAgent. Call after iwd reappears on the bus - * (NameOwnerChanged) — without this, every PSK connect silently hangs - * because no agent is registered against the new iwd instance. */ -void iwd_agent_register(Iwd_Agent *a); void iwd_agent_free(Iwd_Agent *a); void iwd_agent_reply (Iwd_Agent_Request *req, const char *passphrase); diff --git a/src/iwd/iwd_device.c b/src/iwd/iwd_device.c index 572dd5a..1c05c52 100644 --- a/src/iwd/iwd_device.c +++ b/src/iwd/iwd_device.c @@ -3,6 +3,7 @@ #include "iwd_props.h" #include "iwd_manager.h" #include "iwd_network.h" +#include #include #include @@ -148,15 +149,10 @@ iwd_device_free(Iwd_Device *d) /* Reply to Station.GetOrderedNetworks: a(on) — list of (object_path, RSSI). * RSSI is a 16-bit signed value in 100*dBm units. */ -/* Reply callbacks must not hold a raw Iwd_Device back-ref: a device can be - * removed (rfkill, hot-unplug, iwd restart) while a call is in flight, and - * the reply would then UAF. The manager outlives every sub-object, so we - * pass it directly. Network lookups go through the live hash, which is - * safe even after the originating device is gone. */ static void _on_ordered_networks(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED) { - Iwd_Manager *m = data; + Iwd_Device *d = data; const char *en, *em; if (eldbus_message_error_get(msg, &en, &em)) return; @@ -164,7 +160,7 @@ _on_ordered_networks(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EI if (!eldbus_message_arguments_get(msg, "a(on)", &array) || !array) return; - const Eina_Hash *nets = m ? iwd_manager_networks(m) : NULL; + const Eina_Hash *nets = d->manager ? iwd_manager_networks(d->manager) : NULL; Eldbus_Message_Iter *entry; Eina_Bool any = EINA_FALSE; while (eldbus_message_iter_get_and_next(array, 'r', &entry)) @@ -179,7 +175,7 @@ _on_ordered_networks(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EI n->have_signal = EINA_TRUE; any = EINA_TRUE; } - if (any && m) iwd_manager_notify(m); + if (any && d->manager) iwd_manager_notify(d->manager); } static void @@ -187,74 +183,38 @@ _refresh_signals(Iwd_Device *d) { if (!d || !d->station_proxy) return; eldbus_proxy_call(d->station_proxy, "GetOrderedNetworks", - _on_ordered_networks, d->manager, -1, ""); -} - -static void -_on_scan_reply(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED) -{ - Iwd_Manager *m = data; - const char *en, *em; - if (!eldbus_message_error_get(msg, &en, &em)) return; - /* "AlreadyExists" / "InProgress" is the normal race when two scan - * triggers fire close together — don't spam the user with that. */ - if (en && (strstr(en, "InProgress") || strstr(en, "Busy") || - strstr(en, "AlreadyExists"))) - return; - if (m) iwd_manager_report_error(m, "Scan failed: %s", em ? em : en); + _on_ordered_networks, d, -1, ""); } void iwd_device_scan(Iwd_Device *d) { if (!d || !d->station_proxy) return; - eldbus_proxy_call(d->station_proxy, "Scan", _on_scan_reply, d->manager, -1, ""); -} - -static void -_on_disconnect_reply(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED) -{ - Iwd_Manager *m = data; - const char *en, *em; - if (eldbus_message_error_get(msg, &en, &em) && m) - iwd_manager_report_error(m, "Disconnect failed: %s", em ? em : en); + eldbus_proxy_call(d->station_proxy, "Scan", NULL, NULL, -1, ""); } void iwd_device_disconnect(Iwd_Device *d) { if (!d || !d->station_proxy) return; - eldbus_proxy_call(d->station_proxy, "Disconnect", - _on_disconnect_reply, d->manager, -1, ""); + eldbus_proxy_call(d->station_proxy, "Disconnect", NULL, NULL, -1, ""); } -typedef struct -{ - Iwd_Manager *m; - char *ssid; -} _Connect_Hidden_Ctx; - static void _on_connect_hidden_reply(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED) { - _Connect_Hidden_Ctx *ctx = data; const char *en, *em; - if (eldbus_message_error_get(msg, &en, &em) && ctx->m) - iwd_manager_report_error(ctx->m, - "Connect to hidden '%s' failed: %s", - ctx->ssid ? ctx->ssid : "?", em ? em : en); - free(ctx->ssid); - free(ctx); + char *ssid = data; + if (eldbus_message_error_get(msg, &en, &em)) + fprintf(stderr, "e_iwd: ConnectHiddenNetwork('%s') failed: %s: %s\n", + ssid ? ssid : "?", en, em); + free(ssid); } void iwd_device_connect_hidden(Iwd_Device *d, const char *ssid) { if (!d || !d->station_proxy || !ssid || !*ssid) return; - _Connect_Hidden_Ctx *ctx = calloc(1, sizeof(*ctx)); - if (!ctx) return; - ctx->m = d->manager; - ctx->ssid = strdup(ssid); eldbus_proxy_call(d->station_proxy, "ConnectHiddenNetwork", - _on_connect_hidden_reply, ctx, -1, "s", ssid); + _on_connect_hidden_reply, strdup(ssid), -1, "s", ssid); } diff --git a/src/iwd/iwd_labels.c b/src/iwd/iwd_labels.c deleted file mode 100644 index c3cfcf7..0000000 --- a/src/iwd/iwd_labels.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "iwd_labels.h" - -const char * -iwd_state_label(Iwd_State s) -{ - switch (s) { - case IWD_STATE_OFF: return "Wi-Fi disabled"; - case IWD_STATE_IDLE: return "Disconnected"; - case IWD_STATE_SCANNING: return "Scanning…"; - case IWD_STATE_CONNECTING: return "Connecting…"; - case IWD_STATE_CONNECTED: return "Connected"; - case IWD_STATE_ERROR: return "Error"; - } - return ""; -} - -const char * -iwd_security_label(Iwd_Security s) -{ - switch (s) { - case IWD_SEC_OPEN: return "open"; - case IWD_SEC_PSK: return "WPA"; - case IWD_SEC_8021X: return "802.1X"; - case IWD_SEC_WEP: return "WEP"; - case IWD_SEC_UNKNOWN: return "?"; - } - return ""; -} diff --git a/src/iwd/iwd_labels.h b/src/iwd/iwd_labels.h deleted file mode 100644 index 9a4dee4..0000000 --- a/src/iwd/iwd_labels.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef IWD_LABELS_H -#define IWD_LABELS_H - -#include "iwd_manager.h" -#include "iwd_network.h" - -/* Short, user-facing labels for state and security enums. The pointers - * returned are static literals — do not free. */ -const char *iwd_state_label (Iwd_State s); -const char *iwd_security_label(Iwd_Security s); - -#endif diff --git a/src/iwd/iwd_manager.c b/src/iwd/iwd_manager.c index ec4648e..5cd78a2 100644 --- a/src/iwd/iwd_manager.c +++ b/src/iwd/iwd_manager.c @@ -4,8 +4,6 @@ #include "iwd_device.h" #include "iwd_network.h" #include -#include -#include #include #include @@ -25,7 +23,6 @@ struct _Iwd_Manager Eina_List *listeners; /* Listener * */ Iwd_State state; Ecore_Job *notify_job; - char *last_error; Iwd_Agent_Passphrase_Cb pass_cb; void *pass_data; @@ -63,7 +60,6 @@ iwd_manager_listener_add(Iwd_Manager *m, Iwd_Manager_Cb cb, void *data) { if (!m || !cb) return; Listener *l = calloc(1, sizeof(*l)); - if (!l) return; l->cb = cb; l->data = data; m->listeners = eina_list_append(m->listeners, l); } @@ -106,33 +102,6 @@ iwd_manager_notify(Iwd_Manager *m) m->notify_job = ecore_job_add(_notify_job_cb, m); } -const char * -iwd_manager_last_error(const Iwd_Manager *m) { return m ? m->last_error : NULL; } - -void -iwd_manager_clear_error(Iwd_Manager *m) -{ - if (!m || !m->last_error) return; - free(m->last_error); - m->last_error = NULL; -} - -void -iwd_manager_report_error(Iwd_Manager *m, const char *fmt, ...) -{ - if (!m || !fmt) return; - char buf[256]; - va_list ap; - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - /* stderr keeps the dev-visible trail; the stashed copy drives the UI. */ - fprintf(stderr, "e_iwd: %s\n", buf); - free(m->last_error); - m->last_error = strdup(buf); - iwd_manager_notify(m); -} - /* ----- state aggregation ---------------------------------------------- */ static void @@ -253,14 +222,7 @@ _on_iface_removed(void *data, const char *path, const char *iface) } static void -_on_name_appeared(void *data) -{ - /* GetManagedObjects will repopulate adapters/devices/networks; we just - * need to re-register our agent against the new iwd instance. Without - * this, PSK connects silently hang after `systemctl restart iwd`. */ - Iwd_Manager *m = data; - if (m && m->agent) iwd_agent_register(m->agent); -} +_on_name_appeared(void *data EINA_UNUSED) { /* GetManagedObjects will populate */ } static void _on_name_vanished(void *data) @@ -312,7 +274,6 @@ iwd_manager_free(Iwd_Manager *m) eina_hash_free(m->networks); Listener *li; EINA_LIST_FREE(m->listeners, li) free(li); - free(m->last_error); free(m); } diff --git a/src/iwd/iwd_manager.h b/src/iwd/iwd_manager.h index f23d3b5..900fad4 100644 --- a/src/iwd/iwd_manager.h +++ b/src/iwd/iwd_manager.h @@ -36,15 +36,6 @@ void iwd_manager_listener_del (Iwd_Manager *m, Iwd_Manager_Cb cb, void *data); /* Internal: invoked by sub-objects when their state changes. */ void iwd_manager_notify (Iwd_Manager *m); -/* Latest user-facing error string, or NULL. Owned by the manager. - * Cleared on next successful state change or by iwd_manager_clear_error. */ -const char *iwd_manager_last_error (const Iwd_Manager *m); -void iwd_manager_clear_error(Iwd_Manager *m); - -/* Stash a one-shot error message and notify listeners. Used by D-Bus reply - * callbacks when iwd refuses a Connect/Forget/Set(Powered)/etc. */ -void iwd_manager_report_error(Iwd_Manager *m, const char *fmt, ...); - /* The UI installs its passphrase prompt here. The handler must * eventually call iwd_agent_reply()/iwd_agent_cancel() with the request. */ void iwd_manager_set_passphrase_handler(Iwd_Manager *m, diff --git a/src/iwd/iwd_network.c b/src/iwd/iwd_network.c index de83d92..18a84d5 100644 --- a/src/iwd/iwd_network.c +++ b/src/iwd/iwd_network.c @@ -2,6 +2,7 @@ #include "iwd_dbus.h" #include "iwd_props.h" #include "iwd_manager.h" +#include #include #include @@ -79,39 +80,15 @@ iwd_network_free(Iwd_Network *n) free(n); } -/* Reply context captures the *manager* (which outlives all sub-objects) and - * a strdup'd SSID, never the Iwd_Network — the network may disappear from - * the next scan before iwd's reply lands, and a raw back-ref would UAF. */ -typedef struct -{ - Iwd_Manager *m; - char *ssid; -} _Net_Reply_Ctx; - static void _on_connect_reply(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED) { - _Net_Reply_Ctx *ctx = data; const char *en, *em; - if (eldbus_message_error_get(msg, &en, &em) && ctx->m) - iwd_manager_report_error(ctx->m, - "Connect to '%s' failed: %s", - ctx->ssid ? ctx->ssid : "?", em ? em : en); - free(ctx->ssid); - free(ctx); -} - -static void -_on_forget_reply(void *data, const Eldbus_Message *msg, Eldbus_Pending *p EINA_UNUSED) -{ - _Net_Reply_Ctx *ctx = data; - const char *en, *em; - if (eldbus_message_error_get(msg, &en, &em) && ctx->m) - iwd_manager_report_error(ctx->m, - "Forget '%s' failed: %s", - ctx->ssid ? ctx->ssid : "?", em ? em : en); - free(ctx->ssid); - free(ctx); + const char *ssid = data; + if (eldbus_message_error_get(msg, &en, &em)) + fprintf(stderr, "e_iwd: connect to '%s' failed: %s: %s\n", + ssid ? ssid : "?", en, em); + free(data); } int @@ -127,16 +104,6 @@ iwd_network_signal_tier(const Iwd_Network *n) return 1; } -static _Net_Reply_Ctx * -_reply_ctx_new(Iwd_Network *n) -{ - _Net_Reply_Ctx *ctx = calloc(1, sizeof(*ctx)); - if (!ctx) return NULL; - ctx->m = n->manager; - ctx->ssid = n->ssid ? strdup(n->ssid) : NULL; - return ctx; -} - void iwd_network_connect(Iwd_Network *n) { @@ -144,7 +111,7 @@ iwd_network_connect(Iwd_Network *n) /* Network.Connect() takes no args; iwd will dial the registered Agent * for a passphrase if needed. */ eldbus_proxy_call(n->proxy, "Connect", _on_connect_reply, - _reply_ctx_new(n), -1, ""); + n->ssid ? strdup(n->ssid) : NULL, -1, ""); } void @@ -157,7 +124,7 @@ iwd_network_forget(Iwd_Network *n) Eldbus_Proxy *kp = eldbus_proxy_get(kobj, IWD_IFACE_KNOWN_NETWORK); if (kp) { - eldbus_proxy_call(kp, "Forget", _on_forget_reply, _reply_ctx_new(n), -1, ""); + eldbus_proxy_call(kp, "Forget", NULL, NULL, -1, ""); eldbus_proxy_unref(kp); } eldbus_object_unref(kobj); diff --git a/src/meson.build b/src/meson.build index 6f52292..a7a4324 100644 --- a/src/meson.build +++ b/src/meson.build @@ -10,9 +10,10 @@ e_iwd_sources = [ 'iwd/iwd_manager.c', 'iwd/iwd_device.c', 'iwd/iwd_network.c', - 'iwd/iwd_labels.c', + 'ui/wifi_list.c', 'ui/wifi_auth.c', 'ui/wifi_hidden.c', + 'ui/wifi_status.c', ] shared_module('module', diff --git a/src/ui/wifi_auth.c b/src/ui/wifi_auth.c index 81bcfce..8fdb1e5 100644 --- a/src/ui/wifi_auth.c +++ b/src/ui/wifi_auth.c @@ -1,6 +1,5 @@ #include "wifi_auth.h" #include -#include typedef struct _Auth_Ctx { @@ -13,27 +12,11 @@ typedef struct _Auth_Ctx } Auth_Ctx; static void -_finish(Auth_Ctx *c, Eina_Bool ok) +_finish(Auth_Ctx *c, Eina_Bool ok, const char *pass) { if (c->fired) return; c->fired = EINA_TRUE; - - /* Copy the passphrase into a buffer we own so we can wipe it - * after the callback returns. The elm_entry's internal buffer - * is then overwritten before the window (and entry) are destroyed. */ - char *pass = NULL; - if (ok && c->entry) - { - const char *raw = elm_entry_entry_get(c->entry); - if (raw) pass = strdup(raw); - } if (c->cb) c->cb(c->data, pass, ok); - if (pass) - { - explicit_bzero(pass, strlen(pass)); - free(pass); - } - if (c->entry) elm_entry_entry_set(c->entry, ""); if (c->win) evas_object_del(c->win); free(c); } @@ -41,25 +24,21 @@ _finish(Auth_Ctx *c, Eina_Bool ok) static void _on_ok(void *data, Evas_Object *o EINA_UNUSED, void *ev EINA_UNUSED) { - _finish(data, EINA_TRUE); + Auth_Ctx *c = data; + _finish(c, EINA_TRUE, elm_entry_entry_get(c->entry)); } static void _on_cancel(void *data, Evas_Object *o EINA_UNUSED, void *ev EINA_UNUSED) { - _finish(data, EINA_FALSE); + _finish(data, EINA_FALSE, NULL); } static void _on_del(void *data, Evas *e EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *ev EINA_UNUSED) { /* Window closed without cancel/ok — treat as cancel. */ - Auth_Ctx *c = data; - /* The window (and entry) are being destroyed; null entry to skip the - * post-cb entry_set in _finish. */ - c->win = NULL; - c->entry = NULL; - _finish(c, EINA_FALSE); + _finish(data, EINA_FALSE, NULL); } Evas_Object * @@ -68,7 +47,6 @@ wifi_auth_prompt(Evas_Object *parent EINA_UNUSED, const char *ssid, Wifi_Auth_Cb cb, void *data) { Auth_Ctx *c = calloc(1, sizeof(*c)); - if (!c) return NULL; c->cb = cb; c->data = data; /* A floating top-level window so the popup is actually visible — diff --git a/src/ui/wifi_hidden.c b/src/ui/wifi_hidden.c index 2f93215..1e936f8 100644 --- a/src/ui/wifi_hidden.c +++ b/src/ui/wifi_hidden.c @@ -1,6 +1,5 @@ #include "wifi_hidden.h" #include -#include typedef struct _Hidden_Ctx { @@ -18,39 +17,9 @@ _finish(Hidden_Ctx *c, Eina_Bool ok) { if (c->fired) return; c->fired = EINA_TRUE; - - /* Copy SSID + passphrase into buffers we own; wipe the passphrase - * (and overwrite the entry) before the window is destroyed. */ - char *ssid = NULL, *pass = NULL; - if (ok) - { - if (c->e_ssid) - { - const char *r = elm_entry_entry_get(c->e_ssid); - if (r) ssid = strdup(r); - } - if (c->e_pass) - { - const char *r = elm_entry_entry_get(c->e_pass); - if (r) pass = strdup(r); - } - } + const char *ssid = ok ? elm_entry_entry_get(c->e_ssid) : NULL; + const char *pass = ok ? elm_entry_entry_get(c->e_pass) : NULL; if (c->cb) c->cb(c->data, ssid, pass, ok); - if (pass) - { - explicit_bzero(pass, strlen(pass)); - free(pass); - } - /* SSIDs aren't secret, but wiping keeps the heap consistent with the - * passphrase handling and avoids leaving identifiable network names in - * freed memory after a hidden-network prompt. */ - if (ssid) - { - explicit_bzero(ssid, strlen(ssid)); - free(ssid); - } - if (c->e_ssid) elm_entry_entry_set(c->e_ssid, ""); - if (c->e_pass) elm_entry_entry_set(c->e_pass, ""); if (c->win) evas_object_del(c->win); free(c); } @@ -73,11 +42,7 @@ _on_cancel(void *data, Evas_Object *o EINA_UNUSED, void *ev EINA_UNUSED) static void _on_del(void *data, Evas *e EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *ev EINA_UNUSED) { - Hidden_Ctx *c = data; - c->win = NULL; - c->e_ssid = NULL; - c->e_pass = NULL; - _finish(c, EINA_FALSE); + _finish(data, EINA_FALSE); } static Evas_Object * @@ -104,7 +69,6 @@ void wifi_hidden_prompt(Evas_Object *parent EINA_UNUSED, Wifi_Hidden_Cb cb, void *data) { Hidden_Ctx *c = calloc(1, sizeof(*c)); - if (!c) { if (cb) cb(data, NULL, NULL, EINA_FALSE); return; } c->cb = cb; c->data = data; /* Floating top-level so the popup actually shows. */ diff --git a/src/ui/wifi_list.c b/src/ui/wifi_list.c new file mode 100644 index 0000000..2717a01 --- /dev/null +++ b/src/ui/wifi_list.c @@ -0,0 +1,13 @@ +#include "wifi_list.h" + +/* TODO: Genlist of networks, sorted (known first, then signal desc), + * with security icon, signal bars, and click → connect/auth flow. */ + +Evas_Object * +wifi_list_add(Evas_Object *parent) +{ + Evas_Object *gl = elm_genlist_add(parent); + return gl; +} + +void wifi_list_refresh(Evas_Object *list EINA_UNUSED) { /* TODO */ } diff --git a/src/ui/wifi_list.h b/src/ui/wifi_list.h new file mode 100644 index 0000000..cfc0bcf --- /dev/null +++ b/src/ui/wifi_list.h @@ -0,0 +1,9 @@ +#ifndef WIFI_LIST_H +#define WIFI_LIST_H + +#include + +Evas_Object *wifi_list_add(Evas_Object *parent); +void wifi_list_refresh(Evas_Object *list); + +#endif diff --git a/src/ui/wifi_status.c b/src/ui/wifi_status.c new file mode 100644 index 0000000..1f61cfe --- /dev/null +++ b/src/ui/wifi_status.c @@ -0,0 +1,12 @@ +#include "wifi_status.h" + +/* TODO: current connection summary widget (SSID, signal, IP, Disconnect). */ + +Evas_Object * +wifi_status_add(Evas_Object *parent) +{ + Evas_Object *box = elm_box_add(parent); + return box; +} + +void wifi_status_refresh(Evas_Object *o EINA_UNUSED) { /* TODO */ } diff --git a/src/ui/wifi_status.h b/src/ui/wifi_status.h new file mode 100644 index 0000000..857f386 --- /dev/null +++ b/src/ui/wifi_status.h @@ -0,0 +1,9 @@ +#ifndef WIFI_STATUS_H +#define WIFI_STATUS_H + +#include + +Evas_Object *wifi_status_add(Evas_Object *parent); +void wifi_status_refresh(Evas_Object *o); + +#endif