--- /dev/null
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdint.h>
+#include <gdbus/gdbus.h>
+
+#include "dbus-common.h"
+#include "plugin.h"
+#include "adapter.h"
+#include "manager.h"
+#include "log.h"
+
+/* http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm */
+
+#define MAJOR_CLASS_MISCELLANEOUS 0x00
+#define MAJOR_CLASS_COMPUTER 0x01
+
+#define MINOR_CLASS_UNCATEGORIZED 0x00
+#define MINOR_CLASS_DESKTOP 0x01
+#define MINOR_CLASS_SERVER 0x02
+#define MINOR_CLASS_LAPTOP 0x03
+#define MINOR_CLASS_HANDHELD 0x04
+#define MINOR_CLASS_PALM_SIZED 0x05
+#define MINOR_CLASS_WEARABLE 0x06
+#define MINOR_CLASS_TABLET 0x07
+
+static uint8_t major_class = MAJOR_CLASS_MISCELLANEOUS;
+static uint8_t minor_class = MINOR_CLASS_UNCATEGORIZED;
+
+static char *pretty_hostname = NULL;
+
+static void update_name(struct btd_adapter *adapter, gpointer user_data)
+{
+ if (pretty_hostname == NULL)
+ return;
+
+ DBG("name: %s", pretty_hostname);
+
+ adapter_set_allow_name_changes(adapter, FALSE);
+ adapter_set_name(adapter, pretty_hostname);
+}
+
+static void update_class(struct btd_adapter *adapter, gpointer user_data)
+{
+ if (major_class == MAJOR_CLASS_MISCELLANEOUS)
+ return;
+
+ DBG("major: 0x%02x minor: 0x%02x", major_class, minor_class);
+
+ btd_adapter_set_class(adapter, major_class, minor_class);
+}
+
+static const struct {
+ const char *chassis;
+ uint8_t major_class;
+ uint8_t minor_class;
+} chassis_table[] = {
+ { "desktop", MAJOR_CLASS_COMPUTER, MINOR_CLASS_DESKTOP },
+ { "server", MAJOR_CLASS_COMPUTER, MINOR_CLASS_SERVER },
+ { "laptop", MAJOR_CLASS_COMPUTER, MINOR_CLASS_LAPTOP },
+ { "handset", MAJOR_CLASS_COMPUTER, MINOR_CLASS_HANDHELD },
+ { "tablet", MAJOR_CLASS_COMPUTER, MINOR_CLASS_TABLET },
+ { }
+};
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ if (g_str_equal(name, "PrettyHostname") == TRUE) {
+ if (iter == NULL) {
+ g_dbus_proxy_refresh_property(proxy, name);
+ return;
+ }
+
+ if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
+ const char *str;
+
+ dbus_message_iter_get_basic(iter, &str);
+
+ DBG("pretty hostname: %s", str);
+
+ g_free(pretty_hostname);
+ pretty_hostname = g_strdup(str);
+
+ manager_foreach_adapter(update_name, NULL);
+ }
+ } else if (g_str_equal(name, "Chassis") == TRUE) {
+ if (iter == NULL) {
+ g_dbus_proxy_refresh_property(proxy, name);
+ return;
+ }
+
+ if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
+ const char *str;
+ int i;
+
+ dbus_message_iter_get_basic(iter, &str);
+
+ DBG("chassis: %s", str);
+
+ for (i = 0; chassis_table[i].chassis; i++) {
+ if (strcmp(chassis_table[i].chassis, str))
+ continue;
+
+ major_class = chassis_table[i].major_class;
+ minor_class = chassis_table[i].minor_class;
+
+ manager_foreach_adapter(update_class, NULL);
+ break;
+ }
+ }
+ }
+}
+
+static int hostname_probe(struct btd_adapter *adapter)
+{
+ DBG("");
+
+ update_name(adapter, NULL);
+ update_class(adapter, NULL);
+
+ return 0;
+}
+
+static void hostname_remove(struct btd_adapter *adapter)
+{
+ DBG("");
+}
+
+static struct btd_adapter_driver hostname_driver = {
+ .name = "hostname",
+ .probe = hostname_probe,
+ .remove = hostname_remove,
+};
+
+static GDBusClient *hostname_client = NULL;
+static GDBusProxy *hostname_proxy = NULL;
+
+static int hostname_init(void)
+{
+ DBusConnection *conn = btd_get_dbus_connection();
+ int err;
+
+ hostname_client = g_dbus_client_new(conn, "org.freedesktop.hostname1",
+ "/org/freedesktop/hostname1");
+ if (!hostname_client)
+ return -EIO;
+
+ hostname_proxy = g_dbus_proxy_new(hostname_client,
+ "/org/freedesktop/hostname1",
+ "org.freedesktop.hostname1");
+ if (!hostname_proxy) {
+ g_dbus_client_unref(hostname_client);
+ hostname_client = NULL;
+ return -EIO;
+ }
+
+ g_dbus_proxy_set_property_watch(hostname_proxy, property_changed, NULL);
+
+ err = btd_register_adapter_driver(&hostname_driver);
+ if (err < 0) {
+ g_dbus_proxy_unref(hostname_proxy);
+ hostname_proxy = NULL;
+ g_dbus_client_unref(hostname_client);
+ hostname_client = NULL;
+ }
+
+ return err;
+}
+
+static void hostname_exit(void)
+{
+ btd_unregister_adapter_driver(&hostname_driver);
+
+ if (hostname_proxy) {
+ g_dbus_proxy_unref(hostname_proxy);
+ hostname_proxy = NULL;
+ }
+
+ if (hostname_client) {
+ g_dbus_client_unref(hostname_client);
+ hostname_client = NULL;
+ }
+
+ g_free(pretty_hostname);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(hostname, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+ hostname_init, hostname_exit)