+ char *passphrase;
+ struct connman_device *device;
+ struct connman_network *network;
+};
+
+static void append_path(gpointer value, gpointer user_data)
+{
+ struct connman_service *service = value;
+ DBusMessageIter *iter = user_data;
+
+ if (service->path == NULL)
+ return;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+ &service->path);
+}
+
+void __connman_service_list(DBusMessageIter *iter)
+{
+ DBG("");
+
+ g_sequence_foreach(service_list, append_path, iter);
+}
+
+static const char *type2string(enum connman_service_type type)
+{
+ switch (type) {
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ break;
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ return "ethernet";
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ return "wifi";
+ case CONNMAN_SERVICE_TYPE_WIMAX:
+ return "wimax";
+ }
+
+ return NULL;
+}
+
+static const char *mode2string(enum connman_service_mode mode)
+{
+ switch (mode) {
+ case CONNMAN_SERVICE_MODE_UNKNOWN:
+ break;
+ case CONNMAN_SERVICE_MODE_MANAGED:
+ return "managed";
+ case CONNMAN_SERVICE_MODE_ADHOC:
+ return "adhoc";
+ }
+
+ return NULL;
+}
+
+static const char *security2string(enum connman_service_security security)
+{
+ switch (security) {
+ case CONNMAN_SERVICE_SECURITY_UNKNOWN:
+ break;
+ case CONNMAN_SERVICE_SECURITY_NONE:
+ return "none";
+ case CONNMAN_SERVICE_SECURITY_WEP:
+ return "wep";
+ case CONNMAN_SERVICE_SECURITY_WPA:
+ return "wpa";
+ case CONNMAN_SERVICE_SECURITY_WPA2:
+ return "wpa2";
+ }
+
+ return NULL;
+}
+
+static const char *state2string(enum connman_service_state state)
+{
+ switch (state) {
+ case CONNMAN_SERVICE_STATE_UNKNOWN:
+ break;
+ case CONNMAN_SERVICE_STATE_IDLE:
+ return "idle";
+ case CONNMAN_SERVICE_STATE_CARRIER:
+ return "carrier";
+ case CONNMAN_SERVICE_STATE_ASSOCIATION:
+ return "association";
+ case CONNMAN_SERVICE_STATE_CONFIGURATION:
+ return "configuration";
+ case CONNMAN_SERVICE_STATE_READY:
+ return "ready";
+ case CONNMAN_SERVICE_STATE_DISCONNECT:
+ return "disconnect";
+ case CONNMAN_SERVICE_STATE_FAILURE:
+ return "failure";
+ }
+
+ return NULL;
+}
+
+static void state_changed(struct connman_service *service)
+{
+ DBusMessage *signal;
+ DBusMessageIter entry, value;
+ const char *str, *key = "State";
+
+ if (service->path == NULL)
+ return;
+
+ str = state2string(service->state);
+ if (str == NULL)
+ return;
+
+ signal = dbus_message_new_signal(service->path,
+ CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_STRING_AS_STRING, &value);
+ dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
+ dbus_message_iter_close_container(&entry, &value);
+
+ g_dbus_send_message(connection, signal);
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_service *service = data;
+ DBusMessage *reply;
+ DBusMessageIter array, dict;
+ const char *str;
+
+ DBG("conn %p", conn);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &array);
+
+ dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ str = type2string(service->type);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "Type",
+ DBUS_TYPE_STRING, &str);
+
+ str = mode2string(service->mode);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "Mode",
+ DBUS_TYPE_STRING, &str);
+
+ str = security2string(service->security);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "Security",
+ DBUS_TYPE_STRING, &str);
+
+ str = state2string(service->state);
+ if (str != NULL)
+ connman_dbus_dict_append_variant(&dict, "State",
+ DBUS_TYPE_STRING, &str);
+
+ if (service->strength > 0)
+ connman_dbus_dict_append_variant(&dict, "Strength",
+ DBUS_TYPE_BYTE, &service->strength);
+
+ connman_dbus_dict_append_variant(&dict, "Favorite",
+ DBUS_TYPE_BOOLEAN, &service->favorite);
+
+ if (service->name != NULL)
+ connman_dbus_dict_append_variant(&dict, "Name",
+ DBUS_TYPE_STRING, &service->name);
+
+ if (service->passphrase != NULL &&
+ __connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_SECRET) == 0)
+ connman_dbus_dict_append_variant(&dict, "Passphrase",
+ DBUS_TYPE_STRING, &service->passphrase);
+
+ dbus_message_iter_close_container(&array, &dict);
+
+ return reply;
+}
+
+static DBusMessage *set_property(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_service *service = data;
+ DBusMessageIter iter, value;
+ const char *name;
+ int type;
+
+ DBG("conn %p", conn);
+
+ if (dbus_message_iter_init(msg, &iter) == FALSE)
+ return __connman_error_invalid_arguments(msg);
+
+ dbus_message_iter_get_basic(&iter, &name);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
+ return __connman_error_permission_denied(msg);
+
+ type = dbus_message_iter_get_arg_type(&value);
+
+ if (g_str_equal(name, "Passphrase") == TRUE) {
+ const char *passphrase;
+
+ if (type != DBUS_TYPE_STRING)
+ return __connman_error_invalid_arguments(msg);
+
+ if (__connman_security_check_privilege(msg,
+ CONNMAN_SECURITY_PRIVILEGE_SECRET) < 0)
+ return __connman_error_permission_denied(msg);
+
+ dbus_message_iter_get_basic(&value, &passphrase);
+
+ g_free(service->passphrase);
+ service->passphrase = g_strdup(passphrase);
+
+ if (service->network != NULL)
+ connman_network_set_string(service->network,
+ "WiFi.Passphrase", service->passphrase);
+
+ __connman_storage_save_service(service);
+ }
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *connect_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_service *service = data;
+
+ if (service->network != NULL) {
+ int err;
+
+ err = connman_network_connect(service->network);
+ if (err < 0 && err != -EINPROGRESS)
+ return __connman_error_failed(msg);
+
+ service->state = CONNMAN_SERVICE_STATE_ASSOCIATION;
+
+ state_changed(service);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ }
+
+ if (service->device != NULL) {
+ if (service->favorite == FALSE)
+ return __connman_error_no_carrier(msg);
+
+ if (__connman_device_connect(service->device) < 0)
+ return __connman_error_failed(msg);
+
+ service->state = CONNMAN_SERVICE_STATE_READY;
+
+ state_changed(service);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ }
+
+ return __connman_error_not_supported(msg);
+}
+
+static DBusMessage *disconnect_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_service *service = data;
+
+ if (service->network != NULL) {
+ int err;
+
+ err = __connman_network_disconnect(service->network);
+ if (err < 0 && err != -EINPROGRESS)
+ return __connman_error_failed(msg);
+
+ service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
+
+ state_changed(service);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ }
+
+ if (service->device != NULL) {
+ if (service->favorite == FALSE)
+ return __connman_error_no_carrier(msg);
+
+ if (__connman_device_connect(service->device) < 0)
+ return __connman_error_failed(msg);
+
+ service->state = CONNMAN_SERVICE_STATE_IDLE;
+
+ state_changed(service);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ }
+
+ return __connman_error_not_supported(msg);
+}
+
+static DBusMessage *remove_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_service *service = data;
+
+ if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
+ return __connman_error_not_supported(msg);
+
+ if (service->network != NULL) {
+ int err;
+
+ err = __connman_network_disconnect(service->network);
+ if (err < 0 && err != -EINPROGRESS)
+ return __connman_error_failed(msg);
+
+ service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
+
+ state_changed(service);
+ }
+
+ connman_service_set_favorite(service, FALSE);
+
+ __connman_storage_save_service(service);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *move_before(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_service *service = data;
+
+ if (service->favorite == FALSE)
+ return __connman_error_not_supported(msg);
+
+ return __connman_error_not_implemented(msg);
+}
+
+static DBusMessage *move_after(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct connman_service *service = data;
+
+ if (service->favorite == FALSE)
+ return __connman_error_not_supported(msg);
+
+ return __connman_error_not_implemented(msg);
+}
+
+static GDBusMethodTable service_methods[] = {
+ { "GetProperties", "", "a{sv}", get_properties },
+ { "SetProperty", "sv", "", set_property },
+ { "Connect", "", "", connect_service },
+ { "Disconnect", "", "", disconnect_service },
+ { "Remove", "", "", remove_service },
+ { "MoveBefore", "o", "", move_before },
+ { "MoveAfter", "o", "", move_after },
+ { },
+};
+
+static GDBusSignalTable service_signals[] = {
+ { "PropertyChanged", "sv" },
+ { },