diff --git a/src/modules/connman/E_Connman.h b/src/modules/connman/E_Connman.h index 02f56898d..ba59a82cf 100644 --- a/src/modules/connman/E_Connman.h +++ b/src/modules/connman/E_Connman.h @@ -62,6 +62,14 @@ struct Connman_Service enum Connman_State state; enum Connman_Service_Type type; uint8_t strength; + + /* Private */ + struct + { + DBusPendingCall *connect; + DBusPendingCall *disconnect; + void *data; + } pending; }; /* Ecore Events */ @@ -80,6 +88,11 @@ unsigned int e_connman_system_shutdown(void); */ struct Connman_Service *econnman_manager_find_service(struct Connman_Manager *cm, const char *path) EINA_ARG_NONNULL(1, 2); +typedef void (*Econnman_Simple_Cb)(void *data, const char *error); + +bool econnman_service_connect(struct Connman_Service *cs, Econnman_Simple_Cb cb, void *data); +bool econnman_service_disconnect(struct Connman_Service *cs, Econnman_Simple_Cb cb, void *data); + /* UI calls from econnman */ /* diff --git a/src/modules/connman/e_connman.c b/src/modules/connman/e_connman.c index c425466a3..e922f31b1 100644 --- a/src/modules/connman/e_connman.c +++ b/src/modules/connman/e_connman.c @@ -13,6 +13,9 @@ #define CONNMAN_MANAGER_IFACE CONNMAN_BUS_NAME ".Manager" #define CONNMAN_SERVICE_IFACE CONNMAN_BUS_NAME ".Service" +#define MILLI_PER_SEC 1000 +#define CONNMAN_CONNECTION_TIMEOUT 60 * MILLI_PER_SEC + static unsigned int init_count; static E_DBus_Connection *conn; static char *bus_owner; @@ -253,11 +256,28 @@ static void _service_prop_changed(void *data, DBusMessage *msg) _service_parse_prop_changed(cs, name, &var); } +struct connection_data { + struct Connman_Service *cs; + Econnman_Simple_Cb cb; + void *user_data; +}; + static void _service_free(struct Connman_Service *cs) { if (!cs) return; + if (cs->pending.connect) + { + dbus_pending_call_cancel(cs->pending.connect); + free(cs->pending.data); + } + if (cs->pending.disconnect) + { + dbus_pending_call_cancel(cs->pending.disconnect); + free(cs->pending.data); + } + free(cs->name); _eina_str_array_clean(cs->security); eina_array_free(cs->security); @@ -287,6 +307,96 @@ static struct Connman_Service *_service_new(const char *path, DBusMessageIter *p return cs; } +static void _service_connection_cb(void *data, DBusMessage *reply, + DBusError *err) +{ + struct connection_data *cd = data; + + if (cd->cb) + { + const char *s = dbus_error_is_set(err) ? err->message : NULL; + cd->cb(cd->user_data, s); + } + + cd->cs->pending.connect = NULL; + cd->cs->pending.disconnect = NULL; + cd->cs->pending.data = NULL; + + free(cd); +} + +bool econnman_service_connect(struct Connman_Service *cs, + Econnman_Simple_Cb cb, void *data) +{ + DBusMessage *msg; + struct connection_data *cd; + + EINA_SAFETY_ON_NULL_RETURN_VAL(cs, false); + + if (cs->pending.connect || cs->pending.disconnect) + { + ERR("Pending connection: connect=%p disconnect=%p", cs->pending.connect, + cs->pending.disconnect); + return false; + } + + msg = dbus_message_new_method_call(CONNMAN_BUS_NAME, cs->obj.path, + CONNMAN_SERVICE_IFACE, "Connect"); + EINA_SAFETY_ON_NULL_RETURN_VAL(msg, false); + + cd = calloc(1, sizeof(*cd)); + EINA_SAFETY_ON_NULL_GOTO(cd, fail); + + cd->cs = cs; + cd->cb = cb; + cd->user_data = data; + + cs->pending.connect = e_dbus_message_send(conn, msg, + _service_connection_cb, CONNMAN_CONNECTION_TIMEOUT, cd); + + return true; + +fail: + dbus_message_unref(msg); + return false; +} + +bool econnman_service_disconnect(struct Connman_Service *cs, + Econnman_Simple_Cb cb, void *data) +{ + DBusMessage *msg; + struct connection_data *cd; + + EINA_SAFETY_ON_NULL_RETURN_VAL(cs, false); + + if (cs->pending.connect || cs->pending.disconnect) + { + ERR("Pending connection: connect=%p disconnect=%p", cs->pending.connect, + cs->pending.disconnect); + return false; + } + + msg = dbus_message_new_method_call(CONNMAN_BUS_NAME, cs->obj.path, + CONNMAN_SERVICE_IFACE, "Disconnect"); + EINA_SAFETY_ON_NULL_RETURN_VAL(msg, false); + + cd = calloc(1, sizeof(*cd)); + EINA_SAFETY_ON_NULL_GOTO(cd, fail); + + cd->cs = cs; + cd->cb = cb; + cd->user_data = data; + + cs->pending.connect = e_dbus_message_send(conn, msg, + _service_connection_cb, -1, cd); + + return true; + +fail: + dbus_message_unref(msg); + return false; +} + static struct Connman_Service *_manager_find_service_stringshared( struct Connman_Manager *cm, const char *path) { diff --git a/src/modules/connman/e_mod_main.c b/src/modules/connman/e_mod_main.c index 49427d757..6e96f5766 100644 --- a/src/modules/connman/e_mod_main.c +++ b/src/modules/connman/e_mod_main.c @@ -52,6 +52,54 @@ static Evas_Object * _econnman_service_new_icon(struct Connman_Service *cs, return icon; } +static void _econnman_disconnect_cb(void *data, const char *error) +{ + const char *path = data; + + if (error == NULL) + return; + + ERR("Could not disconnect %s: %s", path, error); +} + +static void _econnman_connect_cb(void *data, const char *error) +{ + const char *path = data; + + if (error == NULL) + return; + + ERR("Could not connect %s: %s", path, error); +} + +static void _econnman_popup_selected_cb(void *data) +{ + E_Connman_Instance *inst = data; + const char *path; + struct Connman_Service *cs; + + path = e_widget_ilist_selected_value_get(inst->ui.popup.list); + if (path == NULL) + return; + + cs = econnman_manager_find_service(inst->ctxt->cm, path); + if (cs == NULL) + return; + + switch (cs->state) + { + case CONNMAN_STATE_READY: + case CONNMAN_STATE_ONLINE: + INF("Disconnect %s", path); + econnman_service_disconnect(cs, _econnman_disconnect_cb, (void *) path); + break; + default: + INF("Connect %s", path); + econnman_service_connect(cs, _econnman_connect_cb, (void *) path); + break; + } +} + static void _econnman_popup_update(struct Connman_Manager *cm, E_Connman_Instance *inst) { @@ -67,7 +115,8 @@ static void _econnman_popup_update(struct Connman_Manager *cm, EINA_INLIST_FOREACH(cm->services, cs) { Evas_Object *icon = _econnman_service_new_icon(cs, evas); - e_widget_ilist_append(list, icon, cs->name, NULL, NULL, cs->obj.path); + e_widget_ilist_append(list, icon, cs->name, _econnman_popup_selected_cb, + inst, cs->obj.path); } e_widget_ilist_thaw(list);