/* nm-client.c - * * Copyright 2007 OpenMoko, Inc. * Authored by Chia-I Wu * * Based on libnm-glib by: Dan Williams * Copyright 2005 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "nm-client.h" #include "nm-device.h" G_DEFINE_TYPE (NMClient, nm_client, G_TYPE_OBJECT) #define NM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_CLIENT, NMClientPrivate)) typedef struct { DBusGConnection *connection; DBusGProxy *client_proxy; DBusGProxy *bus_proxy; gboolean manager_running; NMState state; gboolean have_device_list; GHashTable *devices; } NMClientPrivate; enum { MANAGER_RUNNING, DEVICE_ADDED, DEVICE_REMOVED, STATE_CHANGE, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; static void finalize (GObject *object) { NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object); g_object_unref (priv->client_proxy); g_object_unref (priv->bus_proxy); g_hash_table_destroy (priv->devices); dbus_g_connection_unref(priv->connection); G_OBJECT_CLASS (nm_client_parent_class)->finalize (object); } static void manager_running (NMClient *client, gboolean running) { if (!running) { NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client); priv->state = NM_STATE_UNKNOWN; g_hash_table_remove_all (priv->devices); priv->have_device_list = FALSE; } } static void nm_client_class_init (NMClientClass *client_class) { GObjectClass *object_class = G_OBJECT_CLASS (client_class); g_type_class_add_private (client_class, sizeof (NMClientPrivate)); object_class->finalize = finalize; client_class->manager_running = manager_running; /* signals */ signals[MANAGER_RUNNING] = g_signal_new ("manager-running", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMClientClass, manager_running), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); signals[DEVICE_ADDED] = g_signal_new ("device-added", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMClientClass, device_added), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); signals[DEVICE_REMOVED] = g_signal_new ("device-removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMClientClass, device_removed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); signals[STATE_CHANGE] = g_signal_new ("state-change", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMClientClass, state_change), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); } static void nm_client_init (NMClient *client) { NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client); priv->state = NM_STATE_UNKNOWN; priv->devices = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref); } static void client_state_change_proxy(DBusGProxy *proxy, guint state, gpointer user_data) { NMClient *client = NM_CLIENT(user_data); NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE(client); if (priv->state != state) { priv->state = state; g_signal_emit(client, signals[STATE_CHANGE], 0, state); } } static void proxy_name_owner_changed(DBusGProxy *proxy, const char *name, const char *old_owner, const char *new_owner, gpointer user_data) { if (name && !strcmp (name, NM_DBUS_SERVICE)) { NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (user_data); gboolean old_good = (old_owner && strlen (old_owner)); gboolean new_good = (new_owner && strlen (new_owner)); gboolean new_running = FALSE; if (!old_good && new_good) new_running = TRUE; else if (old_good && !new_good) new_running = FALSE; if (new_running != priv->manager_running) { priv->manager_running = new_running; g_signal_emit (NM_CLIENT (user_data), signals[MANAGER_RUNNING], 0, priv->manager_running); } } } static NMDevice * get_device (NMClient *client, const gchar *path, gboolean create_if_not_found) { NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client); NMDevice *device; device = g_hash_table_lookup (priv->devices, path); if (!device && create_if_not_found) { device = nm_device_new(priv->connection, path); if (device) { device->client = client; g_hash_table_insert (priv->devices, g_strdup (path), device); } } return device; } static void client_device_added_proxy (DBusGProxy *proxy, const gchar *path, gpointer user_data) { NMClient *client = NM_CLIENT (user_data); NMDevice *device; device = get_device (client, path, TRUE); if (device) g_signal_emit (client, signals[DEVICE_ADDED], 0, device); } static void client_device_removed_proxy (DBusGProxy *proxy, const gchar *path, gpointer user_data) { NMClient *client = NM_CLIENT (user_data); NMDevice *device; device = get_device (client, path, FALSE); if (device) { g_signal_emit (client, signals[DEVICE_REMOVED], 0, device); g_hash_table_remove (NM_CLIENT_GET_PRIVATE (client)->devices, path); } } NMClient *nm_client_new(void) { DBusGConnection *connection; NMClient *client; NMClientPrivate *priv; GError *err = NULL; connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &err); if (!connection) { g_warning("Couldn't connect to system bus: %s", err->message); g_error_free(err); return NULL; } client = g_object_new(NM_TYPE_CLIENT, NULL); priv = NM_CLIENT_GET_PRIVATE(client); priv->connection = connection; priv->client_proxy = dbus_g_proxy_new_for_name(connection, NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE); dbus_g_proxy_add_signal(priv->client_proxy, "StateChange", G_TYPE_UINT, G_TYPE_INVALID); dbus_g_proxy_connect_signal(priv->client_proxy, "StateChange", G_CALLBACK(client_state_change_proxy), client, NULL); dbus_g_proxy_add_signal(priv->client_proxy, "DeviceAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); dbus_g_proxy_connect_signal(priv->client_proxy, "DeviceAdded", G_CALLBACK(client_device_added_proxy), client, NULL); dbus_g_proxy_add_signal(priv->client_proxy, "DeviceRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); dbus_g_proxy_connect_signal(priv->client_proxy, "DeviceRemoved", G_CALLBACK(client_device_removed_proxy), client, NULL); priv->bus_proxy = dbus_g_proxy_new_for_name (connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); dbus_g_proxy_add_signal(priv->bus_proxy, "NameOwnerChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); dbus_g_proxy_connect_signal(priv->bus_proxy, "NameOwnerChanged", G_CALLBACK(proxy_name_owner_changed), client, NULL); if (!dbus_g_proxy_call(priv->bus_proxy, "NameHasOwner", &err, G_TYPE_STRING, NM_DBUS_SERVICE, G_TYPE_INVALID, G_TYPE_BOOLEAN, &priv->manager_running, G_TYPE_INVALID)) { g_warning ("Error on NameHasOwner DBUS call: %s", err->message); g_error_free (err); } return client; } gboolean nm_client_manager_is_running (NMClient *client) { g_return_val_if_fail (NM_IS_CLIENT (client), FALSE); return NM_CLIENT_GET_PRIVATE (client)->manager_running; } static void devices_to_slist (gpointer key, gpointer value, gpointer user_data) { GSList **list = (GSList **) user_data; *list = g_slist_prepend (*list, value); } GSList * nm_client_get_devices (NMClient *client) { NMClientPrivate *priv; GSList *list = NULL; GPtrArray *paths = NULL; GError *err = NULL; gint i; priv = NM_CLIENT_GET_PRIVATE (client); if (priv->have_device_list) { g_hash_table_foreach (priv->devices, devices_to_slist, &list); return list; } if (!dbus_g_proxy_call (priv->client_proxy, "getDevices", &err, G_TYPE_INVALID, dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &paths, G_TYPE_INVALID)) { g_warning ("failed to get devices: %s", err->message); g_error_free (err); return NULL; } for (i = 0; i < paths->len; i++) { NMDevice *device; gchar *path = g_ptr_array_index (paths, i); device = get_device (client, path, TRUE); if (device) list = g_slist_prepend (list, device); g_free (path); } g_ptr_array_free (paths, TRUE); priv->have_device_list = TRUE; return list; } NMDevice * nm_client_get_device_by_path (NMClient *client, const char *object_path) { NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client); NMDevice *dev; dev = g_hash_table_lookup(priv->devices, object_path); return dev; } void nm_client_activate_device(NMClient *client, NMDevice *dev, DiversityAp *ap) { NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client); const gchar *dev_path, *essid; GError *error = NULL; dev_path = dev->op; essid = (ap) ? diversity_ap_get_ssid(ap) : NULL; g_print("activate %s (%s)\n", dev_path, essid); if (!dbus_g_proxy_call(priv->client_proxy, "setActiveDevice", &error, DBUS_TYPE_G_OBJECT_PATH, dev_path, G_TYPE_STRING, essid, G_TYPE_INVALID, G_TYPE_INVALID)) { g_print("Failed to activate %s: %s\n", dev_path, error->message); g_error_free(error); } } gboolean nm_client_wireless_get_enabled (NMClient *client) { NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client); gboolean enabled; GError *error = NULL; dbus_g_proxy_call(priv->client_proxy, "getWirelessEnabled", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &enabled, G_TYPE_INVALID); if (error) { g_warning("failed to get wireless status: %s", error->message); g_error_free(error); } return enabled; } void nm_client_wireless_set_enabled (NMClient *client, gboolean enabled) { NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client); GError *error = NULL; dbus_g_proxy_call(priv->client_proxy, "setWirelessEnabled", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &enabled, G_TYPE_INVALID); if (error) { g_warning("failed to %s wireless: %s", (enabled) ? "enable" : "disable", error->message); g_error_free(error); } } gboolean nm_client_wireless_hardware_get_enabled (NMClient *client) { return TRUE; } NMState nm_client_get_state (NMClient *client) { NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client); GError *error = NULL; if (priv->state == NM_STATE_UNKNOWN) { dbus_g_proxy_call(priv->client_proxy, "state", &error, G_TYPE_INVALID, G_TYPE_UINT, &priv->state, G_TYPE_INVALID); if (error) { g_warning("failed to get state: %s", error->message); g_error_free(error); } } return priv->state; } void nm_client_sleep (NMClient *client, gboolean sleep) { NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client); gchar *method; GError *error = NULL; if (sleep) { method = "sleep"; } else { method = "wake"; sleep = TRUE; } dbus_g_proxy_call(priv->client_proxy, method, &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &sleep, G_TYPE_INVALID); if (error) { g_warning("failed to sleep/wake: %s", error->message); g_error_free(error); } }