/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2009-2011 Bastien Nocera <hadess@hadess.net>
* Copyright (C) 2010 Giovanni Campagna <scampa.giovanni@gmail.com>
*
*
* 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 <config.h>
#endif
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#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);
}