/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2009-2011 Bastien Nocera * Copyright (C) 2010 Giovanni Campagna * * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ /** * SECTION:bluetooth-utils * @short_description: Bluetooth utility functions * @stability: Stable * @include: bluetooth-utils.h * * Those helper functions are used throughout the Bluetooth * management utilities. **/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "bluetooth-utils.h" #include "gnome-bluetooth-enum-types.h" /** * bluetooth_type_to_string: * @type: a #BluetoothType * * Returns a human-readable string representation of @type usable for display to users. Do not free the return value. * The returned string is already translated with gettext(). * * Return value: a string. **/ const gchar * bluetooth_type_to_string (BluetoothType type) { switch (type) { case BLUETOOTH_TYPE_PHONE: return _("Phone"); case BLUETOOTH_TYPE_MODEM: return _("Modem"); case BLUETOOTH_TYPE_COMPUTER: return _("Computer"); case BLUETOOTH_TYPE_NETWORK: return _("Network"); case BLUETOOTH_TYPE_HEADSET: /* translators: a hands-free headset, a combination of a single speaker with a microphone */ return _("Headset"); case BLUETOOTH_TYPE_HEADPHONES: return _("Headphones"); case BLUETOOTH_TYPE_OTHER_AUDIO: return _("Audio device"); case BLUETOOTH_TYPE_KEYBOARD: return _("Keyboard"); case BLUETOOTH_TYPE_MOUSE: return _("Mouse"); case BLUETOOTH_TYPE_CAMERA: return _("Camera"); case BLUETOOTH_TYPE_PRINTER: return _("Printer"); case BLUETOOTH_TYPE_JOYPAD: return _("Joypad"); case BLUETOOTH_TYPE_TABLET: return _("Tablet"); case BLUETOOTH_TYPE_VIDEO: return _("Video device"); case BLUETOOTH_TYPE_REMOTE_CONTROL: return _("Remote control"); case BLUETOOTH_TYPE_SCANNER: return _("Scanner"); case BLUETOOTH_TYPE_DISPLAY: return _("Display"); case BLUETOOTH_TYPE_WEARABLE: return _("Wearable"); case BLUETOOTH_TYPE_TOY: return _("Toy"); } return _("Unknown"); } /** * bluetooth_type_to_filter_string: * @type: a #BluetoothType * * Returns a human-readable string representation of @type usable for display to users, * when type filters are displayed. Do not free the return value. * The returned string is already translated with gettext(). * * Return value: a string. **/ const gchar * bluetooth_type_to_filter_string (BluetoothType type) { switch (type) { case BLUETOOTH_TYPE_ANY: return _("All types"); default: return bluetooth_type_to_string (type); } g_assert_not_reached (); } /** * bluetooth_verify_address: * @bdaddr: a string representing a Bluetooth address * * Returns whether the string is a valid Bluetooth address. This does not contact the device in any way. * * Return value: %TRUE if the address is valid, %FALSE if not. **/ gboolean bluetooth_verify_address (const char *bdaddr) { guint i; g_return_val_if_fail (bdaddr != NULL, FALSE); if (strlen (bdaddr) != 17) return FALSE; for (i = 0; i < 17; i++) { if (((i + 1) % 3) == 0) { if (bdaddr[i] != ':') return FALSE; continue; } if (g_ascii_isxdigit (bdaddr[i]) == FALSE) return FALSE; } return TRUE; } /** * bluetooth_class_to_type: * @class: a Bluetooth device class * * Returns the type of device corresponding to the given @class value. * * Return value: a #BluetoothType. **/ BluetoothType bluetooth_class_to_type (guint32 class) { switch ((class & 0x1f00) >> 8) { case 0x01: return BLUETOOTH_TYPE_COMPUTER; case 0x02: switch ((class & 0xfc) >> 2) { case 0x01: case 0x02: case 0x03: case 0x05: return BLUETOOTH_TYPE_PHONE; case 0x04: return BLUETOOTH_TYPE_MODEM; } break; case 0x03: return BLUETOOTH_TYPE_NETWORK; case 0x04: switch ((class & 0xfc) >> 2) { case 0x01: case 0x02: return BLUETOOTH_TYPE_HEADSET; case 0x06: return BLUETOOTH_TYPE_HEADPHONES; case 0x0b: /* VCR */ case 0x0c: /* Video Camera */ case 0x0d: /* Camcorder */ return BLUETOOTH_TYPE_VIDEO; default: return BLUETOOTH_TYPE_OTHER_AUDIO; } break; case 0x05: switch ((class & 0xc0) >> 6) { case 0x00: switch ((class & 0x1e) >> 2) { case 0x01: case 0x02: return BLUETOOTH_TYPE_JOYPAD; case 0x03: return BLUETOOTH_TYPE_REMOTE_CONTROL; } break; case 0x01: return BLUETOOTH_TYPE_KEYBOARD; case 0x02: switch ((class & 0x1e) >> 2) { case 0x05: return BLUETOOTH_TYPE_TABLET; default: return BLUETOOTH_TYPE_MOUSE; } } break; case 0x06: if (class & 0x80) return BLUETOOTH_TYPE_PRINTER; if (class & 0x40) return BLUETOOTH_TYPE_SCANNER; if (class & 0x20) return BLUETOOTH_TYPE_CAMERA; if (class & 0x10) return BLUETOOTH_TYPE_DISPLAY; break; case 0x07: return BLUETOOTH_TYPE_WEARABLE; case 0x08: return BLUETOOTH_TYPE_TOY; } return 0; } /** * bluetooth_appearance_to_type: * @appearance: a Bluetooth device appearance * * Returns the type of device corresponding to the given @appearance value, * as usually found in the GAP service. * * Return value: a #BluetoothType. **/ BluetoothType bluetooth_appearance_to_type (guint16 appearance) { switch ((appearance & 0xffc0) >> 6) { case 0x01: return BLUETOOTH_TYPE_PHONE; case 0x02: return BLUETOOTH_TYPE_COMPUTER; case 0x05: return BLUETOOTH_TYPE_DISPLAY; case 0x0a: return BLUETOOTH_TYPE_OTHER_AUDIO; case 0x0b: return BLUETOOTH_TYPE_SCANNER; case 0x0f: /* HID Generic */ switch (appearance & 0x3f) { case 0x01: return BLUETOOTH_TYPE_KEYBOARD; case 0x02: return BLUETOOTH_TYPE_MOUSE; case 0x03: case 0x04: return BLUETOOTH_TYPE_JOYPAD; case 0x05: return BLUETOOTH_TYPE_TABLET; case 0x08: return BLUETOOTH_TYPE_SCANNER; } break; } return 0; } static const char * uuid16_custom_to_string (guint uuid16, const char *uuid) { switch (uuid16) { case 0x2: return "SyncMLClient"; case 0x5601: return "Nokia SyncML Server"; default: g_debug ("Unhandled custom UUID %s (0x%x)", uuid, uuid16); return NULL; } } /* Short names from Table 2 at: * https://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm */ static const char * uuid16_to_string (guint uuid16, const char *uuid) { switch (uuid16) { case BLUETOOTH_UUID_SPP: return "SerialPort"; case BLUETOOTH_UUID_DUN: return "DialupNetworking"; case BLUETOOTH_UUID_IRMC: return "IrMCSync"; case BLUETOOTH_UUID_OPP: return "OBEXObjectPush"; case BLUETOOTH_UUID_FTP: return "OBEXFileTransfer"; case BLUETOOTH_UUID_HSP: return "HSP"; case BLUETOOTH_UUID_A2DP_SOURCE: return "AudioSource"; case BLUETOOTH_UUID_A2DP_SINK: return "AudioSink"; case BLUETOOTH_UUID_AVRCP_TARGET: return "A/V_RemoteControlTarget"; case BLUETOOTH_UUID_A2DP: return "AdvancedAudioDistribution"; case BLUETOOTH_UUID_AVRCP_CONTROL: return "A/V_RemoteControl"; case BLUETOOTH_UUID_HSP_AG: return "Headset_-_AG"; case BLUETOOTH_UUID_PAN_PANU: return "PANU"; case BLUETOOTH_UUID_PAN_NAP: return "NAP"; case BLUETOOTH_UUID_PAN_GN: return "GN"; case BLUETOOTH_UUID_HFP_HF: return "Handsfree"; case BLUETOOTH_UUID_HFP_AG: return "HandsfreeAudioGateway"; case BLUETOOTH_UUID_HID: case 0x1812: return "HumanInterfaceDeviceService"; case BLUETOOTH_UUID_SAP: return "SIM_Access"; case BLUETOOTH_UUID_PBAP: return "Phonebook_Access_-_PSE"; case BLUETOOTH_UUID_GENERIC_AUDIO: return "GenericAudio"; case BLUETOOTH_UUID_SDP: /* ServiceDiscoveryServerServiceClassID */ case BLUETOOTH_UUID_PNP: /* PnPInformation */ /* Those are ignored */ return NULL; case BLUETOOTH_UUID_GENERIC_NET: return "GenericNetworking"; case BLUETOOTH_UUID_VDP_SOURCE: return "VideoSource"; case 0x8e771303: case 0x8e771301: return "SEMC HLA"; case 0x8e771401: return "SEMC Watch Phone"; default: g_debug ("Unhandled UUID %s (0x%x)", uuid, uuid16); return NULL; } } /** * bluetooth_uuid_to_string: * @uuid: a string representing a Bluetooth UUID * * Returns a string representing a human-readable (but not usable for display to users) version of the @uuid. Do not free the return value. * * Return value: a string. **/ const char * bluetooth_uuid_to_string (const char *uuid) { char **parts; guint uuid16; gboolean is_custom = FALSE; if (g_str_has_suffix (uuid, "-0000-1000-8000-0002ee000002") != FALSE) is_custom = TRUE; parts = g_strsplit (uuid, "-", -1); if (parts == NULL || parts[0] == NULL) { g_strfreev (parts); return NULL; } uuid16 = g_ascii_strtoull (parts[0], NULL, 16); g_strfreev (parts); if (uuid16 == 0) return NULL; if (is_custom == FALSE) return uuid16_to_string (uuid16, uuid); return uuid16_custom_to_string (uuid16, uuid); } /** * bluetooth_send_to_address: * @address: Remote device to use * @alias: Remote device's name * * Start a GUI application for transfering files over Bluetooth. **/ void bluetooth_send_to_address (const char *address, const char *alias) { GPtrArray *a; GError *err = NULL; a = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); g_ptr_array_add (a, g_strdup ("bluetooth-sendto")); if (address != NULL) g_ptr_array_add (a, g_strdup_printf ("--device=%s", address)); if (address != NULL && alias != NULL) g_ptr_array_add (a, g_strdup_printf ("--name=%s", alias)); g_ptr_array_add (a, NULL); if (g_spawn_async(NULL, (char **) a->pdata, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &err) == FALSE) { g_printerr("Couldn't execute command: %s\n", err->message); g_error_free (err); } g_ptr_array_free (a, TRUE); }