[Pkg-bluetooth-commits] r480 - in /bluez-utils/branches/upstream/current: ./ audio/ common/ cups/ daemon/ eglib/ hcid/ input/ network/ rfcomm/ sdpd/ serial/ test/ tools/

filippo at users.alioth.debian.org filippo at users.alioth.debian.org
Wed Jul 4 13:37:58 UTC 2007


Author: filippo
Date: Wed Jul  4 13:37:57 2007
New Revision: 480

URL: http://svn.debian.org/wsvn/pkg-bluetooth/?sc=1&rev=480
Log:
[svn-upgrade] Integrating new upstream version, bluez-utils (3.12)

Added:
    bluez-utils/branches/upstream/current/audio/audio.conf
    bluez-utils/branches/upstream/current/audio/device.c
    bluez-utils/branches/upstream/current/audio/device.h
    bluez-utils/branches/upstream/current/audio/error.c
    bluez-utils/branches/upstream/current/audio/error.h
    bluez-utils/branches/upstream/current/audio/gateway.c
    bluez-utils/branches/upstream/current/audio/gateway.h
    bluez-utils/branches/upstream/current/audio/test-audio   (with props)
    bluez-utils/branches/upstream/current/audio/unix.c
    bluez-utils/branches/upstream/current/audio/unix.h
    bluez-utils/branches/upstream/current/daemon/test-database   (with props)
    bluez-utils/branches/upstream/current/daemon/test-manager   (with props)
    bluez-utils/branches/upstream/current/hcid/server.c
    bluez-utils/branches/upstream/current/hcid/server.h
    bluez-utils/branches/upstream/current/serial/error.c
    bluez-utils/branches/upstream/current/serial/error.h
    bluez-utils/branches/upstream/current/serial/port.c
    bluez-utils/branches/upstream/current/serial/port.h
    bluez-utils/branches/upstream/current/serial/storage.c
    bluez-utils/branches/upstream/current/serial/storage.h
Modified:
    bluez-utils/branches/upstream/current/ChangeLog
    bluez-utils/branches/upstream/current/audio/Makefile.am
    bluez-utils/branches/upstream/current/audio/Makefile.in
    bluez-utils/branches/upstream/current/audio/audio-api.txt
    bluez-utils/branches/upstream/current/audio/ctl_bluetooth.c
    bluez-utils/branches/upstream/current/audio/headset.c
    bluez-utils/branches/upstream/current/audio/headset.h
    bluez-utils/branches/upstream/current/audio/ipc.h
    bluez-utils/branches/upstream/current/audio/main.c
    bluez-utils/branches/upstream/current/audio/manager.c
    bluez-utils/branches/upstream/current/audio/manager.h
    bluez-utils/branches/upstream/current/audio/pcm_bluetooth.c
    bluez-utils/branches/upstream/current/common/dbus-helper.c
    bluez-utils/branches/upstream/current/common/dbus.c
    bluez-utils/branches/upstream/current/common/dbus.h
    bluez-utils/branches/upstream/current/common/ppoll.h
    bluez-utils/branches/upstream/current/common/sdp-expat.c
    bluez-utils/branches/upstream/current/common/sdp-glib.c
    bluez-utils/branches/upstream/current/common/sdp-xml.c
    bluez-utils/branches/upstream/current/common/sdp-xml.h
    bluez-utils/branches/upstream/current/configure
    bluez-utils/branches/upstream/current/configure.in
    bluez-utils/branches/upstream/current/cups/Makefile.am
    bluez-utils/branches/upstream/current/cups/Makefile.in
    bluez-utils/branches/upstream/current/cups/main.c
    bluez-utils/branches/upstream/current/daemon/Makefile.am
    bluez-utils/branches/upstream/current/daemon/Makefile.in
    bluez-utils/branches/upstream/current/daemon/echo.c
    bluez-utils/branches/upstream/current/eglib/gmain.c
    bluez-utils/branches/upstream/current/eglib/gmain.h
    bluez-utils/branches/upstream/current/hcid/Makefile.am
    bluez-utils/branches/upstream/current/hcid/Makefile.in
    bluez-utils/branches/upstream/current/hcid/dbus-adapter.c
    bluez-utils/branches/upstream/current/hcid/dbus-adapter.h
    bluez-utils/branches/upstream/current/hcid/dbus-api.txt
    bluez-utils/branches/upstream/current/hcid/dbus-common.c
    bluez-utils/branches/upstream/current/hcid/dbus-common.h
    bluez-utils/branches/upstream/current/hcid/dbus-database.c
    bluez-utils/branches/upstream/current/hcid/dbus-database.h
    bluez-utils/branches/upstream/current/hcid/dbus-hci.c
    bluez-utils/branches/upstream/current/hcid/dbus-hci.h
    bluez-utils/branches/upstream/current/hcid/dbus-sdp.c
    bluez-utils/branches/upstream/current/hcid/dbus-sdp.h
    bluez-utils/branches/upstream/current/hcid/dbus-service.c
    bluez-utils/branches/upstream/current/hcid/dbus-service.h
    bluez-utils/branches/upstream/current/hcid/device.c
    bluez-utils/branches/upstream/current/hcid/hcid.8
    bluez-utils/branches/upstream/current/hcid/hcid.h
    bluez-utils/branches/upstream/current/hcid/main.c
    bluez-utils/branches/upstream/current/hcid/security.c
    bluez-utils/branches/upstream/current/input/device.c
    bluez-utils/branches/upstream/current/input/device.h
    bluez-utils/branches/upstream/current/input/manager.c
    bluez-utils/branches/upstream/current/input/server.c
    bluez-utils/branches/upstream/current/input/storage.c
    bluez-utils/branches/upstream/current/input/storage.h
    bluez-utils/branches/upstream/current/network/connection.c
    bluez-utils/branches/upstream/current/network/connection.h
    bluez-utils/branches/upstream/current/network/manager.c
    bluez-utils/branches/upstream/current/network/manager.h
    bluez-utils/branches/upstream/current/network/network-api.txt
    bluez-utils/branches/upstream/current/network/server.c
    bluez-utils/branches/upstream/current/network/server.h
    bluez-utils/branches/upstream/current/network/test-network
    bluez-utils/branches/upstream/current/rfcomm/main.c
    bluez-utils/branches/upstream/current/rfcomm/rfcomm.1
    bluez-utils/branches/upstream/current/sdpd/main.c
    bluez-utils/branches/upstream/current/sdpd/sdpd.8
    bluez-utils/branches/upstream/current/sdpd/sdpd.h
    bluez-utils/branches/upstream/current/sdpd/server.c
    bluez-utils/branches/upstream/current/sdpd/service.c
    bluez-utils/branches/upstream/current/serial/Makefile.am
    bluez-utils/branches/upstream/current/serial/Makefile.in
    bluez-utils/branches/upstream/current/serial/manager.c
    bluez-utils/branches/upstream/current/serial/manager.h
    bluez-utils/branches/upstream/current/serial/serial-api.txt
    bluez-utils/branches/upstream/current/test/apitest
    bluez-utils/branches/upstream/current/test/l2test.c
    bluez-utils/branches/upstream/current/tools/csr.c
    bluez-utils/branches/upstream/current/tools/hciattach.c
    bluez-utils/branches/upstream/current/tools/hcitool.c
    bluez-utils/branches/upstream/current/tools/sdptool.c

Modified: bluez-utils/branches/upstream/current/ChangeLog
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/ChangeLog?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/ChangeLog (original)
+++ bluez-utils/branches/upstream/current/ChangeLog Wed Jul  4 13:37:57 2007
@@ -1,3 +1,32 @@
+ver 3.12:
+	Add support for limited discovery mode.
+	Add support for setting of event mask.
+	Add GetRemoteServiceIdentifiers method.
+	Add skeleton for local D-Bus server.
+	Add headset gain control methods.
+	Fix various headset implementation issues.
+	Fix various serial port service issues.
+	Fix various input service issues.
+	Let CUPS plugin discover printers in range.
+	Improve the BCM2035 UART init routine.
+	Ignore connection events for non-ACL links.
+
+	Note:
+	This version needs at least bluez-libs-3.12
+
+ver 3.11:
+	Update API documentation.
+	Minimize SDP root records and browse groups.
+	Use same decoder for text and URL strings.
+	Fix SDP pattern extraction for XML.
+	Fix network connection persistent state.
+	Add network connection helper methods.
+	Add initial version of serial port support.
+	Add class of device tracking.
+
+	Note:
+	This version needs at least bluez-libs-3.11
+
 ver 3.10.1:
 	Add option to disable installation of manual pages.
 	Fix input service encryption setup.

Modified: bluez-utils/branches/upstream/current/audio/Makefile.am
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/Makefile.am?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/Makefile.am (original)
+++ bluez-utils/branches/upstream/current/audio/Makefile.am Wed Jul  4 13:37:57 2007
@@ -10,7 +10,9 @@
 
 service_PROGRAMS = bluetoothd-service-audio
 
-bluetoothd_service_audio_SOURCES = main.c manager.h manager.c headset.h headset.c ipc.h
+bluetoothd_service_audio_SOURCES = main.c \
+	manager.h manager.c headset.h headset.c ipc.h unix.h unix.c \
+	error.h error.c device.h device.c gateway.h gateway.c
 
 bluetoothd_service_audio_LDADD = $(top_builddir)/common/libhelper.a \
 				@GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
@@ -34,6 +36,6 @@
 
 INCLUDES = -I$(top_srcdir)/common
 
-EXTRA_DIST = audio.service audio-api.txt asound.conf
+EXTRA_DIST = audio.service audio.conf audio-api.txt test-audio asound.conf
 
 MAINTAINERCLEANFILES = Makefile.in

Modified: bluez-utils/branches/upstream/current/audio/Makefile.in
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/Makefile.in?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/Makefile.in (original)
+++ bluez-utils/branches/upstream/current/audio/Makefile.in Wed Jul  4 13:37:57 2007
@@ -81,10 +81,13 @@
 servicePROGRAMS_INSTALL = $(INSTALL_PROGRAM)
 PROGRAMS = $(service_PROGRAMS)
 am__bluetoothd_service_audio_SOURCES_DIST = main.c manager.h manager.c \
-	headset.h headset.c ipc.h
+	headset.h headset.c ipc.h unix.h unix.c error.h error.c \
+	device.h device.c gateway.h gateway.c
 @AUDIOSERVICE_TRUE at am_bluetoothd_service_audio_OBJECTS =  \
 @AUDIOSERVICE_TRUE@	main.$(OBJEXT) manager.$(OBJEXT) \
- at AUDIOSERVICE_TRUE@	headset.$(OBJEXT)
+ at AUDIOSERVICE_TRUE@	headset.$(OBJEXT) unix.$(OBJEXT) \
+ at AUDIOSERVICE_TRUE@	error.$(OBJEXT) device.$(OBJEXT) \
+ at AUDIOSERVICE_TRUE@	gateway.$(OBJEXT)
 bluetoothd_service_audio_OBJECTS =  \
 	$(am_bluetoothd_service_audio_OBJECTS)
 @AUDIOSERVICE_TRUE at bluetoothd_service_audio_DEPENDENCIES =  \
@@ -284,7 +287,10 @@
 @AUDIOSERVICE_TRUE@@CONFIGFILES_TRUE at confdir = $(sysconfdir)/bluetooth
 @AUDIOSERVICE_TRUE@@CONFIGFILES_TRUE at conf_DATA = audio.service
 @AUDIOSERVICE_TRUE at servicedir = $(libdir)/bluetooth
- at AUDIOSERVICE_TRUE@bluetoothd_service_audio_SOURCES = main.c manager.h manager.c headset.h headset.c ipc.h
+ at AUDIOSERVICE_TRUE@bluetoothd_service_audio_SOURCES = main.c \
+ at AUDIOSERVICE_TRUE@	manager.h manager.c headset.h headset.c ipc.h unix.h unix.c \
+ at AUDIOSERVICE_TRUE@	error.h error.c device.h device.c gateway.h gateway.c
+
 @AUDIOSERVICE_TRUE at bluetoothd_service_audio_LDADD = $(top_builddir)/common/libhelper.a \
 @AUDIOSERVICE_TRUE@				@GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
 
@@ -298,7 +304,7 @@
 @ALSA_TRUE@@AUDIOSERVICE_TRUE at libasound_module_ctl_bluetooth_la_LIBADD = @ALSA_LIBS@ 
 AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @ALSA_CFLAGS@ @SBC_CFLAGS@
 INCLUDES = -I$(top_srcdir)/common
-EXTRA_DIST = audio.service audio-api.txt asound.conf
+EXTRA_DIST = audio.service audio.conf audio-api.txt test-audio asound.conf
 MAINTAINERCLEANFILES = Makefile.in
 all: all-am
 
@@ -403,10 +409,14 @@
 	-rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ctl_bluetooth.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/device.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/error.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gateway.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/headset.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/main.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/manager.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/pcm_bluetooth.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/unix.Po at am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \

Modified: bluez-utils/branches/upstream/current/audio/audio-api.txt
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/audio-api.txt?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/audio-api.txt (original)
+++ bluez-utils/branches/upstream/current/audio/audio-api.txt Wed Jul  4 13:37:57 2007
@@ -2,25 +2,60 @@
 ***************************************
 
 Copyright (C) 2004-2007  Marcel Holtmann <marcel at holtmann.org>
-Copyright (C) 2005-2006  Johan Hedberg <johan.hedberg at nokia.com>
+Copyright (C) 2005-2007  Johan Hedberg <johan.hedberg at nokia.com>
 Copyright (C) 2005-2006  Brad Midgley <bmidgley at xmission.com>
 
 
-Audio Manager hierarchy
-=======================
-
-Interface	org.bluez.audio.Manager
+org.bluez.audio.Manager interface
+=================================
+
 Object path	/org/bluez/audio
 
-Methods		array{string} ListHeadsets()
-
-			Returns list of headset objects that
-			are configured.
+Methods
+		string CreateDevice(string address, array{string} interfaces) [experimental]
+
+			Creates a new audio device object. If not yet done,
+			this method will perform a SDP query on the remote
+			device and return first when the query is complete,
+			so be sure to call this method asynchronously.
+
+			The return parameter is the object path of the newly
+			created object. The method will fail if the remote
+			device does not support all of the interfaces listed
+			in the interfaces parameter.
+
+		void RemoveDevice(string path) [experimental]
+
+			Removes a device from the device tree. If there are
+			any connections open to the device they will be closed.			
+
+		array{string} ListDevices(array{string} interfaces) [experimental]
+
+			Retuns an array of strings indicating the object paths
+			of available devices which implement as a minimum the
+			interfaces given through the parameter.
+
+		string DefaultDevice()
+
+			Returns the object path for the default device.
+
+		void ChangeDefaultDevice(string path)
+
+			Changes the default device.
+
+		array{string} ListHeadsets()
+
+			Returns list of headset objects that are configured.
+
+		string FindDeviceByAddress(string address) [experimental]
+
+			Searches the list of available devices and returns the
+			object path of the first device which matchess address.
+			If no device is found returns a DoesNotExist error.
 
 		string DefaultHeadset()
 
-			Returns the object path for the default
-			headset device.
+			Returns the object path for the default headset device.
 
 		void ChangeDefaultHeadset(string path)
 
@@ -28,15 +63,24 @@
 
 		string CreateHeadset(string address)
 
-			Create a new headset device and returns
-			its object path on return.
+			Create a new headset device and returns its object path
+			on return.
 
 		void RemoveHeadset(string path)
 
 			Removes a headset object and all information
 			related to it.
 
-Signals		void HeadsetCreated(string path)
+Signals
+		void DeviceCreated(string path) [experimental]
+
+			Sent when a new device object has been created.
+
+		void DeviceRemoved(string path) [experimental]
+
+			Sent when a device object has been removed.
+
+		void HeadsetCreated(string path)
 
 			Sent when a new headset object has been created.
 
@@ -49,11 +93,25 @@
 			Sent when the default headset has changed.
 
 
-Audio Headset hierarchy
-=======================
-
-Interface	org.bluez.audio.Headset
-Object path	/org/bluez/audio/headset*
+org.bluez.audio.Device interface
+================================
+
+Object path(s)	/org/bluez/audio/device*
+
+Methods		string GetAddress() [experimental]
+
+			Returns the Bluetooth address of the remote device.
+
+		array{string} GetConnectedInterfaces()	[experimental]
+
+			Returns a string list of interfaces that are in a
+			connected state.
+
+
+org.bluez.audio.Headset interface
+=================================
+
+Object path(s)	/org/bluez/audio/device*
 
 Methods		void Connect()
 
@@ -84,6 +142,24 @@
 			Returns true if an audio connection to the headset
 			is active.
 
+		uint16 GetSpeakerGain()
+
+			Returns the current speaker gain if available,
+			otherwise returns the error NotAvailable.
+
+		uint16 GetMicrophoneGain()
+
+			Returns the current microphone gain if available,
+			otherwise returns the error NotAvailable.
+
+		void SetSpeakerGain(uint16 gain)
+
+			Changes the current speaker gain if possible.
+
+		void SetMicrophoneGain(uint16 gain)
+
+			Changes the current speaker gain if possible.
+
 Signals		void AnswerRequested()
 
 			Sent when the answer button is pressed on the headset
@@ -111,3 +187,15 @@
 		void MicrophoneGainChanged(uint16 gain)
 
 			The microphone gain changed.
+
+
+org.bluez.audio.Source interface
+================================
+
+Object path(s)	/org/bluez/audio/device*
+
+
+org.bluez.audio.Sink interface
+==============================
+
+Object path(s)	/org/bluez/audio/device*

Added: bluez-utils/branches/upstream/current/audio/audio.conf
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/audio.conf?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/audio.conf (added)
+++ bluez-utils/branches/upstream/current/audio/audio.conf Wed Jul  4 13:37:57 2007
@@ -1,0 +1,27 @@
+# Configuration file for the audio service
+
+# This section contains options which are not specific to any
+# particular interface
+[General]
+
+# If we want to disable support for specific services
+# Defaults to supporting all implemented services
+#Disable=Control,Source
+
+# SCO routing. Either PCM or HCI (in which case audio is routed to/from ALSA)
+# Defaults to HCI
+SCORouting=PCM
+
+# Headset interface specific options (i.e. options which affect how the audio
+# service interacts with remote headset devices)
+[Headset]
+
+# Set to true to only support HSP
+# Defaults to false
+DisableHFP=true
+
+# Just an example of potential config options for the other interfaces
+#[Sink]
+#Codecs=SBC,MPEG12
+#SBCChannelMode=joint
+#SBCBitpool=51

Modified: bluez-utils/branches/upstream/current/audio/ctl_bluetooth.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/ctl_bluetooth.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/ctl_bluetooth.c (original)
+++ bluez-utils/branches/upstream/current/audio/ctl_bluetooth.c Wed Jul  4 13:37:57 2007
@@ -31,13 +31,13 @@
 #include <alsa/asoundlib.h>
 #include <alsa/control_external.h>
 
-#ifndef UNIX_PATH_MAX
-#define UNIX_PATH_MAX 108
+#include "ipc.h"
+
+#ifdef ENABLE_DEBUG
+#define DBG(fmt, arg...)  printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
+#else
+#define DBG(fmt, arg...)
 #endif
-
-#define DBG(fmt, arg...)  printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
-
-#define SOCKET_NAME "/org/bluez/audio"
 
 #define BLUETOOTH_MINVOL 0
 #define BLUETOOTH_MAXVOL 15
@@ -57,15 +57,24 @@
 	[BLUETOOTH_CAPTURE]	= "Capture volume",
 };
 
+static void bluetooth_exit(struct bluetooth_data *data)
+{
+	if (data == NULL)
+		return;
+
+	if (data->sock >= 0)
+		close(data->sock);
+
+	free(data);
+}
+
 static void bluetooth_close(snd_ctl_ext_t *ext)
 {
 	struct bluetooth_data *data = ext->private_data;
 
 	DBG("ext %p", ext);
 
-	close(data->sock);
-
-	free(data);
+	bluetooth_exit(data);
 }
 
 static int bluetooth_elem_count(snd_ctl_ext_t *ext)
@@ -129,48 +138,140 @@
 	return 0;
 }
 
+static int bluetooth_send_ctl(struct bluetooth_data *data,
+				struct ipc_packet *pkt, int len)
+{
+	int ret;
+
+	ret = send(data->sock, pkt, len, MSG_NOSIGNAL);
+	if (ret <= 0) {
+		SYSERR("Unable to request new volume value to server");
+		return  -errno;
+	}
+
+	ret = recv(data->sock, pkt, len, 0);
+	if (ret <= 0) {
+		SYSERR("Unable to receive new volume value from server");
+		return  -errno;
+	}
+
+	if(pkt->type != PKT_TYPE_CTL_RSP) {
+		SNDERR("Unexpected packet type %d received", pkt->type);
+		return -EINVAL;
+	}
+
+	if(pkt->length != sizeof(struct ipc_data_ctl)) {
+		SNDERR("Unexpected packet length %d received", pkt->length);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int bluetooth_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
 								long *value)
 {
 	struct bluetooth_data *data = ext->private_data;
-	unsigned char buf[] = { 0x00, 0x00 };
-	int len;
+	struct ipc_packet *pkt;
+	struct ipc_data_ctl *ctl;
+	int len, ret;
 
 	DBG("ext %p key %ld", ext, key);
 
-	len = write(data->sock, buf, sizeof(buf));
-
+	len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_ctl);
+	pkt = malloc(len);
+	memset(pkt, 0, len);
 	*value = 0;
 
-	return 0;
+	pkt->type = PKT_TYPE_CTL_REQ;
+	pkt->length = sizeof(struct ipc_data_ctl);
+	ctl = (struct ipc_data_ctl *) pkt->data;
+	ctl->mode = key;
+
+	if ((ret = bluetooth_send_ctl(data, pkt, len)) < 0)
+		goto done;
+
+	*value = ctl->key;
+done:
+	free(pkt);
+	return ret;
 }
 
 static int bluetooth_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
 								long *value)
 {
 	struct bluetooth_data *data = ext->private_data;
-	unsigned char buf[] = { 0xff, 0xff };
-	int len;
+	struct ipc_packet *pkt;
+	struct ipc_data_ctl *ctl;
+	long current;
+	int len, ret;
 
 	DBG("ext %p key %ld", ext, key);
 
-	len = write(data->sock, buf, sizeof(buf));
-
-	return 0;
+	if ((ret = bluetooth_read_integer(ext, key, &current)) < 0)
+		return ret;
+
+	if (*value == current)
+		return 0;
+
+	len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_ctl);
+	pkt = malloc(len);
+	memset(pkt, 0, len);
+
+	pkt->length = sizeof(struct ipc_data_ctl);
+	ctl = (struct ipc_data_ctl *) pkt->data;
+	ctl->mode = key;
+
+	while (*value != current) {
+		pkt->type = PKT_TYPE_CTL_REQ;
+		ctl->key = (*value > current) ? CTL_KEY_VOL_UP : CTL_KEY_VOL_DOWN;
+
+		if ((ret = bluetooth_send_ctl(data, pkt, len)) < 0)
+			break;
+
+		current = ctl->key;
+	}
+
+	free(pkt);
+	return ret;
 }
 
 static int bluetooth_read_event(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id,
 						unsigned int *event_mask)
 {
 	struct bluetooth_data *data = ext->private_data;
-	unsigned char buf[128];
-	int len;
-
-	//DBG("ext %p id %p", ext, id);
-
-	len = recv(data->sock, buf, sizeof(buf), MSG_DONTWAIT);
-
-	return 0;
+	struct ipc_packet *pkt;
+	struct ipc_data_ctl *ctl;
+	int len, ret;
+
+	DBG("ext %p id %p", ext, id);
+
+	len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_ctl);
+	pkt = malloc(len);
+	memset(pkt, 0, len);
+
+	ret = recv(data->sock, pkt, len, MSG_DONTWAIT);
+	if (ret <= 0)
+		return  -errno;
+
+	if(pkt->type != PKT_TYPE_CTL_NTFY) {
+		SNDERR("Unexpected packet type %d received!", pkt->type);
+		return -EAGAIN;
+	}
+
+	if(pkt->length != sizeof(struct ipc_data_ctl)) {
+		SNDERR("Unexpected packet length %d received", pkt->length);
+		return -EAGAIN;
+	}
+
+	ctl = (struct ipc_data_ctl *) pkt->data;
+	snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
+	snd_ctl_elem_id_set_name(id, ctl->mode == BLUETOOTH_PLAYBACK ?
+				vol_devices[BLUETOOTH_PLAYBACK] :
+				vol_devices[BLUETOOTH_CAPTURE]);
+	*event_mask = SND_CTL_EVENT_MASK_VALUE;
+
+	return 1;
 }
 
 static snd_ctl_ext_callback_t bluetooth_callback = {
@@ -185,68 +286,60 @@
 	.read_event		= bluetooth_read_event,
 };
 
-SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)
-{
-	snd_config_iterator_t iter, next;
-	struct bluetooth_data *data;
-	struct sockaddr_un addr;
-	unsigned int id;
-	int sk, err;
-
-	DBG("Bluetooth Control plugin");
-
-	snd_config_for_each(iter, next, conf) {
-		snd_config_t *n = snd_config_iterator_entry(iter);
-		const char *id;
-
-		if (snd_config_get_id(n, &id) < 0)
-			continue;
-
-		if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
-			continue;
-
-		SNDERR("Unknown field %s", id);
-
+static int bluetooth_init(struct bluetooth_data *data)
+{
+	int sk, err, id;
+	struct sockaddr_un addr = {
+		AF_UNIX, IPC_SOCKET_NAME
+	};
+
+	if (!data)
 		return -EINVAL;
-	}
+
+	memset(data, 0, sizeof(struct bluetooth_data));
+
+	data->sock = -1;
 
 	id = abs(getpid() * rand());
 
-	sk = socket(PF_LOCAL, SOCK_DGRAM, 0);
-	if (sk < 0) {
+	if ((sk = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+		err = -errno;
 		SNDERR("Can't open socket");
 		return -errno;
 	}
 
-	memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s/%d", SOCKET_NAME, id);
-
-	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		SNDERR("Can't bind socket");
-		close(sk);
-		return -errno;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s", SOCKET_NAME);
-
+	DBG("Connecting to address: %s", addr.sun_path + 1);
 	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		err = -errno;
 		SNDERR("Can't connect socket");
 		close(sk);
-		return -errno;
-	}
-
-	data = malloc(sizeof(*data));
+		return err;
+	}
+
+	data->sock = sk;
+
+	return 0;
+}
+
+SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)
+{
+	struct bluetooth_data *data;
+	int err;
+
+	DBG("Bluetooth Control plugin");
+
+	data = malloc(sizeof(struct bluetooth_data));
+	memset(data, 0, sizeof(struct bluetooth_data));
 	if (!data) {
-		close(sk);
-		return -ENOMEM;
-	}
+		err = -ENOMEM;
+		goto error;
+	}
+
+	err = bluetooth_init(data);
+	if (err < 0)
+		goto error;
 
 	memset(data, 0, sizeof(*data));
-
-	data->sock = sk;
 
 	data->ext.version = SND_CTL_EXT_VERSION;
 	data->ext.card_idx = -1;
@@ -258,7 +351,7 @@
 	strncpy(data->ext.mixername, "Bluetooth Audio", sizeof(data->ext.mixername) - 1);
 
 	data->ext.callback = &bluetooth_callback;
-	data->ext.poll_fd = sk;
+	data->ext.poll_fd = data->sock;
 	data->ext.private_data = data;
 
 	err = snd_ctl_ext_create(&data->ext, name, mode);
@@ -270,9 +363,7 @@
 	return 0;
 
 error:
-	close(sk);
-
-	free(data);
+	bluetooth_exit(data);
 
 	return err;
 }

Added: bluez-utils/branches/upstream/current/audio/device.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/device.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/device.c (added)
+++ bluez-utils/branches/upstream/current/audio/device.c Wed Jul  4 13:37:57 2007
@@ -1,0 +1,238 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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 <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "dbus.h"
+#include "dbus-helper.h"
+#include "logging.h"
+#include "textfile.h"
+
+#include "device.h"
+
+static DBusHandlerResult device_get_address(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	struct device *device = data;
+	DBusMessage *reply;
+	char address[18], *ptr = address;
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	ba2str(&device->dst, address);
+
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr,
+							DBUS_TYPE_INVALID);
+
+	return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult device_get_connected(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	DBusMessageIter iter, array_iter;
+	struct device *device = data;
+	DBusMessage *reply;
+	const char *iface;
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+						DBUS_TYPE_STRING_AS_STRING,
+						&array_iter);
+
+	if (device->headset &&
+			headset_get_state(device) >= HEADSET_STATE_CONNECTED) {
+		iface = AUDIO_HEADSET_INTERFACE;
+		dbus_message_iter_append_basic(&array_iter,
+						DBUS_TYPE_STRING, &iface);
+	}
+
+	dbus_message_iter_close_container(&iter, &array_iter);
+
+	return send_message_and_unref(conn, reply);
+}
+
+static DBusMethodVTable device_methods[] = {
+	{ "GetAddress",			device_get_address,	"",	"s" },
+	{ "GetConnectedInterfaces",	device_get_connected,	"",	"s" },
+	{ NULL, NULL, NULL, NULL }
+};
+
+static void device_free(struct device *device)
+{
+	if (device->headset)
+		headset_free(device);
+
+	if (device->conn)
+		dbus_connection_unref(device->conn);
+
+	if (device->adapter_path)
+		g_free(device->adapter_path);
+
+	if (device->path)
+		g_free(device->path);
+
+	g_free(device);
+}
+
+static void device_unregister(DBusConnection *conn, void *data)
+{
+	struct device *device = data;
+
+	info("Unregistered device path:%s", device->path);
+
+	device_free(device);
+}
+
+struct device *device_register(DBusConnection *conn,
+					const char *path, bdaddr_t *bda)
+{
+	struct device *device;
+	bdaddr_t src;
+	int dev_id;
+
+	if (!conn || !path)
+		return NULL;
+
+	bacpy(&src, BDADDR_ANY);
+	dev_id = hci_get_route(NULL);
+	if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0))
+		return NULL;
+
+	device = g_new0(struct device, 1);
+
+	if (!dbus_connection_create_object_path(conn, path, device,
+							device_unregister)) {
+		error("D-Bus failed to register %s path", path);
+		device_free(device);
+		return NULL;
+	}
+
+	if (!dbus_connection_register_interface(conn, path,
+			AUDIO_DEVICE_INTERFACE, device_methods, NULL, NULL)) {
+		error("Failed to register %s interface to %s",
+					AUDIO_DEVICE_INTERFACE, path);
+		dbus_connection_destroy_object_path(conn, path);
+		return NULL;
+	}
+
+	device->path = g_strdup(path);
+	bacpy(&device->dst, bda);
+	bacpy(&device->src, &src);
+	device->conn = dbus_connection_ref(conn);
+	device->adapter_path = g_malloc0(16);
+	snprintf(device->adapter_path, 16, "/org/bluez/hci%d", dev_id);
+
+	return device;
+}
+
+int device_store(struct device *device, gboolean is_default)
+{
+	char value[64];
+	char filename[PATH_MAX + 1];
+	char src_addr[18], dst_addr[18];
+
+	if (!device->path)
+		return -EINVAL;
+
+	ba2str(&device->dst, dst_addr);
+	ba2str(&device->src, src_addr);
+
+	create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio");
+	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+	if (is_default)
+		textfile_put(filename, "default", dst_addr);
+	if (device->headset)
+		snprintf(value, 64, "headset");
+	else if (device->gateway)
+		snprintf(value, 64, "gateway");
+	else if (device->sink)
+		snprintf(value, 64, "sink");
+	else if (device->source)
+		snprintf(value, 64, "source");
+	else if (device->control)
+		snprintf(value, 64, "control");
+	else
+		snprintf(value, 64, "target");
+
+	return textfile_put(filename, dst_addr, value);
+}
+
+void device_finish_sdp_transaction(struct device *device)
+{
+	char address[18], *addr_ptr = address;
+	DBusMessage *msg, *reply;
+	DBusError derr;
+
+	ba2str(&device->dst, address);
+
+	msg = dbus_message_new_method_call("org.bluez", device->adapter_path,
+						"org.bluez.Adapter",
+						"FinishRemoteServiceTransaction");
+	if (!msg) {
+		error("Unable to allocate new method call");
+		return;
+	}
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,
+				 DBUS_TYPE_INVALID);
+
+	dbus_error_init(&derr);
+	reply = dbus_connection_send_with_reply_and_block(device->conn,
+							msg, -1, &derr);
+
+	dbus_message_unref(msg);
+
+	if (dbus_error_is_set(&derr) ||
+				dbus_set_error_from_message(&derr, reply)) {
+		error("FinishRemoteServiceTransaction(%s) failed: %s",
+						address, derr.message);
+		dbus_error_free(&derr);
+		return;
+	}
+
+	dbus_message_unref(reply);
+}

Added: bluez-utils/branches/upstream/current/audio/device.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/device.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/device.h (added)
+++ bluez-utils/branches/upstream/current/audio/device.h Wed Jul  4 13:37:57 2007
@@ -1,0 +1,78 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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
+ *
+ */
+
+#include <bluetooth/bluetooth.h>
+
+#include "headset.h"
+#include "gateway.h"
+
+#define AUDIO_DEVICE_INTERFACE	"org.bluez.audio.Device"
+
+#define GENERIC_AUDIO_UUID	"00001203-0000-1000-8000-00805F9B34FB"
+
+#define HSP_HS_UUID		"00001108-0000-1000-8000-00805F9B34FB"
+#define HSP_AG_UUID		"00001112-0000-1000-8000-00805F9B34FB"
+
+#define HFP_HS_UUID		"0000111E-0000-1000-8000-00805F9B34FB"
+#define HFP_AG_UUID		"0000111F-0000-1000-8000-00805F9B34FB"
+
+#define ADVANCED_AUDIO_UUID	"0000110D-0000-1000-8000-00805F9B34FB"
+
+#define A2DP_SOURCE_UUID	"0000110A-0000-1000-8000-00805F9B34FB"
+#define A2DP_SINK_UUID		"0000110B-0000-1000-8000-00805F9B34FB"
+
+#define AVRCP_REMOTE_UUID	"0000110E-0000-1000-8000-00805F9B34FB"
+#define AVRCP_TARGET_UUID	"0000110C-0000-1000-8000-00805F9B34FB"
+
+/* Move these to respective .h files once they exist */
+#define AUDIO_SINK_INTERFACE		"org.bluez.audio.Sink"
+#define AUDIO_SOURCE_INTERFACE		"org.bluez.audio.Source"
+#define AUDIO_CONTROL_INTERFACE		"org.bluez.audio.Control"
+#define AUDIO_TARGET_INTERFACE		"org.bluez.audio.Target"
+
+struct sink;
+struct source;
+struct control;
+struct target;
+
+struct device {
+	DBusConnection *conn;
+	char *adapter_path;
+	char *path;
+	bdaddr_t src;
+	bdaddr_t dst;
+
+	struct headset *headset;
+	struct gateway *gateway;
+	struct sink *sink;
+	struct source *source;
+	struct control *control;
+	struct target *target;
+};
+
+struct device *device_register(DBusConnection *conn,
+					const char *path, bdaddr_t *bda);
+
+int device_store(struct device *device, gboolean is_default);
+
+void device_finish_sdp_transaction(struct device *device);

Added: bluez-utils/branches/upstream/current/audio/error.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/error.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/error.c (added)
+++ bluez-utils/branches/upstream/current/audio/error.c Wed Jul  4 13:37:57 2007
@@ -1,0 +1,103 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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 "error.h"
+#include "logging.h"
+
+#define AUDIO_ERROR_INTERFACE "org.bluez.audio.Error"
+
+/* FIXME: Remove these once global error functions exist */
+static DBusHandlerResult error_reply(DBusConnection *conn, DBusMessage *msg,
+					const char *name, const char *descr)
+{
+	DBusMessage *derr;
+
+	if (!conn || !msg)
+		return DBUS_HANDLER_RESULT_HANDLED;
+
+	derr = dbus_message_new_error(msg, name, descr);
+	if (!derr) {
+		error("Unable to allocate new error return");
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+	}
+
+	return send_message_and_unref(conn, derr);
+}
+
+DBusHandlerResult err_invalid_args(DBusConnection *conn,
+					DBusMessage *msg, const char *descr)
+{
+	return error_reply(conn, msg,
+				AUDIO_ERROR_INTERFACE ".InvalidArguments",
+				descr ? descr : "Invalid arguments in method call");
+}
+
+DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg)
+{
+	return error_reply(conn, msg,
+				AUDIO_ERROR_INTERFACE ".AlreadyConnected",
+					"Already connected to a device");
+}
+
+DBusHandlerResult err_not_connected(DBusConnection *conn, DBusMessage *msg)
+{
+	return error_reply(conn, msg,
+				AUDIO_ERROR_INTERFACE ".NotConnected",
+					"Not connected to any device");
+}
+
+DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg)
+{
+	return error_reply(conn, msg,
+				AUDIO_ERROR_INTERFACE ".NotSupported",
+				"The service is not supported by the remote device");
+}
+
+DBusHandlerResult err_connect_failed(DBusConnection *conn,
+					DBusMessage *msg, const char *err)
+{
+	return error_reply(conn, msg,
+				AUDIO_ERROR_INTERFACE ".ConnectFailed", err);
+}
+
+DBusHandlerResult err_does_not_exist(DBusConnection *conn, DBusMessage *msg)
+{
+	return error_reply(conn, msg,
+				AUDIO_ERROR_INTERFACE ".DoesNotExist",
+							"Does not exist");
+}
+
+DBusHandlerResult err_not_available(DBusConnection *conn, DBusMessage *msg)
+{
+	return error_reply(conn, msg, ".NotAvailable", "Not available");
+}
+
+DBusHandlerResult err_failed(DBusConnection *conn,
+					DBusMessage *msg, const char *dsc)
+{
+	return error_reply(conn, msg, AUDIO_ERROR_INTERFACE ".Failed", dsc);
+}

Added: bluez-utils/branches/upstream/current/audio/error.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/error.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/error.h (added)
+++ bluez-utils/branches/upstream/current/audio/error.h Wed Jul  4 13:37:57 2007
@@ -1,0 +1,36 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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
+ *
+ */
+
+#include "dbus.h"
+
+DBusHandlerResult err_invalid_args(DBusConnection *conn,
+					DBusMessage *msg, const char *descr);
+DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg);
+DBusHandlerResult err_not_connected(DBusConnection *conn, DBusMessage * msg);
+DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg);
+DBusHandlerResult err_connect_failed(DBusConnection *conn,
+					DBusMessage *msg, const char *err);
+DBusHandlerResult err_does_not_exist(DBusConnection *conn, DBusMessage *msg);
+DBusHandlerResult err_not_available(DBusConnection *conn, DBusMessage *msg);
+DBusHandlerResult err_failed(DBusConnection *conn,
+					DBusMessage *msg, const char *dsc);

Added: bluez-utils/branches/upstream/current/audio/gateway.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/gateway.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/gateway.c (added)
+++ bluez-utils/branches/upstream/current/audio/gateway.c Wed Jul  4 13:37:57 2007
@@ -1,0 +1,551 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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 <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+
+#include "dbus.h"
+#include "dbus-helper.h"
+#include "logging.h"
+#include "manager.h"
+#include "error.h"
+
+static uint32_t hs_record_id = 0;
+static uint32_t hf_record_id = 0;
+
+static GIOChannel *hs_server = NULL;
+static GIOChannel *hf_server = NULL;
+
+static DBusConnection *connection = NULL;
+
+static int gateway_hsp_ag_record(sdp_buf_t *buf, uint8_t ch)
+{
+	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+	uuid_t l2cap_uuid, rfcomm_uuid;
+	sdp_profile_desc_t profile;
+	sdp_list_t *aproto, *proto[2];
+	sdp_record_t record;
+	sdp_data_t *channel;
+	int ret;
+
+	memset(&record, 0, sizeof(sdp_record_t));
+
+	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+	root = sdp_list_append(0, &root_uuid);
+	sdp_set_browse_groups(&record, root);
+
+	sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
+	svclass_id = sdp_list_append(0, &svclass_uuid);
+	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+	sdp_set_service_classes(&record, svclass_id);
+
+	sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
+	profile.version = 0x0100;
+	pfseq = sdp_list_append(0, &profile);
+	sdp_set_profile_descs(&record, pfseq);
+
+	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+	proto[0] = sdp_list_append(0, &l2cap_uuid);
+	apseq = sdp_list_append(0, proto[0]);
+
+	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+	proto[1] = sdp_list_append(0, &rfcomm_uuid);
+	channel = sdp_data_alloc(SDP_UINT8, &ch);
+	proto[1] = sdp_list_append(proto[1], channel);
+	apseq = sdp_list_append(apseq, proto[1]);
+
+	aproto = sdp_list_append(0, apseq);
+	sdp_set_access_protos(&record, aproto);
+
+	sdp_set_info_attr(&record, "Headset Audio Gateway", 0, 0);
+
+	if (sdp_gen_record_pdu(&record, buf) < 0)
+		ret = -1;
+	else
+		ret = 0;
+
+	sdp_data_free(channel);
+	sdp_list_free(proto[0], 0);
+	sdp_list_free(proto[1], 0);
+	sdp_list_free(apseq, 0);
+	sdp_list_free(pfseq, 0);
+	sdp_list_free(aproto, 0);
+	sdp_list_free(root, 0);
+	sdp_list_free(svclass_id, 0);
+	sdp_list_free(record.attrlist, (sdp_free_func_t) sdp_data_free);
+	sdp_list_free(record.pattern, free);
+
+	return ret;
+}
+
+static int gateway_hfp_ag_record(sdp_buf_t *buf, uint8_t ch)
+{
+	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+	uuid_t l2cap_uuid, rfcomm_uuid;
+	sdp_profile_desc_t profile;
+	sdp_list_t *aproto, *proto[2];
+	sdp_record_t record;
+	uint16_t u16 = 0x0009;
+	sdp_data_t *channel, *features;
+	uint8_t netid = 0x01;
+	sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
+	int ret;
+
+	memset(&record, 0, sizeof(sdp_record_t));
+
+	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+	root = sdp_list_append(0, &root_uuid);
+	sdp_set_browse_groups(&record, root);
+
+	sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
+	svclass_id = sdp_list_append(0, &svclass_uuid);
+	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+	sdp_set_service_classes(&record, svclass_id);
+
+	sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
+	profile.version = 0x0105;
+	pfseq = sdp_list_append(0, &profile);
+	sdp_set_profile_descs(&record, pfseq);
+
+	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+	proto[0] = sdp_list_append(0, &l2cap_uuid);
+	apseq = sdp_list_append(0, proto[0]);
+
+	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+	proto[1] = sdp_list_append(0, &rfcomm_uuid);
+	channel = sdp_data_alloc(SDP_UINT8, &ch);
+	proto[1] = sdp_list_append(proto[1], channel);
+	apseq = sdp_list_append(apseq, proto[1]);
+
+	features = sdp_data_alloc(SDP_UINT16, &u16);
+	sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+	aproto = sdp_list_append(0, apseq);
+	sdp_set_access_protos(&record, aproto);
+
+	sdp_set_info_attr(&record, "Hands-Free Audio Gateway", 0, 0);
+
+	sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
+
+	if (sdp_gen_record_pdu(&record, buf) < 0)
+		ret = -1;
+	else
+		ret = 0;
+
+	sdp_data_free(channel);
+	sdp_list_free(proto[0], 0);
+	sdp_list_free(proto[1], 0);
+	sdp_list_free(apseq, 0);
+	sdp_list_free(pfseq, 0);
+	sdp_list_free(aproto, 0);
+	sdp_list_free(root, 0);
+	sdp_list_free(svclass_id, 0);
+	sdp_list_free(record.attrlist, (sdp_free_func_t) sdp_data_free);
+	sdp_list_free(record.pattern, free);
+
+	return ret;
+}
+
+static uint32_t gateway_add_ag_record(uint8_t channel, sdp_buf_t *buf)
+{
+	DBusMessage *msg, *reply;
+	DBusError derr;
+	dbus_uint32_t rec_id;
+
+	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+						"org.bluez.Database",
+						"AddServiceRecord");
+	if (!msg) {
+		error("Can't allocate new method call");
+		return 0;
+	}
+
+	dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+						&buf->data, buf->data_size,
+							DBUS_TYPE_INVALID);
+
+	dbus_error_init(&derr);
+	reply = dbus_connection_send_with_reply_and_block(connection,
+							msg, -1, &derr);
+
+	dbus_message_unref(msg);
+
+	if (dbus_error_is_set(&derr) ||
+			dbus_set_error_from_message(&derr, reply)) {
+		error("Adding service record failed: %s", derr.message);
+		dbus_error_free(&derr);
+		return 0;
+	}
+
+	dbus_message_get_args(reply, &derr, DBUS_TYPE_UINT32, &rec_id,
+							DBUS_TYPE_INVALID);
+
+	if (dbus_error_is_set(&derr)) {
+		error("Invalid arguments to AddServiceRecord reply: %s",
+								derr.message);
+		dbus_message_unref(reply);
+		dbus_error_free(&derr);
+		return 0;
+	}
+
+	dbus_message_unref(reply);
+
+	debug("add_ag_record: got record id 0x%x", rec_id);
+
+	return rec_id;
+}
+
+static int gateway_remove_ag_record(uint32_t rec_id)
+{
+	DBusMessage *msg, *reply;
+	DBusError derr;
+
+	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+						"org.bluez.Database",
+						"RemoveServiceRecord");
+	if (!msg) {
+		error("Can't allocate new method call");
+		return 0;
+	}
+
+	dbus_message_append_args(msg, DBUS_TYPE_UINT32, &rec_id,
+							DBUS_TYPE_INVALID);
+
+	dbus_error_init(&derr);
+	reply = dbus_connection_send_with_reply_and_block(connection,
+							msg, -1, &derr);
+
+	dbus_message_unref(msg);
+
+	if (dbus_error_is_set(&derr)) {
+		error("Removing service record 0x%x failed: %s",
+						rec_id, derr.message);
+		dbus_error_free(&derr);
+		return 0;
+	}
+
+	dbus_message_unref(reply);
+
+	return 0;
+}
+
+static void send_cancel_auth(struct device *device)
+{
+	DBusMessage *cancel;
+	char addr[18], *address = addr;
+	const char *uuid;
+
+	if (headset_get_type(device) == SVC_HEADSET)
+		uuid = HSP_AG_UUID;
+	else
+		uuid = HFP_AG_UUID;
+
+	cancel = dbus_message_new_method_call("org.bluez", "/org/bluez",
+						"org.bluez.Database",
+						"CancelAuthorizationRequest");
+	if (!cancel) {
+		error("Unable to allocate new method call");
+		return;
+	}
+
+	ba2str(&device->dst, addr);
+
+	dbus_message_append_args(cancel, DBUS_TYPE_STRING, &address,
+						DBUS_TYPE_STRING, &uuid,
+							DBUS_TYPE_INVALID);
+
+	send_message_and_unref(connection, cancel);
+}
+
+static void auth_cb(DBusPendingCall *call, void *data)
+{
+	struct device *device = data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError err;
+
+	dbus_error_init(&err);
+	if (dbus_set_error_from_message(&err, reply)) {
+		error("Access denied: %s", err.message);
+		if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
+			debug("Canceling authorization request");
+			send_cancel_auth(device);
+		}
+		dbus_error_free(&err);
+		headset_close_rfcomm(device);
+	} else {
+		char hs_address[18];
+
+		headset_set_state(device, HEADSET_STATE_CONNECTED);
+
+		ba2str(&device->dst, hs_address);
+
+		debug("Accepted headset connection from %s for %s",
+						hs_address, device->path);
+	}
+
+	dbus_message_unref(reply);
+}
+
+static gboolean gateway_io_cb(GIOChannel *chan, GIOCondition cond, void *data)
+{
+	int srv_sk, cli_sk;
+	struct sockaddr_rc addr;
+	socklen_t size;
+	char hs_address[18], *address = hs_address;
+	const char *uuid;
+	struct device *device;
+	DBusMessage *auth;
+	DBusPendingCall *pending;
+
+	if (cond & G_IO_NVAL)
+		return FALSE;
+
+	if (cond & (G_IO_HUP | G_IO_ERR)) {
+		error("Hangup or error on rfcomm server socket");
+		g_io_channel_close(chan);
+		raise(SIGTERM);
+		return FALSE;
+	}
+
+	srv_sk = g_io_channel_unix_get_fd(chan);
+
+	size = sizeof(struct sockaddr_rc);
+	cli_sk = accept(srv_sk, (struct sockaddr *) &addr, &size);
+	if (cli_sk < 0) {
+		error("accept: %s (%d)", strerror(errno), errno);
+		return TRUE;
+	}
+
+	device = manager_device_connected(&addr.rc_bdaddr);
+	if (!device) {
+		close(cli_sk);
+		return TRUE;
+	}
+
+	if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) {
+		debug("Refusing new connection since one already exists");
+		close(cli_sk);
+		return TRUE;
+	}
+
+	if (headset_connect_rfcomm(device, cli_sk) < 0) {
+		error("Allocating new GIOChannel failed!");
+		close(cli_sk);
+		return TRUE;
+	}
+
+	if (chan == hs_server) {
+		headset_set_type(device, SVC_HEADSET);
+		uuid = HSP_AG_UUID;
+	} else {
+		headset_set_type(device, SVC_HANDSFREE);
+		uuid = HFP_AG_UUID;
+	}
+
+	auth = dbus_message_new_method_call("org.bluez", "/org/bluez",
+						"org.bluez.Database",
+						"RequestAuthorization");
+	if (!auth) {
+		error("Unable to allocate RequestAuthorization method call");
+		goto failed;
+	}
+
+	ba2str(&device->dst, hs_address);
+
+	dbus_message_append_args(auth, DBUS_TYPE_STRING, &address,
+						DBUS_TYPE_STRING, &uuid,
+							DBUS_TYPE_INVALID);
+
+	if (!dbus_connection_send_with_reply(connection, auth, &pending, -1)) {
+		error("Sending of authorization request failed");
+		goto failed;
+	}
+
+	dbus_pending_call_set_notify(pending, auth_cb, device, NULL);
+	dbus_pending_call_unref(pending);
+	dbus_message_unref(auth);
+
+	return TRUE;
+
+failed:
+	headset_close_rfcomm(device);
+
+	return TRUE;
+}
+
+static GIOChannel *server_socket(uint8_t *channel)
+{
+	int sock, lm;
+	struct sockaddr_rc addr;
+	socklen_t sa_len;
+	GIOChannel *io;
+
+	sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+	if (sock < 0) {
+		error("server socket: %s (%d)", strerror(errno), errno);
+		return NULL;
+	}
+
+	lm = RFCOMM_LM_SECURE;
+	if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
+		error("server setsockopt: %s (%d)", strerror(errno), errno);
+		close(sock);
+		return NULL;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.rc_family = AF_BLUETOOTH;
+	bacpy(&addr.rc_bdaddr, BDADDR_ANY);
+	addr.rc_channel = channel ? *channel : 0;
+
+	if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		error("server bind: %s", strerror(errno), errno);
+		close(sock);
+		return NULL;
+	}
+
+	if (listen(sock, 1) < 0) {
+		error("server listen: %s", strerror(errno), errno);
+		close(sock);
+		return NULL;
+	}
+
+	sa_len = sizeof(struct sockaddr_rc);
+	getsockname(sock, (struct sockaddr *) &addr, &sa_len);
+	*channel = addr.rc_channel;
+
+	io = g_io_channel_unix_new(sock);
+	if (!io) {
+		error("Unable to allocate new io channel");
+		close(sock);
+		return NULL;
+	}
+
+	return io;
+}
+
+int gateway_init(DBusConnection *conn, gboolean no_hfp, gboolean sco_hci)
+{
+	uint8_t chan = DEFAULT_HS_AG_CHANNEL;
+	sdp_buf_t buf;
+
+	connection = dbus_connection_ref(conn);
+
+	hs_server = server_socket(&chan);
+	if (!hs_server)
+		return -1;
+
+	if (gateway_hsp_ag_record(&buf, chan) < 0) {
+		error("Unable to allocate new service record");
+		return -1;
+	}
+
+	hs_record_id = gateway_add_ag_record(chan, &buf);
+	free(buf.data);
+	if (!hs_record_id) {
+		error("Unable to register HS AG service record");
+		g_io_channel_unref(hs_server);
+		hs_server = NULL;
+		return -1;
+	}
+
+	g_io_add_watch(hs_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+						(GIOFunc) gateway_io_cb, NULL);
+
+	if (no_hfp)
+		return 0;
+
+	chan = DEFAULT_HF_AG_CHANNEL;
+
+	hf_server = server_socket(&chan);
+	if (!hf_server)
+		return -1;
+
+	if (gateway_hfp_ag_record(&buf, chan) < 0) {
+		error("Unable to allocate new service record");
+		return -1;
+	}
+
+	hf_record_id = gateway_add_ag_record(chan, &buf);
+	free(buf.data);
+	if (!hf_record_id) {
+		error("Unable to register HS AG service record");
+		g_io_channel_unref(hf_server);
+		hs_server = NULL;
+		return -1;
+	}
+
+	g_io_add_watch(hf_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+						(GIOFunc) gateway_io_cb, NULL);
+
+	return 0;
+}
+
+void gateway_exit(void)
+{
+	if (hs_record_id) {
+		gateway_remove_ag_record(hs_record_id);
+		hs_record_id = 0;
+	}
+
+	if (hs_server) {
+		g_io_channel_unref(hs_server);
+		hs_server = NULL;
+	}
+
+	if (hf_record_id) {
+		gateway_remove_ag_record(hf_record_id);
+		hf_record_id = 0;
+	}
+
+	if (hf_server) {
+		g_io_channel_unref(hf_server);
+		hf_server = NULL;
+	}
+
+	dbus_connection_unref(connection);
+	connection = NULL;
+}

Added: bluez-utils/branches/upstream/current/audio/gateway.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/gateway.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/gateway.h (added)
+++ bluez-utils/branches/upstream/current/audio/gateway.h Wed Jul  4 13:37:57 2007
@@ -1,0 +1,30 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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
+ *
+ */
+
+#define AUDIO_GATEWAY_INTERFACE "org.bluez.audio.Gateway"
+
+struct gateway;
+
+int gateway_init(DBusConnection *conn, gboolean disable_hfp, gboolean sco_hci);
+
+void gateway_exit(void);

Modified: bluez-utils/branches/upstream/current/audio/headset.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/headset.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/headset.c (original)
+++ bluez-utils/branches/upstream/current/audio/headset.c Wed Jul  4 13:37:57 2007
@@ -53,45 +53,31 @@
 #include "dbus-helper.h"
 #include "logging.h"
 #include "manager.h"
-#include "headset.h"
-
-#define DEFAULT_HS_AG_CHANNEL 12
+#include "error.h"
 
 #define RING_INTERVAL 3000
 
-typedef enum {
-	HEADSET_EVENT_KEYPRESS,
-	HEADSET_EVENT_GAIN,
-	HEADSET_EVENT_UNKNOWN,
-	HEADSET_EVENT_INVALID
-} headset_event_t; 
-
-typedef enum {
-	HEADSET_STATE_UNAUTHORIZED,
-	HEADSET_STATE_DISCONNECTED,
-	HEADSET_STATE_CONNECT_IN_PROGRESS,
-	HEADSET_STATE_CONNECTED,
-	HEADSET_STATE_PLAY_IN_PROGRESS,
-	HEADSET_STATE_PLAYING,
-} headset_state_t;
+#define BUF_SIZE 1024
+
+#define HEADSET_GAIN_SPEAKER 'S'
+#define HEADSET_GAIN_MICROPHONE 'M'
 
 struct pending_connect {
-	int ch;
 	DBusMessage *msg;
 	GIOChannel *io;
+	guint io_id;
+	int sock;
+	struct ipc_packet *pkt;
 };
 
 struct headset {
-	char object_path[128];
-	bdaddr_t bda;
+	uint32_t hsp_handle;
+	uint32_t hfp_handle;
+
+	int rfcomm_ch;
 
 	GIOChannel *rfcomm;
 	GIOChannel *sco;
-
-	char *input;
-	GIOChannel *audio_input;
-	char *output;
-	GIOChannel *audio_output;
 
 	guint ring_timer;
 
@@ -99,20 +85,17 @@
 	int data_start;
 	int data_length;
 
+	headset_type_t type;
+
 	headset_state_t state;
 	struct pending_connect *pending_connect;
+
+	int sp_gain;
+	int mic_gain;
 };
 
 static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg,
 					void *data);
-
-static GIOChannel *hs_server = NULL;
-
-static uint32_t hs_record_id = 0;
-
-static GSList *headsets = NULL;
-
-static DBusConnection *connection = NULL;
 
 static void pending_connect_free(struct pending_connect *c)
 {
@@ -123,153 +106,7 @@
 	g_free(c);
 }
 
-static DBusHandlerResult error_reply(DBusConnection *conn, DBusMessage *msg,
-					const char *name, const char *descr)
-{
-	DBusMessage *derr;
-
-	if (!conn || !msg)
-		return DBUS_HANDLER_RESULT_HANDLED;
-
-	derr = dbus_message_new_error(msg, name, descr);
-	if (!derr) {
-	       	error("Unable to allocate new error return");
-		return DBUS_HANDLER_RESULT_NEED_MEMORY;
-	}
-
-	return send_message_and_unref(conn, derr);
-}
-
-static DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg)
-{
-	return error_reply(conn, msg, "org.bluez.audio.Error.AlreadyConnected",
-				"Already connected to a device");
-}
-
-static DBusHandlerResult err_not_connected(DBusConnection *conn, DBusMessage *msg)
-{
-	return error_reply(conn, msg, "org.bluez.audio.Error.NotConnected",
-				"Not connected to any device");
-}
-
-static DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg)
-{
-	return error_reply(conn, msg, "org.bluez.audio.Error.NotSupported",
-			"The service is not supported by the remote device");
-}
-
-static DBusHandlerResult err_connect_failed(DBusConnection *conn, DBusMessage *msg, int err)
-{
-	return error_reply(conn, msg, "org.bluez.audio.Error.ConnectFailed",
-				strerror(err));
-}
-
-static DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg)
-{
-	return error_reply(conn, msg, "org.bluez.audio.Error.Failed", "Failed");
-}
-
-static gint headset_bda_cmp(gconstpointer headset, gconstpointer bda)
-{
-	const struct headset *hs = headset;
-
-	return bacmp(&hs->bda, bda);
-}
-
-static gboolean headset_close_output(struct headset *hs)
-{
-	assert(hs != NULL);
-
-	if (hs->audio_output == NULL) 
-		return FALSE;
-
-	g_io_channel_close(hs->audio_output);
-	g_io_channel_unref(hs->audio_output);
-	hs->audio_output = NULL;
-
-	return TRUE;
-}
-
-/* FIXME: in the furture, that would be great to provide user space alsa driver (not plugin) */
-static gboolean headset_open_output(struct headset *hs, const char *output)
-{
-	int out;
-
-	assert(hs != NULL && output != NULL);
-
-	headset_close_output(hs);
-	if (output && hs->output) {
-		g_free(hs->output);
-		hs->output = g_strdup(output);
-	}
-
-	assert(hs->output);
-
-	out = open(hs->output, O_WRONLY | O_SYNC | O_CREAT);
-
-	if (out < 0) {
-		error("open(%s): %s %d", hs->output, strerror(errno), errno);
-		return FALSE;
-	}
-
-	hs->audio_output = g_io_channel_unix_new(out);
-	if (!hs->audio_output) {
-		error("Allocating new channel for audio output!");
-		return FALSE;
-	}
-
-	g_io_channel_set_close_on_unref(hs->audio_output, TRUE);
-
-	return TRUE;
-}
-
-static gboolean headset_close_input(struct headset *hs)
-{
-	assert(hs != NULL);
-
-	if (hs->audio_input == NULL) 
-		return FALSE;
-
-	g_io_channel_close(hs->audio_input);
-	g_io_channel_unref(hs->audio_input);
-	hs->audio_input = NULL;
-
-	return TRUE;
-}
-
-#if 0
-static gboolean headset_open_input(struct headset *hs, const char *input)
-{
-	int in;
-
-	assert(hs != NULL);
-	
-	/* we keep the input name, and NULL can be use to reopen */
-	if (input && hs->input) {
-		g_free(hs->input);
-		hs->input = g_strdup(input);
-	}
-
-	assert(hs->input);
-
-	in = open(hs->input, O_RDONLY | O_NOCTTY);
-
-	if (in < 0) {
-		error("open(%s): %s %d", hs->input, strerror(errno), errno);
-		return FALSE;
-	}
-
-	hs->audio_input = g_io_channel_unix_new(in);
-	if (!hs->audio_input) {
-		error("Allocating new channel for audio input!");
-		return FALSE;
-	}
-
-	return TRUE;
-}
-#endif
-
-static void hs_signal_gain_setting(struct headset *hs, const char *buf)
+static void hs_signal_gain_setting(struct device *device, const char *buf)
 {
 	const char *name;
 	dbus_uint16_t gain;
@@ -279,27 +116,39 @@
 		return;
 	}
 
+	gain = (dbus_uint16_t) strtol(&buf[5], NULL, 10);
+
+	if (gain > 15) {
+		error("Invalid gain value received: %u", gain);
+		return;
+	}
+
 	switch (buf[3]) {
-	case 'S':
+	case HEADSET_GAIN_SPEAKER:
+		if (device->headset->sp_gain == gain)
+			return;
 		name = "SpeakerGainChanged";
+		device->headset->sp_gain = gain;
 		break;
-	case 'M':
+	case HEADSET_GAIN_MICROPHONE:
+		if (device->headset->mic_gain == gain)
+			return;
 		name = "MicrophoneGainChanged";
+		device->headset->mic_gain = gain;
 		break;
 	default:
 		error("Unknown gain setting");
 		return;
 	}
 
-	gain = (dbus_uint16_t) strtol(&buf[5], NULL, 10);
-
-	dbus_connection_emit_signal(connection, hs->object_path,
+	dbus_connection_emit_signal(device->conn, device->path,
 					AUDIO_HEADSET_INTERFACE, name,
 					DBUS_TYPE_UINT16, &gain,
 					DBUS_TYPE_INVALID);
 }
 
-static headset_event_t parse_headset_event(const char *buf, char *rsp, int rsp_len)
+static headset_event_t parse_headset_event(const char *buf, char *rsp,
+						int rsp_len)
 {
 	printf("Received: %s\n", buf);
 
@@ -321,28 +170,24 @@
 		return HEADSET_EVENT_UNKNOWN;
 }
 
-static void close_sco(struct headset *hs)
-{
+static void close_sco(struct device *device)
+{
+	struct headset *hs = device->headset;
+
 	g_io_channel_close(hs->sco);
 	g_io_channel_unref(hs->sco);
 	hs->sco = NULL;
-	if (hs->audio_output) {
-		g_io_channel_unref(hs->audio_output);
-		hs->audio_output = NULL;
-	}
-	if (hs->audio_input)
-		headset_close_input(hs);
 	assert(hs->rfcomm);
 	hs->state = HEADSET_STATE_CONNECTED;
-	dbus_connection_emit_signal(connection, hs->object_path,
+	dbus_connection_emit_signal(device->conn, device->path,
 					AUDIO_HEADSET_INTERFACE, "Stopped",
 					DBUS_TYPE_INVALID);
 }
 
-
 static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
-				struct headset *hs)
-{
+				struct device *device)
+{
+	struct headset *hs;
 	unsigned char buf[BUF_SIZE];
 	char *cr, rsp[BUF_SIZE];
 	gsize bytes_read = 0;
@@ -353,10 +198,13 @@
 	if (cond & G_IO_NVAL)
 		return FALSE;
 
+	hs = device->headset;
+
 	if (cond & (G_IO_ERR | G_IO_HUP))
 		goto failed;
 
-	err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf) - 1, &bytes_read);
+	err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf) - 1,
+				&bytes_read);
 	if (err != G_IO_ERROR_NONE)
 		goto failed;
 
@@ -385,9 +233,10 @@
 
 	memset(rsp, 0, sizeof(rsp));
 
-	switch (parse_headset_event(&hs->buf[hs->data_start], rsp, sizeof(rsp))) {
+	switch (parse_headset_event(&hs->buf[hs->data_start], rsp,
+					sizeof(rsp))) {
 	case HEADSET_EVENT_GAIN:
-		hs_signal_gain_setting(hs, &hs->buf[hs->data_start] + 2);
+		hs_signal_gain_setting(device, &hs->buf[hs->data_start] + 2);
 		break;
 
 	case HEADSET_EVENT_KEYPRESS:
@@ -396,7 +245,7 @@
 			hs->ring_timer = 0;
 		}
 
-		dbus_connection_emit_signal(connection, hs->object_path,
+		dbus_connection_emit_signal(device->conn, device->path,
 						AUDIO_HEADSET_INTERFACE,
 						"AnswerRequested",
 						DBUS_TYPE_INVALID);
@@ -414,9 +263,10 @@
 	err = G_IO_ERROR_NONE;
 
 	while (err == G_IO_ERROR_NONE && total_bytes_written < count) {
-		/* FIXME: make it async */
-		err = g_io_channel_write(hs->rfcomm, rsp + total_bytes_written, 
-				count - total_bytes_written, &bytes_written);
+		err = g_io_channel_write(hs->rfcomm,
+						rsp + total_bytes_written, 
+						count - total_bytes_written,
+						&bytes_written);
 		if (err != G_IO_ERROR_NONE)
 			error("Error while writting to the audio output channel");
 		total_bytes_written += bytes_written;
@@ -432,169 +282,74 @@
 
 failed:
 	if (hs->sco)
-		close_sco(hs);
-	hs_disconnect(NULL, NULL, hs);
+		close_sco(device);
+	hs_disconnect(NULL, NULL, device);
 
 	return FALSE;
 }
 
-static void send_cancel_auth(struct headset *hs)
-{
-	DBusMessage *cancel;
-	char addr[18], *address = addr;
-	const char *uuid = "";
-
-	cancel = dbus_message_new_method_call("org.bluez", "/org/bluez",
-						"org.bluez.Database",
-						"CancelAuthorizationRequest");
-	if (!cancel) {
-		error("Unable to allocate new method call");
-		return;
-	}
-
-	ba2str(&hs->bda, addr);
-
-	dbus_message_append_args(cancel, DBUS_TYPE_STRING, &address,
-				DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID);
-
-	send_message_and_unref(connection, cancel);
-}
-
-static void auth_callback(DBusPendingCall *call, void *data)
-{
-	struct headset *hs = data;
-	DBusMessage *reply = dbus_pending_call_steal_reply(call);
-	DBusError err;
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("Access denied: %s", err.message);
-		if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
-			debug("Canceling authorization request");
-			send_cancel_auth(hs);
-		}
-		dbus_error_free(&err);
-		g_io_channel_close(hs->rfcomm);
-		g_io_channel_unref(hs->rfcomm);
-		hs->rfcomm = NULL;
-	} else {
-		char hs_address[18];
-
-		g_io_add_watch(hs->rfcomm, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-				(GIOFunc) rfcomm_io_cb, hs);
-
-		ba2str(&hs->bda, hs_address);
-
-		debug("Accepted connection from %s for %s", hs_address, hs->object_path);
-
-		hs->state = HEADSET_STATE_CONNECTED;
-		dbus_connection_emit_signal(connection, hs->object_path,
-						AUDIO_HEADSET_INTERFACE,
-						"Connected",
-						DBUS_TYPE_INVALID);
-	}
-
-	dbus_message_unref(reply);
-}
-
-static gboolean audio_input_to_sco_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
-	struct headset *hs = data;
-	char buf[1024];
-	gsize bytes_read;
-	gsize bytes_written, total_bytes_written;
-	GIOError err;
+static gboolean sco_cb(GIOChannel *chan, GIOCondition cond,
+			struct device *device)
+{
+	struct headset *hs;
 
 	if (cond & G_IO_NVAL)
 		return FALSE;
 
-	if (cond & (G_IO_HUP | G_IO_ERR))
-		goto failed;
-
-	err = g_io_channel_read(chan, buf, sizeof(buf), &bytes_read);
-	if (err != G_IO_ERROR_NONE)
-		goto failed;
-	
-	total_bytes_written = bytes_written = 0;
-	err = G_IO_ERROR_NONE;
-
-	while (err == G_IO_ERROR_NONE && total_bytes_written < bytes_read) {
-		/* FIXME: make it async */
-		err = g_io_channel_write(hs->sco, buf + total_bytes_written, 
-					bytes_read - total_bytes_written, &bytes_written);
+	hs = device->headset;
+
+	error("Audio connection got disconnected");
+
+	if (hs->sco)
+		close_sco(device);
+
+	return FALSE;
+}
+
+static GIOError headset_send(struct headset *hs, const char *str)
+{
+	GIOError err;
+	gsize total_written, written, count;
+
+	assert(hs != NULL);
+
+	if (hs->state < HEADSET_STATE_CONNECTED || !hs->rfcomm) {
+		error("headset_send: the headset is not connected");
+		return G_IO_ERROR_UNKNOWN;
+	}
+
+	count = strlen(str);
+	written = total_written = 0;
+
+	while (total_written < count) {
+		err = g_io_channel_write(hs->rfcomm, str + total_written,
+					count - total_written, &written);
 		if (err != G_IO_ERROR_NONE)
-			error("Error while writting to the audio output channel");
-		total_bytes_written += bytes_written;
-	};
-
-	return TRUE;
-
-failed:
-	headset_close_input(hs);
-	return FALSE;
-}
-
-static gboolean sco_input_to_audio_output_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
-	struct headset *hs = data;
-	char buf[1024];
-	gsize bytes_read;
-	gsize bytes_written, total_bytes_written;
-	GIOError err;
-
-	if (cond & G_IO_NVAL)
-		return FALSE;
-
-	if (cond & (G_IO_HUP | G_IO_ERR))
-		goto disconn;
-
-	if (!hs->audio_output && hs->output)
-		headset_open_output(hs, hs->output);
-
-	err = g_io_channel_read(chan, buf, sizeof(buf), &bytes_read);
-
-	if (err != G_IO_ERROR_NONE)
-		goto disconn;
-	
-	if (!hs->audio_output) {
-		error("got %d bytes audio but have nowhere to write it", bytes_read);
-		return TRUE;
-	}
-
-	total_bytes_written = bytes_written = 0;
-	err = G_IO_ERROR_NONE;
-
-	while (err == G_IO_ERROR_NONE && total_bytes_written < bytes_read) {
-		/* FIXME: make it async */
-		err = g_io_channel_write(hs->audio_output, buf + total_bytes_written, 
-					bytes_read - total_bytes_written, &bytes_written);
-		if (err != G_IO_ERROR_NONE) {
-			error("Error while writting to the audio output channel");
-		}
-		total_bytes_written += bytes_written;
-	};
-
-	return TRUE;
-
-disconn:
-	error("Audio connection got disconnected");
-	if (hs->sco)
-		close_sco(hs);
-	return FALSE;
+			return err;
+		total_written += written;
+	}
+
+	return G_IO_ERROR_NONE;
 }
 
 static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond,
-				struct headset *hs)
-{
+				struct device *device)
+{
+	struct headset *hs;
 	int ret, sk, err, flags;
 	socklen_t len;
 	DBusMessage *reply;
+	char str[13];
 
 	if (cond & G_IO_NVAL)
 		return FALSE;
 
-	assert(hs != NULL && hs->pending_connect != NULL && 
-		hs->sco == NULL && hs->state == HEADSET_STATE_PLAY_IN_PROGRESS);
+	hs = device->headset;
+
+	assert(hs != NULL);
+	assert(hs->pending_connect != NULL);
+	assert(hs->sco == NULL);
+	assert(hs->state == HEADSET_STATE_PLAY_IN_PROGRESS);
 
 	sk = g_io_channel_unix_get_fd(chan);
 
@@ -611,38 +366,52 @@
 		goto failed;
 	}
 
-	debug("SCO socket opened for headset %s", hs->object_path);
-
+	debug("SCO socket opened for headset %s", device->path);
+
+	info("SCO fd=%d", sk);
 	hs->sco = chan;
 	hs->pending_connect->io = NULL;
 
 	flags = G_IO_ERR | G_IO_HUP | G_IO_NVAL;
-	if (hs->audio_output)
-		flags |= G_IO_IN;
-
-	g_io_add_watch(hs->sco, flags, sco_input_to_audio_output_cb, hs);
-
-	reply = dbus_message_new_method_return(hs->pending_connect->msg);
-	if (reply)
-		send_message_and_unref(connection, reply);
-
-	/* FIXME: do we allow both? pull & push model at the same time on sco && audio_input? */
-	if (hs->audio_input)
-		g_io_add_watch(hs->audio_input, G_IO_IN | G_IO_NVAL,
-				audio_input_to_sco_cb, hs);
+
+	g_io_add_watch(hs->sco, flags, (GIOFunc) sco_cb, device);
+
+	if (hs->pending_connect->msg) {
+		reply = dbus_message_new_method_return(hs->pending_connect->msg);
+		if (reply)
+			send_message_and_unref(device->conn, reply);
+	}
+	else if (hs->pending_connect->pkt) {
+		headset_get_config(device, hs->pending_connect->sock,
+			hs->pending_connect->pkt);
+		unix_send_cfg(hs->pending_connect->sock,
+			hs->pending_connect->pkt);
+	}
 
 	pending_connect_free(hs->pending_connect);
 	hs->pending_connect = NULL;
 
+	fcntl(sk, F_SETFL, 0);
+
 	hs->state = HEADSET_STATE_PLAYING;
-	dbus_connection_emit_signal(connection, hs->object_path,
+	dbus_connection_emit_signal(device->conn, device->path,
 					AUDIO_HEADSET_INTERFACE,
 					"Playing", DBUS_TYPE_INVALID);
 
+	if (hs->sp_gain >= 0) {
+		snprintf(str, sizeof(str) - 1, "\r\n+VGS=%u\r\n", hs->sp_gain);
+		headset_send(device->headset, str);
+	}
+
+	if (hs->mic_gain >= 0) {
+		snprintf(str, sizeof(str) - 1, "\r\n+VGM=%u\r\n", hs->sp_gain);
+		headset_send(device->headset, str);
+	}
+
 	return FALSE;
 
 failed:
-	err_connect_failed(connection, hs->pending_connect->msg, err);
+	err_connect_failed(device->conn, hs->pending_connect->msg, strerror(err));
 	if (hs->pending_connect->io)
 		g_io_channel_close(hs->pending_connect->io);
 	pending_connect_free(hs->pending_connect);
@@ -654,18 +423,87 @@
 	return FALSE;
 }
 
-static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, struct headset *hs)
-{
+static int sco_connect(struct device *device, struct pending_connect *c)
+{
+	struct headset *hs = device->headset;
+	struct sockaddr_sco addr;
+	gboolean do_callback = FALSE;
+	int sk, err;
+
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+	if (sk < 0) {
+		err = errno;
+		error("socket(BTPROTO_SCO): %s (%d)", strerror(err), err);
+		return -err;
+	}
+
+	c->io = g_io_channel_unix_new(sk);
+	if (!c->io) {
+		close(sk);
+		return -EINVAL;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sco_family = AF_BLUETOOTH;
+	bacpy(&addr.sco_bdaddr, BDADDR_ANY);
+
+	if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+		err = errno;
+		error("socket(BTPROTO_SCO): %s (%d)", strerror(err), err);
+		return -err;
+	}
+
+	if (set_nonblocking(sk) < 0) {
+		err = errno;
+		return -err;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sco_family = AF_BLUETOOTH;
+	bacpy(&addr.sco_bdaddr, &device->dst);
+
+	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		if (!(errno == EAGAIN || errno == EINPROGRESS)) {
+			err = errno;
+			error("connect: %s (%d)", strerror(errno), errno);
+			return -err;
+		}
+
+		debug("SCO connect in progress");
+		c->io_id = g_io_add_watch(c->io,
+					G_IO_OUT | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
+					(GIOFunc) sco_connect_cb, device);
+	} else {
+		debug("SCO connect succeeded with first try");
+		do_callback = TRUE;
+	}
+
+	hs->state = HEADSET_STATE_PLAY_IN_PROGRESS;
+	hs->pending_connect = c;
+
+	if (do_callback)
+		sco_connect_cb(c->io, G_IO_OUT, device);
+
+	return 0;
+}
+
+static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond,
+					struct device *device)
+{
+	struct headset *hs;
 	char hs_address[18];
 	int sk, ret, err;
 	socklen_t len;
-	
+
 	if (cond & G_IO_NVAL)
 		return FALSE;
 
-	assert(hs != NULL && hs->pending_connect != NULL && 
-			hs->rfcomm == NULL &&
-			hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS);
+	hs = device->headset;
+
+	assert(hs != NULL);
+	assert(hs->pending_connect != NULL);
+	assert(hs->rfcomm == NULL);
+	assert(hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS);
 
 	sk = g_io_channel_unix_get_fd(chan);
 
@@ -682,26 +520,26 @@
 		goto failed;
 	}
 
-	ba2str(&hs->bda, hs_address);
+	ba2str(&device->dst, hs_address);
 	hs->rfcomm = chan;
 	hs->pending_connect->io = NULL;
 
 	hs->state = HEADSET_STATE_CONNECTED;
-	dbus_connection_emit_signal(connection, hs->object_path,
+	dbus_connection_emit_signal(device->conn, device->path,
 					AUDIO_HEADSET_INTERFACE,
 					"Connected", DBUS_TYPE_INVALID);
 
 	debug("Connected to %s", hs_address);
 
 	g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
-			(GIOFunc) rfcomm_io_cb, hs);
+			(GIOFunc) rfcomm_io_cb, device);
 
 	if (hs->pending_connect->msg) {
 		DBusMessage *reply;
 
 		reply = dbus_message_new_method_return(hs->pending_connect->msg);
 		if (reply)
-			send_message_and_unref(connection, reply);
+			send_message_and_unref(device->conn, reply);
 	}
 
 	pending_connect_free(hs->pending_connect);
@@ -710,7 +548,7 @@
 	return FALSE;
 
 failed:
-	err_connect_failed(connection, hs->pending_connect->msg, err);
+	err_connect_failed(device->conn, hs->pending_connect->msg, strerror(err));
 	if (hs->pending_connect->io)
 		g_io_channel_close(hs->pending_connect->io);
 	pending_connect_free(hs->pending_connect);
@@ -721,18 +559,20 @@
 	return FALSE;
 }
 
-static int rfcomm_connect(struct headset *hs, int *err)
-{
+static int rfcomm_connect(struct device *device, int *err)
+{
+	struct headset *hs = device->headset;
 	struct sockaddr_rc addr;
 	char address[18];
 	int sk;
 
-	assert(hs != NULL && hs->pending_connect != NULL && 
-			hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS);
-
-	ba2str(&hs->bda, address);
-
-	debug("Connecting to %s channel %d", address, hs->pending_connect->ch);
+	assert(hs != NULL);
+	assert(hs->pending_connect != NULL);
+	assert(hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS);
+
+	ba2str(&device->dst, address);
+
+	debug("Connecting to %s channel %d", address, hs->rfcomm_ch);
 
 	sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
 	if (sk < 0) {
@@ -755,17 +595,20 @@
 	}
 
 	if (set_nonblocking(sk) < 0) {
-		*err = errno;
+		if (err)
+			*err = errno;
 		goto failed;
 	}
 
 	memset(&addr, 0, sizeof(addr));
 	addr.rc_family = AF_BLUETOOTH;
-	bacpy(&addr.rc_bdaddr, &hs->bda);
-	addr.rc_channel = hs->pending_connect->ch;
+	bacpy(&addr.rc_bdaddr, &device->dst);
+	addr.rc_channel = hs->rfcomm_ch;
 
 	hs->pending_connect->io = g_io_channel_unix_new(sk);
 	if (!hs->pending_connect->io) {
+		if (err)
+			*err = ENOMEM;
 		error("channel_unix_new failed in rfcomm connect");
 		goto failed;
 	}
@@ -774,17 +617,18 @@
 		if (!(errno == EAGAIN || errno == EINPROGRESS)) {
 			if (err)
 				*err = errno;
-			error("connect() failed: %s (%d)", strerror(errno), errno);
+			error("connect() failed: %s (%d)", strerror(errno),
+					errno);
 			goto failed;
 		}
 
 		debug("Connect in progress");
 
 		g_io_add_watch(hs->pending_connect->io, G_IO_OUT | G_IO_NVAL,
-				(GIOFunc) rfcomm_connect_cb, hs);
+				(GIOFunc) rfcomm_connect_cb, device);
 	} else {
 		debug("Connect succeeded with first try");
-		rfcomm_connect_cb(hs->pending_connect->io, G_IO_OUT, hs);
+		rfcomm_connect_cb(hs->pending_connect->io, G_IO_OUT, device);
 	}
 
 	return 0;
@@ -796,200 +640,23 @@
 	return -1;
 }
 
-static int create_ag_record(sdp_buf_t *buf, uint8_t ch)
-{
-	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-	uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
-	sdp_profile_desc_t profile;
-	sdp_list_t *aproto, *proto[2];
-	sdp_record_t record;
-	sdp_data_t *channel;
-	int ret;
-
-	memset(&record, 0, sizeof(sdp_record_t));
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
-	sdp_set_browse_groups(&record, root);
-
-	sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &svclass_uuid);
-	sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
-	svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
-	sdp_set_service_classes(&record, svclass_id);
-
-	sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
-	profile.version = 0x0100;
-	pfseq = sdp_list_append(0, &profile);
-	sdp_set_profile_descs(&record, pfseq);
-
-	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
-	apseq = sdp_list_append(0, proto[0]);
-
-	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-	proto[1] = sdp_list_append(0, &rfcomm_uuid);
-	channel = sdp_data_alloc(SDP_UINT8, &ch);
-	proto[1] = sdp_list_append(proto[1], channel);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(0, apseq);
-	sdp_set_access_protos(&record, aproto);
-
-	sdp_set_info_attr(&record, "Headset", 0, 0);
-
-	if (sdp_gen_record_pdu(&record, buf) < 0)
-		ret = -1;
-	else
-		ret = 0;
-
-	sdp_data_free(channel);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(pfseq, 0);
-	sdp_list_free(aproto, 0);
-	sdp_list_free(root, 0);
-	sdp_list_free(svclass_id, 0);
-	sdp_list_free(record.attrlist, (sdp_free_func_t) sdp_data_free);
-	sdp_list_free(record.pattern, free);
-
-	return ret;
-}
-
-static uint32_t headset_add_ag_record(uint8_t channel)
-{
-	DBusMessage *msg, *reply;
-	DBusError derr;
-	dbus_uint32_t rec_id;
-	sdp_buf_t buf;
-
-	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
-				"org.bluez.Database", "AddServiceRecord");
-	if (!msg) {
-		error("Can't allocate new method call");
-		return 0;
-	}
-
-	if (create_ag_record(&buf, channel) < 0) {
-		error("Unable to allocate new service record");
-		dbus_message_unref(msg);
-		return 0;
-	}
-
-	dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
-				&buf.data, buf.data_size, DBUS_TYPE_INVALID);
-
-	dbus_error_init(&derr);
-	reply = dbus_connection_send_with_reply_and_block(connection, msg,
-								-1, &derr);
-
-	free(buf.data);
-	dbus_message_unref(msg);
-
-	if (dbus_error_is_set(&derr) || dbus_set_error_from_message(&derr, reply)) {
-		error("Adding service record failed: %s", derr.message);
-		dbus_error_free(&derr);
-		return 0;
-	}
-
-	dbus_message_get_args(reply, &derr, DBUS_TYPE_UINT32, &rec_id,
-				DBUS_TYPE_INVALID);
-
-	if (dbus_error_is_set(&derr)) {
-		error("Invalid arguments to AddServiceRecord reply: %s", derr.message);
-		dbus_message_unref(reply);
-		dbus_error_free(&derr);
-		return 0;
-	}
-
-	dbus_message_unref(reply);
-
-	debug("add_ag_record: got record id 0x%x", rec_id);
-
-	return rec_id;
-}
-
-int headset_remove_ag_record(uint32_t rec_id)
-{
-	DBusMessage *msg, *reply;
-	DBusError derr;
-
-	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
-				"org.bluez.Database", "RemoveServiceRecord");
-	if (!msg) {
-		error("Can't allocate new method call");
-		return 0;
-	}
-
-	dbus_message_append_args(msg, DBUS_TYPE_UINT32, &rec_id,
-						DBUS_TYPE_INVALID);
-
-	dbus_error_init(&derr);
-	reply = dbus_connection_send_with_reply_and_block(connection, msg,
-								-1, &derr);
-
-	dbus_message_unref(msg);
-
-	if (dbus_error_is_set(&derr)) {
-		error("Removing service record 0x%x failed: %s", rec_id, derr.message);
-		dbus_error_free(&derr);
-		return 0;
-	}
-
-	dbus_message_unref(reply);
-
-	return 0;
-}
-
-static void finish_sdp_transaction(bdaddr_t *dba) 
-{
-	char address[18], *addr_ptr = address;
-	DBusMessage *msg, *reply;
-	DBusError derr;
-
-	ba2str(dba, address);
-
-	msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0",
-						"org.bluez.Adapter",
-						"FinishRemoteServiceTransaction");
-	if (!msg) {
-		error("Unable to allocate new method call");
-		return;
-	}
-
-	dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,
-					DBUS_TYPE_INVALID);
-
-	dbus_error_init(&derr);
-	reply = dbus_connection_send_with_reply_and_block(connection, msg,
-								-1, &derr);
-
-	dbus_message_unref(msg);
-
-	if (dbus_error_is_set(&derr) || dbus_set_error_from_message(&derr, reply)) {
-		error("FinishRemoteServiceTransaction(%s) failed: %s",
-				address, derr.message);
-		dbus_error_free(&derr);
-		return;
-	}
-
-	dbus_message_unref(reply);
-}
-
 static void get_record_reply(DBusPendingCall *call, void *data)
 {
 	DBusMessage *reply;
 	DBusError derr;
 	uint8_t *array;
-	int array_len, record_len, err = EIO;
+	int array_len, record_len, err = EIO, ch = -1;
 	sdp_record_t *record = NULL;
 	sdp_list_t *protos, *classes = NULL;
 	uuid_t uuid;
-	struct headset *hs = data;
+	struct device *device = data;
+	struct headset *hs = device->headset;
 	struct pending_connect *c;
 
-	assert(hs != NULL && hs->pending_connect && !hs->rfcomm);
+	assert(hs != NULL);
+	assert(hs->pending_connect);
+	assert(!hs->rfcomm);
+
 	c = hs->pending_connect;
 
 	reply = dbus_pending_call_steal_reply(call);
@@ -1002,14 +669,15 @@
 	}
 
 	if (!dbus_message_get_args(reply, NULL,
-				DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &array, &array_len,
+				DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+				&array, &array_len,
 				DBUS_TYPE_INVALID)) {
 		error("Unable to get args from GetRecordReply");
 		goto failed_not_supported;
 	}
 
 	if (!array) {
-		error("Unable to get handle array from reply");
+		error("get_record_reply: Unable to get handle array from reply");
 		goto failed_not_supported;
 	}
 
@@ -1035,28 +703,33 @@
 		goto failed_not_supported;
 	}
 
-	if ((uuid.type == SDP_UUID32 && uuid.value.uuid32 != HEADSET_SVCLASS_ID) ||
-			(uuid.type == SDP_UUID16 && uuid.value.uuid16 != HEADSET_SVCLASS_ID)) {
+	if ((uuid.type == SDP_UUID32 &&
+			uuid.value.uuid32 != HEADSET_SVCLASS_ID) ||
+			(uuid.type == SDP_UUID16 &&
+			 uuid.value.uuid16 != HEADSET_SVCLASS_ID)) {
 		error("Service classes did not contain the expected UUID");
 		goto failed_not_supported;
 	}
 
 	if (!sdp_get_access_protos(record, &protos)) {
-		c->ch = sdp_get_proto_port(protos, RFCOMM_UUID);
-		sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+		ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+		sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free,
+					NULL);
 		sdp_list_free(protos, NULL);
 		protos = NULL;
 	}
 
-	if (c->ch == -1) {
+	if (ch == -1) {
 		error("Unable to extract RFCOMM channel from service record");
 		goto failed_not_supported;
 	}
 
-	if (rfcomm_connect(hs, &err) < 0) {
+	hs->rfcomm_ch = ch;
+
+	if (rfcomm_connect(device, &err) < 0) {
 		error("Unable to connect");
-		if (c->msg) 
-			err_connect_failed(connection, c->msg, err);
+		if (c->msg)
+			err_connect_failed(device->conn, c->msg, strerror(err));
 		goto failed;
 	}
 
@@ -1064,13 +737,13 @@
 	sdp_record_free(record);
 	dbus_message_unref(reply);
 
-	finish_sdp_transaction(&hs->bda);
+	device_finish_sdp_transaction(device);
 
 	return;
 
 failed_not_supported:
-	if (c->msg) 
-		err_not_supported(connection, c->msg);
+	if (c->msg)
+		err_not_supported(device->conn, c->msg);
 failed:
 	if (classes)
 		sdp_list_free(classes, free);
@@ -1081,17 +754,18 @@
 	pending_connect_free(hs->pending_connect);
 	hs->pending_connect = NULL;
 	hs->state = HEADSET_STATE_DISCONNECTED;
-	finish_sdp_transaction(&hs->bda);
+	device_finish_sdp_transaction(device);
 }
 
 static DBusHandlerResult hs_stop(DBusConnection *conn, DBusMessage *msg,
 					void *data)
 {
-	struct headset *hs = data;
+	struct device *device = data;
+	struct headset *hs = device->headset;
 	DBusMessage *reply = NULL;
 
 	if (!hs || !hs->sco)
-		return err_not_connected(connection, msg);
+		return err_not_connected(conn, msg);
 
 	if (msg) {
 		reply = dbus_message_new_method_return(msg);
@@ -1099,20 +773,21 @@
 			return DBUS_HANDLER_RESULT_NEED_MEMORY;
 	}
 
-	if (hs->state == HEADSET_STATE_PLAY_IN_PROGRESS && hs->pending_connect) {
+	if (hs->state == HEADSET_STATE_PLAY_IN_PROGRESS &&
+			hs->pending_connect) {
 		g_io_channel_close(hs->pending_connect->io);
 		if (hs->pending_connect->msg)
-			err_connect_failed(connection, hs->pending_connect->msg,
-						EINTR);
+			err_connect_failed(conn, hs->pending_connect->msg,
+						strerror(EINTR));
 		pending_connect_free(hs->pending_connect);
 		hs->pending_connect = NULL;
 		hs->state = HEADSET_STATE_CONNECTED;
 	}
 
-	close_sco(hs);
+	close_sco(device);
 
 	if (reply)
-		send_message_and_unref(connection, reply);
+		send_message_and_unref(conn, reply);
 
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
@@ -1120,7 +795,8 @@
 static DBusHandlerResult hs_is_playing(DBusConnection *conn, DBusMessage *msg,
 					void *data)
 {
-	struct headset *hs = data;
+	struct device *device = data;
+	struct headset *hs = device->headset;
 	DBusMessage *reply;
 	dbus_bool_t playing;
 
@@ -1138,7 +814,7 @@
 	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &playing,
 					DBUS_TYPE_INVALID);
 
-	send_message_and_unref(connection, reply);
+	send_message_and_unref(conn, reply);
 	
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
@@ -1146,7 +822,8 @@
 static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg,
 					void *data)
 {
-	struct headset *hs = data;
+	struct device *device = data;
+	struct headset *hs = device->headset;
 	DBusMessage *reply = NULL;
 	char hs_address[18];
 
@@ -1159,7 +836,12 @@
 	}
 
 	if (hs->state > HEADSET_STATE_CONNECTED)
-		hs_stop(NULL, NULL, hs);
+		hs_stop(NULL, NULL, device);
+
+	if (hs->ring_timer) {
+		g_source_remove(hs->ring_timer);
+		hs->ring_timer = 0;
+	}
 
 	if (hs->rfcomm) {
 		g_io_channel_close(hs->rfcomm);
@@ -1170,19 +852,22 @@
 	if (hs->pending_connect) {
 		if (hs->pending_connect->io)
 			g_io_channel_close(hs->pending_connect->io);
+		if (hs->pending_connect->io_id)
+			g_source_remove(hs->pending_connect->io_id);
 		if (hs->pending_connect->msg)
-			err_connect_failed(connection, hs->pending_connect->msg,
-						EINTR);
+			err_connect_failed(conn,
+						hs->pending_connect->msg,
+						strerror(EINTR));
 		pending_connect_free(hs->pending_connect);
 		hs->pending_connect = NULL;
 	}
 
 	hs->state = HEADSET_STATE_DISCONNECTED;
 
-	ba2str(&hs->bda, hs_address);
-	info("Disconnected from %s, %s", &hs_address, hs->object_path);
-
-	dbus_connection_emit_signal(connection, hs->object_path,
+	ba2str(&device->dst, hs_address);
+	info("Disconnected from %s, %s", hs_address, device->path);
+
+	dbus_connection_emit_signal(device->conn, device->path,
 					AUDIO_HEADSET_INTERFACE,
 					"Disconnected", DBUS_TYPE_INVALID);
 
@@ -1190,33 +875,29 @@
 	hs->data_length = 0;
 
 	if (reply)
-		send_message_and_unref(connection, reply);
+		send_message_and_unref(conn, reply);
 	
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
-static DBusHandlerResult hs_is_connected(DBusConnection *conn, DBusMessage *msg,
+static DBusHandlerResult hs_is_connected(DBusConnection *conn,
+						DBusMessage *msg,
 						void *data)
 {
-	struct headset *hs = data;
+	struct device *device = data;
 	DBusMessage *reply;
 	dbus_bool_t connected;
-
-	assert(hs);
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-	if (hs->state >= HEADSET_STATE_CONNECTED)
-		connected = TRUE;
-	else
-		connected = FALSE;
+	connected = (device->headset->state >= HEADSET_STATE_CONNECTED);
 
 	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
 					DBUS_TYPE_INVALID);
 
-	send_message_and_unref(connection, reply);
+	send_message_and_unref(conn, reply);
 	
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
@@ -1226,14 +907,17 @@
 	DBusMessage *msg = NULL, *reply;
 	DBusPendingCall *pending;
 	DBusError derr;
-	struct headset *hs = data;
+	struct device *device = data;
+	struct headset *hs = device->headset;
 	struct pending_connect *c;
 	char address[18], *addr_ptr = address;
 	dbus_uint32_t *array = NULL;
 	dbus_uint32_t handle;
 	int array_len;
 
-	assert(hs != NULL && hs->pending_connect);
+	assert(hs != NULL);
+	assert(hs->pending_connect);
+
 	c = hs->pending_connect;
 
 	reply = dbus_pending_call_steal_reply(call);
@@ -1242,53 +926,55 @@
 	if (dbus_set_error_from_message(&derr, reply)) {
 		error("GetRemoteServiceHandles failed: %s", derr.message);
 		if (c->msg) {
-			if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed"))
-				err_connect_failed(connection, c->msg, EHOSTDOWN);
+			if (dbus_error_has_name(&derr,
+						"org.bluez.Error.ConnectionAttemptFailed"))
+				err_connect_failed(device->conn, c->msg,
+					strerror(EHOSTDOWN));
 			else
-				err_not_supported(connection, c->msg);
+				err_not_supported(device->conn, c->msg);
 		}
 		dbus_error_free(&derr);
 		goto failed;
 	}
 
 	if (!dbus_message_get_args(reply, NULL,
-				DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &array, &array_len,
+				DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+				&array, &array_len,
 				DBUS_TYPE_INVALID)) {
-	  
 		error("Unable to get args from reply");
+		if (c->msg)
+			err_not_supported(device->conn, c->msg);
+		goto failed;
+	}
+
+	if (!array) {
+		error("get_handles_reply: Unable to get handle array from reply");
 		if (c->msg) 
-			err_not_supported(connection, c->msg);
-		goto failed;
-	}
-
-	if (!array) {
-		error("Unable to get handle array from reply");
-		if (c->msg) 
-			err_not_supported(connection, c->msg);
+			err_not_supported(device->conn, c->msg);
 		goto failed;
 	}
 
 	if (array_len < 1) {
 		debug("No record handles found");
 		if (c->msg) 
-			err_not_supported(connection, c->msg);
+			err_not_supported(device->conn, c->msg);
 		goto failed;
 	}
 
 	if (array_len > 1)
 		debug("Multiple records found. Using the first one.");
 
-	msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0",
+	msg = dbus_message_new_method_call("org.bluez", device->adapter_path,
 						"org.bluez.Adapter",
 						"GetRemoteServiceRecord");
 	if (!msg) {
 		error("Unable to allocate new method call");
-		if (c->msg) 
-			err_connect_failed(connection, c->msg, ENOMEM);
-		goto failed;
-	}
-
-	ba2str(&hs->bda, address);
+		if (c->msg)
+			err_connect_failed(device->conn, c->msg, strerror(ENOMEM));
+		goto failed;
+	}
+
+	ba2str(&device->dst, address);
 
 	handle = array[0];
 
@@ -1296,14 +982,14 @@
 					DBUS_TYPE_UINT32, &handle,
 					DBUS_TYPE_INVALID);
 
-	if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) {
+	if (!dbus_connection_send_with_reply(device->conn, msg, &pending, -1)) {
 		error("Sending GetRemoteServiceRecord failed");
 		if (c->msg) 
-			err_connect_failed(connection, c->msg, EIO);
-		goto failed;
-	}
-
-	dbus_pending_call_set_notify(pending, get_record_reply, hs, NULL);
+			err_connect_failed(device->conn, c->msg, strerror(EIO));
+		goto failed;
+	}
+
+	dbus_pending_call_set_notify(pending, get_record_reply, device, NULL);
 	dbus_pending_call_unref(pending);
 	dbus_message_unref(msg);
 	dbus_message_unref(reply);
@@ -1314,26 +1000,28 @@
 	if (msg)
 		dbus_message_unref(msg);
 	dbus_message_unref(reply);
-	hs_disconnect(NULL, NULL, hs);
+	hs_disconnect(NULL, NULL, device);
 }
 
 static DBusHandlerResult hs_connect(DBusConnection *conn, DBusMessage *msg,
 					void *data)
 {
 	DBusPendingCall *pending;
-	struct headset *hs = data;
-	const char *hs_svc = "hsp";
+	struct device *device = data;
+	struct headset *hs = device->headset;
+	const char *hs_svc;
 	const char *addr_ptr;
 	char hs_address[18];
+	int err;
 
 	assert(hs != NULL);
 
 	if (hs->state > HEADSET_STATE_DISCONNECTED || hs->pending_connect)
-		return err_already_connected(connection, msg);
+		return err_already_connected(conn, msg);
 
 	hs->pending_connect = g_try_new0(struct pending_connect, 1);
 	if (!hs->pending_connect) {
-		error("Out of memory when allocating new struct pending_connect");
+		error("Out of memory when allocating struct pending_connect");
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 	}
 
@@ -1341,7 +1029,20 @@
 
 	hs->pending_connect->msg = msg ? dbus_message_ref(msg) : NULL;
 
-	msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0",
+	hs->type = hs->hfp_handle ? SVC_HANDSFREE : SVC_HEADSET;
+
+	if (hs->rfcomm_ch > 0) {
+	       	if (rfcomm_connect(device, &err) < 0) {
+			error("Unable to connect");
+			pending_connect_free(hs->pending_connect);
+			hs->pending_connect = NULL;
+			hs->state = HEADSET_STATE_DISCONNECTED;
+			return err_connect_failed(conn, msg, strerror(err));
+		} else
+			return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	msg = dbus_message_new_method_call("org.bluez", device->adapter_path,
 						"org.bluez.Adapter",
 						"GetRemoteServiceHandles");
 	if (!msg) {
@@ -1352,61 +1053,40 @@
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 	}
 
-	ba2str(&hs->bda, hs_address);
+	if (hs->type == SVC_HEADSET)
+		hs_svc = "hsp";
+	else
+		hs_svc = "hfp";
+
+	ba2str(&device->dst, hs_address);
 	addr_ptr = hs_address;
 	dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,
 					DBUS_TYPE_STRING, &hs_svc,
 					DBUS_TYPE_INVALID);
 
-	if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) {
+	if (!dbus_connection_send_with_reply(conn, msg, &pending, -1)) {
 		error("Sending GetRemoteServiceHandles failed");
 		pending_connect_free(hs->pending_connect);
 		hs->pending_connect = NULL;
 		hs->state = HEADSET_STATE_DISCONNECTED;
 		dbus_message_unref(msg);
-		return err_connect_failed(connection, msg, EIO);
-	}
-
-	dbus_pending_call_set_notify(pending, get_handles_reply, hs, NULL);
+		return err_connect_failed(conn, msg, strerror(EIO));
+	}
+
+	dbus_pending_call_set_notify(pending, get_handles_reply, device, NULL);
 	dbus_pending_call_unref(pending);
 	dbus_message_unref(msg);
 
 	return DBUS_HANDLER_RESULT_HANDLED;;
 }
 
-static GIOError headset_send_ring(struct headset *hs)
-{
-	const char *ring_str = "\r\nRING\r\n";
-	GIOError err;
-	gsize total_written, written, count;
-
-	assert(hs != NULL);
-	if (hs->state < HEADSET_STATE_CONNECTED || !hs->rfcomm) {
-		error("the headset %s is not connected", hs->object_path);
-		return G_IO_ERROR_UNKNOWN;
-	}
-
-	count = strlen(ring_str);
-	written = total_written = 0;
-
-	while (total_written < count) {
-		err = g_io_channel_write(hs->rfcomm, ring_str + total_written,
-					count - total_written, &written);
-		if (err != G_IO_ERROR_NONE)
-			return err;
-		total_written += written;
-	}
-
-	return G_IO_ERROR_NONE;
-}
-
 static gboolean ring_timer_cb(gpointer data)
 {
-	struct headset *hs = data;
-
-	assert(hs != NULL);
-
-	if (headset_send_ring(hs) != G_IO_ERROR_NONE)
+	struct device *device = data;
+
+	assert(device != NULL);
+
+	if (headset_send(device->headset, "\r\nRING\r\n") != G_IO_ERROR_NONE)
 		error("Sending RING failed");
 
 	return TRUE;
@@ -1415,13 +1095,14 @@
 static DBusHandlerResult hs_ring(DBusConnection *conn, DBusMessage *msg,
 					void *data)
 {
-	struct headset *hs = data;
+	struct device *device = data;
+	struct headset *hs = device->headset;
 	DBusMessage *reply = NULL;
 
 	assert(hs != NULL);
 
 	if (hs->state < HEADSET_STATE_CONNECTED)
-		return err_not_connected(connection, msg);
+		return err_not_connected(conn, msg);
 
 	if (msg) {
 		reply = dbus_message_new_method_return(msg);
@@ -1430,32 +1111,34 @@
 	}
 
 	if (hs->ring_timer) {
-		debug("Got Ring method call while ringing already in progress");
+		debug("IndicateCall received when already indicating");
 		goto done;
 	}
 
-	if (headset_send_ring(hs) != G_IO_ERROR_NONE) {
+	if (headset_send(device->headset, "\r\nRING\r\n") != G_IO_ERROR_NONE) {
 		dbus_message_unref(reply);
-		return err_failed(connection, msg);
-	}
-
-	hs->ring_timer = g_timeout_add(RING_INTERVAL, ring_timer_cb, hs);
+		return err_failed(conn, msg, "Failed");
+	}
+
+	hs->ring_timer = g_timeout_add(RING_INTERVAL, ring_timer_cb, device);
 
 done:
 	if (reply)
-		send_message_and_unref(connection, reply);
+		send_message_and_unref(conn, reply);
 
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
-static DBusHandlerResult hs_cancel_ringing(DBusConnection *conn, DBusMessage *msg,
+static DBusHandlerResult hs_cancel_ringing(DBusConnection *conn,
+						DBusMessage *msg,
 						void *data)
 {
-	struct headset *hs = data;
+	struct device *device = data;
+	struct headset *hs = device->headset;
 	DBusMessage *reply = NULL;
 
 	if (hs->state < HEADSET_STATE_CONNECTED)
-		return err_not_connected(connection, msg);
+		return err_not_connected(conn, msg);
 
 	if (msg) {
 		reply = dbus_message_new_method_return(msg);
@@ -1473,7 +1156,7 @@
 
 done:
 	if (reply)
-		send_message_and_unref(connection, reply);
+		send_message_and_unref(conn, reply);
 
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
@@ -1481,89 +1164,171 @@
 static DBusHandlerResult hs_play(DBusConnection *conn, DBusMessage *msg,
 					void *data)
 {
-	struct headset *hs = data;
-	struct sockaddr_sco addr;
+	struct device *device = data;
+	struct headset *hs = device->headset;
 	struct pending_connect *c;
-	int sk, err;
 
 	if (hs->state < HEADSET_STATE_CONNECTED)
-		return err_not_connected(connection, msg); /* FIXME: in progress error? */
+		return err_not_connected(conn, msg);
 
 	if (hs->state >= HEADSET_STATE_PLAY_IN_PROGRESS || hs->pending_connect)
-		return err_already_connected(connection, msg);
+		return err_already_connected(conn, msg);
 
 	if (hs->sco)
-		return err_already_connected(connection, msg);
+		return err_already_connected(conn, msg);
 
 	c = g_try_new0(struct pending_connect, 1);
 	if (!c)
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-	hs->state = HEADSET_STATE_PLAY_IN_PROGRESS;
-
 	c->msg = msg ? dbus_message_ref(msg) : NULL;
 
-	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
-	if (sk < 0) {
-		err = errno;
-		error("socket(BTPROTO_SCO): %s (%d)", strerror(err), err);
-		err_connect_failed(connection, msg, err);
-		goto failed;
-	}
-
-	c->io = g_io_channel_unix_new(sk);
-	if (!c->io) {
-		close(sk);
-		pending_connect_free(c);
-		return DBUS_HANDLER_RESULT_NEED_MEMORY;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.sco_family = AF_BLUETOOTH;
-	bacpy(&addr.sco_bdaddr, BDADDR_ANY);
-
-	if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-		err = errno;
-		error("socket(BTPROTO_SCO): %s (%d)", strerror(err), err);
-		err_connect_failed(connection, msg, err);
-		goto failed;
-	}
-
-	if (set_nonblocking(sk) < 0) {
-		err = errno;
-		err_connect_failed(connection, msg, err);
-		goto failed;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.sco_family = AF_BLUETOOTH;
-	bacpy(&addr.sco_bdaddr, &hs->bda);
-
-	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		if (!(errno == EAGAIN || errno == EINPROGRESS)) {
-			err = errno;
-			error("connect: %s (%d)", strerror(errno), errno);
-			goto failed;
-		}
-
-		debug("Connect in progress");
-
-		g_io_add_watch(c->io, G_IO_OUT | G_IO_NVAL,
-				(GIOFunc) sco_connect_cb, hs);
-	} else {
-		debug("Connect succeeded with first try");
-		sco_connect_cb(c->io, G_IO_OUT, hs);
-	}
-
-	hs->pending_connect = c;
+	if (sco_connect(device, c) < 0)
+		goto failed;
 
 	return 0;
-
 failed:
 	if (c)
 		pending_connect_free(c);
 
 	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult hs_get_speaker_gain(DBusConnection *conn,
+						DBusMessage *msg,
+						void *data)
+{
+	struct device *device = data;
+	struct headset *hs = device->headset;
+	DBusMessage *reply;
+	dbus_uint16_t gain;
+
+	assert(hs);
+
+	if (hs->state < HEADSET_STATE_CONNECTED || hs->sp_gain < 0)
+		return err_not_available(conn, msg);
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	gain = (dbus_uint16_t) hs->sp_gain;
+
+	dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
+					DBUS_TYPE_INVALID);
+
+	send_message_and_unref(conn, reply);
+	
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult hs_get_mic_gain(DBusConnection *conn,
+						DBusMessage *msg,
+						void *data)
+{
+	struct device *device = data;
+	struct headset *hs = device->headset;
+	DBusMessage *reply;
+	dbus_uint16_t gain;
+
+	assert(hs);
+
+	if (hs->state < HEADSET_STATE_CONNECTED || hs->mic_gain < 0)
+		return err_not_available(conn, msg);
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	gain = (dbus_uint16_t) hs->mic_gain;
+
+	dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
+					DBUS_TYPE_INVALID);
+
+	send_message_and_unref(conn, reply);
+	
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult hs_set_gain(DBusConnection *conn,
+					DBusMessage *msg,
+					void *data, char type)
+{
+	struct device *device = data;
+	struct headset *hs = device->headset;
+	DBusMessage *reply;
+	DBusError derr;
+	dbus_uint16_t gain;
+	char str[13];
+
+	assert(hs);
+
+	if (hs->state < HEADSET_STATE_CONNECTED)
+		return err_not_connected(conn, msg);
+
+	dbus_error_init(&derr);
+	dbus_message_get_args(msg, &derr, DBUS_TYPE_UINT16, &gain,
+				DBUS_TYPE_INVALID);
+
+	if (dbus_error_is_set(&derr)) {
+		err_invalid_args(conn, msg, derr.message);
+		dbus_error_free(&derr);
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	if (gain > 15)
+		return err_invalid_args(conn, msg,
+					"Must be less than or equal to 15");
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	if (hs->state != HEADSET_STATE_PLAYING)
+		goto done;
+
+	snprintf(str, sizeof(str) - 1, "\r\n+VG%c=%u\r\n", type, gain);
+
+	if (headset_send(device->headset, str) != G_IO_ERROR_NONE) {
+		dbus_message_unref(reply);
+		return err_failed(conn, msg, "Unable to send to headset");
+	}
+
+done:
+	if (type == HEADSET_GAIN_SPEAKER) {
+		hs->sp_gain = gain;
+		dbus_connection_emit_signal(conn, device->path,
+						AUDIO_HEADSET_INTERFACE,
+						"SpeakerGainChanged",
+						DBUS_TYPE_UINT16, &gain,
+						DBUS_TYPE_INVALID);
+	}
+	else {
+		hs->mic_gain = gain;
+		dbus_connection_emit_signal(conn, device->path,
+						AUDIO_HEADSET_INTERFACE,
+						"MicrophoneGainChanged",
+						DBUS_TYPE_UINT16, &gain,
+						DBUS_TYPE_INVALID);
+	}
+
+	send_message_and_unref(conn, reply);
+	
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult hs_set_speaker_gain(DBusConnection *conn,
+						DBusMessage *msg,
+						void *data)
+{
+	return hs_set_gain(conn, msg, data, HEADSET_GAIN_SPEAKER);
+}
+
+static DBusHandlerResult hs_set_mic_gain(DBusConnection *conn,
+						DBusMessage *msg,
+						void *data)
+{
+	return hs_set_gain(conn, msg, data, HEADSET_GAIN_MICROPHONE);
 }
 
 static DBusMethodVTable headset_methods[] = {
@@ -1575,6 +1340,10 @@
 	{ "Play",		hs_play,		"",	""	},
 	{ "Stop",		hs_stop,		"",	""	},
 	{ "IsPlaying",		hs_is_playing,		"",	"b"	},
+	{ "GetSpeakerGain",	hs_get_speaker_gain,	"",	"q"	},
+	{ "GetMicrophoneGain",	hs_get_mic_gain,	"",	"q"	},
+	{ "SetSpeakerGain",	hs_set_speaker_gain,	"q",	""	},
+	{ "SetMicrophoneGain",	hs_set_mic_gain,	"q",	""	},
 	{ NULL, NULL, NULL, NULL }
 };
 
@@ -1589,275 +1358,224 @@
 	{ NULL, NULL }
 };
 
-static struct headset *headset_add_internal(const bdaddr_t *bda)
-{
-	static int headset_uid = 0;
-	struct headset *hs;
-	GSList *match;
-
-	match = g_slist_find_custom(headsets, bda, headset_bda_cmp);
-	if (match)
-		return match->data;
-
-	hs = g_try_new0(struct headset, 1);
-	if (!hs) {
-		error("Allocating new hs connection struct failed!");
+static void headset_set_channel(struct headset *headset, sdp_record_t *record)
+{
+	int ch;
+	sdp_list_t *protos;
+
+	if (sdp_get_access_protos(record, &protos) < 0) {
+		error("Unable to get access protos from headset record");
+		return;
+	}
+
+	ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+
+	sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+	sdp_list_free(protos, NULL);
+
+	if (ch > 0) {
+		headset->rfcomm_ch = ch;
+		debug("Discovered Headset service on RFCOMM channel %d", ch);
+	} else
+		error("Unable to get RFCOMM channel from Headset record");
+}
+
+void headset_update(void *device, sdp_record_t *record, uint16_t svc)
+{
+	struct headset *headset = ((struct device *) device)->headset;
+
+	switch (svc) {
+	case HANDSFREE_SVCLASS_ID:
+		if (headset->hfp_handle &&
+				(headset->hfp_handle != record->handle)) {
+			error("More than one HFP record found on device");
+			return;
+		}
+
+		headset->hfp_handle = record->handle;
+		break;
+
+	case HEADSET_SVCLASS_ID:
+		if (headset->hsp_handle &&
+				(headset->hsp_handle != record->handle)) {
+			error("More than one HSP record found on device");
+			return;
+		}
+
+		headset->hsp_handle = record->handle;
+
+		/* Ignore this record if we already have access to HFP */
+		if (headset->hfp_handle)
+			return;
+
+		break;
+
+	default:
+		debug("Invalid record passed to headset_update");
+		return;
+	}
+
+	headset_set_channel(headset, record);
+}
+
+struct headset *headset_init(void *device, sdp_record_t *record,
+			uint16_t svc)
+{
+	struct headset *headset;
+
+	headset = g_new0(struct headset, 1);
+	headset->rfcomm_ch = -1;
+	headset->sp_gain = -1;
+	headset->mic_gain = -1;
+
+	if (!record)
+		goto register_iface;
+
+	switch (svc) {
+	case HANDSFREE_SVCLASS_ID:
+		headset->hfp_handle = record->handle;
+		break;
+
+	case HEADSET_SVCLASS_ID:
+		headset->hsp_handle = record->handle;
+		break;
+
+	default:
+		debug("Invalid record passed to headset_init");
+		g_free(headset);
 		return NULL;
 	}
 
-	snprintf(hs->object_path, sizeof(hs->object_path),
-			HEADSET_PATH_BASE "%d", headset_uid++);
-
-	if (!dbus_connection_create_object_path(connection, hs->object_path,
-						hs, NULL)) {
-		error("D-Bus failed to register %s path", hs->object_path);
-		g_free(hs);
+register_iface:
+	if (!dbus_connection_register_interface(((struct device *) device)->conn,
+							((struct device *) device)->path,
+							AUDIO_HEADSET_INTERFACE,
+							headset_methods,
+							headset_signals, NULL)) {
+		g_free(headset);
 		return NULL;
 	}
 
-	if (!dbus_connection_register_interface(connection, hs->object_path,
+	if (record)
+		headset_set_channel(headset, record);
+
+	return headset;
+}
+
+void headset_free(void *device)
+{
+	struct headset *headset = ((struct device *) device)->headset;
+
+	if (headset->state != HEADSET_STATE_DISCONNECTED)
+		hs_disconnect(NULL, NULL, device);
+
+	g_free(headset);
+	headset = NULL;
+}
+
+int headset_get_config(void *device, int sock, struct ipc_packet *pkt)
+{
+	struct headset *headset = ((struct device *) device)->headset;
+	struct ipc_data_cfg *cfg = (struct ipc_data_cfg *) pkt->data;
+	int err = EINVAL;
+	struct pending_connect *c;
+
+	if (headset->sco == NULL) {
+		c = g_try_new0(struct pending_connect, 1);
+		if (c == NULL)
+			goto error;
+		c->sock = sock;
+		c->pkt = pkt;
+		if ((err = sco_connect(device, c)) < 0)
+			goto error;
+		return 0;
+	}
+
+	cfg->fd = g_io_channel_unix_get_fd(headset->sco);
+	cfg->fd_opt = CFG_FD_OPT_READWRITE;
+	cfg->encoding = 0;
+	cfg->bitpool = 0;
+	cfg->channels = 1;
+	cfg->pkt_len = 48;
+	cfg->sample_size = 2;
+	cfg->rate = 8000;
+
+	return 0;
+error:
+	cfg->fd = -1;
+	return -err;
+}
+
+headset_type_t headset_get_type(void *device)
+{
+	struct headset *headset = ((struct device *) device)->headset;
+
+	return headset->type;
+}
+
+void headset_set_type(void *device, headset_type_t type)
+{
+	struct headset *headset = ((struct device *) device)->headset;
+
+	headset->type = type;
+}
+
+int headset_connect_rfcomm(void *device, int sock)
+{
+	struct headset *headset = ((struct device *) device)->headset;
+
+	headset->rfcomm = g_io_channel_unix_new(sock);
+
+	return headset->rfcomm ? 0 : -EINVAL;
+}
+
+int headset_close_rfcomm(void *device)
+{
+	struct headset *headset = ((struct device *) device)->headset;
+
+	g_io_channel_close(headset->rfcomm);
+	g_io_channel_unref(headset->rfcomm);
+	headset->rfcomm = NULL;
+
+	return 0;
+}
+
+void headset_set_state(void *device, headset_state_t state)
+{
+	struct headset *headset = ((struct device *) device)->headset;
+
+	switch(state) {
+	case HEADSET_STATE_DISCONNECTED:
+	case HEADSET_STATE_CONNECT_IN_PROGRESS:
+		break;
+	case HEADSET_STATE_CONNECTED:
+		if (headset->rfcomm) {
+			char hs_address[18];
+
+			g_io_add_watch(headset->rfcomm,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				(GIOFunc) rfcomm_io_cb, device);
+
+			ba2str(&((struct device *) device)->dst, hs_address);
+
+			dbus_connection_emit_signal(((struct device *) device)->conn,
+						((struct device *) device)->path,
 						AUDIO_HEADSET_INTERFACE,
-						headset_methods,
-						headset_signals, NULL)) {
-		error("Failed to register %s interface to %s",
-				AUDIO_HEADSET_INTERFACE, hs->object_path);
-		dbus_connection_destroy_object_path(connection,
-							hs->object_path);
-		g_free(hs);
-		return NULL;
-	}
-
-	bacpy(&hs->bda, bda);
-
-	headsets = g_slist_append(headsets, hs);
-
-	return hs;
-}
-
-const char *headset_add(const bdaddr_t *bda)
-{
-	struct headset *hs;
-
-	hs = headset_add_internal(bda);
-	if (!hs)
-		return NULL;
-
-	return hs->object_path;
-}
-
-const char *headset_get(const bdaddr_t *bda)
-{
-	GSList *match;
-	struct headset *hs;
-
-	match = g_slist_find_custom(headsets, bda, headset_bda_cmp);
-	if (!match)
-		return NULL;
-
-	hs = match->data;
-
-	return hs->object_path;
-}
-
-void headset_remove(const char *path)
-{
-	struct headset *hs;
-
-	if (!dbus_connection_get_object_user_data(connection, path,
-							(void *) &hs))
-		return;
-
-	if (hs->state > HEADSET_STATE_DISCONNECTED)
-		hs_disconnect(NULL, NULL, hs);
-
-	if (!dbus_connection_destroy_object_path(connection, path))
-		error("D-Bus failed to unregister %s path", path);
-
-	headsets = g_slist_remove(headsets, hs);
-
-	g_free(hs);
-}
-
-static gboolean headset_server_io_cb(GIOChannel *chan, GIOCondition cond, void *data)
-{
-	int srv_sk, cli_sk;
-	struct sockaddr_rc addr;
-	socklen_t size;
-	char hs_address[18], *address = hs_address;
-	const char *uuid = "";
-	struct headset *hs = NULL;
-	DBusMessage *auth;
-	DBusPendingCall *pending;
-	GSList *match;
-
-	if (cond & G_IO_NVAL)
-		return FALSE;
-
-	if (cond & (G_IO_HUP | G_IO_ERR)) {
-		error("Hangup or error on rfcomm server socket");
-		g_io_channel_close(chan);
-		raise(SIGTERM);
-		return FALSE;
-	}
-
-	srv_sk = g_io_channel_unix_get_fd(chan);
-
-	size = sizeof(struct sockaddr_rc);
-	cli_sk = accept(srv_sk, (struct sockaddr *) &addr, &size);
-	if (cli_sk < 0) {
-		error("accept: %s (%d)", strerror(errno), errno);
-		return TRUE;
-	}
-
-	match = g_slist_find_custom(headsets, &addr.rc_bdaddr, headset_bda_cmp);
-	if (!match) {
-		hs = headset_add_internal(&addr.rc_bdaddr);
-		if (!hs) {
-			error("Unable to create a new headset object");
-			close(cli_sk);
-			return TRUE;
+						"Connected",
+						DBUS_TYPE_INVALID);
 		}
-
-		manager_add_headset(hs->object_path);
-	}
-	else
-		hs = match->data;
-
-	if (hs->state > HEADSET_STATE_DISCONNECTED || hs->rfcomm) {
-		debug("Refusing new connection since one already exists");
-		close(cli_sk);
-		return TRUE;
-	}
-
-	hs->rfcomm = g_io_channel_unix_new(cli_sk);
-	if (!hs->rfcomm) {
-		error("Allocating new GIOChannel failed!");
-		close(cli_sk);
-		return TRUE;
-	}
-
-	auth = dbus_message_new_method_call("org.bluez", "/org/bluez", "org.bluez.Database",
-						"RequestAuthorization");
-	if (!auth) {
-		error("Unable to allocat new RequestAuthorization method call");
-		goto failed;
-	}
-
-	ba2str(&hs->bda, hs_address);
-
-	dbus_message_append_args(auth, DBUS_TYPE_STRING, &address,
-				DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID);
-
-	if (dbus_connection_send_with_reply(connection, auth, &pending, -1) == FALSE) {
-		error("Sending of authorization request failed");
-		goto failed;
-	}
-
-	dbus_pending_call_set_notify(pending, auth_callback, hs, NULL);
-	dbus_pending_call_unref(pending);
-	dbus_message_unref(auth);
-
-	return TRUE;
-
-failed:
-	if (hs->rfcomm) {
-		g_io_channel_close(hs->rfcomm);
-		g_io_channel_unref(hs->rfcomm);
-		hs->rfcomm = NULL;
-	}
-
-	return TRUE;
-}
-
-static GIOChannel *server_socket(uint8_t *channel)
-{
-	int sock, lm;
-	struct sockaddr_rc addr;
-	socklen_t sa_len;
-	GIOChannel *io;
-
-	sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-	if (sock < 0) {
-		error("server socket: %s (%d)", strerror(errno), errno);
-		return NULL;
-	}
-
-	lm = RFCOMM_LM_SECURE;
-	if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
-		error("server setsockopt: %s (%d)", strerror(errno), errno);
-		close(sock);
-		return NULL;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.rc_family = AF_BLUETOOTH;
-	bacpy(&addr.rc_bdaddr, BDADDR_ANY);
-	addr.rc_channel = 0;
-
-	if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		error("server bind: %s", strerror(errno), errno);
-		close(sock);
-		return NULL;
-	}
-
-	if (listen(sock, 1) < 0) {
-		error("server listen: %s", strerror(errno), errno);
-		close(sock);
-		return NULL;
-	}
-
-	sa_len = sizeof(struct sockaddr_rc);
-	getsockname(sock, (struct sockaddr *) &addr, &sa_len);
-	*channel = addr.rc_channel;
-
-	io = g_io_channel_unix_new(sock);
-	if (!io) {
-		error("Unable to allocate new io channel");
-		close(sock);
-		return NULL;
-	}
-
-	return io;
-}
-
-int headset_init(DBusConnection *conn)
-{
-	uint8_t chan = DEFAULT_HS_AG_CHANNEL;
-
-	connection = dbus_connection_ref(conn);
-
-	hs_server = server_socket(&chan);
-	if (!hs_server)
-		return -1;
-
-	if (!hs_record_id)
-		hs_record_id = headset_add_ag_record(chan);
-
-	if (!hs_record_id) {
-		error("Unable to register service record");
-		g_io_channel_unref(hs_server);
-		hs_server = NULL;
-		return -1;
-	}
-
-	g_io_add_watch(hs_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-				(GIOFunc) headset_server_io_cb, NULL);
-
-	return 0;
-}
-
-void headset_exit(void)
-{
-	if (hs_record_id) {
-		headset_remove_ag_record(hs_record_id);
-		hs_record_id = 0;
-	}
-
-	if (hs_server) {
-		g_io_channel_unref(hs_server);
-		hs_server = NULL;
-	}
-
-	dbus_connection_unref(connection);
-	connection = NULL;
-}
+		break;
+	case HEADSET_STATE_PLAY_IN_PROGRESS:
+	case HEADSET_STATE_PLAYING:
+		break;
+	}
+
+	headset->state = state;
+}
+
+headset_state_t headset_get_state(void *device)
+{
+	struct headset *headset = ((struct device *) device)->headset;
+
+	return headset->state;
+}

Modified: bluez-utils/branches/upstream/current/audio/headset.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/headset.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/headset.h (original)
+++ bluez-utils/branches/upstream/current/audio/headset.h Wed Jul  4 13:37:57 2007
@@ -20,25 +20,54 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
-#ifndef __AUDIO_HEADSET_H
-#define __AUDIO_HEADSET_H
-
-#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
 
 #include <dbus/dbus.h>
 
+#include "unix.h"
+
 #define AUDIO_HEADSET_INTERFACE "org.bluez.audio.Headset"
 
-#define BUF_SIZE 1024
+#define DEFAULT_HS_AG_CHANNEL 12
+#define DEFAULT_HF_AG_CHANNEL 13
 
-const char *headset_get(const bdaddr_t *bda);
+typedef enum {
+	HEADSET_EVENT_KEYPRESS,
+	HEADSET_EVENT_GAIN,
+	HEADSET_EVENT_UNKNOWN,
+	HEADSET_EVENT_INVALID
+} headset_event_t;
 
-const char *headset_add(const bdaddr_t *bda);
+typedef enum {
+	HEADSET_STATE_DISCONNECTED = 0,
+	HEADSET_STATE_CONNECT_IN_PROGRESS,
+	HEADSET_STATE_CONNECTED,
+	HEADSET_STATE_PLAY_IN_PROGRESS,
+	HEADSET_STATE_PLAYING,
+} headset_state_t;
 
-void headset_remove(const char *path);
+typedef enum {
+	SVC_HEADSET,
+	SVC_HANDSFREE
+} headset_type_t;
 
-int headset_init(DBusConnection *conn);
+struct headset;
 
-void headset_exit(void);
+struct headset *headset_init(void *device, sdp_record_t *record,
+			uint16_t svc);
 
-#endif /* __AUDIO_HEADSET_H_ */
+void headset_free(void *device);
+
+void headset_update(void *device, sdp_record_t *record, uint16_t svc);
+
+int headset_get_config(void *device, int sock, struct ipc_packet *pkt);
+
+headset_type_t headset_get_type(void *device);
+void headset_set_type(void *device, headset_type_t type);
+
+int headset_connect_rfcomm(void *device, int sock);
+int headset_close_rfcomm(void *device);
+
+headset_state_t headset_get_state(void *device);
+void headset_set_state(void *device, headset_state_t state);

Modified: bluez-utils/branches/upstream/current/audio/ipc.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/ipc.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/ipc.h (original)
+++ bluez-utils/branches/upstream/current/audio/ipc.h Wed Jul  4 13:37:57 2007
@@ -25,19 +25,85 @@
 
 #define IPC_TYPE_CONNECT  0x0001
 
-struct ipc_hdr {
-	uint16_t id;
-	uint16_t type;
-	uint16_t seqnum;
-	uint16_t length;
+#define IPC_SOCKET_NAME "\0/org/bluez/audio"
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX 108
+#endif
+
+/* Supported roles */
+#define PKT_ROLE_NONE		0
+#define PKT_ROLE_AUTO		1
+#define PKT_ROLE_VOICE		2
+#define PKT_ROLE_HIFI		3
+
+/* Packet types */
+#define PKT_TYPE_CFG_REQ	0
+#define PKT_TYPE_CFG_RSP	1
+#define PKT_TYPE_STATUS_REQ	2
+#define PKT_TYPE_STATUS_RSP	3
+#define PKT_TYPE_CTL_REQ	4
+#define PKT_TYPE_CTL_RSP	5
+#define PKT_TYPE_CTL_NTFY	6
+
+/* Errors codes */
+#define PKT_ERROR_NONE		0
+
+struct ipc_packet {
+	uint8_t id;		/* Device id */
+	uint8_t role;		/* Audio role eg: voice, wifi, auto... */
+	uint8_t type;		/* Packet type */
+	uint8_t error;		/* Packet error code */
+	uint8_t length;		/* Payload length in bytes */
+	uint8_t data[0];	/* Packet payload */
 } __attribute__ ((packed));
 
-struct ipc_connect_cmd {
-	uint8_t src[6];
-	uint8_t dst[6];
-	uint16_t uuid;
+/* File descriptor options */
+#define CFG_FD_OPT_READ		0
+#define CFG_FD_OPT_WRITE	1
+#define CFG_FD_OPT_READWRITE	2
+
+struct ipc_data_cfg {
+	int fd;			/* Stream file descriptor */
+	uint8_t fd_opt;		/* Stream file descriptor options: read, write or readwrite*/
+	uint8_t encoding;	/* Stream encoding */
+	uint8_t bitpool;	/* Encoding bitpool */
+	uint8_t channels;	/* Number of audio channel */
+	uint8_t pkt_len;	/* Stream packet length */
+	uint8_t sample_size;	/* Sample size in bytes */
+	uint16_t rate;		/* Stream sample rate */
 } __attribute__ ((packed));
 
-struct ipc_connect_evt {
-	uint16_t id;
+/* Device status */
+#define STATUS_DISCONNECTED	0
+#define STATUS_CONNECTING	1
+#define STATUS_CONNECTED	2
+#define STATUS_STREAMING	3
+
+struct ipc_data_status {
+	uint8_t status;		/* Stream status */
 } __attribute__ ((packed));
+
+#define CTL_MODE_PLAYBACK	0
+#define CTL_MODE_CAPTURE	1
+#define CTL_MODE_GENERAL	2
+
+/* Supported control operations */
+#define CTL_KEY_POWER		0x40
+#define CTL_KEY_VOL_UP		0x41
+#define CTL_KEY_VOL_DOWN	0x42
+#define CTL_KEY_MUTE		0x43
+#define CTL_KEY_PLAY		0x44
+#define CTL_KEY_STOP		0x45
+#define CTL_KEY_PAUSE		0x46
+#define CTL_KEY_RECORD		0x47
+#define CTL_KEY_REWIND		0x48
+#define CTL_KEY_FAST_FORWARD	0x49
+#define CTL_KEY_EJECT		0x4A
+#define CTL_KEY_FORWARD		0x4B
+#define CTL_KEY_BACKWARD	0x4C
+
+struct ipc_data_ctl {
+	uint8_t mode;		/* Control Mode */
+	uint8_t key;		/* Control Key */
+}  __attribute__ ((packed));

Modified: bluez-utils/branches/upstream/current/audio/main.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/main.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/main.c (original)
+++ bluez-utils/branches/upstream/current/audio/main.c Wed Jul  4 13:37:57 2007
@@ -37,13 +37,64 @@
 #include "logging.h"
 
 #include "manager.h"
-#include "headset.h"
+
+static gboolean disable_hfp = TRUE;
+static gboolean sco_hci = FALSE;
 
 static GMainLoop *main_loop = NULL;
 
 static void sig_term(int sig)
 {
 	g_main_loop_quit(main_loop);
+}
+
+static void read_config(const char *file)
+{
+	GKeyFile *keyfile;
+	GError *err = NULL;
+	gboolean no_hfp;
+	char *sco_routing;
+
+	keyfile = g_key_file_new();
+
+	if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
+		error("Parsing %s failed: %s", file, err->message);
+		g_error_free(err);
+		g_key_file_free(keyfile);
+		return;
+	}
+
+	sco_routing = g_key_file_get_string(keyfile, "General",
+						"SCORouting", &err);
+	if (err) {
+		debug("%s: %s", file, err->message);
+		g_error_free(err);
+		err = NULL;
+	} else {
+		if (strcmp(sco_routing, "PCM") == 0)
+			sco_hci = FALSE;
+		else if (strcmp(sco_routing, "HCI") == 0)
+			sco_hci = TRUE;
+		else
+			error("Invalid Headset Routing value: %s",
+					sco_routing);
+		g_free(sco_routing);
+	}
+
+	no_hfp = g_key_file_get_boolean(keyfile, "Headset",
+						"DisableHFP", &err);
+	if (err) {
+		debug("%s: %s", file, err->message);
+		g_error_free(err);
+		err = NULL;
+	} else
+		disable_hfp = no_hfp;
+
+	debug("Config options: DisableHFP=%s, SCORouting=%s",
+			disable_hfp ? "true" : "false",
+			sco_hci ? "HCI" : "PCM");
+
+	g_key_file_free(keyfile);
 }
 
 int main(int argc, char *argv[])
@@ -65,6 +116,8 @@
 
 	enable_debug();
 
+	read_config(CONFIGDIR "/audio.conf");
+
 	main_loop = g_main_loop_new(NULL, FALSE);
 
 	conn = dbus_bus_system_setup_with_main_loop(NULL, NULL, NULL);
@@ -73,12 +126,17 @@
 		exit(1);
 	}
 
+	if (unix_init() < 0) {
+		error("Unable to setup unix socket");
+		exit(1);
+	}
+
 	if (audio_init(conn) < 0) {
 		error("Audio init failed!");
 		exit(1);
 	}
 
-	if (headset_init(conn) < 0) {
+	if (gateway_init(conn, disable_hfp, sco_hci) < 0) {
 		error("Headset initialization failed!");
 		exit(1);
 	}
@@ -90,7 +148,9 @@
 
 	audio_exit();
 
-	headset_exit();
+	gateway_exit();
+
+	unix_exit();
 
 	dbus_connection_unref(conn);
 

Modified: bluez-utils/branches/upstream/current/audio/manager.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/manager.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/manager.c (original)
+++ bluez-utils/branches/upstream/current/audio/manager.c Wed Jul  4 13:37:57 2007
@@ -26,175 +26,853 @@
 #endif
 
 #include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
 #include <errno.h>
 #include <unistd.h>
 #include <stdint.h>
 #include <assert.h>
-#include <sys/socket.h>
-#include <sys/un.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <ctype.h>
 
 #include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
 #include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
 
 #include <glib.h>
 
 #include <dbus/dbus.h>
 
-#include "dbus.h"
 #include "dbus-helper.h"
 #include "logging.h"
-
-#include "ipc.h"
-#include "headset.h"
+#include "textfile.h"
 #include "manager.h"
-
-#ifndef UNIX_PATH_MAX
-#define UNIX_PATH_MAX 108
-#endif
-
-#define SOCKET_NAME "/org/bluez/audio"
+#include "error.h"
+
+typedef enum {
+	HEADSET	= 1 << 0,
+	GATEWAY	= 1 << 1,
+	SINK	= 1 << 2,
+	SOURCE	= 1 << 3,
+	CONTROL	= 1 << 4,
+	TARGET	= 1 << 5,
+	INVALID	= 1 << 6
+} audio_service_type;
+
+typedef enum {
+		GENERIC_AUDIO = 0,
+		ADVANCED_AUDIO,
+		AV_REMOTE,
+		GET_RECORDS
+} audio_sdp_state_t;
+
+struct audio_sdp_data {
+	struct device *device;
+
+	DBusMessage *msg;	/* Method call or NULL */
+
+	GSList *handles;	/* uint32_t * */
+	GSList *records;	/* sdp_record_t * */
+
+	audio_sdp_state_t state;
+};
 
 static DBusConnection *connection = NULL;
 
-static char *default_hs = NULL;
-
-static GSList *headsets = NULL;
-
-static int unix_sock = -1;
-
-/* FIXME: Remove these once global error functions exist */
-static DBusHandlerResult error_reply(DBusConnection *conn, DBusMessage *msg,
-					const char *name, const char *descr)
-{
-	DBusMessage *derr;
-
-	if (!conn || !msg)
-		return DBUS_HANDLER_RESULT_HANDLED;
-
-	derr = dbus_message_new_error(msg, name, descr);
-	if (!derr) {
-		error("Unable to allocate new error return");
-		return DBUS_HANDLER_RESULT_NEED_MEMORY;
-	}
-
-	return send_message_and_unref(conn, derr);
-}
-
-static DBusHandlerResult err_invalid_args(DBusConnection *conn, DBusMessage *msg,
-						const char *descr)
-{
-	return error_reply(conn, msg, "org.bluez.audio.Error.InvalidArguments",
-			descr ? descr : "Invalid arguments in method call");
-}
-
-static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
-	struct sockaddr_un addr;
-	socklen_t addrlen;
-	unsigned char buf[128];
-	int sk, len;
-
-	debug("chan %p cond %td data %p", chan, cond, data);
-
-	if (cond & G_IO_NVAL)
-		return FALSE;
-
-	if (cond & (G_IO_HUP | G_IO_ERR)) {
-		g_io_channel_close(chan);
-		return FALSE;
-	}
-
-	sk = g_io_channel_unix_get_fd(chan);
-
-	memset(&addr, 0, sizeof(addr));
-	addrlen = sizeof(addr);
-
-	len = recvfrom(sk, buf, sizeof(buf), 0, (struct sockaddr *) &addr, &addrlen);
-
-	debug("path %s len %d", addr.sun_path + 1, len);
+static struct device *default_dev = NULL;
+
+static GSList *devices = NULL;
+
+static void get_next_record(struct audio_sdp_data *data);
+static DBusHandlerResult get_handles(const char *uuid,
+					struct audio_sdp_data *data);
+
+static struct device *find_device(bdaddr_t *bda)
+{
+	GSList *l;
+
+	for (l = devices; l != NULL; l = l->next) {
+		struct device *device = l->data;
+		if (bacmp(&device->dst, bda) == 0)
+			return device;
+	}
+
+	return NULL;
+}
+
+static struct device *create_device(bdaddr_t *bda)
+{
+	static int device_id = 0;
+	char path[128];
+
+	snprintf(path, sizeof(path) - 1,
+			"%s/device%d", AUDIO_MANAGER_PATH, device_id++);
+
+	return device_register(connection, path, bda);
+}
+
+static void remove_device(struct device *device)
+{
+	if (device == default_dev) {
+		debug("Removing default device");
+		default_dev = NULL;
+	}
+
+	devices = g_slist_remove(devices, device);
+
+	dbus_connection_destroy_object_path(connection, device->path);
+}
+
+static gboolean add_device(struct device *device)
+{
+	if (default_dev == NULL && g_slist_length(devices) == 0) {
+		debug("Selecting default device");
+		default_dev = device;
+	}
+
+	devices = g_slist_append(devices, device);
 
 	return TRUE;
 }
 
-void manager_add_headset(const char *path)
-{
-	char *my_path = g_strdup(path);
-
-	headsets = g_slist_append(headsets, my_path);
+static uint16_t get_service_uuid(const sdp_record_t *record)
+{
+	sdp_list_t *classes;
+	uuid_t uuid;
+	uint16_t uuid16 = 0;
+
+	if (sdp_get_service_classes(record, &classes) < 0) {
+		error("Unable to get service classes from record");
+		return 0;
+	}
+
+	memcpy(&uuid, classes->data, sizeof(uuid));
+
+	if (!sdp_uuid128_to_uuid(&uuid)) {
+		error("Not a 16 bit UUID");
+		sdp_list_free(classes, free);
+		return 0;
+	}
+
+	if (uuid.type == SDP_UUID32) {
+		if (uuid.value.uuid32 > 0xFFFF) {
+			error("Not a 16 bit UUID");
+			goto done;
+		}
+		uuid16 = (uint16_t) uuid.value.uuid32;
+	} else
+		uuid16 = uuid.value.uuid16;
+
+done:
+	sdp_list_free(classes, free);
+
+	return uuid16;
+}
+
+static void handle_record(sdp_record_t *record, struct device *device)
+{
+	gboolean is_default;
+	uint16_t uuid16;
+
+	uuid16 = get_service_uuid(record);
+
+	switch (uuid16) {
+	case HEADSET_SVCLASS_ID:
+		debug("Found Headset record");
+		if (device->headset)
+			headset_update(device, record, uuid16);
+		else
+			device->headset = headset_init(device,
+							record, uuid16);
+		break;
+	case HEADSET_AGW_SVCLASS_ID:
+		debug("Found Headset AG record");
+		break;
+	case HANDSFREE_SVCLASS_ID:
+		debug("Found Hansfree record");
+		if (device->headset)
+			headset_update(device, record, uuid16);
+		else
+			device->headset = headset_init(device,
+							record, uuid16);
+		break;
+	case HANDSFREE_AGW_SVCLASS_ID:
+		debug("Found Handsfree AG record");
+		break;
+	case AUDIO_SINK_SVCLASS_ID:
+		debug("Found Audio Sink");
+		break;
+	case AUDIO_SOURCE_SVCLASS_ID:
+		debug("Found Audio Source");
+		break;
+	case AV_REMOTE_SVCLASS_ID:
+		debug("Found AV Remote");
+		break;
+	case AV_REMOTE_TARGET_SVCLASS_ID:
+		debug("Found AV Target");
+		break;
+	default:
+		debug("Unrecognized UUID: 0x%04X", uuid16);
+		break;
+	}
+
+	is_default = (default_dev == device) ? TRUE : FALSE;
+
+	device_store(device, is_default);
+}
+
+static gint record_iface_cmp(gconstpointer a, gconstpointer b)
+{
+	const sdp_record_t *record = a;
+	const char *interface = b;
+
+	switch (get_service_uuid(record)) {
+	case HEADSET_SVCLASS_ID:
+	case HANDSFREE_SVCLASS_ID:
+		return strcmp(interface, AUDIO_HEADSET_INTERFACE);
+
+	case HEADSET_AGW_SVCLASS_ID:
+	case HANDSFREE_AGW_SVCLASS_ID:
+		return strcmp(interface, AUDIO_GATEWAY_INTERFACE);
+
+	case AUDIO_SINK_SVCLASS_ID:
+		return strcmp(interface, AUDIO_SINK_INTERFACE);
+
+	case AUDIO_SOURCE_SVCLASS_ID:
+		return strcmp(interface, AUDIO_SOURCE_INTERFACE);
+
+	case AV_REMOTE_SVCLASS_ID:
+		return strcmp(interface, AUDIO_CONTROL_INTERFACE);
+
+	case AV_REMOTE_TARGET_SVCLASS_ID:
+		return strcmp(interface, AUDIO_TARGET_INTERFACE);
+
+	default:
+		return -1;
+	}
+}
+
+static void finish_sdp(struct audio_sdp_data *data, gboolean success)
+{
+	const char *addr;
+	char **required = NULL;
+	int required_len, i;
+	DBusMessage *reply = NULL;
+	DBusError derr;
+
+	debug("Audio service discovery completed with %s",
+			success ? "success" : "failure");
+
+	device_finish_sdp_transaction(data->device);
+
+	if (!success)
+		goto done;
+
+	if (!data->msg)
+		goto update;
+
+	dbus_error_init(&derr);
+	if (dbus_message_is_method_call(data->msg, AUDIO_MANAGER_INTERFACE,
+		"CreateHeadset")) {
+		dbus_message_get_args(data->msg, &derr,
+					DBUS_TYPE_STRING, &addr,
+					DBUS_TYPE_INVALID);
+		required = dbus_new0(char *, 2);
+		if (required == NULL) {
+			success = FALSE;
+			err_failed(connection, data->msg, "Out of memory");
+			goto done;
+		}
+
+		required[0] = dbus_new0(char,
+			strlen(AUDIO_HEADSET_INTERFACE) + 1);
+		if (required[0] == NULL) {
+			success = FALSE;
+			err_failed(connection, data->msg, "Out of memory");
+			goto done;
+		}
+
+		memcpy(required[0], AUDIO_HEADSET_INTERFACE,
+			strlen(AUDIO_HEADSET_INTERFACE) + 1);
+		required[1] = NULL;
+		required_len = 1;
+	}
+	else
+		dbus_message_get_args(data->msg, &derr,
+					DBUS_TYPE_STRING, &addr,
+					DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+					&required, &required_len,
+					DBUS_TYPE_INVALID);
+
+	if (dbus_error_is_set(&derr)) {
+		error("Unable to get message args");
+		success = FALSE;
+		dbus_error_free(&derr);
+		goto done;
+	}
+
+	/* Return error if no audio related service records were found */
+	if (!data->records) {
+		debug("No audio audio related service records were found");
+		success = FALSE;
+		err_not_supported(connection, data->msg);
+		goto done;
+	}
+
+	for (i = 0; i < required_len; i++) {
+		const char *iface = required[i];
+
+		if (g_slist_find_custom(data->records, iface, record_iface_cmp))
+			continue;
+
+		debug("Required interface %s not supported", iface);
+		success = FALSE;
+		err_not_supported(connection, data->msg);
+		goto done;
+	}
+
+	reply = dbus_message_new_method_return(data->msg);
+	if (!reply) {
+		success = FALSE;
+		err_failed(connection, data->msg, "Out of memory");
+		goto done;
+	}
+
+	add_device(data->device);
+
+update:
+	g_slist_foreach(data->records, (GFunc) handle_record, data->device);
+
+	if (reply) {
+		dbus_connection_emit_signal(connection, AUDIO_MANAGER_PATH,
+						AUDIO_MANAGER_INTERFACE,
+						"DeviceCreated",
+						DBUS_TYPE_STRING,
+						&data->device->path,
+						DBUS_TYPE_INVALID);
+		if (data->device->headset)
+			dbus_connection_emit_signal(connection,
+							AUDIO_MANAGER_PATH,
+							AUDIO_MANAGER_INTERFACE,
+							"HeadsetCreated",
+							DBUS_TYPE_STRING,
+							&data->device->path,
+							DBUS_TYPE_INVALID);
+		dbus_message_append_args(reply, DBUS_TYPE_STRING,
+					&data->device->path,
+					DBUS_TYPE_INVALID);
+		send_message_and_unref(connection, reply);
+	}
+
+done:
+	dbus_free_string_array(required);
+	if (!success)
+		remove_device(data->device);
+	if (data->msg)
+		dbus_message_unref(data->msg);
+	g_slist_foreach(data->handles, (GFunc) g_free, NULL);
+	g_slist_free(data->handles);
+	g_slist_foreach(data->records, (GFunc) sdp_record_free, NULL);
+	g_slist_free(data->records);
+	g_free(data);
+}
+
+static void get_record_reply(DBusPendingCall *call,
+				struct audio_sdp_data *data)
+{
+	DBusMessage *reply;
+	DBusError derr;
+	uint8_t *array;
+	int array_len, record_len;
+	sdp_record_t *record;
+
+	reply = dbus_pending_call_steal_reply(call);
+
+	dbus_error_init(&derr);
+	if (dbus_set_error_from_message(&derr, reply)) {
+		error("GetRemoteServiceRecord failed: %s", derr.message);
+		if (dbus_error_has_name(&derr,
+					"org.bluez.Error.ConnectionAttemptFailed"))
+			err_connect_failed(connection, data->msg,
+				strerror(EHOSTDOWN));
+		else
+			err_failed(connection, data->msg, derr.message);
+		dbus_error_free(&derr);
+		goto failed;
+	}
+
+	if (!dbus_message_get_args(reply, NULL,
+				DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &array, &array_len,
+				DBUS_TYPE_INVALID)) {
+		err_failed(connection, data->msg,
+				"Unable to get args from GetRecordReply");
+		goto failed;
+	}
+
+	record = sdp_extract_pdu(array, &record_len);
+	if (!record) {
+		error("Unable to extract service record from reply");
+		goto done;
+	}
+
+	if (record_len != array_len)
+		debug("warning: array len (%d) != record len (%d)",
+				array_len, record_len);
+
+	data->records = g_slist_append(data->records, record);
+
+done:
+	dbus_message_unref(reply);
+
+	if (data->handles)
+		get_next_record(data);
+	else
+		finish_sdp(data, TRUE);
+
+	return;
+
+failed:
+	if (reply)
+		dbus_message_unref(reply);
+	finish_sdp(data, FALSE);
+}
+
+static void get_next_record(struct audio_sdp_data *data)
+{
+	DBusMessage *msg;
+	DBusPendingCall *pending;
+	char address[18], *ptr = address;
+	dbus_uint32_t *handle;
+
+	msg = dbus_message_new_method_call("org.bluez",
+						data->device->adapter_path,
+						"org.bluez.Adapter",
+						"GetRemoteServiceRecord");
+	if (!msg) {
+		error("Unable to allocate new method call");
+		err_connect_failed(connection, data->msg, strerror(ENOMEM));
+		finish_sdp(data, FALSE);
+		return;
+	}
+
+	handle = data->handles->data;
+
+	data->handles = g_slist_remove(data->handles, data->handles->data);
+
+	ba2str(&data->device->dst, address);
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &ptr,
+					DBUS_TYPE_UINT32, handle,
+					DBUS_TYPE_INVALID);
+
+	g_free(handle);
+
+	if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) {
+		error("Sending GetRemoteServiceRecord failed");
+		err_connect_failed(connection, data->msg, strerror(EIO));
+		finish_sdp(data, FALSE);
+		return;
+	}
+
+	dbus_pending_call_set_notify(pending,
+			(DBusPendingCallNotifyFunction) get_record_reply,
+			data, NULL);
+	dbus_pending_call_unref(pending);
+	dbus_message_unref(msg);
+}
+
+static GSList *find_handle(GSList *handles, dbus_uint32_t handle)
+{
+	while (handles) {
+		if (*(dbus_uint32_t *) handles->data == handle)
+			return handles;
+		handles = handles->next;
+	}
+
+	return NULL;
+}
+
+static void get_handles_reply(DBusPendingCall *call,
+				struct audio_sdp_data *data)
+{
+	DBusMessage *reply;
+	DBusError derr;
+	dbus_uint32_t *array = NULL;
+	int array_len, i;
+
+	reply = dbus_pending_call_steal_reply(call);
+
+	dbus_error_init(&derr);
+	if (dbus_set_error_from_message(&derr, reply)) {
+		error("GetRemoteServiceHandles failed: %s", derr.message);
+		if (dbus_error_has_name(&derr,
+					"org.bluez.Error.ConnectionAttemptFailed"))
+			err_connect_failed(connection, data->msg, strerror(EHOSTDOWN));
+		else
+			err_failed(connection, data->msg, derr.message);
+		dbus_error_free(&derr);
+		goto failed;
+	}
+
+	if (!dbus_message_get_args(reply, NULL,
+				DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+				&array, &array_len,
+				DBUS_TYPE_INVALID)) {
+		err_failed(connection, data->msg,
+				"Unable to get args from reply");
+		goto failed;
+	}
+
+	for (i = 0; i < array_len; i++) {
+		if (!find_handle(data->handles, array[i])) {
+			dbus_uint32_t *handle = g_new(dbus_uint32_t, 1);
+			*handle = array[i];
+			data->handles = g_slist_append(data->handles, handle);
+		}
+	}
+
+	data->state++;
+
+	switch (data->state) {
+	case ADVANCED_AUDIO:
+		get_handles(ADVANCED_AUDIO_UUID, data);
+		break;
+	case AV_REMOTE:
+		get_handles(AVRCP_REMOTE_UUID, data);
+		break;
+	default:
+		if (data->handles)
+			get_next_record(data);
+		else
+			finish_sdp(data, TRUE);
+	}
+
+	dbus_message_unref(reply);
+
+	return;
+
+failed:
+	dbus_message_unref(reply);
+	finish_sdp(data, FALSE);
+}
+
+static DBusHandlerResult get_handles(const char *uuid,
+					struct audio_sdp_data *data)
+{
+	DBusPendingCall *pending;
+	char address[18];
+	const char *ptr = address;
+	DBusMessage *msg;
+
+	msg = dbus_message_new_method_call("org.bluez",
+						data->device->adapter_path,
+						"org.bluez.Adapter",
+						"GetRemoteServiceHandles");
+	if (!msg) {
+		err_failed(connection, data->msg,
+				"Could not create a new dbus message");
+		goto failed;
+	}
+
+	ba2str(&data->device->dst, address);
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &ptr,
+					DBUS_TYPE_STRING, &uuid,
+					DBUS_TYPE_INVALID);
+
+	if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) {
+		err_failed(connection, data->msg,
+				"Sending GetRemoteServiceHandles failed");
+		goto failed;
+	}
+
+	dbus_pending_call_set_notify(pending,
+			(DBusPendingCallNotifyFunction) get_handles_reply,
+			data, NULL);
+	dbus_pending_call_unref(pending);
+	dbus_message_unref(msg);
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+
+failed:
+	if (msg)
+		dbus_message_unref(msg);
+	finish_sdp(data, FALSE);
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult resolve_services(DBusMessage *msg,
+						struct device *device)
+{
+	struct audio_sdp_data *sdp_data;
+
+	sdp_data = g_new0(struct audio_sdp_data, 1);
+	if (msg)
+		sdp_data->msg = dbus_message_ref(msg);
+	sdp_data->device = device;
+
+	return get_handles(GENERIC_AUDIO_UUID, sdp_data);
+}
+
+struct device *manager_device_connected(bdaddr_t *bda)
+{
+	struct device *device;
+	const char *path;
+	gboolean created = FALSE;
+
+	device = find_device(bda);
+	if (device && device->headset)
+		return device;
+
+	if (!device) {
+		device = create_device(bda);
+		if (!add_device(device)) {
+			remove_device(device);
+			return NULL;
+		}
+		created = TRUE;
+	}
+
+	if (!device->headset)
+		device->headset = headset_init(device, NULL, 0);
+
+	if (!device->headset)
+		return NULL;
+
+	path = device->path;
+
+	if (created) {
+		dbus_connection_emit_signal(connection, AUDIO_MANAGER_PATH,
+						AUDIO_MANAGER_INTERFACE,
+						"DeviceCreated",
+						DBUS_TYPE_STRING, &path,
+						DBUS_TYPE_INVALID);
+		resolve_services(NULL, device);
+	}
 
 	dbus_connection_emit_signal(connection, AUDIO_MANAGER_PATH,
 					AUDIO_MANAGER_INTERFACE,
 					"HeadsetCreated",
-					DBUS_TYPE_STRING, &my_path,
-					DBUS_TYPE_INVALID);
-
-	if (!default_hs) {
-		default_hs = my_path;
+					DBUS_TYPE_STRING, &path,
+					DBUS_TYPE_INVALID);
+
+	if (!default_dev) {
+		default_dev = device;
 		dbus_connection_emit_signal(connection, AUDIO_MANAGER_PATH,
 						AUDIO_MANAGER_INTERFACE,
 						"DefaultHeadsetChanged",
-						DBUS_TYPE_STRING, &my_path,
+						DBUS_TYPE_STRING, &path,
 						DBUS_TYPE_INVALID);
 	}
-}
-
-static void manager_remove_headset(char *path)
-{
-	headset_remove(path);
-	g_free(path);
-}
-
-static DBusHandlerResult am_create_headset(DBusConnection *conn, DBusMessage *msg,
+
+	return device;
+}
+
+static gboolean device_supports_interface(struct device *device,
+						const char *iface)
+{
+	if (strcmp(iface, AUDIO_HEADSET_INTERFACE) == 0)
+		return device->headset ? TRUE : FALSE;
+
+	if (strcmp(iface, AUDIO_GATEWAY_INTERFACE) == 0)
+		return device->gateway ? TRUE : FALSE;
+
+	if (strcmp(iface, AUDIO_SOURCE_INTERFACE) == 0)
+		return device->source ? TRUE : FALSE;
+
+	if (strcmp(iface, AUDIO_SINK_INTERFACE) == 0)
+			return device->sink ? TRUE : FALSE;
+
+	if (strcmp(iface, AUDIO_CONTROL_INTERFACE) == 0)
+		return device->control ? TRUE : FALSE;
+
+	if (strcmp(iface, AUDIO_TARGET_INTERFACE) == 0)
+		return device->target ? TRUE : FALSE;
+
+	debug("Unknown interface %s", iface);
+
+	return FALSE;
+}
+
+static gboolean device_matches(struct device *device, char **interfaces)
+{
+	int i;
+
+	for (i = 0; interfaces[i]; i++) {
+		if (device_supports_interface(device, interfaces[i]))
+			continue;
+		debug("Device does not support interface %s", interfaces[i]);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static DBusHandlerResult am_create_device(DBusConnection *conn,
+						DBusMessage *msg,
 						void *data)
 {
-	const char *hs_path;
-	const char *address;
+	const char *address, *path;
+	char **required;
+	int required_len;
 	bdaddr_t bda;
+	struct device *device;
 	DBusMessage *reply;
 	DBusError derr;
 
 	dbus_error_init(&derr);
-	if (!dbus_message_get_args(msg, &derr,
+	if (dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE,
+		"CreateHeadset")) {
+		dbus_message_get_args(msg, &derr,
 					DBUS_TYPE_STRING, &address,
-					DBUS_TYPE_INVALID)) {
-		err_invalid_args(connection, msg, derr.message);
-		return DBUS_HANDLER_RESULT_HANDLED;
-	}
+					DBUS_TYPE_INVALID);
+		required = dbus_new0(char *, 2);
+		if (required == NULL)
+			return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+		required[0] = dbus_new0(char,
+			strlen(AUDIO_HEADSET_INTERFACE) + 1);
+		if (required[0] == NULL) {
+			dbus_free(required);
+			return DBUS_HANDLER_RESULT_NEED_MEMORY;
+		}
+
+		memcpy(required[0], AUDIO_HEADSET_INTERFACE,
+			strlen(AUDIO_HEADSET_INTERFACE) + 1);
+		required[1] = NULL;
+		required_len = 1;
+	}
+	else
+		dbus_message_get_args(msg, &derr,
+					DBUS_TYPE_STRING, &address,
+					DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+					&required, &required_len,
+					DBUS_TYPE_INVALID);
+
 	if (dbus_error_is_set(&derr)) {
 		err_invalid_args(connection, msg, derr.message);
 		dbus_error_free(&derr);
 		return DBUS_HANDLER_RESULT_HANDLED;
 	}
 
+	str2ba(address, &bda);
+
+	device = find_device(&bda);
+	if (!device) {
+		device = create_device(&bda);
+		dbus_free_string_array(required);
+		return resolve_services(msg, device);
+	}
+
+	if (!device_matches(device, required)) {
+		dbus_free_string_array(required);
+		return err_not_supported(conn, msg);
+	}
+
+	dbus_free_string_array(required);
+
+	path = device->path;
+
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-	str2ba(address, &bda);
-
-	hs_path = headset_get(&bda);
-	if (!hs_path) {
-		hs_path = headset_add(&bda);
-		if (!hs_path)
-			return error_reply(connection, msg,
-					"org.bluez.audio.Error.Failed",
-					"Unable to create new headset object");
-		manager_add_headset(hs_path);
-	}
-
-	dbus_message_append_args(reply, DBUS_TYPE_STRING, &hs_path,
-					DBUS_TYPE_INVALID);
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,
+					DBUS_TYPE_INVALID);
+
+	return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult am_list_devices(DBusConnection *conn,
+						DBusMessage *msg,
+						void *data)
+{
+	DBusMessageIter iter, array_iter;
+	DBusMessage *reply;
+	DBusError derr;
+	GSList *l;
+	char **required;
+	int required_len;
+
+	dbus_error_init(&derr);
+
+	if (dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE,
+		"ListHeadsets")) {
+		required = dbus_new0(char *, 2);
+		if (required == NULL)
+			return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+		required[0] = dbus_new0(char,
+			strlen(AUDIO_HEADSET_INTERFACE) + 1);
+		if (required[0] == NULL) {
+			dbus_free(required);
+			return DBUS_HANDLER_RESULT_NEED_MEMORY;
+		}
+
+		memcpy(required[0], AUDIO_HEADSET_INTERFACE,
+			strlen(AUDIO_HEADSET_INTERFACE) + 1);
+		required[1] = NULL;
+		required_len = 1;
+	}
+	else
+		dbus_message_get_args(msg, &derr,
+					DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+					&required, &required_len,
+					DBUS_TYPE_INVALID);
+
+	if (dbus_error_is_set(&derr)) {
+		err_invalid_args(connection, msg, derr.message);
+		dbus_error_free(&derr);
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+				DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+	for (l = devices; l != NULL; l = l->next) {
+		struct device *device = l->data;
+
+		if (!device_matches(device, required))
+			continue;
+
+		dbus_message_iter_append_basic(&array_iter,
+						DBUS_TYPE_STRING, &device->path);
+	}
+
+	dbus_message_iter_close_container(&iter, &array_iter);
+
+	dbus_free_string_array(required);
 
 	return send_message_and_unref(connection, reply);
 }
 
-static DBusHandlerResult am_remove_headset(DBusConnection *conn, DBusMessage *msg,
+static gint device_path_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct device *device = a;
+	const char *path = b;
+
+	return strcmp(device->path, path);
+}
+
+static DBusHandlerResult am_remove_device(DBusConnection *conn,
+						DBusMessage *msg,
 						void *data)
 {
 	DBusError derr;
 	DBusMessage *reply;
 	GSList *match;
-	char *path;
+	const char *path;
+	struct device *device;
 
 	dbus_error_init(&derr);
 	if (!dbus_message_get_args(msg, &derr,
@@ -209,29 +887,32 @@
 		return DBUS_HANDLER_RESULT_HANDLED;
 	}
 
-	match = g_slist_find_custom(headsets, path, (GCompareFunc) strcmp);
+	match = g_slist_find_custom(devices, path, device_path_cmp);
 	if (!match)
-		return error_reply(connection, msg,
-					"org.bluez.audio.Error.DoesNotExist",
-					"The headset does not exist");
+		return err_does_not_exist(connection, msg);
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-	path = match->data;
-
-	headsets = g_slist_remove(headsets, path);
-
-	if (default_hs == path) {
+	device = match->data;
+
+	remove_device(device);
+
+	if (default_dev == device) {
 		const char *param;
-
-		if (!headsets)
-			default_hs = NULL;
-		else
-			default_hs = headsets->data;
-
-		param = default_hs ? default_hs : "";
+		GSList *l;
+
+		default_dev = NULL;
+
+		for (l = devices; l != NULL; l = l->next) {
+			device = l->data;
+
+			if (device->headset)
+				default_dev = device;
+		}
+
+		param = default_dev ? default_dev->path : "";
 
 		dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
 						AUDIO_MANAGER_INTERFACE,
@@ -246,66 +927,85 @@
 					DBUS_TYPE_STRING, &path,
 					DBUS_TYPE_INVALID);
 
-	headset_remove(path);
-
-	g_free(path);
+	dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
+					AUDIO_MANAGER_INTERFACE,
+					"DeviceRemoved",
+					DBUS_TYPE_STRING, &path,
+					DBUS_TYPE_INVALID);
 
 	return send_message_and_unref(connection, reply);
 }
 
-static DBusHandlerResult am_list_headsets(DBusConnection *conn, DBusMessage *msg,
+static DBusHandlerResult am_find_by_addr(DBusConnection *conn,
+						DBusMessage *msg,
 						void *data)
 {
-	DBusMessageIter iter;
-	DBusMessageIter array_iter;
+	const char *address;
 	DBusMessage *reply;
-	GSList *l;
+	DBusError derr;
+	struct device *device;
+	bdaddr_t bda;
+
+	dbus_error_init(&derr);
+	dbus_message_get_args(msg, &derr,
+				DBUS_TYPE_STRING, &address,
+				DBUS_TYPE_INVALID);
+	if (dbus_error_is_set(&derr)) {
+		err_invalid_args(connection, msg, derr.message);
+		dbus_error_free(&derr);
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	str2ba(address, &bda);
+
+	device = find_device(&bda);
+
+	if (!device)
+		return err_does_not_exist(conn, msg);
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-	dbus_message_iter_init_append(reply, &iter);
-
-	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-				DBUS_TYPE_STRING_AS_STRING, &array_iter);
-
-	for (l = headsets; l != NULL; l = l->next)
-		dbus_message_iter_append_basic(&array_iter,
-						DBUS_TYPE_STRING, &l->data);
-
-	dbus_message_iter_close_container(&iter, &array_iter);
-
-	return send_message_and_unref(connection, reply);
-}
-
-static DBusHandlerResult am_get_default_headset(DBusConnection *conn, DBusMessage *msg,
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &device->path,
+					DBUS_TYPE_INVALID);
+
+	return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult am_default_device(DBusConnection *conn,
+						DBusMessage *msg,
 						void *data)
 {
 	DBusMessage *reply;
 
-	if (!default_hs)
-		return error_reply(connection, msg,
-					"org.bluez.audio.Error.DoesNotExist",
-					"There is no default headset");
+	if (!default_dev)
+		return err_does_not_exist(connection, msg);
+
+	if (default_dev->headset == NULL &&
+		dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE,
+							"DefaultHeadset"))
+		return err_does_not_exist(connection, msg);
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-	dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_hs,
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_dev->path,
 					DBUS_TYPE_INVALID);
 
 	return send_message_and_unref(connection, reply);
 }
 
-static DBusHandlerResult am_change_default_headset(DBusConnection *conn, DBusMessage *msg,
+static DBusHandlerResult am_change_default_device(DBusConnection *conn,
+							DBusMessage *msg,
 							void *data)
 {
 	DBusError derr;
 	DBusMessage *reply;
 	GSList *match;
 	const char *path;
+	struct device *device;
 
 	dbus_error_init(&derr);
 	if (!dbus_message_get_args(msg, &derr,
@@ -320,85 +1020,158 @@
 		return DBUS_HANDLER_RESULT_HANDLED;
 	}
 
-	match = g_slist_find_custom(headsets, path, (GCompareFunc) strcmp);
+	match = g_slist_find_custom(devices, path, device_path_cmp);
 	if (!match)
-		return error_reply(connection, msg,
-					"org.bluez.audio.Error.DoesNotExist",
-					"The headset does not exist");
+		return err_does_not_exist(connection, msg);
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-	default_hs = match->data;
-
-	dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
-					AUDIO_MANAGER_INTERFACE,
-					"DefaultHeadsetChanged",
-					DBUS_TYPE_STRING, &default_hs,
-					DBUS_TYPE_INVALID);
-
+	device = match->data;
+
+	if (!dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE,
+		"ChangeDefaultHeadset"))
+		dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
+						AUDIO_MANAGER_INTERFACE,
+						"DefaultDeviceChanged",
+						DBUS_TYPE_STRING, &device->path,
+						DBUS_TYPE_INVALID);
+	else if (device->headset)
+		dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
+						AUDIO_MANAGER_INTERFACE,
+						"DefaultHeadsetChanged",
+						DBUS_TYPE_STRING, &device->path,
+						DBUS_TYPE_INVALID);
+	else
+		return err_does_not_exist(connection, msg);
+
+	default_dev = device;
+	device_store(device, TRUE);
 	return send_message_and_unref(connection, reply);
 }
 
 static DBusMethodVTable manager_methods[] = {
-	{ "CreateHeadset",		am_create_headset,
-		"s",	"s"	},
-	{ "RemoveHeadset",		am_remove_headset,
-		"s",	""	},
-	{ "ListHeadsets",		am_list_headsets,
-		"",	"as"	},
-	{ "DefaultHeadset",		am_get_default_headset,
-		"",	"s"	},
-	{ "ChangeDefaultHeadset",	am_change_default_headset,
-		"s",	""	},
+	{ "CreateDevice",		am_create_device,
+		"sas",	"s"		},
+	{ "RemoveDevice",		am_remove_device,
+		"s",	""		},
+	{ "ListDevices",		am_list_devices,
+		"as",	"as"		},
+	{ "DefaultDevice",		am_default_device,
+		"",	"s"		},
+	{ "ChangeDefaultDevice",	am_change_default_device,
+		"s",	""		},
+	{ "CreateHeadset",		am_create_device,
+		"s",	"s"		},
+	{ "RemoveHeadset",		am_remove_device,
+		"s",	""		},
+	{ "ListHeadsets",		am_list_devices,
+		"",	"as"		},
+	{ "FindDeviceByAddress",	am_find_by_addr,
+		"s",	"s"		},
+	{ "DefaultHeadset",		am_default_device,
+		"",	"s"		},
+	{ "ChangeDefaultHeadset",	am_change_default_device,
+		"s",	""		},
 	{ NULL, NULL, NULL, NULL },
 };
 
 static DBusSignalVTable manager_signals[] = {
+	{ "DeviceCreated",		"s"	},
+	{ "DeviceRemoved",		"s"	},
 	{ "HeadsetCreated",		"s"	},
 	{ "HeadsetRemoved",		"s"	},
+	{ "DefaultDeviceChanged",	"s"	},
 	{ "DefaultHeadsetChanged",	"s"	},
 	{ NULL, NULL }
 };
 
+static void parse_stored_devices(char *key, char *value, void *data)
+{
+	struct device *device;
+	bdaddr_t dst;
+
+	if (!key || !value || strcmp(key, "default") == 0)
+		return;
+
+	info("Loading device %s (%s)", key, value);
+	str2ba(key, &dst);
+
+	device = create_device(&dst);
+	if (!device)
+		return;
+
+	if (strcmp(value, "headset") == 0)
+		device->headset = headset_init(device, NULL, 0);
+
+	add_device(device);
+}
+
+static void register_devices_stored(const char *adapter)
+{
+	char filename[PATH_MAX + 1];
+	struct stat st;
+	struct device *device;
+	bdaddr_t src;
+	bdaddr_t dst;
+	char *addr;
+
+	create_name(filename, PATH_MAX, STORAGEDIR, adapter, "audio");
+
+	str2ba(adapter, &src);
+
+	if (stat(filename, &st) < 0)
+		return;
+
+	if (!(st.st_mode & __S_IFREG))
+		return;
+
+	textfile_foreach(filename, parse_stored_devices, &src);
+
+	addr = textfile_get(filename, "default");
+	if (!addr)
+		return;
+
+	str2ba(addr, &dst);
+	device = find_device(&dst);
+
+	if (device) {
+		info("Setting %s as default device", addr);
+		default_dev = device;
+	}
+
+	free(addr);
+}
+
+static void register_stored(void)
+{
+	char dirname[PATH_MAX + 1];
+	struct dirent *de;
+	DIR *dir;
+
+	snprintf(dirname, PATH_MAX, "%s", STORAGEDIR);
+
+	dir = opendir(dirname);
+	if (!dir)
+		return;
+
+	while ((de = readdir(dir)) != NULL) {
+		if (!isdigit(de->d_name[0]))
+			continue;
+
+		/* Device objects */
+		register_devices_stored(de->d_name);
+	}
+
+	closedir(dir);
+}
+
 int audio_init(DBusConnection *conn)
 {
-	GIOChannel *io;
-	struct sockaddr_un addr;
-	int sk;
-
-	sk = socket(PF_LOCAL, SOCK_DGRAM, 0);
-	if (sk < 0) {
-		error("Can't create unix socket: %s (%d)", strerror(errno), errno);
-		return -1;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s", SOCKET_NAME);
-
-	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		error("Can't bind unix socket: %s (%d)", strerror(errno), errno);
-		close(sk);
-		return -1;
-	}
-
-	set_nonblocking(sk);
-
-	unix_sock = sk;
-
-	io = g_io_channel_unix_new(sk);
-
-	g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-							unix_event, NULL);
-
-	g_io_channel_unref(io);
-
 	if (!dbus_connection_create_object_path(conn, AUDIO_MANAGER_PATH,
 						NULL, NULL)) {
 		error("D-Bus failed to register %s path", AUDIO_MANAGER_PATH);
-		close(sk);
 		return -1;
 	}
 
@@ -410,28 +1183,30 @@
 				AUDIO_MANAGER_INTERFACE, AUDIO_MANAGER_PATH);
 		dbus_connection_destroy_object_path(conn,
 							AUDIO_MANAGER_PATH);
-		close(sk);
 		return -1;
 	}
 
 	connection = dbus_connection_ref(conn);
 
+	info("Registered manager path:%s", AUDIO_MANAGER_PATH);
+
+	register_stored();
+
 	return 0;
 }
 
 void audio_exit(void)
 {
-	close(unix_sock);
-
-	unix_sock = -1;
-
-	if (headsets) {
-		g_slist_foreach(headsets, (GFunc) manager_remove_headset, NULL);
-		g_slist_free(headsets);
-		headsets = NULL;
-	}
+	g_slist_foreach(devices, (GFunc) remove_device, NULL);
+	g_slist_free(devices);
+	devices = NULL;
 
 	dbus_connection_unref(connection);
 
 	connection = NULL;
 }
+
+struct device *manager_default_device()
+{
+	return default_dev;
+}

Modified: bluez-utils/branches/upstream/current/audio/manager.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/manager.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/manager.h (original)
+++ bluez-utils/branches/upstream/current/audio/manager.h Wed Jul  4 13:37:57 2007
@@ -21,19 +21,18 @@
  *
  */
 
-#include <bluetooth/bluetooth.h>
-
 #include <dbus/dbus.h>
 
-#include "headset.h"
+#include "device.h"
 
+#define MAX_PATH_LENGTH 64 /* D-Bus path */
 #define AUDIO_MANAGER_PATH "/org/bluez/audio"
 #define AUDIO_MANAGER_INTERFACE "org.bluez.audio.Manager"
-
-#define HEADSET_PATH_BASE AUDIO_MANAGER_PATH "/headset"
-
-void manager_add_headset(const char *path);
 
 int audio_init(DBusConnection *conn);
 
 void audio_exit(void);
+
+struct device *manager_device_connected(bdaddr_t *bda);
+
+struct device *manager_default_device();

Modified: bluez-utils/branches/upstream/current/audio/pcm_bluetooth.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/pcm_bluetooth.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/pcm_bluetooth.c (original)
+++ bluez-utils/branches/upstream/current/audio/pcm_bluetooth.c Wed Jul  4 13:37:57 2007
@@ -31,32 +31,44 @@
 #include <alsa/asoundlib.h>
 #include <alsa/pcm_external.h>
 
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sco.h>
+
 #include "ipc.h"
 
-#ifndef UNIX_PATH_MAX
-#define UNIX_PATH_MAX 108
+#ifdef ENABLE_DEBUG
+#define DBG(fmt, arg...)  printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
+#else
+#define DBG(fmt, arg...)
 #endif
 
-#define DBG(fmt, arg...)  printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
-
-#define SOCKET_NAME "/org/bluez/audio"
+#ifndef SCO_TXBUFS
+#define SCO_TXBUFS 0x03
+#endif
+
+#ifndef SCO_RXBUFS
+#define SCO_RXBUFS 0x04
+#endif
 
 struct bluetooth_data {
 	snd_pcm_ioplug_t io;
 	snd_pcm_sframes_t hw_ptr;
-	int sock;
+	struct ipc_data_cfg cfg;	/* Bluetooth device config */
+	int sock;			/* Daemon unix socket */
+	uint8_t *buffer;		/* Transfer buffer */
+	uint8_t count;			/* Transfer buffer counter */
 };
 
 static int bluetooth_start(snd_pcm_ioplug_t *io)
 {
-	DBG("io %p", io);
+	DBG("bluetooth_start %p", io);
 
 	return 0;
 }
 
 static int bluetooth_stop(snd_pcm_ioplug_t *io)
 {
-	DBG("io %p", io);
+	DBG("bluetooth_stop %p", io);
 
 	return 0;
 }
@@ -65,22 +77,196 @@
 {
 	struct bluetooth_data *data = io->private_data;
 
-	//DBG("io %p", io);
-
-	//DBG("hw_ptr=%lu", data->hw_ptr);
+	DBG("bluetooth_pointer %p", io);
+
+	DBG("hw_ptr=%lu", data->hw_ptr);
 
 	return data->hw_ptr;
 }
 
+static void bluetooth_exit(struct bluetooth_data *data)
+{
+	if (data == NULL)
+		return;
+
+	if (data->sock >= 0)
+		close(data->sock);
+
+	if (data->buffer)
+		free(data->buffer);
+
+	free(data);
+}
+
 static int bluetooth_close(snd_pcm_ioplug_t *io)
 {
 	struct bluetooth_data *data = io->private_data;
 
-	DBG("io %p", io);
-
-	free(data);
-
-	return 0;
+	DBG("bluetooth_close %p", io);
+
+	bluetooth_exit(data);
+
+	return 0;
+}
+
+static int bluetooth_prepare(snd_pcm_ioplug_t *io)
+{
+	struct bluetooth_data *data = io->private_data;
+
+	DBG("Preparing with io->period_size = %lu, io->buffer_size = %lu",
+			io->period_size, io->buffer_size);
+
+	if (io->stream == SND_PCM_STREAM_PLAYBACK)
+		/* If not null for playback, xmms doesn't display time
+		 * correctly */
+		data->hw_ptr = 0;
+	else
+		/* ALSA library is really picky on the fact hw_ptr is not null.
+		 * If it is, capture won't start */
+		data->hw_ptr = io->period_size;
+
+	return 0;
+}
+
+static int bluetooth_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params)
+{
+	struct bluetooth_data *data = io->private_data;
+	struct ipc_data_cfg cfg = data->cfg;
+	uint32_t period_count = io->buffer_size / io->period_size;
+	int opt_name, err;
+
+	DBG("fd = %d, period_count = %d", cfg.fd, period_count);
+
+	opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
+			SCO_TXBUFS : SCO_RXBUFS;
+
+	if (setsockopt(cfg.fd, SOL_SCO, opt_name, &period_count,
+			sizeof(period_count)) == 0)
+		return 0;
+
+	opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
+		SO_SNDBUF : SO_RCVBUF;
+
+	if (setsockopt(cfg.fd, SOL_SCO, opt_name, &period_count,
+			sizeof(period_count)) == 0)
+		return 0;
+
+	err = errno;
+	SNDERR("%s (%d)", strerror(err), err);
+
+	return -err;
+}
+
+static snd_pcm_sframes_t bluetooth_read(snd_pcm_ioplug_t *io,
+					const snd_pcm_channel_area_t *areas,
+					snd_pcm_uframes_t offset,
+					snd_pcm_uframes_t size)
+{
+	struct bluetooth_data *data = io->private_data;
+	struct ipc_data_cfg cfg = data->cfg;
+	snd_pcm_uframes_t frames_to_write, ret;
+	unsigned char *buff;
+	int nrecv, frame_size = 0;
+
+	DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu, io->nonblock=%u",
+		areas->step, areas->first, offset, size, io->nonblock);
+
+	if (data->count > 0)
+		goto proceed;
+
+	frame_size = areas->step / 8;
+
+	nrecv = recv(cfg.fd, data->buffer, cfg.pkt_len,
+			MSG_WAITALL | (io->nonblock ? MSG_DONTWAIT : 0));
+
+	if (nrecv < 0) {
+		ret = (errno == EPIPE) ? -EIO : -errno;
+		goto done;
+	}
+
+	if (nrecv != cfg.pkt_len) {
+		ret = -EIO;
+		SNDERR(strerror(-ret));
+		goto done;
+	}
+
+	/* Increment hardware transmition pointer */
+	data->hw_ptr = (data->hw_ptr + cfg.pkt_len / cfg.sample_size) % io->buffer_size;
+
+proceed:
+	buff = (unsigned char *) areas->addr + (areas->first + areas->step * offset) / 8;
+
+	if ((data->count + cfg.sample_size * size) <= cfg.pkt_len)
+		frames_to_write = size;
+	else
+		frames_to_write = (cfg.pkt_len - data->count) / frame_size;
+
+	memcpy(buff, data->buffer + data->count, frame_size * frames_to_write);
+	data->count += (frame_size * frames_to_write);
+	data->count %= cfg.pkt_len;
+
+	/* Return written frames count */
+	ret = frames_to_write;
+
+done:
+	DBG("returning %lu", ret);
+	return ret;
+}
+
+static snd_pcm_sframes_t bluetooth_write(snd_pcm_ioplug_t *io,
+					const snd_pcm_channel_area_t *areas,
+					snd_pcm_uframes_t offset,
+					snd_pcm_uframes_t size)
+{
+	struct bluetooth_data *data = io->private_data;
+	struct ipc_data_cfg cfg = data->cfg;
+	snd_pcm_sframes_t ret = 0;
+	snd_pcm_uframes_t frames_to_read;
+	uint8_t *buff;
+	int rsend, frame_size;
+
+	DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu,"
+			"io->nonblock=%u", areas->step, areas->first,
+			offset, size, io->nonblock);
+
+	frame_size = areas->step / 8;
+	if ((data->count + size * frame_size) <= cfg.pkt_len)
+		frames_to_read = size;
+	else
+		frames_to_read = (cfg.pkt_len - data->count) / frame_size;
+
+	DBG("count = %d, frames_to_read = %lu", data->count, frames_to_read);
+
+	/* Ready for more data */
+	buff = (uint8_t *) areas->addr + (areas->first + areas->step * offset) / 8;
+	memcpy(data->buffer + data->count, buff, frame_size * frames_to_read);
+
+	if ((data->count + frames_to_read * frame_size) != cfg.pkt_len) {
+		/* Remember we have some frame in the pipe now */
+		data->count += frames_to_read * frame_size;
+		ret = frames_to_read;
+		goto done;
+	}
+
+	rsend = send(cfg.fd, data->buffer, cfg.pkt_len,
+			io->nonblock ? MSG_DONTWAIT : 0);
+	if (rsend > 0) {
+		/* Reset count pointer */
+		data->count = 0;
+
+		/* Increment hardware transmition pointer */
+		data->hw_ptr = (data->hw_ptr + cfg.pkt_len / frame_size)
+				% io->buffer_size;
+
+		ret = frames_to_read;
+	} else if (rsend < 0)
+		ret = (errno == EPIPE) ? -EIO : -errno;
+	else
+		ret = -EIO;
+
+done:
+	DBG("returning %d", (int)ret);
+	return ret;
 }
 
 static snd_pcm_ioplug_callback_t bluetooth_playback_callback = {
@@ -88,11 +274,9 @@
 	.stop		= bluetooth_stop,
 	.pointer	= bluetooth_pointer,
 	.close		= bluetooth_close,
-#if 0
 	.hw_params	= bluetooth_hw_params,
 	.prepare	= bluetooth_prepare,
 	.transfer	= bluetooth_write,
-#endif
 };
 
 static snd_pcm_ioplug_callback_t bluetooth_capture_callback = {
@@ -100,17 +284,17 @@
 	.stop		= bluetooth_stop,
 	.pointer	= bluetooth_pointer,
 	.close		= bluetooth_close,
-#if 0
 	.hw_params	= bluetooth_hw_params,
 	.prepare	= bluetooth_prepare,
 	.transfer	= bluetooth_read,
-#endif
 };
 
 #define ARRAY_NELEMS(a) (sizeof((a)) / sizeof((a)[0]))
 
 static int bluetooth_hw_constraint(snd_pcm_ioplug_t *io)
 {
+	struct bluetooth_data *data = io->private_data;
+	struct ipc_data_cfg cfg = data->cfg;
 	snd_pcm_access_t access_list[] = {
 		SND_PCM_ACCESS_RW_INTERLEAVED,
 		/* Mmap access is really useless fo this driver, but we
@@ -123,30 +307,215 @@
 	};
 	int err;
 
+	/* access type */
 	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
 					ARRAY_NELEMS(access_list), access_list);
 	if (err < 0)
 		return err;
 
+	/* supported formats */
 	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
 					ARRAY_NELEMS(format_list), format_list);
 	if (err < 0)
 		return err;
 
-	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, 1, 1);
-	if (err < 0)
-		return err;
-
-	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, 8000, 8000);
-	if (err < 0)
-		return err;
-
-	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 48, 48);
-	if (err < 0)
-		return err;
-
-	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 200);
-	if (err < 0)
+	/* supported channels */
+	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS,
+					cfg.channels, cfg.channels);
+	if (err < 0)
+		return err;
+
+	/* supported rate */
+	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE,
+					cfg.rate, cfg.rate);
+	if (err < 0)
+		return err;
+
+	/* supported block size */
+	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
+					cfg.pkt_len, cfg.pkt_len);
+	if (err < 0)
+		return err;
+
+	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS,
+					2, 200);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int bluetooth_recvmsg_fd(struct bluetooth_data *data)
+{
+	char cmsg_b[CMSG_SPACE(sizeof(int))];
+	struct ipc_packet pkt;
+	int err, ret;
+	struct iovec iov = {
+		.iov_base = &pkt,
+		.iov_len  = sizeof(pkt)
+        };
+	struct msghdr msgh = {
+		.msg_name       = 0,
+		.msg_namelen    = 0,
+		.msg_iov        = &iov,
+		.msg_iovlen     = 1,
+		.msg_control    = &cmsg_b,
+		.msg_controllen = CMSG_LEN(sizeof(int)),
+		.msg_flags      = 0
+	};
+
+	ret = recvmsg(data->sock, &msgh, 0);
+
+	if (ret < 0) {
+		err = errno;
+		SNDERR("Unable to receive fd: %s (%d)", strerror(err), err);
+		return -err;
+	}
+
+	if (pkt.type == PKT_TYPE_CFG_RSP) {
+		struct cmsghdr *cmsg;
+		/* Receive auxiliary data in msgh */
+		for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
+				cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
+			if (cmsg->cmsg_level == SOL_SOCKET
+				&& cmsg->cmsg_type == SCM_RIGHTS)
+				data->cfg.fd = (*(int *) CMSG_DATA(cmsg));
+				DBG("fd = %d", data->cfg.fd);
+				return 0;
+		}
+	}
+	else
+		SNDERR("Unexpected packet type received: type = %d", pkt.type);
+
+	return -EINVAL;
+}
+
+static int bluetooth_cfg(struct bluetooth_data *data)
+{
+	int ret, len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_cfg);
+	struct ipc_packet *pkt;
+
+	DBG("Sending PKT_TYPE_CFG_REQ...");
+
+	if ((pkt = malloc(len)) == 0)
+		return -ENOMEM;
+
+	memset(pkt, 0, len);
+	pkt->type = PKT_TYPE_CFG_REQ;
+	pkt->role = PKT_ROLE_NONE;
+	pkt->error = PKT_ERROR_NONE;
+
+	if ((ret = send(data->sock, pkt, len, 0)) < 0) {
+		ret = -errno;
+		goto done;
+	} else if (ret == 0) {
+		ret = -EIO;
+		goto done;
+	}
+
+	DBG("OK - %d bytes sent", ret);
+
+	DBG("Waiting for response...");
+
+	memset(pkt, 0, len);
+	if ((ret = recv(data->sock, pkt, len, 0)) < 0) {
+		ret = -errno;
+		goto done;
+	} else if (ret == 0) {
+		ret = -EIO;
+		goto done;
+	}
+
+	DBG("OK - %d bytes received", ret);
+
+	if (pkt->type != PKT_TYPE_CFG_RSP) {
+		SNDERR("Unexpected packet type received: type = %d",
+				pkt->type);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if (pkt->error != PKT_ERROR_NONE) {
+		SNDERR("Error while configuring device: error = %d",
+				pkt->error);
+		ret = pkt->error;
+		goto done;
+	}
+
+	if (pkt->length != sizeof(struct ipc_data_cfg)) {
+		SNDERR("Error while configuring device: packet size doesn't "
+				"match");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	memcpy(&data->cfg, pkt->data, sizeof(struct ipc_data_cfg));
+
+	DBG("Device configuration:");
+
+	DBG("fd=%d, fd_opt=%u, channels=%u, pkt_len=%u, sample_size=%u,"
+			"rate=%u", data->cfg.fd, data->cfg.fd_opt,
+			data->cfg.channels, data->cfg.pkt_len,
+			data->cfg.sample_size, data->cfg.rate);
+
+	if (data->cfg.fd == -1) {
+		SNDERR("Error while configuring device: could not acquire "
+				"audio socket");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	if ((ret = bluetooth_recvmsg_fd(data)) < 0)
+		goto done;
+
+	if ((data->buffer = malloc(data->cfg.pkt_len)) == 0)
+		return -ENOMEM;
+
+	/* It is possible there is some outstanding
+	data in the pipe - we have to empty it */
+	while(recv(data->cfg.fd, data->buffer, data->cfg.pkt_len,
+		MSG_DONTWAIT) > 0);
+
+	memset(data->buffer, 0, data->cfg.pkt_len);
+
+done:
+	free(pkt);
+	return ret;
+}
+
+static int bluetooth_init(struct bluetooth_data *data)
+{
+	int sk, err, id;
+	struct sockaddr_un addr = {
+		AF_UNIX, IPC_SOCKET_NAME
+	};
+
+	if (!data)
+		return -EINVAL;
+
+	memset(data, 0, sizeof(struct bluetooth_data));
+
+	data->sock = -1;
+
+	id = abs(getpid() * rand());
+
+	if ((sk = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+		err = -errno;
+		SNDERR("Can't open socket");
+		return -errno;
+	}
+
+	DBG("Connecting to address: %s", addr.sun_path + 1);
+	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		err = -errno;
+		SNDERR("Can't connect socket");
+		close(sk);
+		return err;
+	}
+
+	data->sock = sk;
+
+	if ((err = bluetooth_cfg(data)) < 0)
 		return err;
 
 	return 0;
@@ -154,86 +523,32 @@
 
 SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)
 {
-	snd_config_iterator_t iter, next;
 	struct bluetooth_data *data;
-	struct sockaddr_un addr;
-	unsigned int id;
-	int sk, err;
+	int err;
 
 	DBG("Bluetooth PCM plugin (%s)",
 		stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture");
 
-	snd_config_for_each(iter, next, conf) {
-		snd_config_t *n = snd_config_iterator_entry(iter);
-		const char *id;
-
-		if (snd_config_get_id(n, &id) < 0)
-			continue;
-
-		if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
-			continue;
-
-		if (strcmp(id, "bdaddr") == 0) {
-			const char *str;
-			if (snd_config_get_string(n, &str) < 0) {
-				SNDERR("Invalid type for %s", id);
-				return -EINVAL;
-			}
-			printf("bdaddr %s\n", str);
-			continue;
-		}
-
-		SNDERR("Unknown field %s", id);
-
-		return -EINVAL;
-	}
-
-	id = abs(getpid() * rand());
-
-	sk = socket(PF_LOCAL, SOCK_DGRAM, 0);
-	if (sk < 0) {
-		SNDERR("Can't open socket");
-		return -errno;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s/%d", SOCKET_NAME, id);
-
-	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		SNDERR("Can't bind socket");
-		close(sk);
-		return -errno;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s", SOCKET_NAME);
-
-	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		SNDERR("Can't connect socket");
-		close(sk);
-		return -errno;
-	}
-
-	data = malloc(sizeof(*data));
+	data = malloc(sizeof(struct bluetooth_data));
+	memset(data, 0, sizeof(struct bluetooth_data));
 	if (!data) {
-		close(sk);
-		return -ENOMEM;
-	}
-
-	memset(data, 0, sizeof(*data));
-
-	data->sock = sk;
+		err = -ENOMEM;
+		goto error;
+	}
+
+	err = bluetooth_init(data);
+	if (err < 0)
+		goto error;
 
 	data->io.version = SND_PCM_IOPLUG_VERSION;
-	data->io.name = "Bluetooth Audio";
-	data->io.mmap_rw =  0;		/* No direct mmap communication */
+	data->io.name = "Bluetooth Audio Device";
+	data->io.mmap_rw = 0; /* No direct mmap communication */
 
 	data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
 		&bluetooth_playback_callback : &bluetooth_capture_callback;
-	data->io.poll_fd = sk;
-	data->io.poll_events = POLLIN;
+	data->io.poll_fd = data->cfg.fd;
+	data->io.poll_events = stream == SND_PCM_STREAM_PLAYBACK ?
+					POLLOUT : POLLIN;
 	data->io.private_data = data;
 
 	err = snd_pcm_ioplug_create(&data->io, name, stream, mode);
@@ -243,7 +558,7 @@
 	err = bluetooth_hw_constraint(&data->io);
 	if (err < 0) {
 		snd_pcm_ioplug_delete(&data->io);
-		goto error; 
+		goto error;
 	}
 
 	*pcmp = data->io.pcm;
@@ -251,9 +566,7 @@
 	return 0;
 
 error:
-	close(sk);
-
-	free(data);
+	bluetooth_exit(data);
 
 	return err;
 }

Added: bluez-utils/branches/upstream/current/audio/test-audio
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/test-audio?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/test-audio (added)
+++ bluez-utils/branches/upstream/current/audio/test-audio Wed Jul  4 13:37:57 2007
@@ -1,0 +1,19 @@
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'),
+							'org.bluez.Manager')
+
+conn = manager.ActivateService('audio')
+
+audio = dbus.Interface(bus.get_object(conn, '/org/bluez/audio'),
+						'org.bluez.audio.Manager')
+
+try:
+	headset = dbus.Interface(bus.get_object(conn, audio.DefaultHeadset()),
+						'org.bluez.audio.Headset')
+except:
+	pass

Propchange: bluez-utils/branches/upstream/current/audio/test-audio
------------------------------------------------------------------------------
    svn:executable = *

Added: bluez-utils/branches/upstream/current/audio/unix.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/unix.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/unix.c (added)
+++ bluez-utils/branches/upstream/current/audio/unix.c Wed Jul  4 13:37:57 2007
@@ -1,0 +1,217 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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 <stdio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include <glib.h>
+
+#include "logging.h"
+#include "dbus.h"
+
+#include "manager.h"
+
+static int unix_sock = -1;
+
+/* Pass file descriptor through local domain sockets (AF_LOCAL, formerly AF_UNIX)
+and the sendmsg() system call with the cmsg_type field of a "struct cmsghdr" set
+to SCM_RIGHTS and the data being an integer value equal to the handle of the 
+file descriptor to be passed.*/
+static int unix_sendmsg_fd(int sock, int fd, struct ipc_packet *pkt)
+{
+	char cmsg_b[CMSG_SPACE(sizeof(int))];
+	struct cmsghdr *cmsg;
+	struct iovec iov =  {
+		.iov_base = pkt,
+		.iov_len  = sizeof(struct ipc_packet)
+        };
+
+	struct msghdr msgh = {
+		.msg_name       = 0,
+		.msg_namelen    = 0,
+		.msg_iov        = &iov,
+		.msg_iovlen     = 1,
+		.msg_control    = &cmsg_b,
+		.msg_controllen = CMSG_LEN(sizeof(int)),
+		.msg_flags      = 0
+	};
+
+	cmsg = CMSG_FIRSTHDR(&msgh);
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = SCM_RIGHTS;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+	/* Initialize the payload */
+	(*(int *) CMSG_DATA(cmsg)) = fd;
+
+	return sendmsg(sock, &msgh, MSG_NOSIGNAL);
+}
+
+static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+	struct device *device;
+	struct sockaddr_un addr;
+	socklen_t addrlen;
+	struct ipc_packet *pkt;
+	struct ipc_data_cfg *cfg;
+	int sk, clisk, len;
+
+	debug("chan %p cond %td data %p", chan, cond, data);
+
+	if (cond & G_IO_NVAL)
+		return FALSE;
+
+	if (cond & (G_IO_HUP | G_IO_ERR)) {
+		g_io_channel_close(chan);
+		return FALSE;
+	}
+
+	sk = g_io_channel_unix_get_fd(chan);
+
+	memset(&addr, 0, sizeof(addr));
+	addrlen = sizeof(addr);
+
+	clisk = accept(sk, (struct sockaddr *) &addr, &addrlen);
+	if (clisk < 0) {
+		error("accept: %s (%d)", strerror(errno), errno);
+		return TRUE;
+	}
+
+	len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_cfg);
+	pkt = g_malloc0(len);
+	len = recv(clisk, pkt, len, 0);
+
+	debug("path %s len %d", addr.sun_path + 1, len);
+
+	switch (pkt->type) {
+	case PKT_TYPE_CFG_REQ:
+		info("Package PKT_TYPE_CFG_REQ:%u", pkt->role);
+
+		cfg = (struct ipc_data_cfg *) pkt->data;
+
+		memset(cfg, 0, sizeof(struct ipc_data_cfg));
+		if ((device = manager_default_device())) {
+			if (device->headset)
+				headset_get_config(device, clisk, pkt);
+		}
+
+		if (cfg->fd != 0)
+			unix_send_cfg(clisk, pkt);
+		break;
+	case PKT_TYPE_STATUS_REQ:
+		info("Package PKT_TYPE_STATUS_REQ");
+		break;
+	case PKT_TYPE_CTL_REQ:
+		info("Package PKT_TYPE_CTL_REQ");
+		break;
+	}
+
+	return TRUE;
+}
+
+int unix_init(void)
+{
+	GIOChannel *io;
+	struct sockaddr_un addr = {
+		AF_UNIX, IPC_SOCKET_NAME
+	};
+
+	int sk, err;
+
+	sk = socket(PF_LOCAL, SOCK_STREAM, 0);
+	if (sk < 0) {
+		err = errno;
+		error("Can't create unix socket: %s (%d)", strerror(err), err);
+		return -err;
+	}
+
+	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		error("Can't bind unix socket: %s (%d)", strerror(errno), errno);
+		close(sk);
+		return -1;
+	}
+
+	set_nonblocking(sk);
+
+	unix_sock = sk;
+
+	listen(sk, 1);
+
+	io = g_io_channel_unix_new(sk);
+
+	g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+							unix_event, NULL);
+
+	g_io_channel_unref(io);
+
+	info("Unix socket created: %d", sk);
+
+	return 0;
+}
+
+void unix_exit(void)
+{
+	close(unix_sock);
+	unix_sock = -1;
+}
+
+int unix_send_cfg(int sock, struct ipc_packet *pkt)
+{
+	struct ipc_data_cfg *cfg = (struct ipc_data_cfg *) pkt->data;
+	int len;
+
+	info("fd=%d, fd_opt=%u, channels=%u, pkt_len=%u, sample_size=%u,"
+		"rate=%u", cfg->fd, cfg->fd_opt, cfg->channels,
+		cfg->pkt_len, cfg->sample_size, cfg->rate);
+
+	pkt->type = PKT_TYPE_CFG_RSP;
+	pkt->length = sizeof(struct ipc_data_cfg);
+	pkt->error = PKT_ERROR_NONE;
+
+	len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_cfg);
+	len = send(sock, pkt, len, 0);
+	if (len < 0)
+		info("Error %s(%d)", strerror(errno), errno);
+
+	info("%d bytes sent", len);
+
+	if (cfg->fd != -1) {
+		len = unix_sendmsg_fd(sock, cfg->fd, pkt);
+		if (len < 0)
+			info("Error %s(%d)", strerror(errno), errno);
+		info("%d bytes sent", len);
+	}
+
+	g_free(pkt);
+	close(sock);
+	return 0;
+}

Added: bluez-utils/branches/upstream/current/audio/unix.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/unix.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/unix.h (added)
+++ bluez-utils/branches/upstream/current/audio/unix.h Wed Jul  4 13:37:57 2007
@@ -1,0 +1,29 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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
+ *
+ */
+
+#include "ipc.h"
+
+int unix_init(void);
+
+void unix_exit(void);
+int unix_send_cfg(int sock, struct ipc_packet *pkt);

Modified: bluez-utils/branches/upstream/current/common/dbus-helper.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/dbus-helper.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/dbus-helper.c (original)
+++ bluez-utils/branches/upstream/current/common/dbus-helper.c Wed Jul  4 13:37:57 2007
@@ -285,7 +285,7 @@
 
 static void update_parent_data(DBusConnection *conn, const char *child_path)
 {
-	struct generic_data *data;
+	struct generic_data *data = NULL;
 	char *parent_path, *slash;
 
 	parent_path = g_strdup(child_path);
@@ -350,10 +350,10 @@
 							const char *path,
 							void **data_p)
 {
-	struct generic_data *data;
+	struct generic_data *data = NULL;
 
 	if (!dbus_connection_get_object_path_data(connection, path,
-							(void *) &data))
+						(void *) &data) || !data)
 		return FALSE;
 
 	*data_p = data->user_data;
@@ -367,11 +367,11 @@
 					DBusSignalVTable *signals,
 					DBusPropertyVTable *properties)
 {
-	struct generic_data *data;
+	struct generic_data *data = NULL;
 	struct interface_data *iface;
 
 	if (!dbus_connection_get_object_path_data(connection, path,
-							(void *) &data))
+						(void *) &data) || !data)
 		return FALSE;
 
 	if (find_interface(data->interfaces, name))
@@ -395,11 +395,11 @@
 dbus_bool_t dbus_connection_unregister_interface(DBusConnection *connection,
 					const char *path, const char *name)
 {
-	struct generic_data *data;
+	struct generic_data *data = NULL;
 	struct interface_data *iface;
 
 	if (!dbus_connection_get_object_path_data(connection, path,
-							(void *) &data))
+						(void *) &data) || !data)
 		return FALSE;
 
 	iface = find_interface(data->interfaces, name);
@@ -431,6 +431,9 @@
 	switch (type) {
 	case DBUS_TYPE_STRING:
 		sig = DBUS_TYPE_STRING_AS_STRING;
+		break;
+	case DBUS_TYPE_INT16:
+		sig = DBUS_TYPE_INT16_AS_STRING;
 		break;
 	case DBUS_TYPE_UINT32:
 		sig = DBUS_TYPE_UINT32_AS_STRING;
@@ -459,15 +462,15 @@
 						int first,
 						va_list var_args)
 {
-	struct generic_data *data;
+	struct generic_data *data = NULL;
 	struct interface_data *iface;
-	DBusMessageIter iter;
 	DBusSignalVTable *sig_data;
 	DBusMessage *signal;
-	int type;
-	const char *args = NULL;
-
-	if (!dbus_connection_get_object_path_data(conn, path, (void *) &data)) {
+	dbus_bool_t ret;
+	const char *signature, *args = NULL;
+
+	if (!dbus_connection_get_object_path_data(conn, path,
+					(void *) &data) || !data) {
 		error("dbus_connection_emit_signal: path %s isn't registered",
 				path);
 		return FALSE;
@@ -499,33 +502,23 @@
 		return FALSE;
 	}
 
-	dbus_message_iter_init_append(signal, &iter);
-
-	for (type = first; type != DBUS_TYPE_INVALID;
-			type = va_arg(var_args, int), args++) {
-		void *value;
-
-		if (type != *args) {
-			error("%s.%s: expected arg type '%c' but got '%c'",
-					interface, name, *args, type);
-			dbus_message_unref(signal);
-			return FALSE;
-		}
-		
-		value = va_arg(var_args, void *);
-
-		if (!dbus_message_iter_append_basic(&iter, type, value)) {
-			error("%s.%s: appending argument of type '%c' failed",
-					interface, name, type);
-			dbus_message_unref(signal);
-			return FALSE;
-		}
-	}
-
-	dbus_connection_send(conn, signal, NULL);
+	ret = dbus_message_append_args_valist(signal, first, var_args);
+	if (!ret)
+		goto fail;
+
+	signature = dbus_message_get_signature(signal);
+	if (strcmp(args, signature) != 0) {
+		error("%s.%s: expected signature'%s' but got '%s'",
+				interface, name, args, signature);
+		ret = FALSE;
+		goto fail;
+	}
+
+	ret = dbus_connection_send(conn, signal, NULL);
+fail:
 	dbus_message_unref(signal);
 
-	return TRUE;
+	return ret;
 }
 
 dbus_bool_t dbus_connection_emit_signal(DBusConnection *conn, const char *path,

Modified: bluez-utils/branches/upstream/current/common/dbus.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/dbus.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/dbus.c (original)
+++ bluez-utils/branches/upstream/current/common/dbus.c Wed Jul  4 13:37:57 2007
@@ -61,6 +61,12 @@
 	GIOChannel *io;
 	DBusConnection *conn;
 };
+
+struct server_info {
+	guint watch_id;
+	GIOChannel *io;
+	DBusServer *server;
+};
 #endif
 
 struct disconnect_data {
@@ -74,25 +80,34 @@
 };
 
 struct name_data {
+	DBusConnection *connection;
 	char *name;
 	GSList *callbacks;
 };
 
-static struct name_data *name_data_find(const char *name)
+static struct name_data *name_data_find(DBusConnection *connection,
+							const char *name)
 {
 	GSList *current;
 
-	for (current = name_listeners; current != NULL; current = current->next) {
+	for (current = name_listeners;
+			current != NULL; current = current->next) {
 		struct name_data *data = current->data;
-		if (strcmp(name, data->name) == 0)
-			return data;
+
+		if (name == NULL && data->name == NULL) {
+			if (connection == data->connection)
+				return data;
+		} else {
+			if (strcmp(name, data->name) == 0)
+				return data;
+		}
 	}
 
 	return NULL;
 }
 
 static struct name_callback *name_callback_find(GSList *callbacks,
-						name_cb_t func, void *user_data)
+					name_cb_t func, void *user_data)
 {
 	GSList *current;
 
@@ -105,19 +120,36 @@
 	return NULL;
 }
 
-static void name_data_free(struct name_data *data)
+static void name_data_call_and_free(struct name_data *data)
 {
 	GSList *l;
 
-	for (l = data->callbacks; l != NULL; l = l->next)
-		g_free(l->data);
+	for (l = data->callbacks; l != NULL; l = l->next) {
+		struct name_callback *cb = l->data;
+		if (cb->func)
+			cb->func(data->name, cb->user_data);
+		g_free(cb);
+	}
 
 	g_slist_free(data->callbacks);
 	g_free(data->name);
 	g_free(data);
 }
 
-static int name_data_add(const char *name, name_cb_t func, void *user_data)
+static void name_data_free(struct name_data *data)
+{
+	GSList *l;
+
+	for (l = data->callbacks; l != NULL; l = l->next)
+		g_free(l->data);
+
+	g_slist_free(data->callbacks);
+	g_free(data->name);
+	g_free(data);
+}
+
+static int name_data_add(DBusConnection *connection,
+			const char *name, name_cb_t func, void *user_data)
 {
 	int first = 1;
 	struct name_data *data = NULL;
@@ -128,7 +160,7 @@
 	cb->func = func;
 	cb->user_data = user_data;
 
-	data = name_data_find(name);
+	data = name_data_find(connection, name);
 	if (data) {
 		first = 0;
 		goto done;
@@ -136,6 +168,7 @@
 
 	data = g_new0(struct name_data, 1);
 
+	data->connection = connection;
 	data->name = g_strdup(name);
 
 	name_listeners = g_slist_append(name_listeners, data);
@@ -145,12 +178,13 @@
 	return first;
 }
 
-static void name_data_remove(const char *name, name_cb_t func, void *user_data)
+static void name_data_remove(DBusConnection *connection,
+			const char *name, name_cb_t func, void *user_data)
 {
 	struct name_data *data;
 	struct name_callback *cb = NULL;
 
-	data = name_data_find(name);
+	data = name_data_find(connection, name);
 	if (!data)
 		return;
 
@@ -190,7 +224,7 @@
 	if (*new != '\0')
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-	data = name_data_find(name);
+	data = name_data_find(connection, name);
 	if (!data) {
 		error("Got NameOwnerChanged signal for %s which has no listeners", name);
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -215,50 +249,51 @@
 	int first;
 
 	if (!name_listener_initialized) {
-		if (!dbus_connection_add_filter(connection, name_exit_filter, NULL, NULL)) {
+		if (!dbus_connection_add_filter(connection,
+					name_exit_filter, NULL, NULL)) {
 			error("dbus_connection_add_filter() failed");
 			return -1;
 		}
 		name_listener_initialized = 1;
 	}
 
-	first = name_data_add(name, func, user_data);
+	first = name_data_add(connection, name, func, user_data);
 	/* The filter is already added if this is not the first callback
 	 * registration for the name */
 	if (!first)
 		return 0;
 
-	debug("name_listener_add(%s)", name);
-
-	snprintf(match_string, sizeof(match_string),
-			"interface=%s,member=NameOwnerChanged,arg0=%s",
-			DBUS_INTERFACE_DBUS, name);
-
-	dbus_error_init(&err);
-	dbus_bus_add_match(connection, match_string, &err);
-
-	if (dbus_error_is_set(&err)) {
-		error("Adding match rule \"%s\" failed: %s", match_string,
-				err.message);
-		dbus_error_free(&err);
-		name_data_remove(name, func, user_data);
-		return -1;
+	if (name) {
+		debug("name_listener_add(%s)", name);
+
+		snprintf(match_string, sizeof(match_string),
+				"interface=%s,member=NameOwnerChanged,arg0=%s",
+						DBUS_INTERFACE_DBUS, name);
+
+		dbus_error_init(&err);
+		dbus_bus_add_match(connection, match_string, &err);
+
+		if (dbus_error_is_set(&err)) {
+			error("Adding match rule \"%s\" failed: %s",
+						match_string, err.message);
+			dbus_error_free(&err);
+			name_data_remove(connection, name, func, user_data);
+			return -1;
+		}
 	}
 
 	return 0;
 }
 
 int name_listener_remove(DBusConnection *connection, const char *name,
-				name_cb_t func, void *user_data)
+					name_cb_t func, void *user_data)
 {
 	struct name_data *data;
 	struct name_callback *cb;
 	DBusError err;
 	char match_string[128];
 
-	debug("name_listener_remove(%s)", name);
-
-	data = name_data_find(name);
+	data = name_data_find(connection, name);
 	if (!data) {
 		error("remove_name_listener: no listener for %s", name);
 		return -1;
@@ -277,21 +312,43 @@
 	if (data->callbacks)
 		return 0;
 
-	snprintf(match_string, sizeof(match_string),
-			"interface=%s,member=NameOwnerChanged,arg0=%s",
-			DBUS_INTERFACE_DBUS, name);
-
-	dbus_error_init(&err);
-	dbus_bus_remove_match(connection, match_string, &err);
-
-	if (dbus_error_is_set(&err)) {
-		error("Removing owner match rule for %s failed: %s",
+	if (name) {
+		debug("name_listener_remove(%s)", name);
+
+		snprintf(match_string, sizeof(match_string),
+				"interface=%s,member=NameOwnerChanged,arg0=%s",
+						DBUS_INTERFACE_DBUS, name);
+
+		dbus_error_init(&err);
+
+		dbus_bus_remove_match(connection, match_string, &err);
+
+		if (dbus_error_is_set(&err)) {
+			error("Removing owner match rule for %s failed: %s",
 							name, err.message);
-		dbus_error_free(&err);
+			dbus_error_free(&err);
+			return -1;
+		}
+	}
+
+	name_data_remove(connection, name, func, user_data);
+
+	return 0;
+}
+
+int name_listener_indicate_disconnect(DBusConnection *connection)
+{
+	struct name_data *data;
+
+	data = name_data_find(connection, NULL);
+	if (!data) {
+		error("name_listener_indicate_disconnect: no listener found");
 		return -1;
 	}
 
-	name_data_remove(name, func, user_data);
+	debug("name_listener_indicate_disconnect");
+
+	name_data_call_and_free(data);
 
 	return 0;
 }
@@ -371,6 +428,75 @@
 }
 
 #ifndef HAVE_DBUS_GLIB
+static dbus_int32_t server_slot = -1;
+
+static gboolean server_func(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+	DBusWatch *watch = data;
+	int flags = 0;
+
+	if (cond & G_IO_IN)  flags |= DBUS_WATCH_READABLE;
+	if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
+	if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP;
+	if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR;
+
+	dbus_watch_handle(watch, flags);
+
+	return TRUE;
+}
+
+static dbus_bool_t add_server(DBusWatch *watch, void *data)
+{
+	GIOCondition cond = G_IO_HUP | G_IO_ERR;
+	DBusServer *server = data;
+	struct server_info *info;
+	int fd, flags;
+
+	if (!dbus_watch_get_enabled(watch))
+		return TRUE;
+
+	info = g_new(struct server_info, 1);
+
+	fd = dbus_watch_get_fd(watch);
+	info->io = g_io_channel_unix_new(fd);
+	info->server = dbus_server_ref(server);
+
+	dbus_watch_set_data(watch, info, NULL);
+
+	flags = dbus_watch_get_flags(watch);
+
+	if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN;
+	if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT;
+
+	info->watch_id = g_io_add_watch(info->io, cond, server_func, watch);
+
+	return TRUE;
+}
+
+static void remove_server(DBusWatch *watch, void *data)
+{
+	struct server_info *info = dbus_watch_get_data(watch);
+
+	dbus_watch_set_data(watch, NULL, NULL);
+
+	if (info) {
+		g_source_remove(info->watch_id);
+		g_io_channel_unref(info->io);
+		dbus_server_unref(info->server);
+		g_free(info);
+	}
+}
+
+static void server_toggled(DBusWatch *watch, void *data)
+{
+	/* Because we just exit on OOM, enable/disable is
+	 * no different from add/remove */
+	if (dbus_watch_get_enabled(watch))
+		add_server(watch, data);
+	else
+		remove_server(watch, data);
+}
+
 static gboolean message_dispatch_cb(void *data)
 {
 	DBusConnection *connection = data;
@@ -520,6 +646,45 @@
 }
 #endif
 
+void setup_dbus_server_with_main_loop(DBusServer *server)
+{
+#ifdef HAVE_DBUS_GLIB
+	debug("Using D-Bus GLib server setup");
+
+	dbus_server_setup_with_g_main(server, NULL);
+#else
+	dbus_server_allocate_data_slot(&server_slot);
+	if (server_slot < 0)
+		return;
+
+	dbus_server_set_data(server, server_slot, server, NULL);
+
+	dbus_server_set_watch_functions(server, add_server, remove_server,
+						server_toggled, server, NULL);
+
+	dbus_server_set_timeout_functions(server, add_timeout, remove_timeout,
+						timeout_toggled, server, NULL);
+#endif
+}
+
+void setup_dbus_with_main_loop(DBusConnection *conn)
+{
+#ifdef HAVE_DBUS_GLIB
+	debug("Using D-Bus GLib connection setup");
+
+	dbus_connection_setup_with_g_main(conn, NULL);
+#else
+	dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
+						watch_toggled, conn, NULL);
+
+	dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
+						timeout_toggled, conn, NULL);
+
+	dbus_connection_set_dispatch_status_function(conn, dispatch_status_cb,
+								conn, NULL);
+#endif
+}
+
 DBusConnection *init_dbus(const char *name,
 				void (*disconnect_cb)(void *), void *user_data)
 {
@@ -537,18 +702,7 @@
 		return NULL;
 	}
 
-#ifdef HAVE_DBUS_GLIB
-	dbus_connection_setup_with_g_main(conn, NULL);
-#else
-	dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
-						watch_toggled, conn, NULL);
-
-	dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
-						timeout_toggled, conn, NULL);
-
-	dbus_connection_set_dispatch_status_function(conn, dispatch_status_cb,
-								conn, NULL);
-#endif
+	setup_dbus_with_main_loop(conn);
 
 	if (name) {
 		dbus_error_init(&err);
@@ -589,6 +743,28 @@
 	return conn;
 }
 
+DBusConnection *init_dbus_direct(const char *address)
+{
+	DBusConnection *conn;
+	DBusError err;
+
+	dbus_error_init(&err);
+
+	conn = dbus_connection_open(address, &err);
+
+	if (dbus_error_is_set(&err)) {
+		error("Can't connect to message server: %s", err.message);
+		dbus_error_free(&err);
+		return NULL;
+	}
+
+	setup_dbus_with_main_loop(conn);
+
+	dbus_connection_set_exit_on_disconnect(conn, FALSE);
+
+	return conn;
+}
+
 DBusConnection *dbus_bus_system_setup_with_main_loop(const char *name,
 				void (*disconnect_cb)(void *), void *user_data)
 {

Modified: bluez-utils/branches/upstream/current/common/dbus.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/dbus.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/dbus.h (original)
+++ bluez-utils/branches/upstream/current/common/dbus.h Wed Jul  4 13:37:57 2007
@@ -26,8 +26,13 @@
 
 #include <dbus/dbus.h>
 
+void setup_dbus_server_with_main_loop(DBusServer *server);
+void setup_dbus_with_main_loop(DBusConnection *conn);
+
 DBusConnection *init_dbus(const char *name,
 				void (*disconnect_cb)(void *), void *user_data);
+
+DBusConnection *init_dbus_direct(const char *address);
 
 DBusConnection *dbus_bus_system_setup_with_main_loop(const char *name,
 				void (*disconnect_cb)(void *), void *user_data);
@@ -41,6 +46,7 @@
 				name_cb_t func, void *user_data);
 int name_listener_remove(DBusConnection *connection, const char *name,
 				name_cb_t func, void *user_data);
+int name_listener_indicate_disconnect(DBusConnection *connection);
 
 dbus_bool_t dbus_bus_get_unix_process_id(DBusConnection *conn, const char *name,
 						unsigned long *pid);

Modified: bluez-utils/branches/upstream/current/common/ppoll.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/ppoll.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/ppoll.h (original)
+++ bluez-utils/branches/upstream/current/common/ppoll.h Wed Jul  4 13:37:57 2007
@@ -1,4 +1,10 @@
-static inline int ppoll(struct pollfd *fds, nfds_t nfds,
+#ifdef ppoll
+#undef ppoll
+#endif
+
+#define ppoll compat_ppoll
+
+static inline int compat_ppoll(struct pollfd *fds, nfds_t nfds,
 		const struct timespec *timeout, const sigset_t *sigmask)
 {
 	return poll(fds, nfds, timeout ? timeout->tv_sec * 1000 : 500);

Modified: bluez-utils/branches/upstream/current/common/sdp-expat.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/sdp-expat.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/sdp-expat.c (original)
+++ bluez-utils/branches/upstream/current/common/sdp-expat.c Wed Jul  4 13:37:57 2007
@@ -116,7 +116,8 @@
 			}
 		}
 
-		context->stack_head->data = sdp_xml_parse_datatype(el, context->stack_head);
+		context->stack_head->data = sdp_xml_parse_datatype(el,
+					context->stack_head, context->sdprec);
 
 		/* Could not parse an entry */
 		if (context->stack_head->data == NULL)

Modified: bluez-utils/branches/upstream/current/common/sdp-glib.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/sdp-glib.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/sdp-glib.c (original)
+++ bluez-utils/branches/upstream/current/common/sdp-glib.c Wed Jul  4 13:37:57 2007
@@ -115,8 +115,8 @@
 			}
 		}
 
-		ctx_data->stack_head->data =
-			sdp_xml_parse_datatype(element_name, ctx_data->stack_head);
+		ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name,
+				ctx_data->stack_head, ctx_data->record);
 
 		if (ctx_data->stack_head->data == NULL)
 			error("Can't parse element %s", element_name);
@@ -213,7 +213,7 @@
 
 	record = sdp_record_alloc();
 	if (!record) {
-		sdp_record_free(record);
+		free(ctx_data);
 		return NULL;
 	}
 

Modified: bluez-utils/branches/upstream/current/common/sdp-xml.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/sdp-xml.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/sdp-xml.c (original)
+++ bluez-utils/branches/upstream/current/common/sdp-xml.c Wed Jul  4 13:37:57 2007
@@ -440,17 +440,20 @@
 	return sdp_data_alloc(SDP_UUID128, &val);
 }
 
-sdp_data_t *sdp_xml_parse_uuid(const char *data)
-{
-	int len;
+sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
+{
+	sdp_data_t *ret;
 	char *endptr;
 	uint32_t val;
 	uint16_t val2;
+	int len;
 
 	len = strlen(data);
 
-	if (len == 36)
-		return sdp_xml_parse_uuid128(data);
+	if (len == 36) {
+		ret = sdp_xml_parse_uuid128(data);
+		goto result;
+	}
 
 	val = strtoll(data, &endptr, 16);
 
@@ -458,15 +461,20 @@
 	if (*endptr != '\0')
 		return NULL;
 
-	if (val > USHRT_MAX)
-		return sdp_data_alloc(SDP_UUID32, &val);
+	if (val > USHRT_MAX) {
+		ret = sdp_data_alloc(SDP_UUID32, &val);
+		goto result;
+	}
 
 	val2 = val;
 
-	return sdp_data_alloc(SDP_UUID16, &val2);
-
-	/* Should never get here */
-	return NULL;
+	ret = sdp_data_alloc(SDP_UUID16, &val2);
+
+result:
+	if (record && ret)
+		sdp_pattern_add_uuid(record, &ret->val.uuid);
+
+	return ret;
 }
 
 sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
@@ -482,14 +490,14 @@
 		if (!strcmp("true", data)) {
 			val = 1;
 		}
-		
+
 		else if (!strcmp("false", data)) {
 			val = 0;
 		}
 		else {
 			return NULL;
 		}
-		
+
 		ret = sdp_data_alloc(dtd, &val);
 		break;
 	}
@@ -497,35 +505,35 @@
 	case SDP_INT8:
 	{
 		int8_t val = strtoul(data, &endptr, 0);
-
-       		/* Failed to parse */
-		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;		
-
-		ret = sdp_data_alloc(dtd, &val);
-		break;
-	}
-
-	case SDP_UINT8:
-	{
-		uint8_t val = strtoul(data, &endptr, 0);
 
 		/* Failed to parse */
 		if ((endptr != data) && (*endptr != '\0'))
 			return NULL;
-		
-		ret = sdp_data_alloc(dtd, &val);
-		break;
-	}
-
-	case SDP_INT16:
-	{
-		int16_t val = strtoul(data, &endptr, 0);
+
+		ret = sdp_data_alloc(dtd, &val);
+		break;
+	}
+
+	case SDP_UINT8:
+	{
+		uint8_t val = strtoul(data, &endptr, 0);
 
 		/* Failed to parse */
 		if ((endptr != data) && (*endptr != '\0'))
 			return NULL;
-	
+
+		ret = sdp_data_alloc(dtd, &val);
+		break;
+	}
+
+	case SDP_INT16:
+	{
+		int16_t val = strtoul(data, &endptr, 0);
+
+		/* Failed to parse */
+		if ((endptr != data) && (*endptr != '\0'))
+			return NULL;
+
 		ret = sdp_data_alloc(dtd, &val);
 		break;
 	}
@@ -534,9 +542,9 @@
 	{
 		uint16_t val = strtoul(data, &endptr, 0);
 
-       		/* Failed to parse */
+		/* Failed to parse */
 		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;		
+			return NULL;
 
 		ret = sdp_data_alloc(dtd, &val);
 		break;
@@ -546,10 +554,10 @@
 	{
 		int32_t val = strtoul(data, &endptr, 0);
 
-       		/* Failed to parse */
+		/* Failed to parse */
 		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;		
-		
+			return NULL;
+
 		ret = sdp_data_alloc(dtd, &val);
 		break;
 	}
@@ -558,9 +566,9 @@
 	{
 		uint32_t val = strtoul(data, &endptr, 0);
 
-       		/* Failed to parse */
+		/* Failed to parse */
 		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;		
+			return NULL;
 
 		ret = sdp_data_alloc(dtd, &val);
 		break;
@@ -570,10 +578,10 @@
 	{
 		int64_t val = strtoull(data, &endptr, 0);
 		
-       		/* Failed to parse */
+		/* Failed to parse */
 		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;		
-		
+			return NULL;
+
 		ret = sdp_data_alloc(dtd, &val);
 		break;
 	}
@@ -582,9 +590,9 @@
 	{
 		uint64_t val = strtoull(data, &endptr, 0);
 
-       		/* Failed to parse */
+		/* Failed to parse */
 		if ((endptr != data) && (*endptr != '\0'))
-			return NULL;		
+			return NULL;
 
 		ret = sdp_data_alloc(dtd, &val);
 		break;
@@ -615,22 +623,7 @@
 	return ret;
 }
 
-static sdp_data_t *sdp_xml_parse_url_with_size(const char *data, uint8_t dtd)
-{
-	return sdp_data_alloc(dtd, data);
-}
-
-sdp_data_t *sdp_xml_parse_url(const char *data)
-{
-	uint8_t dtd = SDP_URL_STR8;
-
-	if (strlen(data) > UCHAR_MAX)
-		dtd = SDP_URL_STR16;
-
-	return sdp_xml_parse_url_with_size(data, dtd);
-}
-
-static char *sdp_xml_parse_text_decode(const char *data, char encoding, uint32_t *length)
+static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32_t *length)
 {
 	int len = strlen(data);
 	char *text;
@@ -664,23 +657,27 @@
 	return text;
 }
 
-#if 0
-static sdp_data_t *sdp_xml_parse_text_with_size(const char *data, char encoding, uint8_t dtd)
-{
-	char *text;
+sdp_data_t *sdp_xml_parse_url(const char *data)
+{
+	uint8_t dtd = SDP_URL_STR8;
+	char *url;
 	uint32_t length;
 	sdp_data_t *ret;
 
-	text = sdp_xml_parse_text_decode(data, encoding, &length);
-	ret = sdp_data_alloc_with_length(dtd, text, length);
-
-	debug("Unit size %d length %d: -->%s<--\n", ret->unitSize, length, text);
-
-	free(text);
+	url = sdp_xml_parse_string_decode(data,
+				SDP_XML_ENCODING_NORMAL, &length);
+
+	if (length > UCHAR_MAX)
+		dtd = SDP_URL_STR16;
+
+	ret = sdp_data_alloc_with_length(dtd, url, length);
+
+	debug("URL size %d length %d: -->%s<--", ret->unitSize, length, url);
+
+	free(url);
 
 	return ret;
 }
-#endif
 
 sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
 {
@@ -689,14 +686,14 @@
 	uint32_t length;
 	sdp_data_t *ret;
 
-	text = sdp_xml_parse_text_decode(data, encoding, &length);
+	text = sdp_xml_parse_string_decode(data, encoding, &length);
 
 	if (length > UCHAR_MAX)
 		dtd = SDP_TEXT_STR16;
 
 	ret = sdp_data_alloc_with_length(dtd, text, length);
 
-	debug("Unit size %d length %d: -->%s<--\n", ret->unitSize, length, text);
+	debug("Text size %d length %d: -->%s<--", ret->unitSize, length, text);
 
 	free(text);
 
@@ -759,7 +756,8 @@
 	return elem;
 }
 
-sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem)
+sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
+							sdp_record_t *record)
 {
 	const char *data = elem->text;
 
@@ -786,7 +784,7 @@
 	else if (!strcmp(el, "int128"))
 		return sdp_xml_parse_int(data, SDP_INT128);
 	else if (!strcmp(el, "uuid"))
-		return sdp_xml_parse_uuid(data);
+		return sdp_xml_parse_uuid(data, record);
 	else if (!strcmp(el, "url"))
 		return sdp_xml_parse_url(data);
 	else if (!strcmp(el, "text"))

Modified: bluez-utils/branches/upstream/current/common/sdp-xml.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/sdp-xml.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/sdp-xml.h (original)
+++ bluez-utils/branches/upstream/current/common/sdp-xml.h Wed Jul  4 13:37:57 2007
@@ -37,7 +37,7 @@
 sdp_data_t *sdp_xml_parse_text(const char *data, char encoding);
 sdp_data_t *sdp_xml_parse_url(const char *data);
 sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd);
-sdp_data_t *sdp_xml_parse_uuid(const char *data);
+sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record);
 
 struct sdp_xml_data {
 	char *text;			/* Pointer to the current buffer */
@@ -53,7 +53,8 @@
 void sdp_xml_data_free(struct sdp_xml_data *elem);
 struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem);
 
-sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem);
+sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
+							sdp_record_t *record);
 
 sdp_record_t *sdp_xml_parse_record(const char *data, int size);
 

Modified: bluez-utils/branches/upstream/current/configure
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/configure?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/configure (original)
+++ bluez-utils/branches/upstream/current/configure Wed Jul  4 13:37:57 2007
@@ -1906,7 +1906,7 @@
 
 # Define the identity of the package.
  PACKAGE=bluez-utils
- VERSION=3.10.1
+ VERSION=3.12
 
 
 cat >>confdefs.h <<_ACEOF

Modified: bluez-utils/branches/upstream/current/configure.in
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/configure.in?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/configure.in (original)
+++ bluez-utils/branches/upstream/current/configure.in Wed Jul  4 13:37:57 2007
@@ -1,7 +1,7 @@
 AC_PREREQ(2.50)
 AC_INIT()
 
-AM_INIT_AUTOMAKE(bluez-utils, 3.10.1)
+AM_INIT_AUTOMAKE(bluez-utils, 3.12)
 AM_CONFIG_HEADER(config.h)
 
 AM_MAINTAINER_MODE

Modified: bluez-utils/branches/upstream/current/cups/Makefile.am
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/cups/Makefile.am?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/cups/Makefile.am (original)
+++ bluez-utils/branches/upstream/current/cups/Makefile.am Wed Jul  4 13:37:57 2007
@@ -3,13 +3,19 @@
 cupsdir = $(libdir)/cups/backend
 
 cups_PROGRAMS = bluetooth
-else
-noinst_PROGRAMS = bluetooth
+
+bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c
+
+bluetooth_LDADD = $(top_builddir)/common/libhelper.a \
+			@DBUS_LIBS@ @GLIB_LIBS@ @BLUEZ_LIBS@ 
+
+if EXPAT
+bluetooth_LDADD += -lexpat
+endif
 endif
 
-bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c
-bluetooth_LDADD = @BLUEZ_LIBS@
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@
 
-AM_CFLAGS = @BLUEZ_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common
 
 MAINTAINERCLEANFILES = Makefile.in

Modified: bluez-utils/branches/upstream/current/cups/Makefile.in
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/cups/Makefile.in?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/cups/Makefile.in (original)
+++ bluez-utils/branches/upstream/current/cups/Makefile.in Wed Jul  4 13:37:57 2007
@@ -37,7 +37,7 @@
 build_triplet = @build@
 host_triplet = @host@
 @CUPS_TRUE at cups_PROGRAMS = bluetooth$(EXEEXT)
- at CUPS_FALSE@noinst_PROGRAMS = bluetooth$(EXEEXT)
+ at CUPS_TRUE@@EXPAT_TRUE at am__append_1 = -lexpat
 subdir = cups
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -50,11 +50,15 @@
 CONFIG_CLEAN_FILES =
 am__installdirs = "$(DESTDIR)$(cupsdir)"
 cupsPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
-PROGRAMS = $(cups_PROGRAMS) $(noinst_PROGRAMS)
-am_bluetooth_OBJECTS = main.$(OBJEXT) sdp.$(OBJEXT) spp.$(OBJEXT) \
-	hcrp.$(OBJEXT)
+PROGRAMS = $(cups_PROGRAMS)
+am__bluetooth_SOURCES_DIST = main.c sdp.c spp.c hcrp.c
+ at CUPS_TRUE@am_bluetooth_OBJECTS = main.$(OBJEXT) sdp.$(OBJEXT) \
+ at CUPS_TRUE@	spp.$(OBJEXT) hcrp.$(OBJEXT)
 bluetooth_OBJECTS = $(am_bluetooth_OBJECTS)
-bluetooth_DEPENDENCIES =
+am__DEPENDENCIES_1 =
+ at CUPS_TRUE@bluetooth_DEPENDENCIES =  \
+ at CUPS_TRUE@	$(top_builddir)/common/libhelper.a \
+ at CUPS_TRUE@	$(am__DEPENDENCIES_1)
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
@@ -67,7 +71,7 @@
 LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
 	$(AM_LDFLAGS) $(LDFLAGS) -o $@
 SOURCES = $(bluetooth_SOURCES)
-DIST_SOURCES = $(bluetooth_SOURCES)
+DIST_SOURCES = $(am__bluetooth_SOURCES_DIST)
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -242,9 +246,12 @@
 sysconfdir = @sysconfdir@
 target_alias = @target_alias@
 @CUPS_TRUE at cupsdir = $(libdir)/cups/backend
-bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c
-bluetooth_LDADD = @BLUEZ_LIBS@
-AM_CFLAGS = @BLUEZ_CFLAGS@
+ at CUPS_TRUE@bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c
+ at CUPS_TRUE@bluetooth_LDADD = $(top_builddir)/common/libhelper.a \
+ at CUPS_TRUE@	@DBUS_LIBS@ @GLIB_LIBS@ @BLUEZ_LIBS@ \
+ at CUPS_TRUE@	$(am__append_1)
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common
 MAINTAINERCLEANFILES = Makefile.in
 all: all-am
 
@@ -303,13 +310,6 @@
 
 clean-cupsPROGRAMS:
 	@list='$(cups_PROGRAMS)'; for p in $$list; do \
-	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
-	  echo " rm -f $$p $$f"; \
-	  rm -f $$p $$f ; \
-	done
-
-clean-noinstPROGRAMS:
-	@list='$(noinst_PROGRAMS)'; for p in $$list; do \
 	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
 	  echo " rm -f $$p $$f"; \
 	  rm -f $$p $$f ; \
@@ -470,7 +470,7 @@
 clean: clean-am
 
 clean-am: clean-cupsPROGRAMS clean-generic clean-libtool \
-	clean-noinstPROGRAMS mostlyclean-am
+	mostlyclean-am
 
 distclean: distclean-am
 	-rm -rf ./$(DEPDIR)
@@ -519,17 +519,16 @@
 uninstall-am: uninstall-cupsPROGRAMS uninstall-info-am
 
 .PHONY: CTAGS GTAGS all all-am check check-am clean clean-cupsPROGRAMS \
-	clean-generic clean-libtool clean-noinstPROGRAMS ctags \
-	distclean distclean-compile distclean-generic \
-	distclean-libtool distclean-tags distdir dvi dvi-am html \
-	html-am info info-am install install-am install-cupsPROGRAMS \
-	install-data install-data-am install-exec install-exec-am \
-	install-info install-info-am install-man install-strip \
-	installcheck installcheck-am installdirs maintainer-clean \
-	maintainer-clean-generic mostlyclean mostlyclean-compile \
-	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
-	tags uninstall uninstall-am uninstall-cupsPROGRAMS \
-	uninstall-info-am
+	clean-generic clean-libtool ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-cupsPROGRAMS install-data install-data-am install-exec \
+	install-exec-am install-info install-info-am install-man \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags uninstall uninstall-am \
+	uninstall-cupsPROGRAMS uninstall-info-am
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.

Modified: bluez-utils/branches/upstream/current/cups/main.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/cups/main.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/cups/main.c (original)
+++ bluez-utils/branches/upstream/current/cups/main.c Wed Jul  4 13:37:57 2007
@@ -38,11 +38,507 @@
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
+#include <glib.h>
+
+#include "dbus.h"
+#include "sdp-xml.h"
+
 extern int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel);
 extern int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm);
 
 extern int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies);
 extern int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies);
+
+#define PRINTER_SERVICE_CLASS_NAME "printer"
+
+struct cups_device {
+	char *bdaddr;
+	char *name;
+	char *id;
+};
+
+static GSList *device_list = NULL;
+static GMainLoop *loop = NULL;
+static DBusConnection *conn = NULL;
+
+#define ATTRID_1284ID 0x0300
+
+static char *parse_xml_sdp(const char *xml)
+{
+	sdp_record_t *sdp_record;
+	sdp_list_t *l;
+	char *str = NULL;
+
+	sdp_record = sdp_xml_parse_record(xml, strlen(xml));
+	if (sdp_record == NULL)
+		return NULL;
+	for (l = sdp_record->attrlist; l != NULL; l = l->next) {
+		sdp_data_t *data;
+
+		data = (sdp_data_t *) l->data;
+		if (data->attrId != ATTRID_1284ID)
+			continue;
+		/* Ignore the length, it's null terminated */
+		str = g_strdup(data->val.str + 2);
+		break;
+	}
+	sdp_record_free(sdp_record);
+
+	return str;
+}
+
+static char *device_get_ieee1284_id(const char *adapter, const char *bdaddr)
+{
+	guint service_handle;
+	DBusMessage *message, *reply;
+	DBusMessageIter iter, reply_iter, iter_array;
+	const char *hcr_print = "00001126-0000-1000-8000-00805f9b34fb";
+	char *xml, *id;
+
+	/* Look for the service handle of the HCRP service */
+	message = dbus_message_new_method_call("org.bluez", adapter,
+						"org.bluez.Adapter",
+						"GetRemoteServiceHandles");
+	dbus_message_iter_init_append(message, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &hcr_print);
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, NULL);
+
+	dbus_message_unref(message);
+
+	if (!reply)
+		return NULL;
+
+	dbus_message_iter_init(reply, &reply_iter);
+	if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
+		dbus_message_unref(reply);
+		return NULL;
+	}
+
+	/* Hopefully we only get one handle, or take a punt */
+	dbus_message_iter_recurse(&reply_iter, &iter_array);
+	while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_UINT32) {
+		dbus_message_iter_get_basic(&iter_array, &service_handle);
+		dbus_message_iter_next(&iter_array);
+	}
+
+	dbus_message_unref(reply);
+
+	/* Now get the XML for the HCRP service record */
+	message = dbus_message_new_method_call("org.bluez", adapter,
+						"org.bluez.Adapter",
+						"GetRemoteServiceRecordAsXML");
+	dbus_message_iter_init_append(message, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &service_handle);
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, NULL);
+
+	dbus_message_unref(message);
+
+	if (!reply)
+		return NULL;
+
+	dbus_message_iter_init(reply, &reply_iter);
+	dbus_message_iter_get_basic(&reply_iter, &xml);
+
+	id = parse_xml_sdp(xml);
+
+	dbus_message_unref(reply);
+
+	return id;
+}
+
+static void add_device_to_list(const char *name, const char *bdaddr, const char *id)
+{
+	struct cups_device *device;
+	GSList *l;
+
+	/* Look for the device in the list */
+	for (l = device_list; l != NULL; l = l->next) {
+		device = (struct cups_device *) l->data;
+
+		if (strcmp(device->bdaddr, bdaddr) == 0) {
+			g_free(device->name);
+			device->name = g_strdup(name);
+			return;
+		}
+	}
+
+	/* Or add it to the list if it's not there */
+	device = g_new0(struct cups_device, 1);
+	device->bdaddr = g_strdup(bdaddr);
+	device->name = g_strdup(name);
+	device->id = g_strdup(id);
+
+	device_list = g_slist_prepend(device_list, device);
+}
+
+static char *escape_name(const char *str, char orig, char dest)
+{
+	char *ret, *s;
+
+	ret = g_strdup(str);
+	while ((s = strchr(ret, orig)) != NULL)
+		s[0] = dest;
+	return ret;
+}
+
+static void print_printer_details(const char *name, const char *bdaddr, const char *id)
+{
+	char *uri, *escaped;
+	guint len;
+
+	escaped = escape_name(name, '\"', '\'');
+	len = strlen("bluetooth://") + 12 + 1;
+	uri = g_malloc(len);
+	snprintf(uri, len, "bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c",
+		 bdaddr[0], bdaddr[1],
+		 bdaddr[3], bdaddr[4],
+		 bdaddr[6], bdaddr[7],
+		 bdaddr[9], bdaddr[10],
+		 bdaddr[12], bdaddr[13],
+		 bdaddr[15], bdaddr[16]);
+	printf("network %s \"Unknown\" \"%s (Bluetooth)\"", uri, escaped);
+	if (id != NULL)
+		printf(" \"%s\"\n", id);
+	else
+		printf ("\n");
+	g_free(escaped);
+	g_free(uri);
+}
+
+static gboolean device_is_printer(const char *adapter, const char *bdaddr)
+{
+	char *class;
+	DBusMessage *message, *reply;
+	DBusMessageIter iter, reply_iter;
+
+	message = dbus_message_new_method_call("org.bluez", adapter,
+					       "org.bluez.Adapter",
+					       "GetRemoteMinorClass");
+	dbus_message_iter_init_append(message, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, NULL);
+
+	dbus_message_unref(message);
+
+	if (!reply)
+		return FALSE;
+
+	dbus_message_iter_init(reply, &reply_iter);
+	dbus_message_iter_get_basic(&reply_iter, &class);
+
+	if (class != NULL && strcmp(class, PRINTER_SERVICE_CLASS_NAME) == 0) {
+		dbus_message_unref(reply);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static char *device_get_name(const char *adapter, const char *bdaddr)
+{
+	DBusMessage *message, *reply;
+	DBusMessageIter iter, reply_iter;
+	char *name;
+
+	message = dbus_message_new_method_call("org.bluez", adapter,
+						"org.bluez.Adapter",
+						"GetRemoteName");
+	dbus_message_iter_init_append(message, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, NULL);
+
+	dbus_message_unref(message);
+
+	if (!reply)
+		return NULL;
+
+	dbus_message_iter_init(reply, &reply_iter);
+	dbus_message_iter_get_basic(&reply_iter, &name);
+
+	name = g_strdup(name);
+	dbus_message_unref(reply);
+
+	return name;
+}
+
+static void remote_device_found(const char *adapter, const char *bdaddr, guint class, int rssi)
+{
+	uint8_t major_index = (class >> 8) & 0x1F;
+	uint8_t minor_index;
+	uint8_t shift_minor = 0;
+	gboolean found = FALSE;
+	char *name, *id;
+
+	/* Check if we have a printer
+	 * From hcid/dbus-adapter.c minor_class_str() */
+	if (major_index != 6)
+		return;
+
+	minor_index = (class >> 4) & 0x0F;
+	while (shift_minor < 4) {
+		if (((minor_index >> shift_minor) & 0x01) == 0x01) {
+			if (shift_minor == 3) {
+				found = TRUE;
+				break;
+			}
+		}
+		shift_minor++;
+	}
+
+	if (!found)
+		return;
+
+	name = device_get_name(adapter, bdaddr);
+	id = device_get_ieee1284_id(adapter, bdaddr);
+	add_device_to_list(name, bdaddr, id);
+	g_free(name);
+	g_free(id);
+}
+
+static void remote_name_updated(const char *bdaddr, const char *name)
+{
+	add_device_to_list(name, bdaddr, NULL);
+}
+
+static void discovery_completed(void)
+{
+	GSList *l;
+
+	for (l = device_list; l != NULL; l = l->next) {
+		struct cups_device *device = (struct cups_device *) l->data;
+
+		if (device->name == NULL)
+			device->name = escape_name(device->bdaddr, ':', '-');
+		print_printer_details(device->name, device->bdaddr, device->id);
+		g_free(device->name);
+		g_free(device->bdaddr);
+		g_free(device->id);
+		g_free(device);
+	}
+
+	g_slist_free(device_list);
+	device_list = NULL;
+
+	g_main_loop_quit(loop);
+}
+
+static void remote_device_disappeared(const char *bdaddr)
+{
+	GSList *l;
+
+	for (l = device_list; l != NULL; l = l->next) {
+		struct cups_device *device = (struct cups_device *) l->data;
+
+		if (strcmp(device->bdaddr, bdaddr) == 0) {
+			g_free(device->name);
+			g_free(device->bdaddr);
+			g_free(device);
+			device_list = g_slist_delete_link(device_list, l);
+			return;
+		}
+	}
+}
+
+static gboolean list_known_printers(const char *adapter)
+{
+	DBusMessageIter reply_iter, iter_array;
+	DBusError error;
+	DBusMessage *message, *reply;
+
+	message = dbus_message_new_method_call ("org.bluez", adapter,
+						"org.bluez.Adapter",
+						"ListRemoteDevices");
+	if (message == NULL)
+		return FALSE;
+
+	dbus_error_init(&error);
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, &error);
+
+	dbus_message_unref(message);
+
+	if (&error != NULL && dbus_error_is_set(&error))
+		return FALSE;
+
+	dbus_message_iter_init(reply, &reply_iter);
+	if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
+		dbus_message_unref(reply);
+		return FALSE;
+	}
+
+	dbus_message_iter_recurse(&reply_iter, &iter_array);
+	while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_STRING) {
+		char *bdaddr;
+
+		dbus_message_iter_get_basic(&iter_array, &bdaddr);
+		if (device_is_printer(adapter, bdaddr)) {
+			char *name, *id;
+			name = device_get_name(adapter, bdaddr);
+			id = device_get_ieee1284_id(adapter, bdaddr);
+			add_device_to_list(name, bdaddr, id);
+			g_free(name);
+			g_free(id);
+		}
+		dbus_message_iter_next(&iter_array);
+	}
+
+	dbus_message_unref(reply);
+
+	return FALSE;
+}
+
+static DBusHandlerResult filter_func(DBusConnection *connection, DBusMessage *message, void *user_data)
+{
+	const char *adapter;
+
+	if (dbus_message_is_signal(message, "org.bluez.Adapter",
+						"RemoteDeviceFound")) {
+		char *bdaddr;
+		guint class;
+		int rssi;
+
+		dbus_message_get_args(message, NULL,
+					DBUS_TYPE_STRING, &bdaddr,
+					DBUS_TYPE_UINT32, &class,
+					DBUS_TYPE_INT32, &rssi,
+					DBUS_TYPE_INVALID);
+		adapter = dbus_message_get_path(message);
+		remote_device_found(adapter, bdaddr, class, rssi);
+	} else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+							"RemoteNameUpdated")) {
+		char *bdaddr, *name;
+
+		dbus_message_get_args(message, NULL,
+					DBUS_TYPE_STRING, &bdaddr,
+					DBUS_TYPE_STRING, &name,
+					DBUS_TYPE_INVALID);
+		remote_name_updated(bdaddr, name);
+	} else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+						"RemoteDeviceDisappeared")) {
+		char *bdaddr;
+
+		dbus_message_get_args(message, NULL,
+					DBUS_TYPE_STRING, &bdaddr,
+					DBUS_TYPE_INVALID);
+		remote_device_disappeared(bdaddr);
+	} else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+						"DiscoveryCompleted")) {
+		discovery_completed();
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void list_printers(void)
+{
+	/* 1. Connect to the bus
+	 * 2. Get the manager
+	 * 3. Get the default adapter
+	 * 4. Get a list of devices
+	 * 5. Get the class of each device
+	 * 6. Print the details from each printer device
+	 */
+	DBusError error;
+	dbus_bool_t hcid_exists;
+	DBusMessage *reply, *message;
+	DBusMessageIter reply_iter;
+	char *adapter, *match;
+	guint len;
+
+	conn = init_dbus(NULL, NULL, NULL);
+	if (conn == NULL)
+		return;
+
+	dbus_error_init(&error);
+	hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error);
+	if (&error != NULL && dbus_error_is_set(&error))
+		return;
+
+	if (!hcid_exists)
+		return;
+
+	/* Get the default adapter */
+	message = dbus_message_new_method_call("org.bluez", "/org/bluez",
+						"org.bluez.Manager",
+						"DefaultAdapter");
+	if (message == NULL) {
+		dbus_connection_unref(conn);
+		return;
+	}
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, &error);
+
+	dbus_message_unref(message);
+
+	if (&error != NULL && dbus_error_is_set(&error)) {
+		dbus_connection_unref(conn);
+		return;
+	}
+
+	dbus_message_iter_init(reply, &reply_iter);
+	if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_STRING) {
+		dbus_message_unref(reply);
+		dbus_connection_unref(conn);
+		return;
+	}
+
+	dbus_message_iter_get_basic(&reply_iter, &adapter);
+	adapter = g_strdup(adapter);
+	dbus_message_unref(reply);
+
+	if (!dbus_connection_add_filter(conn, filter_func, adapter, g_free)) {
+		g_free(adapter);
+		dbus_connection_unref(conn);
+		return;
+	}
+
+#define MATCH_FORMAT				\
+	"type='signal',"			\
+	"interface='org.bluez.Adapter',"	\
+	"sender='org.bluez',"			\
+	"path='%s'"
+
+	len = strlen(MATCH_FORMAT) - 2 + strlen(adapter) + 1;
+	match = g_malloc(len);
+	snprintf(match, len, "type='signal',"
+				"interface='org.bluez.Adapter',"
+				"sender='org.bluez',"
+				"path='%s'",
+				adapter);
+	dbus_bus_add_match(conn, match, &error);
+	g_free(match);
+
+	message = dbus_message_new_method_call("org.bluez", adapter,
+					"org.bluez.Adapter",
+					"DiscoverDevicesWithoutNameResolving");
+
+	if (!dbus_connection_send_with_reply(conn, message, NULL, -1)) {
+		dbus_message_unref(message);
+		dbus_connection_unref(conn);
+		g_free(adapter);
+		return;
+	}
+	dbus_message_unref(message);
+
+	/* Also add the the recent devices */
+	g_timeout_add(0, (GSourceFunc) list_known_printers, adapter);
+
+	loop = g_main_loop_new(NULL, TRUE);
+	g_main_loop_run(loop);
+
+	dbus_connection_unref(conn);
+}
 
 /*
  *  Usage: printer-uri job-id user title copies options [file]
@@ -73,7 +569,7 @@
 #endif /* HAVE_SIGSET */
 
 	if (argc == 1) {
-		puts("network bluetooth \"Unknown\" \"Bluetooth printer\"");
+		list_printers();
 		return 0;
 	}
 

Modified: bluez-utils/branches/upstream/current/daemon/Makefile.am
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/daemon/Makefile.am?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/daemon/Makefile.am (original)
+++ bluez-utils/branches/upstream/current/daemon/Makefile.am Wed Jul  4 13:37:57 2007
@@ -50,6 +50,7 @@
 
 INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/sdpd
 
-EXTRA_DIST = bluetooth.conf echo.service hal-namespace.txt
+EXTRA_DIST = bluetooth.conf echo.service \
+		test-manager test-database hal-namespace.txt
 
 MAINTAINERCLEANFILES = Makefile.in

Modified: bluez-utils/branches/upstream/current/daemon/Makefile.in
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/daemon/Makefile.in?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/daemon/Makefile.in (original)
+++ bluez-utils/branches/upstream/current/daemon/Makefile.in Wed Jul  4 13:37:57 2007
@@ -294,7 +294,9 @@
 auth_agent_LDADD = @DBUS_LIBS@
 AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@
 INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/sdpd
-EXTRA_DIST = bluetooth.conf echo.service hal-namespace.txt
+EXTRA_DIST = bluetooth.conf echo.service \
+		test-manager test-database hal-namespace.txt
+
 MAINTAINERCLEANFILES = Makefile.in
 all: all-am
 

Modified: bluez-utils/branches/upstream/current/daemon/echo.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/daemon/echo.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/daemon/echo.c (original)
+++ bluez-utils/branches/upstream/current/daemon/echo.c Wed Jul  4 13:37:57 2007
@@ -49,7 +49,8 @@
 	char *address;
 };
 
-static gboolean session_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+static gboolean session_event(GIOChannel *chan,
+					GIOCondition cond, gpointer data)
 {
 	unsigned char buf[672];
 	gsize len, written;
@@ -75,7 +76,7 @@
 	info("Canceling authorization for %s", address);
 
 	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
-				"org.bluez.Database", "CancelAuthorizationRequest");
+			"org.bluez.Database", "CancelAuthorizationRequest");
 	if (!msg) {
 		error("Allocation of method message failed");
 		return;
@@ -104,8 +105,9 @@
 		dbus_error_free(&err);
 	} else {
 		info("Accepting incoming connection");
-		g_io_add_watch(auth->io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-						session_event, NULL);
+		g_io_add_watch(auth->io,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+							session_event, NULL);
 	}
 
 	g_io_channel_unref(auth->io);
@@ -169,7 +171,8 @@
 	return 0;
 }
 
-static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+static gboolean connect_event(GIOChannel *chan,
+					GIOCondition cond, gpointer data)
 {
 	DBusConnection *conn = data;
 	GIOChannel *io;
@@ -236,6 +239,7 @@
 static int setup_sdp(DBusConnection *conn, uint8_t channel)
 {
 	DBusMessage *msg, *reply;
+	DBusError err;
 	sdp_record_t *record;
 	sdp_buf_t buf;
 	sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
@@ -305,7 +309,9 @@
 	dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
 				&buf.data, buf.data_size, DBUS_TYPE_INVALID);
 
-	reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, NULL);
+	dbus_error_init(&err);
+
+	reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
 
 	dbus_message_unref(msg);
 
@@ -313,6 +319,8 @@
 
 	if (!reply) {
 		error("Registration of service record failed");
+		error("%s", err.message);
+		dbus_error_free(&err);
 		return -1;
 	}
 
@@ -326,6 +334,7 @@
 static int register_standalone(DBusConnection *conn)
 {
 	DBusMessage *msg, *reply;
+	DBusError err;
 	const char *ident = "echo", *name = "Echo service", *desc = "";
 
 	info("Registering service");
@@ -341,12 +350,16 @@
 				DBUS_TYPE_STRING, &name,
 				DBUS_TYPE_STRING, &desc, DBUS_TYPE_INVALID);
 
-	reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, NULL);
+	dbus_error_init(&err);
+
+	reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
 
 	dbus_message_unref(msg);
 
 	if (!reply) {
 		error("Registration of service failed");
+		error("%s", err.message);
+		dbus_error_free(&err);
 		return -1;
 	}
 
@@ -364,15 +377,12 @@
 	g_main_loop_quit(main_loop);
 }
 
-static void sig_hup(int sig)
-{
-}
-
 int main(int argc, char *argv[])
 {
-	DBusConnection *system_bus;
-	GIOChannel *server_io;
+	DBusConnection *conn;
+	GIOChannel *io;
 	struct sigaction sa;
+	char *addr;
 
 	start_logging("echo", "Bluetooth echo service ver %s", VERSION);
 
@@ -381,40 +391,52 @@
 	sa.sa_handler = sig_term;
 	sigaction(SIGTERM, &sa, NULL);
 	sigaction(SIGINT,  &sa, NULL);
-	sa.sa_handler = sig_hup;
-	sigaction(SIGHUP, &sa, NULL);
 
 	sa.sa_handler = SIG_IGN;
 	sigaction(SIGCHLD, &sa, NULL);
 	sigaction(SIGPIPE, &sa, NULL);
 
+	enable_debug();
+
+	addr = getenv("BLUETOOTHD_ADDRESS");
+	if (!addr) {
+		error("No D-Bus server address available");
+		exit(1);
+	}
+
+	debug("Bluetooth daemon at %s", addr);
+
 	main_loop = g_main_loop_new(NULL, FALSE);
 
-	system_bus = init_dbus(NULL, NULL, NULL);
-	if (!system_bus) {
-		error("Connection to system bus failed");
+	if (argc > 1 && !strcmp(argv[1], "-s"))
+		conn = init_dbus_direct(addr);
+	else
+		conn = init_dbus(NULL, NULL, NULL);
+
+	if (!conn) {
+		error("Connection to bus failed");
 		g_main_loop_unref(main_loop);
 		exit(1);
 	}
 
-	server_io = setup_rfcomm(system_bus, 23);
-	if (!server_io) {
+	io = setup_rfcomm(conn, 23);
+	if (!io) {
 		error("Creation of server channel failed");
-		dbus_connection_unref(system_bus);
+		dbus_connection_unref(conn);
 		g_main_loop_unref(main_loop);
 		exit(1);
 	}
 
-	setup_sdp(system_bus, 23);
+	setup_sdp(conn, 23);
 
 	if (argc > 1 && !strcmp(argv[1], "-s"))
-		register_standalone(system_bus);
+		register_standalone(conn);
 
 	g_main_loop_run(main_loop);
 
-	g_io_channel_unref(server_io);
-
-	dbus_connection_unref(system_bus);
+	g_io_channel_unref(io);
+
+	dbus_connection_unref(conn);
 
 	g_main_loop_unref(main_loop);
 

Added: bluez-utils/branches/upstream/current/daemon/test-database
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/daemon/test-database?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/daemon/test-database (added)
+++ bluez-utils/branches/upstream/current/daemon/test-database Wed Jul  4 13:37:57 2007
@@ -1,0 +1,119 @@
+#!/usr/bin/python
+
+import time
+import dbus
+
+bus = dbus.SystemBus()
+
+xml = ' \
+<?xml version="1.0" encoding="UTF-8" ?> 	\
+<record>					\
+  <attribute id="0x0001">			\
+    <sequence>					\
+      <uuid value="0x1101"/>			\
+    </sequence>					\
+  </attribute>					\
+						\
+  <attribute id="0x0002">			\
+     <uint32 value="0"/>			\
+  </attribute>					\
+						\
+  <attribute id="0x0003">			\
+    <uuid value="00001101-0000-1000-8000-00805f9b34fb"/> \
+  </attribute>					\
+						\
+  <attribute id="0x0004">			\
+    <sequence>					\
+      <sequence>				\
+        <uuid value="0x0100"/>			\
+      </sequence>				\
+      <sequence>				\
+        <uuid value="0x0003"/>			\
+        <uint8 value="23"/>			\
+      </sequence>				\
+    </sequence>					\
+  </attribute>					\
+						\
+  <attribute id="0x0005">			\
+    <sequence>					\
+      <uuid value="0x1002"/>			\
+    </sequence>					\
+  </attribute>					\
+						\
+  <attribute id="0x0006">			\
+    <sequence>					\
+      <uint16 value="0x656e"/>			\
+      <uint16 value="0x006a"/>			\
+      <uint16 value="0x0100"/>			\
+    </sequence>					\
+  </attribute>					\
+						\
+  <attribute id="0x0007">			\
+     <uint32 value="0"/>			\
+  </attribute>					\
+						\
+  <attribute id="0x0008">			\
+     <uint8 value="0xff"/>			\
+  </attribute>					\
+						\
+  <attribute id="0x0009">			\
+    <sequence>					\
+      <sequence>				\
+        <uuid value="0x1101"/>			\
+        <uint16 value="0x0100"/>		\
+      </sequence>				\
+    </sequence>					\
+  </attribute>					\
+						\
+  <attribute id="0x000a">			\
+    <url value="http://www.bluez.org/"/>	\
+  </attribute>					\
+						\
+  <attribute id="0x000b">			\
+    <url value="http://www.bluez.org/"/>	\
+  </attribute>					\
+						\
+  <attribute id="0x000c">			\
+    <url value="http://www.bluez.org/"/>	\
+  </attribute>					\
+						\
+  <attribute id="0x0100">			\
+    <text value="Serial Port"/>			\
+  </attribute>					\
+						\
+  <attribute id="0x0101">			\
+    <text value="Serial Port Service"/>		\
+  </attribute>					\
+						\
+  <attribute id="0x0102">			\
+     <text value="BlueZ"/>			\
+  </attribute>					\
+						\
+  <attribute id="0x0200">			\
+    <sequence>					\
+      <uint16 value="0x0100"/>			\
+    </sequence>					\
+  </attribute>					\
+						\
+  <attribute id="0x0201">			\
+     <uint32 value="0"/>			\
+  </attribute>					\
+</record>					\
+'
+
+database = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'),
+							'org.bluez.Database')
+
+handle = database.AddServiceRecordFromXML(xml)
+
+print "Service record with handle 0x%04x added" % (handle)
+
+print "Press CTRL-C to remove service record"
+
+try:
+	time.sleep(1000)
+	print "Terminating session"
+except:
+	pass
+
+database.RemoveServiceRecord(dbus.UInt32(handle))

Propchange: bluez-utils/branches/upstream/current/daemon/test-database
------------------------------------------------------------------------------
    svn:executable = *

Added: bluez-utils/branches/upstream/current/daemon/test-manager
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/daemon/test-manager?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/daemon/test-manager (added)
+++ bluez-utils/branches/upstream/current/daemon/test-manager Wed Jul  4 13:37:57 2007
@@ -1,0 +1,27 @@
+#!/usr/bin/python
+
+import gobject
+
+import dbus
+import dbus.mainloop.glib
+
+def adapter_added(path):
+	print "Adapter with path %s added" % (path)
+
+def adapter_removed(path):
+	print "Adapter with path %s removed" % (path)
+
+if __name__ == "__main__":
+	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+	bus = dbus.SystemBus()
+
+	manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'),
+							'org.bluez.Manager')
+
+	manager.connect_to_signal("AdapterAdded", adapter_added)
+
+	manager.connect_to_signal("AdapterRemoved", adapter_removed)
+
+	mainloop = gobject.MainLoop()
+	mainloop.run()

Propchange: bluez-utils/branches/upstream/current/daemon/test-manager
------------------------------------------------------------------------------
    svn:executable = *

Modified: bluez-utils/branches/upstream/current/eglib/gmain.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/eglib/gmain.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/eglib/gmain.c (original)
+++ bluez-utils/branches/upstream/current/eglib/gmain.c Wed Jul  4 13:37:57 2007
@@ -1127,6 +1127,77 @@
 	}
 }
 
+GSList *g_slist_nth(GSList *list, guint n)
+{
+	while (n-- > 0 && list)
+		list = list->next;
+
+	return list;
+}
+
+gpointer g_slist_nth_data(GSList *list, guint n)
+{
+	while (n-- > 0 && list)
+		list = list->next;
+
+	return list ? list->data : NULL;
+}
+
+gint g_slist_position(GSList *list, GSList *link)
+{
+	gint i;
+
+	for (i = 0; list; list = list->next, i++) {
+		if (list == link)
+			return i;
+	}
+
+	return -1;
+}
+
+GSList* g_slist_last(GSList *list)
+{
+	if (list)
+		while (list->next)
+			list = list->next;
+
+	return list;
+}
+
+static inline GSList* _g_slist_remove_link(GSList *list, GSList *link)
+{
+	GSList *tmp;
+	GSList *prev;
+
+	prev = NULL;
+	tmp = list;
+
+	while (tmp) {
+		if (tmp == link) {
+			if (prev)
+				prev->next = tmp->next;
+			if (list == tmp)
+				list = list->next;
+
+			tmp->next = NULL;
+			break;
+		}
+
+		prev = tmp;
+		tmp = tmp->next;
+	}
+
+	return list;
+}
+
+GSList* g_slist_delete_link(GSList *list, GSList *link)
+{
+	list = _g_slist_remove_link(list, link);
+	g_free(link);
+
+	return list;
+}
+
 /* Memory allocation functions */
 
 gpointer g_malloc(gulong n_bytes)

Modified: bluez-utils/branches/upstream/current/eglib/gmain.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/eglib/gmain.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/eglib/gmain.h (original)
+++ bluez-utils/branches/upstream/current/eglib/gmain.h Wed Jul  4 13:37:57 2007
@@ -183,7 +183,7 @@
 GSList *g_slist_find(GSList *list, gconstpointer data);
 
 GSList *g_slist_find_custom(GSList *list, const void *data,
-			GCompareFunc cmp_func);
+							GCompareFunc cmp_func);
 
 GSList *g_slist_sort(GSList *list, GCompareFunc cmp_func);
 
@@ -191,6 +191,12 @@
 
 void g_slist_foreach(GSList *list, GFunc func, void *user_data);
 void g_slist_free(GSList *list);
+GSList *g_slist_delete_link(GSList *list, GSList *link);
+
+GSList *g_slist_nth(GSList *list, guint n);
+gpointer g_slist_nth_data(GSList *list, guint n);
+int g_slist_position(GSList *list, GSList *link);
+GSList* g_slist_last(GSList *list);
 
 /* End GSList declarations */
 

Modified: bluez-utils/branches/upstream/current/hcid/Makefile.am
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/Makefile.am?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/Makefile.am (original)
+++ bluez-utils/branches/upstream/current/hcid/Makefile.am Wed Jul  4 13:37:57 2007
@@ -15,6 +15,7 @@
 
 libhciserver_a_SOURCES = hcid.h security.c device.c \
 	storage.c parser.h parser.y lexer.l kword.c kword.h \
+	server.h server.c \
 	dbus-hci.h dbus-hci.c dbus-common.c dbus-common.h \
 	dbus-error.c dbus-error.h dbus-manager.c dbus-manager.h \
 	dbus-database.c dbus-database.h dbus-security.c dbus-security.h \

Modified: bluez-utils/branches/upstream/current/hcid/Makefile.in
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/Makefile.in?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/Makefile.in (original)
+++ bluez-utils/branches/upstream/current/hcid/Makefile.in Wed Jul  4 13:37:57 2007
@@ -57,11 +57,12 @@
 libhciserver_a_LIBADD =
 am_libhciserver_a_OBJECTS = security.$(OBJEXT) device.$(OBJEXT) \
 	storage.$(OBJEXT) parser.$(OBJEXT) lexer.$(OBJEXT) \
-	kword.$(OBJEXT) dbus-hci.$(OBJEXT) dbus-common.$(OBJEXT) \
-	dbus-error.$(OBJEXT) dbus-manager.$(OBJEXT) \
-	dbus-database.$(OBJEXT) dbus-security.$(OBJEXT) \
-	dbus-adapter.$(OBJEXT) dbus-device.$(OBJEXT) \
-	dbus-service.$(OBJEXT) dbus-sdp.$(OBJEXT) dbus-test.$(OBJEXT)
+	kword.$(OBJEXT) server.$(OBJEXT) dbus-hci.$(OBJEXT) \
+	dbus-common.$(OBJEXT) dbus-error.$(OBJEXT) \
+	dbus-manager.$(OBJEXT) dbus-database.$(OBJEXT) \
+	dbus-security.$(OBJEXT) dbus-adapter.$(OBJEXT) \
+	dbus-device.$(OBJEXT) dbus-service.$(OBJEXT) \
+	dbus-sdp.$(OBJEXT) dbus-test.$(OBJEXT)
 libhciserver_a_OBJECTS = $(am_libhciserver_a_OBJECTS)
 am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \
 	"$(DESTDIR)$(man8dir)" "$(DESTDIR)$(confdir)" \
@@ -287,6 +288,7 @@
 noinst_LIBRARIES = libhciserver.a
 libhciserver_a_SOURCES = hcid.h security.c device.c \
 	storage.c parser.h parser.y lexer.l kword.c kword.h \
+	server.h server.c \
 	dbus-hci.h dbus-hci.c dbus-common.c dbus-common.h \
 	dbus-error.c dbus-error.h dbus-manager.c dbus-manager.h \
 	dbus-database.c dbus-database.h dbus-security.c dbus-security.h \
@@ -411,6 +413,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/main.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/parser.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/security.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/server.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/storage.Po at am__quote@
 
 .c.o:

Modified: bluez-utils/branches/upstream/current/hcid/dbus-adapter.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-adapter.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-adapter.c (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-adapter.c Wed Jul  4 13:37:57 2007
@@ -228,27 +228,34 @@
 	return bonding;
 }
 
-static const char *hcimode2str(uint8_t mode)
-{
-	const char *scan_mode;
-
-	switch (mode) {
-	case SCAN_DISABLED:
-		scan_mode = MODE_OFF;
-		break;
-	case SCAN_PAGE:
-		scan_mode = MODE_CONNECTABLE;
-		break;
-	case (SCAN_PAGE | SCAN_INQUIRY):
-		scan_mode = MODE_DISCOVERABLE;
-		break;
-	case SCAN_INQUIRY:
-		/* inquiry scan mode is not handled, return unknown */
+const char *mode2str(uint8_t mode)
+{
+	switch(mode) {
+	case MODE_OFF:
+		return "off";
+	case MODE_CONNECTABLE:
+		return "connectable";
+	case MODE_DISCOVERABLE:
+		return "discoverable";
+	case MODE_LIMITED:
+		return "limited";
 	default:
-		/* reserved */
-		scan_mode = MODE_UNKNOWN;
-	}
-	return scan_mode;
+		return "unknown";
+	}
+}
+
+uint8_t str2mode(const char *mode)
+{
+	if (strcasecmp("off", mode) == 0)
+		return MODE_OFF;
+	else if (strcasecmp("connectable", mode) == 0)
+		return MODE_CONNECTABLE;
+	else if (strcasecmp("discoverable", mode) == 0)
+		return MODE_DISCOVERABLE;
+	else if (strcasecmp("limited", mode) == 0)
+		return MODE_LIMITED;
+	else
+		return MODE_UNKNOWN;
 }
 
 static DBusHandlerResult adapter_get_info(DBusConnection *conn,
@@ -301,8 +308,9 @@
 	dbus_message_iter_append_dict_entry(&dict, "company",
 			DBUS_TYPE_STRING, &property);
 
-	property = hcimode2str(adapter->mode);
-	dbus_message_iter_append_dict_entry(&dict, "mode", 
+	property = mode2str(adapter->mode);
+
+	dbus_message_iter_append_dict_entry(&dict, "mode",
 			DBUS_TYPE_STRING, &property);
 
 	dbus_message_iter_append_dict_entry(&dict, "discoverable_timeout",
@@ -449,12 +457,40 @@
 	return send_message_and_unref(conn, reply);
 }
 
+static DBusHandlerResult adapter_list_modes(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	DBusMessage *reply;
+	DBusMessageIter iter;
+	DBusMessageIter array_iter;
+	const char *mode_ptr[] = { "off", "connectable", "discoverable", "limited" };
+	int i;
+
+	if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+		return error_invalid_arguments(conn, msg);
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	dbus_message_iter_init_append(reply, &iter);
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+						DBUS_TYPE_STRING_AS_STRING, &array_iter);
+	for (i = 0; i < 4; i++)
+		dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING,
+								&mode_ptr[i]);
+
+	dbus_message_iter_close_container(&iter, &array_iter);
+
+	return send_message_and_unref(conn, reply);
+}
+
 static DBusHandlerResult adapter_get_mode(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
 	const struct adapter *adapter = data;
 	DBusMessage *reply = NULL;
-	const char *scan_mode;
+	const char *mode;
 
 	if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
 		return error_invalid_arguments(conn, msg);
@@ -463,8 +499,9 @@
 	if (!reply)
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-	scan_mode = hcimode2str(adapter->mode);
-	dbus_message_append_args(reply, DBUS_TYPE_STRING, &scan_mode,
+	mode = mode2str(adapter->mode);
+
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &mode,
 					DBUS_TYPE_INVALID);
 
 	return send_message_and_unref(conn, reply);
@@ -473,32 +510,38 @@
 static DBusHandlerResult adapter_set_mode(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
-	const struct adapter *adapter = data;
-	DBusMessage *reply;
-	const char* scan_mode;
-	uint8_t hci_mode;
-	const uint8_t current_mode = adapter->mode;
+	struct adapter *adapter = data;
+	DBusMessage *reply;
+	const char *mode;
+	uint8_t scan_enable;
+	uint8_t new_mode, current_scan = adapter->scan_enable;
 	bdaddr_t local;
-	int dd;
+	gboolean limited;
+	int err, dd;
 
 	if (!dbus_message_get_args(msg, NULL,
-				DBUS_TYPE_STRING, &scan_mode,
+				DBUS_TYPE_STRING, &mode,
 				DBUS_TYPE_INVALID))
 		return error_invalid_arguments(conn, msg);
 
-	if (!scan_mode)
-		return error_invalid_arguments(conn, msg);
-
-	if (strcasecmp(MODE_OFF, scan_mode) == 0)
-		hci_mode = SCAN_DISABLED;
-	else if (strcasecmp(MODE_CONNECTABLE, scan_mode) == 0)
-		hci_mode = SCAN_PAGE;
-	else if (strcasecmp(MODE_DISCOVERABLE, scan_mode) == 0)
-		hci_mode = (SCAN_PAGE | SCAN_INQUIRY);
-	else
-		return error_invalid_arguments(conn, msg);
-
-	str2ba(adapter->address, &local);
+	if (!mode)
+		return error_invalid_arguments(conn, msg);
+
+	new_mode = str2mode(mode);
+	switch(new_mode) {
+	case MODE_OFF:
+		scan_enable = SCAN_DISABLED;
+		break;
+	case MODE_CONNECTABLE:
+		scan_enable = SCAN_PAGE;
+		break;
+	case MODE_DISCOVERABLE:
+	case MODE_LIMITED:
+		scan_enable = (SCAN_PAGE | SCAN_INQUIRY);
+		break;
+	default:
+		return error_invalid_arguments(conn, msg);
+	}
 
 	dd = hci_open_dev(adapter->dev_id);
 	if (dd < 0)
@@ -507,13 +550,13 @@
 	if (!adapter->up &&
 			(hcid.offmode == HCID_OFFMODE_NOSCAN ||
 			 (hcid.offmode == HCID_OFFMODE_DEVDOWN &&
-			  hci_mode != SCAN_DISABLED))) {
+			  scan_enable != SCAN_DISABLED))) {
 		/* Start HCI device */
 		if (ioctl(dd, HCIDEVUP, adapter->dev_id) == 0)
 			goto done; /* on success */
 
 		if (errno != EALREADY) {
-			int err = errno;
+			err = errno;
 			error("Can't init device hci%d: %s (%d)\n",
 				adapter->dev_id, strerror(errno), errno);
 
@@ -522,7 +565,7 @@
 		}
 	}
 
-	if (adapter->up && hci_mode == SCAN_DISABLED &&
+	if (adapter->up && scan_enable == SCAN_DISABLED &&
 			hcid.offmode == HCID_OFFMODE_DEVDOWN) {
 		if (ioctl(dd, HCIDEVDOWN, adapter->dev_id) < 0) {
 			hci_close_dev(dd);
@@ -532,22 +575,28 @@
 		goto done;
 	}
 
-	/* Check if the new requested mode is different from the current */
-	if (current_mode != hci_mode) {
+	limited = (new_mode == MODE_LIMITED ? TRUE : FALSE);
+	err = set_limited_discoverable(dd, adapter->class, limited);
+	if (err < 0) {
+		hci_close_dev(dd);
+		return error_failed(conn, msg, -err);
+	}
+
+	if (current_scan != scan_enable) {
 		struct hci_request rq;
 		uint8_t status = 0;
 
 		memset(&rq, 0, sizeof(rq));
 		rq.ogf    = OGF_HOST_CTL;
 		rq.ocf    = OCF_WRITE_SCAN_ENABLE;
-		rq.cparam = &hci_mode;
-		rq.clen   = sizeof(hci_mode);
+		rq.cparam = &scan_enable;
+		rq.clen   = sizeof(scan_enable);
 		rq.rparam = &status;
 		rq.rlen   = sizeof(status);
 		rq.event = EVT_CMD_COMPLETE;
 
 		if (hci_send_req(dd, &rq, 1000) < 0) {
-			int err = errno;
+			err = errno;
 			error("Sending write scan enable command failed: %s (%d)",
 					strerror(errno), errno);
 			hci_close_dev(dd);
@@ -560,16 +609,35 @@
 			hci_close_dev(dd);
 			return error_failed(conn, msg, bt_error(status));
 		}
-	}
-
+	} else {
+		/* discoverable or limited */
+		if ((scan_enable & SCAN_INQUIRY) && (new_mode != adapter->mode)) {
+			dbus_connection_emit_signal(conn,
+					dbus_message_get_path(msg),
+					ADAPTER_INTERFACE,
+					"ModeChanged",
+					DBUS_TYPE_STRING, &mode,
+					DBUS_TYPE_INVALID);
+
+			if (adapter->timeout_id)
+				g_source_remove(adapter->timeout_id);
+
+			if (adapter->discov_timeout != 0)
+				adapter->timeout_id = g_timeout_add(adapter->discov_timeout * 1000,
+						discov_timeout_handler, adapter);
+		}
+	}
 done:
-	write_device_mode(&local, scan_mode);
+	str2ba(adapter->address, &local);
+	write_device_mode(&local, mode);
 
 	hci_close_dev(dd);
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	adapter->mode = new_mode;
 
 	return send_message_and_unref(conn, reply);
 }
@@ -620,7 +688,7 @@
 		adapter->timeout_id = 0;
 	}
 
-	if ((timeout != 0) && (adapter->mode & SCAN_INQUIRY))
+	if ((timeout != 0) && (adapter->scan_enable & SCAN_INQUIRY))
 		adapter->timeout_id = g_timeout_add(timeout * 1000,
 						discov_timeout_handler,
 						adapter);
@@ -644,13 +712,13 @@
 {
 	const struct adapter *adapter = data;
 	DBusMessage *reply;
-	const uint8_t hci_mode = adapter->mode;
+	const uint8_t scan_enable = adapter->scan_enable;
 	dbus_bool_t connectable = FALSE;
 
 	if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
 		return error_invalid_arguments(conn, msg);
 
-	if (hci_mode & SCAN_PAGE)
+	if (scan_enable & SCAN_PAGE)
 		connectable = TRUE;
 
 	reply = dbus_message_new_method_return(msg);
@@ -668,13 +736,13 @@
 {
 	const struct adapter *adapter = data;
 	DBusMessage *reply;
-	const uint8_t hci_mode = adapter->mode;
+	const uint8_t scan_enable = adapter->scan_enable;
 	dbus_bool_t discoverable = FALSE;
 
 	if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
 		return error_invalid_arguments(conn, msg);
 
-	if (hci_mode & SCAN_INQUIRY)
+	if (scan_enable & SCAN_INQUIRY)
 		discoverable = TRUE;
 
 	reply = dbus_message_new_method_return(msg);
@@ -744,15 +812,14 @@
 					DBUS_TYPE_STRING_AS_STRING, &array_iter);
 
 	while (l) {
-		char *peer_addr;
-		bdaddr_t tmp;
+		char peer_addr[18];
+		const char *paddr = peer_addr;
 		struct active_conn_info *dev = l->data;
 
-		baswap(&tmp, &dev->bdaddr); peer_addr = batostr(&tmp);
+		ba2str(&dev->bdaddr, peer_addr);
 
 		dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING,
-						&peer_addr);
-		bt_free(peer_addr);
+						&paddr);
 
 		l = l->next;
 	}
@@ -768,8 +835,6 @@
 	const struct adapter *adapter = data;
 	DBusMessage *reply;
 	const char *str_ptr = "computer";
-	uint8_t cls[3];
-	int dd;
 
 	if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
 		return error_invalid_arguments(conn, msg);
@@ -778,22 +843,8 @@
 	if (!reply)
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-	dd = hci_open_dev(adapter->dev_id);
-	if (dd < 0)
-		return error_no_such_adapter(conn, msg);
-
-	if (hci_read_class_of_dev(dd, cls, 1000) < 0) {
-		int err = errno;
-		error("Can't read class of device on hci%d: %s(%d)",
-				adapter->dev_id, strerror(errno), errno);
-		hci_close_dev(dd);
-		return error_failed(conn, msg, err);
-	}
-
-	hci_close_dev(dd);
-
 	/* FIXME: Currently, only computer major class is supported */
-	if ((cls[1] & 0x1f) != 1)
+	if ((adapter->class[1] & 0x1f) != 1)
 		return error_unsupported_major_class(conn, msg);
 
 	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
@@ -810,31 +861,13 @@
 	DBusMessageIter iter;
 	DBusMessageIter array_iter;
 	const char **minor_ptr;
-	uint8_t cls[3];
 	uint8_t major_class;
-	int dd, size, i;
-
-	if (!adapter->up)
-		return error_not_ready(conn, msg);
+	int size, i;
 
 	if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
 		return error_invalid_arguments(conn, msg);
 
-	dd = hci_open_dev(adapter->dev_id);
-	if (dd < 0)
-		return error_no_such_adapter(conn, msg);
-
-	if (hci_read_class_of_dev(dd, cls, 1000) < 0) {
-		int err = errno;
-		error("Can't read class of device on hci%d: %s(%d)",
-				adapter->dev_id, strerror(errno), errno);
-		hci_close_dev(dd);
-		return error_failed(conn, msg, err);
-	}
-
-	hci_close_dev(dd);
-
-	major_class = cls[1] & 0x1F;
+	major_class = adapter->class[1] & 0x1F;
 
 	switch (major_class) {
 	case 1: /* computer */
@@ -871,91 +904,63 @@
 	struct adapter *adapter = data;
 	DBusMessage *reply;
 	const char *str_ptr = "";
-	uint8_t cls[3];
 	uint8_t minor_class;
-	int dd;
+
+	if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+		return error_invalid_arguments(conn, msg);
+
+	/* FIXME: Currently, only computer major class is supported */
+	if ((adapter->class[1] & 0x1f) != 1)
+		return error_unsupported_major_class(conn, msg);
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	minor_class = adapter->class[0] >> 2;
+
+	/* Validate computer minor class */
+	if (minor_class > (sizeof(computer_minor_cls) / sizeof(*computer_minor_cls)))
+		goto failed;
+
+	str_ptr = computer_minor_cls[minor_class];
+
+failed:
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
+					DBUS_TYPE_INVALID);
+
+	return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult adapter_set_minor_class(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	struct adapter *adapter = data;
+	DBusMessage *reply;
+	const char *minor;
+	uint32_t dev_class = 0xFFFFFFFF;
+	int i, dd;
 
 	if (!adapter->up)
 		return error_not_ready(conn, msg);
 
-	if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+	if (!dbus_message_get_args(msg, NULL,
+				DBUS_TYPE_STRING, &minor,
+				DBUS_TYPE_INVALID))
+		return error_invalid_arguments(conn, msg);
+
+	if (!minor)
 		return error_invalid_arguments(conn, msg);
 
 	dd = hci_open_dev(adapter->dev_id);
 	if (dd < 0)
 		return error_no_such_adapter(conn, msg);
 
-	if (hci_read_class_of_dev(dd, cls, 1000) < 0) {
-		int err = errno;
-		error("Can't read class of device on hci%d: %s(%d)",
-				adapter->dev_id, strerror(errno), errno);
+	/* Currently, only computer major class is supported */
+	if ((adapter->class[1] & 0x1f) != 1) {
 		hci_close_dev(dd);
-		return error_failed(conn, msg, err);
-	}
-
-	hci_close_dev(dd);
-
-	/* FIXME: Currently, only computer major class is supported */
-	if ((cls[1] & 0x1f) != 1)
 		return error_unsupported_major_class(conn, msg);
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
-	minor_class = cls[0] >> 2;
-
-	/* Validate computer minor class */
-	if (minor_class > (sizeof(computer_minor_cls) / sizeof(*computer_minor_cls)))
-		goto failed;
-
-	str_ptr = computer_minor_cls[minor_class];
-
-failed:
-	dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
-					DBUS_TYPE_INVALID);
-
-	return send_message_and_unref(conn, reply);
-}
-
-static DBusHandlerResult adapter_set_minor_class(DBusConnection *conn,
-						DBusMessage *msg, void *data)
-{
-	struct adapter *adapter = data;
-	DBusMessage *reply;
-	bdaddr_t bdaddr;
-	const char *minor;
-	uint8_t cls[3];
-	uint32_t dev_class = 0xFFFFFFFF;
-	int i, dd;
-
-	if (!adapter->up)
-		return error_not_ready(conn, msg);
-
-	if (!dbus_message_get_args(msg, NULL,
-				DBUS_TYPE_STRING, &minor,
-				DBUS_TYPE_INVALID))
-		return error_invalid_arguments(conn, msg);
-
-	if (!minor)
-		return error_invalid_arguments(conn, msg);
-
-	dd = hci_open_dev(adapter->dev_id);
-	if (dd < 0)
-		return error_no_such_adapter(conn, msg);
-
-	if (hci_read_class_of_dev(dd, cls, 1000) < 0) {
-		int err = errno;
-		error("Can't read class of device on hci%d: %s(%d)",
-				adapter->dev_id, strerror(errno), errno);
-		hci_close_dev(dd);
-		return error_failed(conn, msg, err);
-	}
-
-	/* Currently, only computer major class is supported */
-	if ((cls[1] & 0x1f) != 1)
-		return error_unsupported_major_class(conn, msg);
-
+	}
 	for (i = 0; i < sizeof(computer_minor_cls) / sizeof(*computer_minor_cls); i++)
 		if (!strcasecmp(minor, computer_minor_cls[i])) {
 			/* Remove the format type */
@@ -964,18 +969,13 @@
 		}
 
 	/* Check if it's a valid minor class */
-	if (dev_class == 0xFFFFFFFF)
-		return error_invalid_arguments(conn, msg);
-
-	/* update the minor class before store */
-	cls[0] = (dev_class & 0xff);
+	if (dev_class == 0xFFFFFFFF) {
+		hci_close_dev(dd);
+		return error_invalid_arguments(conn, msg);
+	}
 
 	/* set the service class and major class  */
-	dev_class |= (cls[2] << 16) | (cls[1] << 8);
-
-	hci_devba(adapter->dev_id, &bdaddr);
-
-	write_local_class(&bdaddr, cls);
+	dev_class |= (adapter->class[2] << 16) | (adapter->class[1] << 8);
 
 	if (hci_write_class_of_dev(dd, dev_class, 2000) < 0) {
 		int err = errno;
@@ -1006,8 +1006,7 @@
 	DBusMessageIter iter;
 	DBusMessageIter array_iter;
 	const char *str_ptr;
-	uint8_t cls[3];
-	int dd, i;
+	int i;
 
 	if (!adapter->up)
 		return error_not_ready(conn, msg);
@@ -1015,19 +1014,9 @@
 	if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
 		return error_invalid_arguments(conn, msg);
 
-	dd = hci_open_dev(adapter->dev_id);
-	if (dd < 0)
-		return error_no_such_adapter(conn, msg);
-
-	if (hci_read_class_of_dev(dd, cls, 1000) < 0) {
-		int err = errno;
-		error("Can't read class of device on hci%d: %s(%d)",
-				adapter->dev_id, strerror(errno), errno);
-		hci_close_dev(dd);
-		return error_failed(conn, msg, err);
-	}
-
-	reply = dbus_message_new_method_return(msg);
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
 	dbus_message_iter_init_append(reply, &iter);
 
@@ -1035,7 +1024,7 @@
 				DBUS_TYPE_STRING_AS_STRING, &array_iter);
 
 	for (i = 0; i < (sizeof(service_cls) / sizeof(*service_cls)); i++) {
-		if (cls[2] & (1 << i)) {
+		if (adapter->class[2] & (1 << i)) {
 			str_ptr = service_cls[i];
 			dbus_message_iter_append_basic(&array_iter,
 						DBUS_TYPE_STRING, &str_ptr);
@@ -1043,8 +1032,6 @@
 	}
 
 	dbus_message_iter_close_container(&iter, &array_iter);
-
-	hci_close_dev(dd);
 
 	return send_message_and_unref(conn, reply);
 }
@@ -1276,6 +1263,13 @@
 							void *data)
 {
 	return get_remote_svc_handles(conn, msg, data);
+}
+
+static DBusHandlerResult adapter_get_remote_svc_identifiers(DBusConnection *conn,
+								DBusMessage *msg,
+								void *data)
+{
+	return get_remote_svc_identifiers(conn, msg, data);
 }
 
 static DBusHandlerResult adapter_finish_sdp_transact(DBusConnection *conn,
@@ -1978,7 +1972,7 @@
 	if (!l)
 		return error_not_connected(conn, msg);
 
-	if(adapter->pending_dc)
+	if (adapter->pending_dc)
 		return error_disconnect_in_progress(conn, msg);
 
 	adapter->pending_dc = g_new0(struct pending_dc_info, 1);
@@ -1989,7 +1983,7 @@
 			      dc_pending_timeout_handler,
 			      adapter);
 
-	if(!adapter->pending_dc->timeout_id) {
+	if (!adapter->pending_dc->timeout_id) {
 		g_free(adapter->pending_dc);
 		adapter->pending_dc = NULL;
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
@@ -3110,6 +3104,8 @@
 		"",	"s"	},
 	{ "GetCompany",				adapter_get_company,
 		"",	"s"	},
+	{ "ListAvailableModes",			adapter_list_modes,
+		"",	"as"	},
 	{ "GetMode",				adapter_get_mode,
 		"",	"s"	},
 	{ "SetMode",				adapter_set_mode,
@@ -3140,7 +3136,7 @@
 		"",	"s"	},
 	{ "SetName",				adapter_set_name,
 		"s",	""	},
-	
+
 	{ "GetRemoteInfo",			adapter_get_remote_info,
 		"s",	"{sv}"	},
 	{ "GetRemoteServiceRecord",		adapter_get_remote_svc,
@@ -3149,6 +3145,8 @@
 		"su",	"s"	},
 	{ "GetRemoteServiceHandles",		adapter_get_remote_svc_handles,
 		"ss",	"au"	},
+	{ "GetRemoteServiceIdentifiers",	adapter_get_remote_svc_identifiers,
+		"s",	"as"	},
 	{ "FinishRemoteServiceTransaction",	adapter_finish_sdp_transact,
 		"s",	""	},
 
@@ -3255,8 +3253,11 @@
 	{ "RemoteDeviceConnected",		"s"	},
 	{ "RemoteDeviceDisconnectRequested",	"s"	},
 	{ "RemoteDeviceDisconnected",		"s"	},
+	{ "RemoteIdentifiersUpdated",		"sas"	},
 	{ "BondingCreated",			"s"	},
 	{ "BondingRemoved",			"s"	},
+	{ "TrustAdded",				"s"	},
+	{ "TrustRemoved",			"s"	},
 	{ NULL, NULL }
 };
 
@@ -3266,4 +3267,3 @@
 							adapter_methods,
 							adapter_signals, NULL);
 }
-

Modified: bluez-utils/branches/upstream/current/hcid/dbus-adapter.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-adapter.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-adapter.h (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-adapter.h Wed Jul  4 13:37:57 2007
@@ -90,7 +90,9 @@
 	char address[18];		/* adapter Bluetooth Address */
 	guint timeout_id;		/* discoverable timeout id */
 	uint32_t discov_timeout;	/* discoverable time(msec) */
-	uint8_t mode;			/* scan mode */
+	uint8_t scan_enable;		/* scan mode: SCAN_DISABLED, SCAN_PAGE, SCAN_INQUIRY */
+	uint8_t mode;			/* off, connectable, discoverable, limited */
+	uint8_t class[3];		/* device class */
 	int discov_active;		/* standard discovery active: includes name resolution step */
 	int pdiscov_active;		/* periodic discovery active */
 	int pinq_idle;			/* tracks the idle time for periodic inquiry */
@@ -116,6 +118,8 @@
 
 const char *minor_class_str(uint32_t class);
 
+const char *mode2str(uint8_t mode);
+
 GSList *service_classes_str(uint32_t class);
 
 int pending_remote_name_cancel(struct adapter *adapter);

Modified: bluez-utils/branches/upstream/current/hcid/dbus-api.txt
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-api.txt?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-api.txt (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-api.txt Wed Jul  4 13:37:57 2007
@@ -354,11 +354,17 @@
 
 			Possible errors: org.bluez.Error.Failed
 
+		array{string} ListAvailableModes()
+
+			Returns a list of available modes the adapter can
+			be switched into.
+
 		string GetMode()
 
 			Returns the current mode of a adapter.
 
-			Valid modes: "off", "connectable", "discoverable"
+			Valid modes: "off", "connectable", "discoverable",
+					"limited".
 
 			Possible errors: none
 
@@ -374,7 +380,7 @@
 
 			Returns the discoverable timeout in seconds. A value
 			of zero means that the timeout is disabled and it will
-			stay in discoverable mode forever.
+			stay in discoverable/limited mode forever.
 
 			The default value for the discoverable timeout should
 			be 180 seconds (3 minutes).
@@ -385,10 +391,10 @@
 
 			Sets the discoverable timeout in seconds. A value of
 			zero disables the timeout and the adapter would be
-			always discoverable.
+			always discoverable/limited.
 
 			Changing this value doesn't set the adapter into
-			discoverable mode. The SetMode method must be used.
+			discoverable/limited mode. The SetMode method must be used.
 
 			Possible errors: org.bluez.Error.NotReady
 					 org.bluez.Error.InvalidArguments
@@ -405,8 +411,8 @@
 
 		boolean IsDiscoverable()
 
-			Returns true if the local adapter is discoverable and
-			false if it is only connectable or switched off.
+			Returns true if the local adapter is discoverable/limited
+			and false if it is only connectable or switched off.
 
 			It is also possible to use GetMode to retrieve this
 			information.
@@ -434,9 +440,8 @@
 			For the other values, unsupported major class
 			error is returned.
 
-			Possible errors: org.bluez.Error.NoSuchAdapter
+			Possible errors: org.bluez.Error.InvalidArguments
 					 org.bluez.Error.UnsupportedMajorClass
-					 org.bluez.Error.Failed
 
 		array{string} ListAvailableMinorClasses()
 
@@ -448,9 +453,7 @@
 			If the major class is not "computer" an error should
 			be returned.
 
-			Possible errors: org.bluez.Error.NotReady
-					 org.bluez.Error.NoSuchAdapter
-					 org.bluez.Error.Failed
+			Possible errors: org.bluez.Error.InvalidArguments
 					 org.bluez.Error.UnsupportedMajorClass
 
 		string GetMinorClass()
@@ -466,10 +469,8 @@
 
 			The default value is "uncategorized".
 
-			Possible errors: org.bluez.Error.NotReady
-					 org.bluez.Error.NoSuchAdapter
-					 org.bluez.Error.Failed
-					 org.bluez.Error.UnsupportedMajorClass
+			Possible errors:org.bluez.Error.InvalidArguments
+					org.bluez.Error.UnsupportedMajorClass
 
 		void SetMinorClass(string minor)
 
@@ -962,6 +963,15 @@
 					 org.bluez.Error.InProgress
 					 org.bluez.Error.Failed
 
+		array{string} GetRemoteServiceIdentifiers(string address)
+
+			This method will request the SDP database of a remote
+			device for all supported services. The identifiers are
+			returned in UUID 128 string format.
+
+			Possible errors: org.bluez.Error.InProgress
+					 org.bluez.Error.Failed
+
 		void FinishRemoteServiceTransaction(string address)
 
 			This method will finish all SDP transaction for that
@@ -1054,6 +1064,13 @@
 
 			This signal will be send every time the service daemon
 			detect a new name for a remote device.
+
+		void RemoteIdentifiersUpdated(string address, array{string identifiers})
+
+			This signal is sent to indicate the provided services of a given
+			remote device. It will be sent after GetRemoteServiceIdentifiers
+			calls. This signal has at least one identifier and it does not
+			contain repeated entries.
 
 		void RemoteNameFailed(string address)
 

Modified: bluez-utils/branches/upstream/current/hcid/dbus-common.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-common.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-common.c (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-common.c Wed Jul  4 13:37:57 2007
@@ -207,45 +207,6 @@
 	return 0;
 }
 
-
-int check_address(const char *addr)
-{
-	char tmp[18];
-	char *ptr = tmp;
-
-	if (!addr)
-		return -1;
-
-	if (strlen(addr) != 17)
-		return -1;
-
-	memcpy(tmp, addr, 18);
-
-	while (*ptr) {
-
-		*ptr = toupper(*ptr);
-		if (*ptr < '0'|| (*ptr > '9' && *ptr < 'A') || *ptr > 'F')
-			return -1;
-
-		ptr++;
-		*ptr = toupper(*ptr);
-		if (*ptr < '0'|| (*ptr > '9' && *ptr < 'A') || *ptr > 'F')
-			return -1;
-
-		ptr++;
-		*ptr = toupper(*ptr);
-		if (*ptr == 0)
-			break;
-
-		if (*ptr != ':')
-			return -1;
-
-		ptr++;
-	}
-
-	return 0;
-}
-
 void hcid_dbus_set_experimental(void)
 {
 	experimental = 1;

Modified: bluez-utils/branches/upstream/current/hcid/dbus-common.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-common.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-common.h (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-common.h Wed Jul  4 13:37:57 2007
@@ -49,7 +49,7 @@
 
 int find_conn(int s, int dev_id, long arg);
 
-int check_address(const char *addr);
+#define check_address(address) bachk(address)
 
 DBusHandlerResult handle_method_call(DBusConnection *conn, DBusMessage *msg, void *data);
 

Modified: bluez-utils/branches/upstream/current/hcid/dbus-database.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-database.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-database.c (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-database.c Wed Jul  4 13:37:57 2007
@@ -227,7 +227,6 @@
 						DBusMessage *msg, void *data)
 {
 	struct record_data *user_record;
-	DBusMessage *reply;
 	DBusMessageIter iter, array;
 	sdp_record_t *sdp_record;
 	dbus_uint32_t handle;
@@ -247,20 +246,14 @@
 	if (!user_record)
 		return error_not_available(conn, msg);
 
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
 	sdp_record = sdp_extract_pdu(bin_record, &scanned);
 	if (!sdp_record) {
 		error("Parsing of service record failed");
-		dbus_message_unref(reply);
 		return error_invalid_arguments(conn, msg);
 	}
 
 	if (scanned != size) {
 		error("Size mismatch of service record");
-		dbus_message_unref(reply);
 		sdp_record_free(sdp_record);
 		return error_invalid_arguments(conn, msg);
 	}
@@ -271,17 +264,25 @@
 
 		sdp_record->handle = handle;
 		err = add_record_to_server(sdp_record);
-	} else
+		if (err < 0) {
+			sdp_record_free(sdp_record);
+			error("Failed to update the service record");
+			return error_failed(conn, msg, EIO);
+		}
+	} else {
+		sdp_data_t *d = sdp_data_alloc(SDP_UINT32, &handle);
+		sdp_attr_replace(sdp_record, SDP_ATTR_RECORD_HANDLE, d);
+
 		err = update_sdp_record(handle, sdp_record);
-
-	if (err < 0) {
-		error("Failed to update the service record");
-		dbus_message_unref(reply);
 		sdp_record_free(sdp_record);
-		return error_failed(conn, msg, EIO);
-	}
-
-	return send_message_and_unref(conn, reply);
+		if (err < 0) {
+			error("Failed to update the service record");
+			return error_failed(conn, msg, EIO);
+		}
+	}
+
+	return send_message_and_unref(conn,
+			dbus_message_new_method_return(msg));
 }
 
 static DBusHandlerResult remove_service_record(DBusConnection *conn,
@@ -336,7 +337,7 @@
 
 	sender = dbus_message_get_sender(msg);
 
-	if (service_register(sender, ident, name, desc) < 0)
+	if (service_register(conn, sender, ident, name, desc) < 0)
 		return error_failed(conn, msg, EIO);
 
 	reply = dbus_message_new_method_return(msg);
@@ -366,7 +367,7 @@
 	if (!service->external || strcmp(sender, service->bus_name))
 		return error_not_authorized(conn, msg);
 
-	if (service_unregister(service) < 0)
+	if (service_unregister(conn, service) < 0)
 		return error_failed(conn, msg, EIO);
 
 	reply = dbus_message_new_method_return(msg);
@@ -460,6 +461,27 @@
 							NULL, NULL);
 }
 
+DBusHandlerResult database_message(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	DBusMethodVTable *current;
+
+	for (current = database_methods;
+			current->name && current->message_function; current++) {
+		if (!dbus_message_is_method_call(msg, DATABASE_INTERFACE,
+								current->name))
+			continue;
+
+		if (dbus_message_has_signature(msg, current->signature)) {
+			debug("%s: %s.%s()", dbus_message_get_path(msg),
+					DATABASE_INTERFACE, current->name);
+			return current->message_function(conn, msg, data);
+		}
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
 void set_sdp_server_enable(void)
 {
 	sdp_server_enable = 1;

Modified: bluez-utils/branches/upstream/current/hcid/dbus-database.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-database.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-database.h (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-database.h Wed Jul  4 13:37:57 2007
@@ -21,13 +21,11 @@
  *
  */
 
-#ifndef __BLUEZ_DBUS_DATABASE_H
-#define __BLUEZ_DBUS_DATABASE_H
-
 #define DATABASE_INTERFACE "org.bluez.Database"
 
 dbus_bool_t database_init(DBusConnection *conn, const char *path);
 
+DBusHandlerResult database_message(DBusConnection *conn,
+						DBusMessage *msg, void *data);
+
 void set_sdp_server_enable(void);
-
-#endif /* __BLUEZ_DBUS_DATABSE_H */

Modified: bluez-utils/branches/upstream/current/hcid/dbus-hci.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-hci.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-hci.c (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-hci.c Wed Jul  4 13:37:57 2007
@@ -262,24 +262,34 @@
 	return ret;
 }
 
-static void adapter_mode_changed(struct adapter *adapter, const char *path, uint8_t mode)
-{
-	const char *scan_mode;
-
-	adapter->mode = mode;
-
-	switch (mode) {
+static void adapter_mode_changed(struct adapter *adapter,
+			const char *path, uint8_t scan_enable)
+{
+	const char *mode;
+
+	adapter->scan_enable = scan_enable;
+
+	switch (scan_enable) {
 	case SCAN_DISABLED:
-		scan_mode = MODE_OFF;
-		break; 
+		mode = "off";
+		adapter->mode = MODE_OFF;
+		break;
 	case SCAN_PAGE:
-		scan_mode = MODE_CONNECTABLE;
+		mode = "connectable";
+		adapter->mode = MODE_CONNECTABLE;
 		break;
 	case (SCAN_PAGE | SCAN_INQUIRY):
-		scan_mode = MODE_DISCOVERABLE;
+
 		if (adapter->discov_timeout != 0)
 			adapter->timeout_id = g_timeout_add(adapter->discov_timeout * 1000,
 					discov_timeout_handler, adapter);
+
+		if (adapter->mode == MODE_LIMITED) {
+			mode = "limited";
+		} else {
+			adapter->mode = MODE_DISCOVERABLE;
+			mode = "discoverable";
+		}
 		break;
 	case SCAN_INQUIRY:
 		/* Address the scenario where another app changed the scan mode */
@@ -294,7 +304,7 @@
 
 	dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE,
 					"ModeChanged",
-					DBUS_TYPE_STRING, &scan_mode,
+					DBUS_TYPE_STRING, &mode,
 					DBUS_TYPE_INVALID);
 }
 
@@ -428,7 +438,7 @@
 		dc_pending_timeout_cleanup(adapter);
 	}
 
-	g_free (adapter);
+	g_free(adapter);
 
 unreg:
 	if (!dbus_connection_destroy_object_path(connection, path)) {
@@ -542,7 +552,7 @@
 	struct adapter* adapter;
 	struct hci_conn_list_req *cl = NULL;
 	struct hci_conn_info *ci;
-	uint8_t mode;
+	const char *mode;
 	int i, err, dd = -1, ret = -1;
 
 	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -570,14 +580,13 @@
 	adapter->discov_timeout = get_discoverable_timeout(id);
 	adapter->discov_type = DISCOVER_TYPE_NONE;
 
-	mode = get_startup_mode(id);
-
 	dd = hci_open_dev(id);
 	if (dd < 0)
 		goto failed;
 
-	hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &mode);
-
+	adapter->scan_enable = get_startup_scan(id);
+	hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
+					1, &adapter->scan_enable);
 	/*
 	 * Get the adapter Bluetooth address
 	 */
@@ -586,7 +595,13 @@
 	if (err < 0)
 		goto failed;
 
-	adapter_mode_changed(adapter, path, mode);
+	err = get_device_class(adapter->dev_id, adapter->class);
+	if (err < 0)
+		goto failed;
+
+	adapter->mode = get_startup_mode(id);
+	if (adapter->mode == MODE_LIMITED)
+		set_limited_discoverable(dd, adapter->class, TRUE);
 
 	/* 
 	 * retrieve the active connections: address the scenario where
@@ -608,6 +623,12 @@
 
 	ret = 0;
 
+	mode = mode2str(adapter->mode);
+	dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE,
+					"ModeChanged",
+					DBUS_TYPE_STRING, &mode,
+					DBUS_TYPE_INVALID);
+
 failed:
 	if (ret == 0 && get_default_adapter() < 0)
 		set_default_adapter(id);
@@ -637,7 +658,7 @@
 {
 	char path[MAX_PATH_LENGTH];
 	struct adapter *adapter;
-	const char *scan_mode = MODE_OFF;
+	const char *mode = "off";
 
 	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
 
@@ -701,11 +722,12 @@
 	}
 
 	send_adapter_signal(connection, adapter->dev_id, "ModeChanged",
-				DBUS_TYPE_STRING, &scan_mode,
+				DBUS_TYPE_STRING, &mode,
 				DBUS_TYPE_INVALID);
 
 	adapter->up = 0;
-	adapter->mode = SCAN_DISABLED;
+	adapter->scan_enable = SCAN_DISABLED;
+	adapter->mode = MODE_OFF;
 	adapter->discov_active = 0;
 	adapter->pdiscov_active = 0;
 	adapter->pinq_idle = 0;
@@ -794,19 +816,18 @@
 					uint8_t status)
 {
 	struct adapter *adapter;
-	char *local_addr, *peer_addr;
+	char path[MAX_PATH_LENGTH], local_addr[18], peer_addr[18];
+	const char *paddr = peer_addr;
 	GSList *l;
-	bdaddr_t tmp;
-	char path[MAX_PATH_LENGTH];
 	int id;
 
-	baswap(&tmp, local); local_addr = batostr(&tmp);
-	baswap(&tmp, peer); peer_addr = batostr(&tmp);
+	ba2str(local, local_addr);
+	ba2str(peer, peer_addr);
 
 	id = hci_devid(local_addr);
 	if (id < 0) {
 		error("No matching device id for %s", local_addr);
-		goto failed;
+		return;
 	}
 
 	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -815,7 +836,7 @@
 	if (!dbus_connection_get_object_user_data(connection, path,
 							(void *) &adapter)) {
 		error("Getting %s path data failed!", path);
-		goto failed;
+		return;
 	}
 
 	if (status)
@@ -831,14 +852,14 @@
 		if (!status)
 			send_adapter_signal(connection, adapter->dev_id,
 						"BondingCreated",
-						DBUS_TYPE_STRING, &peer_addr,
+						DBUS_TYPE_STRING, &paddr,
 						DBUS_TYPE_INVALID);
 	}
 
 	release_passkey_agents(adapter, peer);
 
 	if (!adapter->bonding || bacmp(&adapter->bonding->bdaddr, peer))
-		goto failed; /* skip: no bonding req pending */
+		return; /* skip: no bonding req pending */
 
 	if (adapter->bonding->cancel) {
 		/* reply authentication canceled */
@@ -860,26 +881,20 @@
 	g_io_channel_close(adapter->bonding->io);
 	bonding_request_free(adapter->bonding);
 	adapter->bonding = NULL;
-
-failed:
-	bt_free(local_addr);
-	bt_free(peer_addr);
 }
 
 void hcid_dbus_inquiry_start(bdaddr_t *local)
 {
 	struct adapter *adapter;
-	char path[MAX_PATH_LENGTH];
-	char *local_addr;
-	bdaddr_t tmp;
+	char path[MAX_PATH_LENGTH], local_addr[18];
 	int id;
 
-	baswap(&tmp, local); local_addr = batostr(&tmp);
+	ba2str(local, local_addr);
 
 	id = hci_devid(local_addr);
 	if (id < 0) {
 		error("No matching device id for %s", local_addr);
-		goto failed;
+		return;
 	}
 
 	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -901,9 +916,6 @@
 
 	send_adapter_signal(connection, adapter->dev_id, "DiscoveryStarted",
 				DBUS_TYPE_INVALID);
-
-failed:
-	bt_free(local_addr);
 }
 
 int found_device_req_name(struct adapter *adapter)
@@ -943,10 +955,9 @@
 
 	/* send at least one request or return failed if the list is empty */
 	do {
-		const char *signal = NULL;
 		struct remote_dev_info *dev = l->data;
-		char *peer_addr;
-		bdaddr_t tmp;
+		char peer_addr[18];
+		const char *signal = NULL, *paddr = peer_addr;
 
 		 /* flag to indicate the current remote name requested */ 
 		dev->name_status = NAME_REQUESTED;
@@ -956,7 +967,7 @@
 		bacpy(&cp.bdaddr, &dev->bdaddr);
 		cp.pscan_rep_mode = 0x02;
 
-		baswap(&tmp, &dev->bdaddr); peer_addr = batostr(&tmp);
+		ba2str(&dev->bdaddr, peer_addr);
 
 		if (hci_send_req(dd, &rq, 500) < 0) {
 			error("Unable to send the HCI remote name request: %s (%d)",
@@ -979,10 +990,8 @@
 
 		if (signal)
 			send_adapter_signal(connection, adapter->dev_id, signal,
-						DBUS_TYPE_STRING, &peer_addr,
+						DBUS_TYPE_STRING, &paddr,
 						DBUS_TYPE_INVALID);
-
-		free(peer_addr);
 
 		if (req_sent)
 			break;
@@ -1024,18 +1033,16 @@
 {
 	struct adapter *adapter;
 	GSList *l;
-	char path[MAX_PATH_LENGTH];
-	char *local_addr;
+	char path[MAX_PATH_LENGTH], local_addr[18];
 	struct remote_dev_info *dev;
 	bdaddr_t tmp;
 	int id;
 
-	baswap(&tmp, local); local_addr = batostr(&tmp);
+	ba2str(local, local_addr);
 
 	id = hci_devid(local_addr);
 	if (id < 0) {
 		error("No matching device id for %s", local_addr);
-		bt_free(local_addr);
 		return;
 	}
 
@@ -1124,28 +1131,23 @@
 done:
 	/* Proceed with any queued up audits */
 	process_audits_list(path);
-
-	bt_free(local_addr);
 }
 
 void hcid_dbus_periodic_inquiry_start(bdaddr_t *local, uint8_t status)
 {
 	struct adapter *adapter;
-	char path[MAX_PATH_LENGTH];
-	char *local_addr;
-	bdaddr_t tmp;
+	char path[MAX_PATH_LENGTH], local_addr[18];
 	int id;
 
 	/* Don't send the signal if the cmd failed */
 	if (status)
 		return;
 
-	baswap(&tmp, local); local_addr = batostr(&tmp);
-
+	ba2str(local, local_addr);
 	id = hci_devid(local_addr);
 	if (id < 0) {
 		error("No matching device id for %s", local_addr);
-		goto failed;
+		return;
 	}
 
 	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1162,29 +1164,24 @@
 	dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE,
 					"PeriodicDiscoveryStarted",
 					DBUS_TYPE_INVALID);
-
-failed:
-	bt_free(local_addr);
 }
 
 void hcid_dbus_periodic_inquiry_exit(bdaddr_t *local, uint8_t status)
 {
 	struct adapter *adapter;
-	char path[MAX_PATH_LENGTH];
-	char *local_addr;
-	bdaddr_t tmp;
+	char path[MAX_PATH_LENGTH], local_addr[18];
 	int id;
 
 	/* Don't send the signal if the cmd failed */
 	if (status)
 		return;
 
-	baswap(&tmp, local); local_addr = batostr(&tmp);
+	ba2str(local, local_addr);
 
 	id = hci_devid(local_addr);
 	if (id < 0) {
 		error("No matching device id for %s", local_addr);
-		goto done;
+		return;
 	}
 
 	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1192,7 +1189,7 @@
 	if (!dbus_connection_get_object_user_data(connection, path,
 							(void *) &adapter)) {
 		error("Getting %s path data failed!", path);
-		goto done;
+		return;
 	}
 
 	/* reset the discover type to be able to handle D-Bus and non D-Bus
@@ -1232,8 +1229,6 @@
 	dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE,
 					"PeriodicDiscoveryStopped",
 					DBUS_TYPE_INVALID);
-done:
-	bt_free(local_addr);
 }
 
 static char *extract_eir_name(uint8_t *data, uint8_t *type)
@@ -1258,25 +1253,24 @@
 void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class,
 				int8_t rssi, uint8_t *data)
 {
-	char filename[PATH_MAX + 1];
-	char path[MAX_PATH_LENGTH];
+	char filename[PATH_MAX + 1], path[MAX_PATH_LENGTH];
 	struct adapter *adapter;
 	GSList *l;
+	char local_addr[18], peer_addr[18], *name, *tmp_name;
+	const char *paddr = peer_addr;
 	struct remote_dev_info match;
-	char *local_addr, *peer_addr, *name, *tmp_name;
 	dbus_int16_t tmp_rssi = rssi;
-	bdaddr_t tmp;
 	uint8_t name_type = 0x00;
 	name_status_t name_status;
 	int id;
 
-	baswap(&tmp, local); local_addr = batostr(&tmp);
-	baswap(&tmp, peer); peer_addr = batostr(&tmp);
+	ba2str(local, local_addr);
+	ba2str(peer, peer_addr);
 
 	id = hci_devid(local_addr);
 	if (id < 0) {
 		error("No matching device id for %s", local_addr);
-		goto done;
+		return;
 	}
 
 	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1284,7 +1278,7 @@
 	if (!dbus_connection_get_object_user_data(connection, path,
 							(void *) &adapter)) {
 		error("Getting %s path data failed!", path);
-		goto done;
+		return;
 	}
 
 	write_remote_class(local, peer, class);
@@ -1314,7 +1308,7 @@
 	/* send the device found signal */
 	dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE,
 					"RemoteDeviceFound",
-					DBUS_TYPE_STRING, &peer_addr,
+					DBUS_TYPE_STRING, &paddr,
 					DBUS_TYPE_UINT32, &class,
 					DBUS_TYPE_INT16, &tmp_rssi,
 					DBUS_TYPE_INVALID);
@@ -1326,7 +1320,7 @@
 	l = g_slist_find_custom(adapter->found_devices, &match,
 			(GCompareFunc) found_device_cmp);
 	if (l)
-		goto done;
+		return;
 
 	/* the inquiry result can be triggered by NON D-Bus client */
 	if (adapter->discov_type & RESOLVE_NAME)
@@ -1359,7 +1353,7 @@
 		dbus_connection_emit_signal(connection, path,
 						ADAPTER_INTERFACE,
 						"RemoteNameUpdated",
-						DBUS_TYPE_STRING, &peer_addr,
+						DBUS_TYPE_STRING, &paddr,
 						DBUS_TYPE_STRING, &name,
 						DBUS_TYPE_INVALID);
 		g_free(name);
@@ -1370,16 +1364,12 @@
 
 	/* add in the list to track name sent/pending */
 	found_device_add(&adapter->found_devices, peer, rssi, name_status);
-
-done:
-	bt_free(local_addr);
-	bt_free(peer_addr);
 }
 
 void hcid_dbus_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class)
 {
-	char *local_addr, *peer_addr;
-	bdaddr_t tmp;
+	char local_addr[18], peer_addr[18];
+	const char *paddr = peer_addr;
 	uint32_t old_class = 0;
 	int id;
 
@@ -1388,40 +1378,36 @@
 	if (old_class == class)
 		return;
 
-	baswap(&tmp, local); local_addr = batostr(&tmp);
-	baswap(&tmp, peer); peer_addr = batostr(&tmp);
+	ba2str(local, local_addr);
+	ba2str(peer, peer_addr);
 	id = hci_devid(local_addr);
 	if (id < 0) {
 		error("No matching device id for %s", local_addr);
-		goto failed;
+		return;
 	}
 
 	send_adapter_signal(connection, id, "RemoteClassUpdated",
-				DBUS_TYPE_STRING, &peer_addr,
+				DBUS_TYPE_STRING, &paddr,
 				DBUS_TYPE_UINT32, &class,
 				DBUS_TYPE_INVALID);
 
-failed:
-	bt_free(local_addr);
-	bt_free(peer_addr);
 }
 
 void hcid_dbus_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status,
 				char *name)
 {
 	struct adapter *adapter;
-	char path[MAX_PATH_LENGTH];
-	char *local_addr, *peer_addr;
-	bdaddr_t tmp;
+	char path[MAX_PATH_LENGTH], local_addr[18], peer_addr[18];
+	const char *paddr = peer_addr;
 	int id;
 
-	baswap(&tmp, local); local_addr = batostr(&tmp);
-	baswap(&tmp, peer); peer_addr = batostr(&tmp);
+	ba2str(local, local_addr);
+	ba2str(peer, peer_addr);
 
 	id = hci_devid(local_addr);
 	if (id < 0) {
 		error("No matching device id for %s", local_addr);
-		goto done;
+		return;
 	}
 
 	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1429,20 +1415,20 @@
 	if (!dbus_connection_get_object_user_data(connection, path,
 							(void *) &adapter)) {
 		error("Getting %s path data failed!", path);
-		goto done;
+		return;
 	}
 
 	if (status)
 		dbus_connection_emit_signal(connection, path,
 						ADAPTER_INTERFACE,
 						"RemoteNameFailed",
-						DBUS_TYPE_STRING, &peer_addr,
+						DBUS_TYPE_STRING, &paddr,
 						DBUS_TYPE_INVALID);
 	else 
 		dbus_connection_emit_signal(connection, path,
 						ADAPTER_INTERFACE,
 						"RemoteNameUpdated",
-						DBUS_TYPE_STRING, &peer_addr,
+						DBUS_TYPE_STRING, &paddr,
 						DBUS_TYPE_STRING, &name,
 						DBUS_TYPE_INVALID);
 
@@ -1451,7 +1437,7 @@
 
 	/* check if there is more devices to request names */
 	if (!found_device_req_name(adapter))
-		goto done; /* skip if a new request has been sent */
+		return; /* skip if a new request has been sent */
 
 	/* free discovered devices list */
 	g_slist_foreach(adapter->found_devices, (GFunc) g_free, NULL);
@@ -1489,28 +1475,23 @@
 						DBUS_TYPE_INVALID);
 		adapter->discov_active = 0;
 	}
-
-done:
-	bt_free(local_addr);
-	bt_free(peer_addr);
 }
 
 void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle,
 				bdaddr_t *peer)
 {
-	char path[MAX_PATH_LENGTH];
+	char path[MAX_PATH_LENGTH], local_addr[18], peer_addr[18];
+	const char *paddr = peer_addr;
 	struct adapter *adapter;
-	char *local_addr, *peer_addr;
-	bdaddr_t tmp;
 	int id;
 
-	baswap(&tmp, local); local_addr = batostr(&tmp);
-	baswap(&tmp, peer); peer_addr = batostr(&tmp);
+	ba2str(local, local_addr);
+	ba2str(peer, peer_addr);
 
 	id = hci_devid(local_addr);
 	if (id < 0) {
 		error("No matching device id for %s", local_addr);
-		goto done;
+		return;
 	}
 
 	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1518,7 +1499,7 @@
 	if (!dbus_connection_get_object_user_data(connection, path,
 							(void *) &adapter)) {
 		error("Getting %s path data failed!", path);
-		goto done;
+		return;
 	}
 
 	if (status) {
@@ -1542,28 +1523,23 @@
 		dbus_connection_emit_signal(connection, path,
 						ADAPTER_INTERFACE,
 						"RemoteDeviceConnected",
-						DBUS_TYPE_STRING, &peer_addr,
+						DBUS_TYPE_STRING, &paddr,
 						DBUS_TYPE_INVALID);
 
 		/* add in the active connetions list */
 		active_conn_append(&adapter->active_conn, peer, handle);
 	}
-
-done:
-	bt_free(local_addr);
-	bt_free(peer_addr);
 }
 
 void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status,
 				uint16_t handle, uint8_t reason)
 {
 	DBusMessage *reply;
-	char path[MAX_PATH_LENGTH];
+	char path[MAX_PATH_LENGTH], local_addr[18], peer_addr[18];
+	const char *paddr = peer_addr;
 	struct adapter *adapter;
 	struct active_conn_info *dev;
 	GSList *l;
-	char *local_addr, *peer_addr = NULL;
-	bdaddr_t tmp;
 	int id;
 
 	if (status) {
@@ -1571,12 +1547,12 @@
 		return;
 	}
 
-	baswap(&tmp, local); local_addr = batostr(&tmp);
+	ba2str(local, local_addr);
 
 	id = hci_devid(local_addr);
 	if (id < 0) {
 		error("No matching device id for %s", local_addr);
-		goto failed;
+		return;
 	}
 
 	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1584,18 +1560,18 @@
 	if (!dbus_connection_get_object_user_data(connection, path,
 							(void *) &adapter)) {
 		error("Getting %s path data failed!", path);
-		goto failed;
+		return;
 	}
 
 	l = g_slist_find_custom(adapter->active_conn, &handle,
 			active_conn_find_by_handle);
 
 	if (!l)
-		goto failed;
+		return;
 
 	dev = l->data;
 
-	baswap(&tmp, &dev->bdaddr); peer_addr = batostr(&tmp);
+	ba2str(&dev->bdaddr, peer_addr);
 
 	/* clean pending HCI cmds */
 	hci_req_queue_remove(adapter->dev_id, &dev->bdaddr);
@@ -1650,17 +1626,51 @@
 	/* Send the remote device disconnected signal */
 	dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE,
 					"RemoteDeviceDisconnected",
-					DBUS_TYPE_STRING, &peer_addr,
+					DBUS_TYPE_STRING, &paddr,
 					DBUS_TYPE_INVALID);
 
 	adapter->active_conn = g_slist_remove(adapter->active_conn, dev);
 	g_free(dev);
 
-failed:
-	if (peer_addr)
-		free(peer_addr);
-
-	free(local_addr);
+}
+
+int set_limited_discoverable(int dd, const uint8_t *cls, gboolean limited)
+{
+	uint32_t dev_class;
+	int err;
+	int num = (limited ? 2 : 1);
+	uint8_t lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
+	/*
+	 * 1: giac
+	 * 2: giac + liac
+	 */
+	if (hci_write_current_iac_lap(dd, num, lap, 1000) < 0) {
+		err = errno;
+		error("Can't write current IAC LAP: %s(%d)",
+				strerror(err), err);
+		return -err;
+	}
+
+	if (limited) {
+		if (cls[1] & 0x20)
+			return 0; /* Already limited */
+
+		dev_class = (cls[2] << 16) | ((cls[1] | 0x20) << 8) | cls[0];
+	} else {
+		if (!(cls[1] & 0x20))
+			return 0; /* Already clear */
+
+		dev_class = (cls[2] << 16) | ((cls[1] & 0xdf) << 8) | cls[0];
+	}
+
+	if (hci_write_class_of_dev(dd, dev_class, 1000) < 0) {
+		err = errno;
+		error("Can't write class of device: %s(%d)",
+				strerror(err), err);
+		return -err;
+	}
+
+	return 0;
 }
 
 gboolean discov_timeout_handler(void *data)
@@ -1668,11 +1678,11 @@
 	struct adapter *adapter = data;
 	struct hci_request rq;
 	int dd;
-	uint8_t hci_mode = adapter->mode;
+	uint8_t scan_enable = adapter->scan_enable;
 	uint8_t status = 0;
 	gboolean retval = TRUE;
 
-	hci_mode &= ~SCAN_INQUIRY;
+	scan_enable &= ~SCAN_INQUIRY;
 
 	dd = hci_open_dev(adapter->dev_id);
 	if (dd < 0) {
@@ -1683,8 +1693,8 @@
 	memset(&rq, 0, sizeof(rq));
 	rq.ogf    = OGF_HOST_CTL;
 	rq.ocf    = OCF_WRITE_SCAN_ENABLE;
-	rq.cparam = &hci_mode;
-	rq.clen   = sizeof(hci_mode);
+	rq.cparam = &scan_enable;
+	rq.clen   = sizeof(scan_enable);
 	rq.rparam = &status;
 	rq.rlen   = sizeof(status);
 	rq.event  = EVT_CMD_COMPLETE;
@@ -1698,6 +1708,8 @@
 		error("Setting scan enable failed with status 0x%02x", status);
 		goto failed;
 	}
+
+	set_limited_discoverable(dd, adapter->class, FALSE);
 
 	adapter->timeout_id = 0;
 	retval = FALSE;
@@ -1716,21 +1728,18 @@
  *****************************************************************/
 void hcid_dbus_setname_complete(bdaddr_t *local)
 {
-	char *local_addr;
-	bdaddr_t tmp;
-	int id;
-	int dd = -1;
+	int id, dd = -1;
 	read_local_name_rp rp;
 	struct hci_request rq;
 	const char *pname = (char *) rp.name;
-	char name[249];
-
-	baswap(&tmp, local); local_addr = batostr(&tmp);
+	char local_addr[18], name[249];
+
+	ba2str(local, local_addr);
 
 	id = hci_devid(local_addr);
 	if (id < 0) {
 		error("No matching device id for %s", local_addr);
-		goto failed;
+		return;
 	}
 
 	dd = hci_open_dev(id);
@@ -1756,6 +1765,7 @@
 					rp.status);
 			rp.name[0] = '\0';
 		}
+		hci_close_dev(dd);
 	}
 
 	strncpy(name, pname, sizeof(name) - 1);
@@ -1764,30 +1774,21 @@
 
 	send_adapter_signal(connection, id, "NameChanged",
 				DBUS_TYPE_STRING, &pname, DBUS_TYPE_INVALID);
-
-failed:
-	if (dd >= 0)
-		hci_close_dev(dd);
-
-	bt_free(local_addr);
 }
 
 void hcid_dbus_setscan_enable_complete(bdaddr_t *local)
 {
 	struct adapter *adapter;
-	char *local_addr;
-	char path[MAX_PATH_LENGTH];
-	bdaddr_t tmp;
+	char path[MAX_PATH_LENGTH], local_addr[18];
 	read_scan_enable_rp rp;
 	struct hci_request rq;
-	int id;
-	int dd = -1;
-
-	baswap(&tmp, local); local_addr = batostr(&tmp);
+	int id, dd = -1;
+
+	ba2str(local, local_addr);
 	id = hci_devid(local_addr);
 	if (id < 0) {
 		error("No matching device id for %s", local_addr);
-		goto failed;
+		return;
 	}
 
 	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1795,7 +1796,7 @@
 	dd = hci_open_dev(id);
 	if (dd < 0) {
 		error("HCI device open failed: hci%d", id);
-		goto failed;
+		return;
 	}
 
 	memset(&rq, 0, sizeof(rq));
@@ -1828,14 +1829,53 @@
 		adapter->timeout_id = 0;
 	}
 
-	if (adapter->mode != rp.enable)
+	if (adapter->scan_enable != rp.enable)
 		adapter_mode_changed(adapter, path, rp.enable);
 
 failed:
 	if (dd >= 0)
 		hci_close_dev(dd);
-
-	bt_free(local_addr);
+}
+
+void hcid_dbus_write_class_complete(bdaddr_t *local)
+{
+	struct adapter *adapter;
+	char path[MAX_PATH_LENGTH], local_addr[18];
+	int id, dd = -1;
+	uint8_t cls[3];
+
+	ba2str(local, local_addr);
+	id = hci_devid(local_addr);
+	if (id < 0) {
+		error("No matching device id for %s", local_addr);
+		return;
+	}
+
+	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
+	if (!dbus_connection_get_object_user_data(connection, path,
+							(void *) &adapter)) {
+		error("Getting %s path data failed!", path);
+		return;
+	}
+
+	dd = hci_open_dev(id);
+	if (dd < 0) {
+		error("HCI device open failed: hci%d", id);
+		goto failed;
+	}
+
+	if (hci_read_class_of_dev(dd, cls, 1000) < 0) {
+		error("Can't read class of device on hci%d: %s(%d)",
+					id, strerror(errno), errno);
+		goto failed;
+	}
+
+	write_local_class(local, cls);
+	memcpy(adapter->class, cls, 3);
+
+failed:
+	if (dd >= 0)
+		hci_close_dev(dd);
 }
 
 void hcid_dbus_pin_code_reply(bdaddr_t *local, void *ptr)
@@ -1847,18 +1887,16 @@
 	} __attribute__ ((packed)) ret_pin_code_req_reply;
 
 	struct adapter *adapter;
-	char *local_addr;
 	ret_pin_code_req_reply *ret = ptr + EVT_CMD_COMPLETE_SIZE;
 	GSList *l;
-	char path[MAX_PATH_LENGTH];
-	bdaddr_t tmp;
+	char path[MAX_PATH_LENGTH], local_addr[18];
 	int id;
 
-	baswap(&tmp, local); local_addr = batostr(&tmp);
+	ba2str(local, local_addr);
 	id = hci_devid(local_addr);
 	if (id < 0) {
 		error("No matching device id for %s", local_addr);
-		goto failed;
+		return;
 	}
 
 	snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1866,7 +1904,7 @@
 	if (!dbus_connection_get_object_user_data(connection, path,
 							(void *) &adapter)) {
 		error("Getting %s path data failed!", path);
-		goto failed;
+		return;
 	}
 
 	l = g_slist_find_custom(adapter->pin_reqs, &ret->bdaddr, pin_req_cmp);
@@ -1874,9 +1912,6 @@
 		struct pending_pin_info *p = l->data;
 		p->replied = 1;
 	}
-
-failed:
-	bt_free(local_addr);
 }
 
 void create_bond_req_exit(const char *name, struct adapter *adapter)

Modified: bluez-utils/branches/upstream/current/hcid/dbus-hci.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-hci.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-hci.h (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-hci.h Wed Jul  4 13:37:57 2007
@@ -49,6 +49,7 @@
 void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status);
 void hcid_dbus_setname_complete(bdaddr_t *local);
 void hcid_dbus_setscan_enable_complete(bdaddr_t *local);
+void hcid_dbus_write_class_complete(bdaddr_t *local);
 void hcid_dbus_pin_code_reply(bdaddr_t *local, void *ptr);
 
 int unregister_adapter_path(const char *path);
@@ -72,6 +73,8 @@
 			name_status_t name_status);
 int found_device_req_name(struct adapter *dbus_data);
 
+int set_limited_discoverable(int dd, const uint8_t *cls, gboolean limited);
+
 int discov_timeout_handler(void *data);
 
 void set_dbus_connection(DBusConnection *conn);

Modified: bluez-utils/branches/upstream/current/hcid/dbus-sdp.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-sdp.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-sdp.c (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-sdp.c Wed Jul  4 13:37:57 2007
@@ -65,19 +65,21 @@
 #define DEFAULT_XML_BUF_SIZE	1024
 
 typedef struct {
-	uint16_t dev_id;
-	char *dst;
-	void *search_data;
+	uint16_t	dev_id;
+	char		*dst;
+	void		*search_data;
 	get_record_cb_t *cb;
-	void *data;
+	void 		*data;
 } get_record_data_t;
 
 struct transaction_context {
-	DBusConnection *conn;
-	DBusMessage *rq;
-	sdp_session_t *session;
-	GIOChannel *io;
-	guint io_id;
+	DBusConnection	*conn;
+	DBusMessage	*rq;
+	sdp_session_t	*session;
+	GIOChannel	*io;
+	guint		io_id;
+	uuid_t		uuid;
+	GSList		*identifiers;
 
 	/* Used for internal async get remote service record implementation */
 	get_record_data_t *call;
@@ -284,6 +286,7 @@
 	{ "fax",	FAX_SVCLASS_ID,			"Fax"			},
 	{ "spp",	SERIAL_PORT_SVCLASS_ID,		"Serial Port"		},
 	{ "hsp",	HEADSET_SVCLASS_ID,		"Headset"		},
+	{ "hfp",	HANDSFREE_SVCLASS_ID,		"Handsfree"		},
 	{ NULL }
 };
 
@@ -417,6 +420,11 @@
 			sdp_close(ctxt->session);
 
 		g_io_channel_unref(ctxt->io);
+	}
+
+	if (ctxt->identifiers) {
+		g_slist_foreach(ctxt->identifiers, (GFunc) g_free, NULL);
+		g_slist_free(ctxt->identifiers);
 	}
 
 	g_free(ctxt);
@@ -675,7 +683,7 @@
 	reply = dbus_message_new_method_return(ctxt->rq);
 	dbus_message_iter_init_append(reply, &iter);
 	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-			DBUS_TYPE_UINT32_AS_STRING, &array_iter);
+				DBUS_TYPE_UINT32_AS_STRING, &array_iter);
 
 	pdata = rsp;
 
@@ -696,13 +704,187 @@
 		pdata += sizeof(uint32_t);
 
 		dbus_message_iter_append_basic(&array_iter,
-				DBUS_TYPE_UINT32, &handle);
+						DBUS_TYPE_UINT32, &handle);
 	} while (--tsrc);
 
 
 done:
 	dbus_message_iter_close_container(&iter, &array_iter);
 	send_message_and_unref(ctxt->conn, reply);
+
+failed:
+	transaction_context_free(ctxt, TRUE);
+}
+
+static const char *extract_service_class(sdp_data_t *d)
+{
+	sdp_data_t *seq;
+	uuid_t *uuid;
+	static char uuid_str[37];
+
+	/* Expected sequence of UUID16 */
+	if (d->attrId != SDP_ATTR_SVCLASS_ID_LIST || d->dtd != SDP_SEQ8)
+		return NULL;
+
+	if (!d->val.dataseq)
+		return NULL;
+
+	seq = d->val.dataseq;
+	if (!SDP_IS_UUID(seq->dtd))
+		return NULL;
+
+	uuid = &seq->val.uuid;
+	if (uuid->type != SDP_UUID16)
+		return NULL;
+
+	sprintf(uuid_str, "0000%04x-0000-1000-8000-00805f9b34fb",
+							uuid->value.uuid16);
+
+	return uuid_str;
+}
+
+static int service_search_attr(struct transaction_context *ctxt, uint16_t uuid)
+{
+	sdp_list_t *attrids, *search;
+	uint32_t range = 0x0000ffff;
+	int ret = 0;
+
+	sdp_uuid16_create(&ctxt->uuid, uuid);
+
+	search = sdp_list_append(0, &ctxt->uuid);
+	attrids = sdp_list_append(NULL, &range);
+
+	/*
+	 * Create/send the search request and set the
+	 * callback to indicate the request completion
+	 */
+	if (sdp_service_search_attr_async(ctxt->session, search,
+				SDP_ATTR_REQ_RANGE, attrids) < 0)
+		ret = -sdp_get_error(ctxt->session);
+
+	sdp_list_free(search, NULL);
+	sdp_list_free(attrids, NULL);
+
+	return ret;
+}
+
+static void remote_svc_identifiers_completed_cb(uint8_t type, uint16_t err,
+			uint8_t *rsp, size_t size, void *udata)
+{
+	struct transaction_context *ctxt = udata;
+	const char *src, *dst, *puuid;
+	const char *devid_uuid = "00001200-0000-1000-8000-00805f9b34fb";
+	char **identifiers;
+	DBusMessage *reply;
+	GSList *l = NULL;
+	int scanned, extracted = 0, len = 0, recsize = 0;
+	uint8_t dtd = 0;
+
+	if (!ctxt)
+		return;
+
+	if (err == 0xffff) {
+		/* Check for protocol error or I/O error */
+		int sdp_err = sdp_get_error(ctxt->session);
+		if (sdp_err < 0) {
+			error("search failed: Invalid session!");
+			error_failed(ctxt->conn, ctxt->rq, EINVAL);
+			goto failed;
+		}
+
+		error("search failed: %s (%d)", strerror(sdp_err), sdp_err);
+		error_failed(ctxt->conn, ctxt->rq, sdp_err);
+		goto failed;
+	}
+
+	if (type == SDP_ERROR_RSP) {
+		error_sdp_failed(ctxt->conn, ctxt->rq, err);
+		goto failed;
+	}
+
+	/* Check response PDU ID */
+	if (type != SDP_SVC_SEARCH_ATTR_RSP) {
+		error("SDP error: %s (%d)", strerror(EPROTO), EPROTO);
+		error_failed(ctxt->conn, ctxt->rq, EPROTO);
+		goto failed;
+	}
+
+	src = get_address_from_message(ctxt->conn, ctxt->rq);
+	dbus_message_get_args(ctxt->rq, NULL,
+			DBUS_TYPE_STRING, &dst,
+			DBUS_TYPE_INVALID);
+
+	scanned = sdp_extract_seqtype(rsp, &dtd, &len);
+	rsp += scanned;
+	for (; extracted < len; rsp += recsize, extracted += recsize) {
+		sdp_record_t *rec;
+		sdp_data_t *d;
+
+		recsize = 0;
+		rec = sdp_extract_pdu(rsp, &recsize);
+		if (!rec)
+			break;
+
+		sdp_store_record(src, dst, rec->handle, rsp, recsize);
+
+		d = sdp_data_get(rec, SDP_ATTR_SVCLASS_ID_LIST);
+		if (!d) {
+			sdp_record_free(rec);
+			continue;
+		}
+
+		puuid = extract_service_class(d);
+		sdp_record_free(rec);
+		if (!puuid)
+			continue;
+
+		/* Ignore repeated identifiers */
+		l = g_slist_find_custom(ctxt->identifiers,
+				puuid, (GCompareFunc) strcmp);
+		if (l)
+			continue;
+
+		ctxt->identifiers = g_slist_append(ctxt->identifiers,
+							g_strdup(puuid));
+	}
+
+	/* If public browse response is empty: search for L2CAP */
+	if (!ctxt->identifiers && ctxt->uuid.value.uuid16 == PUBLIC_BROWSE_GROUP)
+		if (service_search_attr(ctxt, L2CAP_UUID) == 0)
+			return; /* Wait the response */
+
+	/* Request DeviceID if it was not returned previously */
+	l = g_slist_find_custom(ctxt->identifiers,
+			devid_uuid, (GCompareFunc) strcmp);
+	if (!l && ctxt->uuid.value.uuid16 != PNP_INFO_SVCLASS_ID)
+		if (service_search_attr(ctxt, PNP_INFO_SVCLASS_ID) == 0)
+			return; /* Wait the response */
+
+	reply = dbus_message_new_method_return(ctxt->rq);
+
+	identifiers = g_new(char *, g_slist_length(ctxt->identifiers));
+
+	for (l = ctxt->identifiers, len = 0; l; l = l->next, len++)
+		identifiers[len] = l->data;
+
+	dbus_message_append_args(reply,
+			DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+			&identifiers, len,
+			DBUS_TYPE_INVALID);
+	send_message_and_unref(ctxt->conn, reply);
+
+	if (len)
+		dbus_connection_emit_signal(ctxt->conn,
+				dbus_message_get_path(ctxt->rq),
+				ADAPTER_INTERFACE,
+				"RemoteIdentifiersUpdated",
+				DBUS_TYPE_STRING, &dst,
+				DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+				&identifiers, len,
+				DBUS_TYPE_INVALID);
+
+	if (identifiers)
+		g_free(identifiers);
 
 failed:
 	transaction_context_free(ctxt, TRUE);
@@ -882,6 +1064,9 @@
 	int err;
 	connect_cb_t *cb;
 
+	if (!adapter->up)
+		return error_not_ready(conn, msg);
+
 	if (!dbus_message_get_args(msg, NULL,
 			DBUS_TYPE_STRING, &dst,
 			DBUS_TYPE_UINT32, &handle,
@@ -908,7 +1093,6 @@
 {
 	sdp_list_t *search = NULL;
 	const char *dst, *svc;
-	uuid_t uuid;
 
 	if (sdp_set_notify(ctxt->session, remote_svc_handles_completed_cb, ctxt) < 0)
 		return -EINVAL;
@@ -919,11 +1103,11 @@
 			DBUS_TYPE_INVALID);
 
 	if (strlen(svc) > 0)
-		str2uuid(&uuid, svc);
+		str2uuid(&ctxt->uuid, svc);
 	else
-		sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
-
-	search = sdp_list_append(0, &uuid);
+		sdp_uuid16_create(&ctxt->uuid, PUBLIC_BROWSE_GROUP);
+
+	search = sdp_list_append(0, &ctxt->uuid);
 
 	/* Create/send the search request and set the callback to indicate the request completion */
 	if (sdp_service_search_async(ctxt->session, search, 64) < 0) {
@@ -937,12 +1121,24 @@
 	return 0;
 }
 
+static int remote_svc_identifiers_conn_cb(struct transaction_context *ctxt)
+{
+	if (sdp_set_notify(ctxt->session,
+			remote_svc_identifiers_completed_cb, ctxt) < 0)
+		return -EINVAL;
+
+	return service_search_attr(ctxt, PUBLIC_BROWSE_GROUP);
+}
+
 DBusHandlerResult get_remote_svc_handles(DBusConnection *conn, DBusMessage *msg, void *data)
 {
 	struct adapter *adapter = data;
 	const char *dst, *svc;
 	int err;
 	uuid_t uuid;
+
+	if (!adapter->up)
+		return error_not_ready(conn, msg);
 
 	if (!dbus_message_get_args(msg, NULL,
 			DBUS_TYPE_STRING, &dst,
@@ -963,6 +1159,32 @@
 
 	if (!connect_request(conn, msg, adapter->dev_id,
 				dst, remote_svc_handles_conn_cb, &err)) {
+		error("Search request failed: %s (%d)", strerror(err), err);
+		return error_failed(conn, msg, err);
+	}
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult get_remote_svc_identifiers(DBusConnection *conn, DBusMessage *msg, void *data)
+{
+	struct adapter *adapter = data;
+	const char *dst;
+	int err;
+
+	if (!adapter->up)
+		return error_not_ready(conn, msg);
+
+	if (!dbus_message_get_args(msg, NULL,
+			DBUS_TYPE_STRING, &dst,
+			DBUS_TYPE_INVALID))
+		return error_invalid_arguments(conn, msg);
+
+	if (find_pending_connect(dst))
+		return error_service_search_in_progress(conn, msg);
+
+	if (!connect_request(conn, msg, adapter->dev_id,
+				dst, remote_svc_identifiers_conn_cb, &err)) {
 		error("Search request failed: %s (%d)", strerror(err), err);
 		return error_failed(conn, msg, err);
 	}

Modified: bluez-utils/branches/upstream/current/hcid/dbus-sdp.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-sdp.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-sdp.h (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-sdp.h Wed Jul  4 13:37:57 2007
@@ -35,6 +35,8 @@
 
 DBusHandlerResult get_remote_svc_handles(DBusConnection *conn, DBusMessage *msg, void *data);
 
+DBusHandlerResult get_remote_svc_identifiers(DBusConnection *conn, DBusMessage *msg, void *data);
+
 DBusHandlerResult get_remote_svc_rec(DBusConnection *conn, DBusMessage *msg, void *data, sdp_format_t format);
 
 DBusHandlerResult finish_remote_svc_transact(DBusConnection *conn, DBusMessage *msg, void *data);

Modified: bluez-utils/branches/upstream/current/hcid/dbus-service.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-service.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-service.c (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-service.c Wed Jul  4 13:37:57 2007
@@ -43,6 +43,7 @@
 #include "dbus-helper.h"
 #include "hcid.h"
 #include "notify.h"
+#include "server.h"
 #include "dbus-common.h"
 #include "dbus-error.h"
 #include "dbus-manager.h"
@@ -408,7 +409,7 @@
 int service_start(struct service *service, DBusConnection *conn)
 {
 	DBusError derr;
-	char *argv[2], command[PATH_MAX];
+	char *addr, *argv[2], *envp[2], command[PATH_MAX], address[256];
 
 	if (!dbus_connection_add_filter(conn, service_filter, service, NULL)) {
 		error("Unable to add signal filter");
@@ -425,11 +426,19 @@
 	}
 
 	snprintf(command, sizeof(command) - 1, "%s/bluetoothd-service-%s",
-			SERVICEDIR, service->ident);
+						SERVICEDIR, service->ident);
 	argv[0] = command;
 	argv[1] = NULL;
 
-	if (!g_spawn_async(SERVICEDIR, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
+	addr = get_local_server_address();
+
+	snprintf(address, sizeof(address) - 1, "BLUETOOTHD_ADDRESS=%s", addr);
+	envp[0] = address;
+	envp[1] = NULL;
+
+	dbus_free(addr);
+
+	if (!g_spawn_async(SERVICEDIR, argv, envp, G_SPAWN_DO_NOT_REAP_CHILD,
 				service_setup, service, &service->pid, NULL)) {
 		error("Unable to execute %s", argv[0]);
 		dbus_connection_remove_filter(conn, service_filter, service);
@@ -718,7 +727,8 @@
 	return 0;
 }
 
-static int unregister_service(struct service *service)
+static int unregister_service_for_connection(DBusConnection *connection,
+						struct service *service)
 {
 	DBusConnection *conn = get_dbus_connection();
 
@@ -728,7 +738,7 @@
 		goto cleanup;
 
 	if (service->bus_name)
-		name_listener_remove(conn, service->bus_name,
+		name_listener_remove(connection, service->bus_name,
 					(name_cb_t) service_exit, service);
 
 	dbus_connection_emit_signal(conn, service->object_path,
@@ -759,6 +769,11 @@
 	}
 	
 	return 0;
+}
+
+static int unregister_service(struct service *service)
+{
+	return unregister_service_for_connection(get_dbus_connection(), service);
 }
 
 void release_services(DBusConnection *conn)
@@ -1021,10 +1036,9 @@
 	service_free(service);
 }
 
-int service_register(const char *bus_name, const char *ident,
+int service_register(DBusConnection *conn, const char *bus_name, const char *ident,
 				const char *name, const char *description)
 {
-	DBusConnection *conn = get_dbus_connection();
 	struct service *service;
 
 	if (!conn)
@@ -1044,14 +1058,14 @@
 	name_listener_add(conn, bus_name, (name_cb_t) external_service_exit,
 				service);
 
-	dbus_connection_emit_signal(conn, service->object_path,
+	dbus_connection_emit_signal(get_dbus_connection(), service->object_path,
 					SERVICE_INTERFACE, "Started",
 					DBUS_TYPE_INVALID);
 
 	return 0;
 }
 
-int service_unregister(struct service *service)
-{
-	return unregister_service(service);
-}
+int service_unregister(DBusConnection *conn, struct service *service)
+{
+	return unregister_service_for_connection(conn, service);
+}

Modified: bluez-utils/branches/upstream/current/hcid/dbus-service.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-service.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-service.h (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-service.h Wed Jul  4 13:37:57 2007
@@ -59,9 +59,9 @@
 
 int init_services(const char *path);
 
-int service_register(const char *bus_name, const char *ident,
+int service_register(DBusConnection *conn, const char *bus_name, const char *ident,
 				const char *name, const char *description);
 
-int service_unregister(struct service *service);
+int service_unregister(DBusConnection *conn, struct service *service);
 
 #endif /* __BLUEZ_DBUS_SERVICE_H */

Modified: bluez-utils/branches/upstream/current/hcid/device.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/device.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/device.c (original)
+++ bluez-utils/branches/upstream/current/hcid/device.c Wed Jul  4 13:37:57 2007
@@ -81,6 +81,7 @@
 	uint16_t manufacturer;
 
 	uint8_t  name[248];
+	uint8_t  class[3];
 
 	struct hci_peer *peers;
 	struct hci_conn *conns;
@@ -203,7 +204,8 @@
 	struct hci_dev *dev;
 	struct hci_version ver;
 	uint8_t features[8], inqmode;
-	int dd;
+	uint8_t events[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00 };
+	int dd, err;
 
 	ASSERT_DEV_ID;
 
@@ -233,14 +235,22 @@
 	dev->manufacturer = ver.manufacturer;
 
 	if (hci_read_local_features(dd, features, 1000) < 0) {
-		int err = errno;
+		err = errno;
 		error("Can't read features for hci%d: %s (%d)",
-					dev_id, strerror(errno), errno);
+					dev_id, strerror(err), err);
 		hci_close_dev(dd);
 		return -err;
 	}
 
 	memcpy(dev->features, features, 8);
+
+	if (hci_read_class_of_dev(dd, dev->class, 1000) < 0) {
+		err = errno;
+		error("Can't read class of device on hci%d: %s(%d)",
+				dev_id, strerror(err), err);
+		hci_close_dev(dd);
+		return -err;
+	}
 
 	inqmode = get_inquiry_mode(dev);
 	if (inqmode < 1)
@@ -254,6 +264,26 @@
 		return -err;
 	}
 
+	if (ver.hci_rev > 1) {
+		if (features[5] & LMP_SNIFF_SUBR)
+			events[5] |= 0x20;
+
+		if (features[5] & LMP_PAUSE_ENC)
+			events[5] |= 0x80;
+
+		if (features[6] & LMP_EXT_INQ)
+			events[5] |= 0x40;
+
+		if (features[6] & LMP_NFLUSH_PKTS)
+			events[7] |= 0x01;
+			
+		if (features[7] & LMP_LSTO)
+			events[6] |= 0x80;
+
+		hci_send_cmd(dd, OGF_HOST_CTL, OCF_SET_EVENT_MASK,
+						sizeof(events), events);
+	}
+
 done:
 	hci_close_dev(dd);
 
@@ -283,6 +313,18 @@
 	dev = &devices[dev_id];
 
 	return ba2str(&dev->bdaddr, address);
+}
+
+int get_device_class(uint16_t dev_id, uint8_t *cls)
+{
+	struct hci_dev *dev;
+
+	ASSERT_DEV_ID;
+
+	dev = &devices[dev_id];
+	memcpy(cls, dev->class, 3);
+
+	return 0;
 }
 
 int get_device_version(uint16_t dev_id, char *version, size_t size)

Modified: bluez-utils/branches/upstream/current/hcid/hcid.8
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/hcid.8?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/hcid.8 (original)
+++ bluez-utils/branches/upstream/current/hcid/hcid.8 Wed Jul  4 13:37:57 2007
@@ -34,6 +34,9 @@
 .TP
 .BI \-s
 Enable internal SDP server.
+.TP
+.BI \-m\ mtu\-size
+Use specific MTU size for SDP server.
 .TP 
 .BI \-f\ config\-file
 Use alternate configuration file instead of /etc/bluetooth/hcid.conf

Modified: bluez-utils/branches/upstream/current/hcid/hcid.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/hcid.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/hcid.h (original)
+++ bluez-utils/branches/upstream/current/hcid/hcid.h Wed Jul  4 13:37:57 2007
@@ -39,19 +39,6 @@
 
 /* When all services should trust a remote device */
 #define GLOBAL_TRUST "[all]"
-
-/*
- * Scanning modes, used by DEV_SET_MODE
- * off: remote devices are not allowed to find or connect to this device
- * connectable: remote devices are allowed to connect, but they are not
- *              allowed to find it.
- * discoverable: remote devices are allowed to connect and find this device
- * unknown: reserved to not allowed/future modes
- */
-#define MODE_OFF		"off"
-#define MODE_CONNECTABLE	"connectable"
-#define MODE_DISCOVERABLE	"discoverable"
-#define MODE_UNKNOWN		"unknown"
 
 enum {
 	HCID_SET_NAME,
@@ -64,6 +51,22 @@
 	HCID_SET_LM,
 	HCID_SET_LP,
 };
+
+/*
+ * Scanning modes, used by DEV_SET_MODE
+ * off: remote devices are not allowed to find or connect to this device
+ * connectable: remote devices are allowed to connect, but they are not
+ *              allowed to find it.
+ * discoverable: remote devices are allowed to connect and find this device
+ * limited: limited discoverable - GIAC + IAC enabled and set limited
+ *          bit on device class.
+ */
+
+#define MODE_OFF		0x00
+#define MODE_CONNECTABLE	0x01
+#define MODE_DISCOVERABLE	0x02
+#define MODE_LIMITED		0x03
+#define MODE_UNKNOWN		0xff
 
 struct device_opts {
 	unsigned long flags;
@@ -76,6 +79,7 @@
 	uint16_t link_mode;
 	uint16_t link_policy;
 	uint8_t  scan;
+	uint8_t  mode;
 	uint32_t discovto;
 };
 
@@ -140,6 +144,7 @@
 
 struct device_opts *alloc_device_opts(char *ref);
 
+uint8_t get_startup_scan(int hdev);
 uint8_t get_startup_mode(int hdev);
 int get_discoverable_timeout(int dev_id);
 
@@ -157,6 +162,7 @@
 int stop_device(uint16_t dev_id);
 
 int get_device_address(uint16_t dev_id, char *address, size_t size);
+int get_device_class(uint16_t dev_id, uint8_t *class);
 int get_device_version(uint16_t dev_id, char *version, size_t size);
 int get_device_revision(uint16_t dev_id, char *revision, size_t size);
 int get_device_manufacturer(uint16_t dev_id, char *manufacturer, size_t size);

Modified: bluez-utils/branches/upstream/current/hcid/main.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/main.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/main.c (original)
+++ bluez-utils/branches/upstream/current/hcid/main.c Wed Jul  4 13:37:57 2007
@@ -50,6 +50,7 @@
 
 #include "hcid.h"
 #include "sdpd.h"
+#include "server.h"
 #include "dbus-common.h"
 #include "dbus-service.h"
 #include "dbus-database.h"
@@ -65,6 +66,7 @@
 {
 	memset(device_opts, 0, sizeof(*device_opts));
 	device_opts->scan = SCAN_PAGE;
+	device_opts->mode = MODE_CONNECTABLE;
 	device_opts->name = g_strdup("BlueZ");
 	device_opts->discovto = HCID_DEFAULT_DISCOVERABLE_TIMEOUT;
 }
@@ -143,7 +145,7 @@
 	return device_opts;
 }
 
-uint8_t get_startup_mode(int hdev)
+static struct device_opts *get_opts(int hdev)
 {
 	struct device_opts *device_opts = NULL;
 	struct hci_dev_info di;
@@ -151,7 +153,7 @@
 	int sock;
 
 	if (hdev < 0)
-		return SCAN_DISABLED;
+		return NULL;
 
 	sock = hci_open_dev(hdev);
 	if (sock < 0)
@@ -177,7 +179,25 @@
 	if (!device_opts)
 		device_opts = &default_device;
 
+	return device_opts;
+}
+
+uint8_t get_startup_scan(int hdev)
+{
+	struct device_opts *device_opts = get_opts(hdev);
+	if (!device_opts)
+		return SCAN_DISABLED;
+
 	return device_opts->scan;
+}
+
+uint8_t get_startup_mode(int hdev)
+{
+	struct device_opts *device_opts = get_opts(hdev);
+	if (!device_opts)
+		return MODE_OFF;
+
+	return device_opts->mode;
 }
 
 int get_discoverable_timeout(int hdev)
@@ -326,16 +346,30 @@
 
 	/* Set scan mode */
 	if (read_device_mode(&di.bdaddr, mode, sizeof(mode)) == 0) {
-		if (!strcmp(mode, MODE_OFF) && hcid.offmode == HCID_OFFMODE_NOSCAN)
+		if (!strcmp(mode, "off") && hcid.offmode == HCID_OFFMODE_NOSCAN) {
+			device_opts->mode = MODE_OFF;
 			device_opts->scan = SCAN_DISABLED;
-		else if (!strcmp(mode, MODE_CONNECTABLE))
+		} else if (!strcmp(mode, "connectable")) {
+			device_opts->mode = MODE_CONNECTABLE;
 			device_opts->scan = SCAN_PAGE;
-		else if (!strcmp(mode, MODE_DISCOVERABLE)) {
+		} else if (!strcmp(mode, "discoverable")) {
 			/* Set discoverable only if timeout is 0 */
-			if (!get_discoverable_timeout(dev_id))
+			if (!get_discoverable_timeout(dev_id)) {
 				device_opts->scan = SCAN_PAGE | SCAN_INQUIRY;
-			else
+				device_opts->mode = MODE_DISCOVERABLE;
+			} else {
 				device_opts->scan = SCAN_PAGE;
+				device_opts->mode = MODE_CONNECTABLE;
+			}
+		} else if (!strcmp(mode, "limited")) {
+			/* Set discoverable only if timeout is 0 */
+			if (!get_discoverable_timeout(dev_id)) {
+				device_opts->scan = SCAN_PAGE | SCAN_INQUIRY;
+				device_opts->mode = MODE_LIMITED;
+			} else {
+				device_opts->scan = SCAN_PAGE;
+				device_opts->mode = MODE_CONNECTABLE;
+			}
 		}
 	}
 
@@ -431,9 +465,11 @@
 		if (read_local_class(&di.bdaddr, cls) < 0) {
 			class = htobl(device_opts->class);
 			memcpy(cp.dev_class, &class, 3);
-		} else
+		} else {
+			if (!(device_opts->scan & SCAN_INQUIRY))
+				cls[1] &= 0xdf; /* Clear discoverable bit */
 			memcpy(cp.dev_class, cls, 3);
-
+		}
 		hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV,
 					WRITE_CLASS_OF_DEV_CP_SIZE, &cp);
 	}
@@ -500,7 +536,7 @@
 		char mode[16];
 
 		if (read_device_mode(&di.bdaddr, mode, sizeof(mode)) == 0 &&
-						strcmp(mode, MODE_OFF) == 0) {
+						strcmp(mode, "off") == 0) {
 			ioctl(dd, HCIDEVDOWN, dev_id);
 			exit(0);
 		}
@@ -675,7 +711,7 @@
 {
 	printf("hcid - HCI daemon ver %s\n", VERSION);
 	printf("Usage: \n");
-	printf("\thcid [-n] [-d] [-s] [-f config file]\n");
+	printf("\thcid [-n] [-d] [-s] [-m mtu] [-f config file]\n");
 }
 
 int main(int argc, char *argv[])
@@ -684,6 +720,7 @@
 	struct hci_filter flt;
 	struct sigaction sa;
 	GIOChannel *ctl_io, *child_io;
+	uint16_t mtu = 0;
 	int opt, daemonize = 1, debug = 0, sdp = 0, experimental = 0;
 
 	/* Default HCId settings */
@@ -702,7 +739,7 @@
 
 	init_defaults();
 
-	while ((opt = getopt(argc, argv, "ndsxf:")) != EOF) {
+	while ((opt = getopt(argc, argv, "ndsm:xf:")) != EOF) {
 		switch (opt) {
 		case 'n':
 			daemonize = 0;
@@ -714,6 +751,10 @@
 
 		case 's':
 			sdp = 1;
+			break;
+
+		case 'm':
+			mtu = atoi(optarg);
 			break;
 
 		case 'x':
@@ -825,10 +866,12 @@
 
 	if (sdp) {
 		set_sdp_server_enable();
-		start_sdp_server(0, hcid.deviceid, SDP_SERVER_COMPAT);
+		start_sdp_server(mtu, hcid.deviceid, SDP_SERVER_COMPAT);
 	}
 
 	notify_init();
+
+	init_local_server();
 
 	init_services(CONFIGDIR);
 
@@ -844,6 +887,8 @@
 
 	notify_close();
 
+	shutdown_local_server();
+
 	cleanup_sdp_session();
 
 	g_main_loop_unref(event_loop);

Modified: bluez-utils/branches/upstream/current/hcid/security.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/security.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/security.c (original)
+++ bluez-utils/branches/upstream/current/hcid/security.c Wed Jul  4 13:37:57 2007
@@ -436,6 +436,9 @@
 	case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
 		hcid_dbus_setscan_enable_complete(sba);
 		break;
+	case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV):
+		hcid_dbus_write_class_complete(sba);
+		break;
 	case cmd_opcode_pack(OGF_LINK_CTL, OCF_PIN_CODE_REPLY):
 	case cmd_opcode_pack(OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY):
 		hcid_dbus_pin_code_reply(sba, ptr);
@@ -582,9 +585,11 @@
 	evt_conn_complete *evt = ptr;
 	char filename[PATH_MAX];
 	remote_name_req_cp cp_name;
-	bdaddr_t tmp;
 	struct hci_req_data *data;
-	char *str, *local_addr, *peer_addr;
+	char local_addr[18], peer_addr[18], *str;
+
+	if (evt->link_type != ACL_LINK)
+		return;
 
 	hcid_dbus_conn_complete(sba, evt->status, evt->handle, &evt->bdaddr);
 
@@ -605,8 +610,8 @@
 	hci_req_queue_append(data);
 
 	/* check if the remote version needs be requested */
-	baswap(&tmp, sba); local_addr = batostr(&tmp);
-	baswap(&tmp, &evt->bdaddr); peer_addr = batostr(&tmp);
+	ba2str(sba, local_addr);
+	ba2str(&evt->bdaddr, peer_addr);
 
 	create_name(filename, sizeof(filename), STORAGEDIR, local_addr, "manufacturers");
 
@@ -623,9 +628,6 @@
 		hci_req_queue_append(data);
 	} else
 		free(str);
-
-	free(local_addr);
-	free(peer_addr);
 }
 
 static inline void disconn_complete(int dev, bdaddr_t *sba, void *ptr)

Added: bluez-utils/branches/upstream/current/hcid/server.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/server.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/server.c (added)
+++ bluez-utils/branches/upstream/current/hcid/server.c Wed Jul  4 13:37:57 2007
@@ -1,0 +1,136 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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 <string.h>
+#include <dbus.h>
+
+#include "dbus-database.h"
+
+#include "logging.h"
+#include "server.h"
+
+static DBusHandlerResult filter_function(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	if (dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL, "Disconnected") &&
+			strcmp(dbus_message_get_path(msg), DBUS_PATH_LOCAL) == 0) {
+		debug("Received local disconnected signal");
+		name_listener_indicate_disconnect(conn);
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult message_handler(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	if (strcmp(dbus_message_get_interface(msg), DATABASE_INTERFACE) == 0)
+		return database_message(conn, msg, data);
+
+	debug("%s -> %s.%s", dbus_message_get_path(msg),
+		dbus_message_get_interface(msg), dbus_message_get_member(msg));
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void unregister_handler(DBusConnection *conn, void *data)
+{
+	debug("Unregister local connection %p", conn);
+}
+
+static void handle_connection(DBusServer *server, DBusConnection *conn, void *data)
+{
+	DBusObjectPathVTable vtable = { &unregister_handler, &message_handler,
+							NULL, NULL, NULL, NULL};
+
+	debug("New local connection %p", conn);
+
+	dbus_connection_add_filter(conn, filter_function, NULL, NULL);
+
+	if (dbus_connection_register_object_path(conn, "/org/bluez",
+						&vtable, NULL) == FALSE) {
+		error("Can't register local object path");
+		return;
+	}
+
+	dbus_connection_ref(conn);
+
+	//dbus_connection_setup_with_g_main(conn, NULL);
+	setup_dbus_with_main_loop(conn);
+}
+
+static DBusServer *server = NULL;
+
+char *get_local_server_address(void)
+{
+	return dbus_server_get_address(server);
+}
+
+void init_local_server(void)
+{
+	const char *ext_only[] = { "EXTERNAL", NULL };
+	char *address;
+	DBusError err;
+
+	dbus_error_init(&err);
+
+	server = dbus_server_listen("unix:tmpdir=/var/run", &err);
+	if (server == NULL) {
+		error("Can't create local D-Bus server");
+		dbus_error_free(&err);
+		return;
+	}
+
+	address = dbus_server_get_address(server);
+
+	info("Created local server at %s", address);
+
+	dbus_free(address);
+
+	//dbus_server_setup_with_g_main(server, NULL);
+	setup_dbus_server_with_main_loop(server);
+
+	dbus_server_set_new_connection_function(server, handle_connection,
+								NULL, NULL);
+
+	dbus_server_set_auth_mechanisms(server, ext_only);
+}
+
+void shutdown_local_server(void)
+{
+	if (server == NULL)
+		return;
+
+	info("Shutting down local server");
+
+	dbus_server_disconnect(server);
+
+	dbus_server_unref(server);
+
+	server = NULL;
+}

Added: bluez-utils/branches/upstream/current/hcid/server.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/server.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/server.h (added)
+++ bluez-utils/branches/upstream/current/hcid/server.h Wed Jul  4 13:37:57 2007
@@ -1,0 +1,27 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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
+ *
+ */
+
+void init_local_server(void);
+void shutdown_local_server(void);
+
+char *get_local_server_address(void);

Modified: bluez-utils/branches/upstream/current/input/device.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/input/device.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/input/device.c (original)
+++ bluez-utils/branches/upstream/current/input/device.c Wed Jul  4 13:37:57 2007
@@ -59,11 +59,6 @@
 
 #define UPDOWN_ENABLED		1
 
-struct pending_connect {
-	DBusConnection *conn;
-	DBusMessage *msg;
-};
-
 struct fake_input {
 	GIOChannel	*io;
 	int		rfcomm; /* RFCOMM socket */
@@ -77,10 +72,18 @@
 	char			*name;
 	uint8_t			major;
 	uint8_t			minor;
-	struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */
+	uint16_t		product;
+	uint16_t		vendor;
 	struct fake_input	*fake;
-	struct pending_connect *pending_connect;
+	DBusMessage		*pending_connect;
+	DBusConnection		*conn;
+	char			*path;
+	int			ctrl_sk;
+	int			intr_sk;
+	guint			watch;
 };
+
+GSList *devices = NULL;
 
 static struct device *device_new(bdaddr_t *src, bdaddr_t *dst)
 {
@@ -95,24 +98,12 @@
 	read_device_name(src, dst, &idev->name);
 	read_device_class(src, dst, &cls);
 
-	idev->major = (cls >> 8) & 0x1f;
-	idev->minor = (cls >> 2) & 0x3f;
-
-	/* FIXME:  hidp could be alloc dynamically */
-	snprintf(idev->hidp.name, 128, "%s", idev->name);
+	idev->major 	= (cls >> 8) & 0x1f;
+	idev->minor	= (cls >> 2) & 0x3f;
+	idev->ctrl_sk	= -1;
+	idev->intr_sk	= -1;
 
 	return idev;
-}
-
-static void pending_connect_free(struct pending_connect *pc)
-{
-	if (!pc)
-		return;
-	if (pc->conn)
-		dbus_connection_unref(pc->conn);
-	if (pc->msg)
-		dbus_message_unref(pc->msg);
-	g_free(pc);
 }
 
 static void device_free(struct device *idev)
@@ -121,13 +112,13 @@
 		return;
 	if (idev->name)
 		g_free(idev->name);
-	if (idev->hidp.rd_data)
-		g_free(idev->hidp.rd_data);
 	if (idev->fake)
 		g_free(idev->fake);
-	if (idev->pending_connect) 
-		pending_connect_free(idev->pending_connect);
-
+	if (idev->path)
+		g_free(idev->path);
+	if (idev->pending_connect)
+		dbus_message_unref(idev->pending_connect);
+	dbus_connection_unref(idev->conn);
 	g_free(idev);
 }
 
@@ -416,24 +407,24 @@
 						(GIOFunc) rfcomm_io_cb, fake);
 
 	/* Replying to the requestor */
-	reply = dbus_message_new_method_return(idev->pending_connect->msg);
-	send_message_and_unref(idev->pending_connect->conn, reply);
+	reply = dbus_message_new_method_return(idev->pending_connect);
+	send_message_and_unref(idev->conn, reply);
 
 	/* Sending the Connected signal */
-	path = dbus_message_get_path(idev->pending_connect->msg);
-	dbus_connection_emit_signal(idev->pending_connect->conn, path,
+	path = dbus_message_get_path(idev->pending_connect);
+	dbus_connection_emit_signal(idev->conn, path,
 			INPUT_DEVICE_INTERFACE, "Connected",
 			DBUS_TYPE_INVALID); 
 
-	pending_connect_free(idev->pending_connect);
+	dbus_message_unref(idev->pending_connect);
 	idev->pending_connect = NULL;
 
 	return FALSE;
 
 failed:
-	err_connection_failed(idev->pending_connect->conn,
-			idev->pending_connect->msg, strerror(err));
-	pending_connect_free(idev->pending_connect);
+	err_connection_failed(idev->conn,
+			idev->pending_connect, strerror(err));
+	dbus_message_unref(idev->pending_connect);
 	idev->pending_connect = NULL;
 
 	g_io_channel_close(chan);
@@ -509,11 +500,100 @@
 	return -err;
 }
 
+static gboolean connection_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+	struct device *idev = data;
+	gboolean ret = TRUE;
+
+	if (cond & G_IO_NVAL)
+		ret = FALSE;
+
+	if (cond & (G_IO_HUP | G_IO_ERR)) {
+		g_io_channel_close(chan);
+		ret = FALSE;
+	}
+
+	if (ret == FALSE) {
+		dbus_connection_emit_signal(idev->conn,
+				idev->path,
+				INPUT_DEVICE_INTERFACE,
+				"Disconnected",
+				DBUS_TYPE_INVALID);
+		idev->watch = 0;
+	}
+
+	return ret;
+}
+
+static guint create_watch(int sk, struct device *idev)
+{
+	guint id;
+	GIOChannel *io;
+
+	io = g_io_channel_unix_new(sk);
+	id = g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+			connection_event, idev);
+	g_io_channel_unref(io);
+
+	return id;
+}
+
+static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, int ctrl_sk, int intr_sk, const char *name)
+{
+	struct hidp_connadd_req req;
+	char addr[18];
+	int ctl, err, timeout = 30;
+
+	ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
+	if (ctl < 0) {
+		error("Can't open HIDP interface");
+		return -errno;
+	}
+
+	ba2str(dst, addr);
+
+	memset(&req, 0, sizeof(req));
+	req.ctrl_sock = ctrl_sk;
+	req.intr_sock = intr_sk;
+	req.flags     = 0;
+	req.idle_to   = timeout * 60;
+
+	err = get_stored_device_info(src, dst, &req);
+	if (err < 0) {
+		error("Rejected connection from unknown device %s", addr);
+		goto cleanup;
+	}
+
+	if (req.subclass & 0x40) {
+		err = encrypt_link(src, dst);
+		if (err < 0 && err != -ENOKEY)
+			goto cleanup;
+	}
+
+	if (name)
+		strncpy(req.name, name, 128);
+
+	info("New input device %s (%s)", addr, req.name);
+
+	if (req.vendor == 0x054c && req.product == 0x0268) {
+		unsigned char buf[] = { 0x53, 0xf4,  0x42, 0x03, 0x00, 0x00 };
+		err = write(ctrl_sk, buf, sizeof(buf));
+	}
+
+	err = ioctl(ctl, HIDPCONNADD, &req);
+cleanup:
+	close(ctl);
+
+	if (req.rd_data)
+		free(req.rd_data);
+
+	return err;
+}
+
 static gboolean interrupt_connect_cb(GIOChannel *chan,
 			GIOCondition cond, struct device *idev)
 {
-	int ctl, isk, ret, err;
-	const char *path;
+	int isk, ret, err;
 	socklen_t len;
 
 	isk = g_io_channel_unix_get_fd(chan);
@@ -530,9 +610,6 @@
 		goto failed;
 
 	}
-
-	idev->hidp.intr_sock = isk;
-	idev->hidp.idle_to = 30 * 60;	/* 30 minutes */
 
 	len = sizeof(ret);
 	if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {
@@ -547,55 +624,34 @@
 		goto failed;
 	}
 
-	ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
-	if (ctl < 0) {
-		err = errno;
-		error("Can't open HIDP control socket");
-		goto failed;
-	}
-
-	if (idev->hidp.subclass & 0x40) {
-		int ret;
-		ret = encrypt_link(&idev->src, &idev->dst);
-		if (ret < 0 && ret != -ENOKEY) {
-			err = -ret;
-			close(ctl);
-			goto failed;
-		}
-	}
-
-	if (ioctl(ctl, HIDPCONNADD, &idev->hidp) < 0) {
-		err = errno;
-		close(ctl);
-		goto failed;
-	}
+	idev->intr_sk = isk;
+	err = hidp_connadd(&idev->src, &idev->dst, idev->ctrl_sk, idev->intr_sk, idev->name);
+	if (err < 0)
+		goto failed;
+
+	idev->watch = create_watch(idev->ctrl_sk, idev);
+	dbus_connection_emit_signal(idev->conn,
+			idev->path,
+			INPUT_DEVICE_INTERFACE,
+			"Connected",
+			DBUS_TYPE_INVALID);
 
 	/* Replying to the requestor */
-	send_message_and_unref(idev->pending_connect->conn,
-		dbus_message_new_method_return(idev->pending_connect->msg));
-
-	/* Sending the Connected signal */
-	path = dbus_message_get_path(idev->pending_connect->msg);
-	dbus_connection_emit_signal(idev->pending_connect->conn, path,
-			INPUT_DEVICE_INTERFACE, "Connected" ,
-			DBUS_TYPE_INVALID); 
-
-	close (ctl);
+	send_message_and_unref(idev->conn,
+		dbus_message_new_method_return(idev->pending_connect));
+
 	goto cleanup;
 failed:
-	err_connection_failed(idev->pending_connect->conn,
-				idev->pending_connect->msg, strerror(err));
-
-cleanup:
+	err_connection_failed(idev->conn,
+		idev->pending_connect, strerror(err));
 	if (isk > 0)
 		close(isk);
-
-	close(idev->hidp.ctrl_sock);
-
-	idev->hidp.intr_sock = -1;
-	idev->hidp.ctrl_sock = -1;
-
-	pending_connect_free(idev->pending_connect);
+	close(idev->ctrl_sk);
+	idev->intr_sk = -1;
+	idev->ctrl_sk = -1;
+
+cleanup:
+	dbus_message_unref(idev->pending_connect);
 	idev->pending_connect = NULL;
 
 	return FALSE;
@@ -622,7 +678,7 @@
 	}
 
 	/* Set HID control channel */
-	idev->hidp.ctrl_sock = csk;
+	idev->ctrl_sk = csk;
 
 	len = sizeof(ret);
 	if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {
@@ -652,10 +708,10 @@
 	if (csk > 0)
 		close(csk);
 
-	idev->hidp.ctrl_sock = -1;
-	err_connection_failed(idev->pending_connect->conn,
-			idev->pending_connect->msg, strerror(err));
-	pending_connect_free(idev->pending_connect);
+	idev->ctrl_sk = -1;
+	err_connection_failed(idev->conn,
+			idev->pending_connect, strerror(err));
+	dbus_message_unref(idev->pending_connect);
 	idev->pending_connect = NULL;
 
 	return FALSE;
@@ -687,6 +743,14 @@
 	}
 
 	/* Standard HID disconnect */
+	if (idev->ctrl_sk >= 0) {
+		close(idev->ctrl_sk);
+		idev->ctrl_sk = -1;
+	}
+	if (idev->intr_sk >= 0) {
+		close(idev->intr_sk);
+		idev->intr_sk = -1;
+	}
 
 	ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
 	if (ctl < 0) {
@@ -719,9 +783,6 @@
 	close(ctl);
 	errno = err;
 
-	idev->hidp.intr_sock = -1;
-	idev->hidp.ctrl_sock = -1;
-
 	return -err;
 }
 
@@ -773,21 +834,14 @@
 	if (is_connected(idev))
 		return err_already_connected(conn, msg);
 
-	idev->pending_connect = g_try_new0(struct pending_connect, 1);
-	if (!idev->pending_connect) {
-		error("Out of memory when allocating new struct pending_connect");
-		return DBUS_HANDLER_RESULT_NEED_MEMORY;
-	}
-
-	idev->pending_connect->conn = dbus_connection_ref(conn);
-	idev->pending_connect->msg = dbus_message_ref(msg);
+	idev->pending_connect = dbus_message_ref(msg);
 
 	/* Fake input device */
 	if (idev->fake) {
 		if (rfcomm_connect(idev) < 0) {
 			const char *str = strerror(errno);
 			error("RFCOMM connect failed: %s(%d)", str, errno);
-			pending_connect_free(idev->pending_connect);
+			dbus_message_unref(idev->pending_connect);
 			idev->pending_connect = NULL;
 			return err_connection_failed(conn, msg, str);
 		}
@@ -797,11 +851,10 @@
 	/* HID devices */
 	if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL,
 				(GIOFunc) control_connect_cb, idev) < 0) {
-
 		int err = errno;
 
 		error("L2CAP connect failed: %s(%d)", strerror(err), err);
-		pending_connect_free(idev->pending_connect);
+		dbus_message_unref(idev->pending_connect);
 		idev->pending_connect = NULL;
 		return err_connection_failed(conn, msg, strerror(err));
 	}
@@ -813,22 +866,13 @@
 						DBusMessage *msg, void *data)
 {
 	struct device *idev = data;
-	const char *path;
 
 	if (disconnect(idev, 0) < 0)
 		return err_failed(conn, msg, strerror(errno));
 
 	/* Replying to the requestor */
-	send_message_and_unref(conn,
+	return send_message_and_unref(conn,
 			dbus_message_new_method_return(msg));
-
-	/* Sending the Disconnect signal */ 
-	path = dbus_message_get_path(msg);
-	dbus_connection_emit_signal(conn, path,
-			INPUT_DEVICE_INTERFACE, "Disconnected",
-			DBUS_TYPE_INVALID); 
-
-	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
 static DBusHandlerResult device_is_connected(DBusConnection *conn,
@@ -897,7 +941,7 @@
 {
 	struct device *idev = data;
 	DBusMessage *reply;
-	const char *pname = idev->hidp.name;
+	const char *pname = idev->name;
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
@@ -921,7 +965,7 @@
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
 	dbus_message_append_args(reply,
-			DBUS_TYPE_UINT16, &idev->hidp.product,
+			DBUS_TYPE_UINT16, &idev->product,
 			DBUS_TYPE_INVALID);
 
 	return send_message_and_unref(conn, reply);
@@ -938,7 +982,7 @@
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
 	dbus_message_append_args(reply,
-			DBUS_TYPE_UINT16, &idev->hidp.vendor,
+			DBUS_TYPE_UINT16, &idev->vendor,
 			DBUS_TYPE_INVALID);
 
 	return send_message_and_unref(conn, reply);
@@ -995,7 +1039,9 @@
 	dbus_connection_emit_signal(conn, INPUT_PATH,
 			INPUT_MANAGER_INTERFACE, "DeviceCreated",
 			DBUS_TYPE_STRING, &path,
-			DBUS_TYPE_INVALID); 
+			DBUS_TYPE_INVALID);
+
+	devices = g_slist_append(devices, idev);
 
 	info("Created input device: %s", path);
 
@@ -1011,9 +1057,10 @@
 
 	idev = device_new(src, dst);
 	path = create_input_path(idev->major, idev->minor);
-
-	/* rd_data must not be deallocated since the memory address is copied */
-	memcpy(&idev->hidp, hid, sizeof(struct hidp_connadd_req));
+	idev->path	= g_strdup(path);
+	idev->product	= hid->product;
+	idev->vendor	= hid->vendor;
+	idev->conn	= dbus_connection_ref(conn);
 
 	err = register_path(conn, path, idev);
 
@@ -1032,6 +1079,10 @@
 
 	idev = device_new(src, dst);
 	path = create_input_path(idev->major, idev->minor);
+	idev->path = g_strdup(path);
+	idev->conn = dbus_connection_ref(conn);
+
+	/* FIXME: Missing set product and vendor */
 
 	idev->fake = g_new0(struct fake_input, 1);
 	idev->fake->ch = ch;
@@ -1058,6 +1109,23 @@
 	}
 
 	del_stored_device_info(&idev->src, &idev->dst);
+
+	devices = g_slist_remove(devices, idev);
+
+	/*
+	 * Workaround: if connected, the watch will not be able
+	 * to access the D-Bus data assigned to this path
+	 * because the object path data was destroyed.
+	 */
+	if (idev->watch) {
+		g_source_remove(idev->watch);
+		idev->watch  = 0;
+		dbus_connection_emit_signal(conn,
+				path,
+				INPUT_DEVICE_INTERFACE,
+				"Disconnected",
+				DBUS_TYPE_INVALID);
+	}
 
 	dbus_connection_destroy_object_path(conn, path);
 
@@ -1069,32 +1137,16 @@
 	return 0;
 }
 
-int input_device_get_bdaddr(DBusConnection *conn, const char *path,
-						bdaddr_t *src, bdaddr_t *dst)
-{
-	struct device *idev;
-
-	if (!dbus_connection_get_object_user_data(conn, path,
-							(void *) &idev))
-		return -1;
-
-	if (!idev)
-		return -1;
-
-	bacpy(src, &idev->src);
-	bacpy(dst, &idev->dst);
-
-	return 0;
-}
-
-int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, void *data)
+int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm,
+						GIOFunc cb, void *data)
 {
 	GIOChannel *io;
 	struct sockaddr_l2 addr;
 	struct l2cap_options opts;
 	int sk, err;
 
-	if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0)
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+	if (sk < 0)
 		return -1;
 
 	memset(&addr, 0, sizeof(addr));
@@ -1108,12 +1160,14 @@
 		goto failed;
 
 	memset(&opts, 0, sizeof(opts));
+#if 0
 	opts.imtu = HIDP_DEFAULT_MTU;
 	opts.omtu = HIDP_DEFAULT_MTU;
 	opts.flush_to = 0xffff;
 
 	if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0)
 		goto failed;
+#endif
 
 	memset(&addr, 0, sizeof(addr));
 	addr.l2_family  = AF_BLUETOOTH;
@@ -1131,9 +1185,8 @@
 
 		g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
 				(GIOFunc) cb, data);
-	} else {
+	} else
 		cb(io, G_IO_OUT, data);
-	}
 
 	g_io_channel_unref(io);
 
@@ -1146,3 +1199,92 @@
 
 	return -1;
 }
+
+static struct device *find_device(bdaddr_t *src, bdaddr_t *dst)
+{
+	struct device *idev;
+	GSList *list;
+
+	for (list = devices; list != NULL; list = list->next) {
+		idev = list->data;
+
+		if (!bacmp(&idev->src, src) && !bacmp(&idev->dst, dst))
+			return idev;
+	}
+
+	return NULL;
+}
+
+gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst)
+{
+	struct device *idev = find_device(src, dst);
+	if (!idev)
+		return FALSE;
+	else
+		return TRUE;
+}
+
+int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk)
+{
+	struct device *idev = find_device(src, dst);
+	if (!idev)
+		return -ENOENT;
+
+	switch (psm) {
+	case L2CAP_PSM_HIDP_CTRL:
+		idev->ctrl_sk = nsk;
+		break;
+	case L2CAP_PSM_HIDP_INTR:
+		idev->intr_sk = nsk;
+		break;
+	}
+
+	return 0;
+}
+
+int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst)
+{
+	struct device *idev = find_device(src, dst);
+	if (!idev)
+		return -ENOENT;
+
+	if (idev->ctrl_sk >= 0) {
+		close(idev->ctrl_sk);
+		idev->ctrl_sk = -1;
+	}
+
+	if (idev->intr_sk >= 0) {
+		close(idev->intr_sk);
+		idev->intr_sk = -1;
+	}
+
+	return 0;
+}
+
+int input_device_connadd(bdaddr_t *src, bdaddr_t *dst)
+{
+	struct device *idev;
+	int err;
+
+	idev = find_device(src, dst);
+	if (!idev)
+		return -ENOENT;
+
+	err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name);
+	if (err < 0) {
+		close(idev->ctrl_sk);
+		close(idev->intr_sk);
+		idev->ctrl_sk = -1;
+		idev->intr_sk = -1;
+
+		return err;
+	}
+
+	idev->watch = create_watch(idev->ctrl_sk, idev);
+	dbus_connection_emit_signal(idev->conn,
+			idev->path,
+			INPUT_DEVICE_INTERFACE,
+			"Connected",
+			DBUS_TYPE_INVALID);
+	return 0;
+}

Modified: bluez-utils/branches/upstream/current/input/device.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/input/device.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/input/device.h (original)
+++ bluez-utils/branches/upstream/current/input/device.h Wed Jul  4 13:37:57 2007
@@ -20,16 +20,23 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
-#define L2CAP_PSM_HIDP_CTRL		0x11
-#define L2CAP_PSM_HIDP_INTR		0x13
+
+#define L2CAP_PSM_HIDP_CTRL	0x11
+#define L2CAP_PSM_HIDP_INTR	0x13
 
 int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst,
-				struct hidp_connadd_req *hidp, const char **ppath);
+			struct hidp_connadd_req *hidp, const char **ppath);
 int fake_input_register(DBusConnection *conn, bdaddr_t *src,
 			bdaddr_t *dst, uint8_t ch, const char **ppath);
 int input_device_unregister(DBusConnection *conn, const char *path);
 
-int input_device_get_bdaddr(DBusConnection *conn, const char *path,
-						bdaddr_t *src, bdaddr_t *dst);
+gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst);
+
+int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk);
+
+int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst);
+
+int input_device_connadd(bdaddr_t *src, bdaddr_t *dst);
+
 int l2cap_connect(bdaddr_t *src, bdaddr_t *dst,
-		unsigned short psm, GIOFunc cb, void *data);
+				unsigned short psm, GIOFunc cb, void *data);

Modified: bluez-utils/branches/upstream/current/input/manager.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/input/manager.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/input/manager.c (original)
+++ bluez-utils/branches/upstream/current/input/manager.c Wed Jul  4 13:37:57 2007
@@ -778,23 +778,12 @@
 	dbus_message_unref(reply);
 }
 
-static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr)
-{
-	bdaddr_t src, dst;
-
-	if (input_device_get_bdaddr(connection, path, &src, &dst) < 0)
-		return -1;
-
-	return bacmp(&dst, bdaddr);
-}
-
 static DBusHandlerResult create_device(DBusConnection *conn,
 					DBusMessage *msg, void *data)
 {
 	struct pending_req *pr;
 	DBusError derr;
 	const char *addr;
-	GSList *l;
 	bdaddr_t src, dst;
 	uint32_t cls = 0;
 	int dev_id;
@@ -821,10 +810,7 @@
 	}
 
 	str2ba(addr, &dst);
-
-	l = g_slist_find_custom(device_paths, &dst,
-					(GCompareFunc) path_bdaddr_cmp);
-	if (l)
+	if (input_device_is_registered(&src, &dst))
 		return err_already_exists(conn, msg, "Input Already exists");
 
 	if (read_device_class(&src, &dst, &cls) < 0) {
@@ -954,9 +940,40 @@
 	 * acceptable since the source is different.
 	 */
 	if (input_device_register(connection, src, &dst, &hidp, &path) < 0)
+		goto cleanup;
+
+	device_paths = g_slist_append(device_paths, g_strdup(path));
+cleanup:
+	if (hidp.rd_data)
+		g_free(hidp.rd_data);
+}
+
+/* hidd to input transition function */
+static void stored_hidd(char *key, char *value, void *data)
+{
+	struct hidp_connadd_req hidp; 
+	char *str, filename[PATH_MAX + 1], addr[18];
+	bdaddr_t dst, *src = data;
+
+	ba2str(src, addr);
+	create_name(filename, PATH_MAX, STORAGEDIR, addr, "input");
+
+	str = textfile_get(filename, key);
+	if (str) {
+		/* Skip: entry found in input file */
+		free(str);
 		return;
-
-	device_paths = g_slist_append(device_paths, g_strdup(path));
+	}
+
+	memset(&hidp, 0, sizeof(struct hidp_connadd_req));
+
+	if (parse_stored_hidd(value, &hidp) < 0)
+		return;
+
+	str2ba(key, &dst);
+	store_device_info(src, &dst, &hidp);
+	if (hidp.rd_data)
+		g_free(hidp.rd_data);
 }
 
 static void register_stored_inputs(void)
@@ -977,10 +994,16 @@
 		if (!isdigit(de->d_name[0]))
 			continue;
 
+		str2ba(de->d_name, &src);
+
+		/* move the hidd entries to the input storage */
+		create_name(filename, PATH_MAX, STORAGEDIR,
+						de->d_name, "hidd");
+		textfile_foreach(filename, stored_hidd, &src);
+
+		/* load the input stored devices */
 		create_name(filename, PATH_MAX, STORAGEDIR,
 						de->d_name, "input");
-
-		str2ba(de->d_name, &src);
 
 		textfile_foreach(filename, stored_input, &src);
 	}

Modified: bluez-utils/branches/upstream/current/input/server.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/input/server.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/input/server.c (original)
+++ bluez-utils/branches/upstream/current/input/server.c Wed Jul  4 13:37:57 2007
@@ -42,102 +42,11 @@
 #include "logging.h"
 #include "dbus.h"
 
+#include "device.h"
 #include "server.h"
 #include "storage.h"
 
-struct session_data {
-	bdaddr_t src;
-	bdaddr_t dst;
-	int ctrl_sk;
-	int intr_sk;
-};
-
-static GSList *sessions = NULL;
 static DBusConnection *connection = NULL;
-
-static struct session_data *find_session(bdaddr_t *src, bdaddr_t *dst)
-{
-	GSList *list;
-
-	for (list = sessions; list != NULL; list = list->next) {
-		struct session_data *session = list->data;
-
-		if (!bacmp(&session->src, src) && !bacmp(&session->dst, dst))
-			return session;
-	}
-
-	return NULL;
-}
-
-static gboolean session_event(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
-	if (cond & G_IO_NVAL)
-		return FALSE;
-
-	if (cond & (G_IO_HUP | G_IO_ERR)) {
-		g_io_channel_close(chan);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static void create_device(struct session_data *session)
-{
-	struct hidp_connadd_req req;
-	char addr[18];
-	int ctl, err, timeout = 30;
-
-	ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
-	if (ctl < 0) {
-		error("Can't open HIDP interface");
-		goto cleanup;
-	}
-
-	ba2str(&session->dst, addr);
-
-	memset(&req, 0, sizeof(req));
-	req.ctrl_sock = session->ctrl_sk;
-	req.intr_sock = session->intr_sk;
-	req.flags     = 0;
-	req.idle_to   = timeout * 60;
-
-	if (get_stored_device_info(&session->src, &session->dst, &req) < 0) {
-		error("Rejected connection from unknown device %s", addr);
-		goto cleanup;
-	}
-
-	if (req.subclass & 0x40) {
-		err = encrypt_link(&session->src, &session->dst);
-		if (err < 0 && err != -ENOKEY) {
-			if (req.rd_data)
-				free(req.rd_data);
-			goto cleanup;
-		}
-	}
-
-	info("New input device %s (%s)", addr, req.name);
-
-	if (req.vendor == 0x054c && req.product == 0x0268) {
-		unsigned char buf[] = { 0x53, 0xf4,  0x42, 0x03, 0x00, 0x00 };
-		err = write(session->ctrl_sk, buf, sizeof(buf));
-	}
-
-	err = ioctl(ctl, HIDPCONNADD, &req);
-
-	close(ctl);
-
-	if (req.rd_data)
-		free(req.rd_data);
-
-cleanup:
-	sessions = g_slist_remove(sessions, session);
-
-	close(session->intr_sk);
-	close(session->ctrl_sk);
-
-	g_free(session);
-}
 
 static void cancel_authorization(const char *addr)
 {
@@ -160,38 +69,41 @@
 	send_message_and_unref(connection, msg);
 }
 
+struct authorization_data {
+	bdaddr_t src;
+	bdaddr_t dst;
+};
+
 static void authorization_callback(DBusPendingCall *pcall, void *data)
 {
-	struct session_data *session = data;
+	struct authorization_data *auth = data;
 	DBusMessage *reply = dbus_pending_call_steal_reply(pcall);
 	DBusError derr;
 
 	dbus_error_init(&derr);
-	if (dbus_set_error_from_message(&derr, reply)) {
-		error("Access denied: %s", derr.message);
-		if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) {
-			char addr[18];
-			memset(addr, 0, sizeof(addr));
-			ba2str(&session->dst, addr);
-			cancel_authorization(addr);
-		}
-		dbus_error_free(&derr);
-
-		sessions = g_slist_remove(sessions, session);
-
-		close(session->intr_sk);
-		close(session->ctrl_sk);
-
-		g_free(session);
-	} else {
-		create_device(session);
-	}
-
+	if (dbus_set_error_from_message(&derr, reply) != TRUE) {
+		dbus_message_unref(reply);
+		input_device_connadd(&auth->src, &auth->dst);
+		return;
+	}
+
+	error("Authorization denied: %s", derr.message);
+	if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) {
+		char addr[18];
+		memset(addr, 0, sizeof(addr));
+		ba2str(&auth->dst, addr);
+		cancel_authorization(addr);
+	}
+
+	input_device_close_channels(&auth->src, &auth->dst);
+
+	dbus_error_free(&derr);
 	dbus_message_unref(reply);
 }
 
-static int authorize_device(struct session_data *session)
-{
+static int authorize_device(bdaddr_t *src, bdaddr_t *dst)
+{
+	struct authorization_data *auth;
 	DBusMessage *msg;
 	DBusPendingCall *pending;
 	char addr[18];
@@ -206,7 +118,7 @@
 	}
 
 	memset(addr, 0, sizeof(addr));
-	ba2str(&session->dst, addr);
+	ba2str(dst, addr);
 	dbus_message_append_args(msg,
 			DBUS_TYPE_STRING, &paddr,
 			DBUS_TYPE_STRING, &uuid,
@@ -216,28 +128,18 @@
 				msg, &pending, -1) == FALSE)
 		return -EACCES;
 
-	dbus_pending_call_set_notify(pending, authorization_callback, session, NULL);
+	auth = g_new0(struct authorization_data, 1);
+	bacpy(&auth->src, src);
+	bacpy(&auth->dst, dst);
+	dbus_pending_call_set_notify(pending, authorization_callback, auth, g_free);
 	dbus_pending_call_unref(pending);
 	dbus_message_unref(msg);
 
 	return 0;
 }
 
-static void create_watch(int sk, struct session_data *session)
-{
-	GIOChannel *io;
-
-	io = g_io_channel_unix_new(sk);
-
-	g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-						session_event, session);
-
-	g_io_channel_unref(io);
-}
-
 static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data)
 {
-	struct session_data *session;
 	struct sockaddr_l2 addr;
 	socklen_t addrlen;
 	bdaddr_t src, dst;
@@ -268,43 +170,19 @@
 
 	debug("Incoming connection on PSM %d", psm);
 
-	session = find_session(&src, &dst);
-	if (session) {
-		if (psm == 19) {
-			session->intr_sk = nsk;
-			if (authorize_device(session) < 0) {
-				error("Authorization request failed");
-				sessions = g_slist_remove(sessions, session);
-
-				close(session->intr_sk);
-				close(session->ctrl_sk);
-
-				g_free(session);
-
-				return TRUE;
-			}
-			debug("Waiting authorization ...");
-		} else {
-			error("Control channel already established");
-			close(nsk);
+	if (input_device_set_channel(&src, &dst, psm, nsk) < 0) {
+		/* Send unplug virtual cable to unknown devices */
+		if (psm == L2CAP_PSM_HIDP_CTRL) {
+			unsigned char unplug[] = { 0x15 };
+			int err;
+			err = write(nsk, unplug, sizeof(unplug));
 		}
-	} else {
-		if (psm == 17) {
-			session = g_new0(struct session_data, 1);
-
-			bacpy(&session->src, &src);
-			bacpy(&session->dst, &dst);
-			session->ctrl_sk = nsk;
-			session->intr_sk = -1;
-
-			sessions = g_slist_append(sessions, session);
-
-			create_watch(nsk, session);
-		} else {
-			error("No control channel available");
-			close(nsk);
-		}
-	}
+		close(nsk);
+		return TRUE;
+	}
+
+	if ((psm == L2CAP_PSM_HIDP_INTR) && (authorize_device(&src, &dst) < 0))
+		input_device_close_channels(&src, &dst);
 
 	return TRUE;
 }
@@ -347,14 +225,14 @@
 
 int server_start(DBusConnection *conn)
 {
-	ctrl_io = setup_l2cap(17);
+	ctrl_io = setup_l2cap(L2CAP_PSM_HIDP_CTRL);
 	if (!ctrl_io) {
 		error("Failed to listen on control channel");
 		return -1;
 	}
 	g_io_channel_set_close_on_unref(ctrl_io, TRUE);
 
-	intr_io = setup_l2cap(19);
+	intr_io = setup_l2cap(L2CAP_PSM_HIDP_INTR);
 	if (!intr_io) {
 		error("Failed to listen on interrupt channel");
 		g_io_channel_unref(ctrl_io);

Modified: bluez-utils/branches/upstream/current/input/storage.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/input/storage.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/input/storage.c (original)
+++ bluez-utils/branches/upstream/current/input/storage.c Wed Jul  4 13:37:57 2007
@@ -59,22 +59,22 @@
 	return create_name(buf, size, STORAGEDIR, addr, name);
 }
 
-int parse_stored_device_info(const char *str, struct hidp_connadd_req *req)
+int parse_stored_hidd(const char *str, struct hidp_connadd_req *req)
 {
 	char tmp[3];
-	const char *desc;
+	char *desc;
 	unsigned int vendor, product, version, subclass, country, parser, pos;
-	size_t len;
 	int i;
 
-	sscanf(str, "%04X:%04X:%04X %02X %02X %04X %08X %n",
+	desc = malloc(4096);
+	if (!desc)
+		return -ENOMEM;
+
+	memset(desc, 0, 4096);
+
+	sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n",
 			&vendor, &product, &version, &subclass, &country,
-			&parser, &req->flags, &pos);
-
-	desc  = &str[pos];
-	len = strlen(desc);
-	if (len <= 0)
-		return -ENOENT;
+			&parser, desc, &req->flags, &pos);
 
 	req->vendor   = vendor;
 	req->product  = product;
@@ -83,9 +83,10 @@
 	req->country  = country;
 	req->parser   = parser;
 
-	req->rd_size = len / 2;
+	req->rd_size = strlen(desc) / 2;
 	req->rd_data = g_try_malloc0(req->rd_size);
 	if (!req->rd_data) {
+		g_free(desc);
 		return -ENOMEM;
 	}
 
@@ -95,6 +96,47 @@
 		req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16);
 	}
 
+	g_free(desc);
+
+	return 0;
+}
+
+int parse_stored_device_info(const char *str, struct hidp_connadd_req *req)
+{
+	char tmp[3];
+	const char *desc;
+	unsigned int vendor, product, version, subclass, country, parser, pos;
+	size_t len;
+	int i;
+
+	sscanf(str, "%04X:%04X:%04X %02X %02X %04X %08X %n",
+			&vendor, &product, &version, &subclass, &country,
+			&parser, &req->flags, &pos);
+
+	desc  = &str[pos];
+	len = strlen(desc);
+	if (len <= 0)
+		return -ENOENT;
+
+	req->vendor   = vendor;
+	req->product  = product;
+	req->version  = version;
+	req->subclass = subclass;
+	req->country  = country;
+	req->parser   = parser;
+
+	req->rd_size = len / 2;
+	req->rd_data = g_try_malloc0(req->rd_size);
+	if (!req->rd_data) {
+		return -ENOMEM;
+	}
+
+	memset(tmp, 0, sizeof(tmp));
+	for (i = 0; i < req->rd_size; i++) {
+		memcpy(tmp, desc + (i * 2), 2);
+		req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16);
+	}
+
 	return 0;
 }
 
@@ -124,10 +166,12 @@
 	char filename[PATH_MAX + 1];
 	char addr[18];
 
+	ba2str(dst, addr);
+
+	create_filename(filename, PATH_MAX, src, "hidd");
+	textfile_del(filename, addr);
+
 	create_filename(filename, PATH_MAX, src, "input");
-
-	ba2str(dst, addr);
-
 	return textfile_del(filename, addr);
 }
 

Modified: bluez-utils/branches/upstream/current/input/storage.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/input/storage.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/input/storage.h (original)
+++ bluez-utils/branches/upstream/current/input/storage.h Wed Jul  4 13:37:57 2007
@@ -29,6 +29,7 @@
 int store_device_info(bdaddr_t *src, bdaddr_t *dst,
 				struct hidp_connadd_req *req);
 
+int parse_stored_hidd(const char *str, struct hidp_connadd_req *req);
 int parse_stored_device_info(const char *str,
 				struct hidp_connadd_req *req);
 

Modified: bluez-utils/branches/upstream/current/network/connection.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/connection.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/connection.c (original)
+++ bluez-utils/branches/upstream/current/network/connection.c Wed Jul  4 13:37:57 2007
@@ -28,7 +28,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
-
+#include <sys/stat.h>
 #include <netinet/in.h>
 
 #include <bluetooth/bluetooth.h>
@@ -675,7 +675,8 @@
 	return 0;
 }
 
-int connection_store(DBusConnection *conn, const char *path)
+int connection_store(DBusConnection *conn, const char *path,
+			gboolean default_path)
 {
 	struct network_conn *nc;
 	const char *role;
@@ -696,25 +697,29 @@
 	role = bnep_name(nc->id);
 	snprintf(key, 32, "%s#%s", dst_addr, role);
 
-	len = strlen(nc->name) + strlen(nc->desc)  + 2;
-	value = g_malloc0(len);
-	snprintf(value, len, "%s:%s", nc->name, nc->desc);
-
 	ba2str(&nc->src, src_addr);
 	create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "network");
-
-	err = textfile_put(filename, key, value);
-
-	g_free(value);
-
-	return err; 
+	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+	if (default_path)
+		err = textfile_put(filename, "default", key);
+	else {
+		len = strlen(nc->name) + strlen(nc->desc)  + 2;
+		value = g_malloc0(len);
+		snprintf(value, len, "%s:%s", nc->name, nc->desc);
+		err = textfile_put(filename, key, value);
+		g_free(value);
+	}
+
+	return err;
 }
 
 int connection_find_data(DBusConnection *conn,
 		const char *path, const char *pattern)
 {
 	struct network_conn *nc;
-	char addr[18];
+	char addr[18], key[32];
+	const char *role;
 
 	if (!dbus_connection_get_object_user_data(conn, path, (void *) &nc))
 		return -1;
@@ -730,6 +735,12 @@
 	if (strcasecmp(pattern, addr) == 0)
 		return 0;
 
+	role = bnep_name(nc->id);
+	snprintf(key, 32, "%s#%s", addr, role);
+
+	if (strcasecmp(pattern, key) == 0)
+		return 0;
+
 	return -1;
 }
 
@@ -742,3 +753,37 @@
 
 	return (nc->state == CONNECTING);
 }
+
+int connection_remove_stored(DBusConnection *conn, const char *path)
+{
+	struct network_conn *nc;
+	const char *role;
+	char key[32];
+	char filename[PATH_MAX + 1];
+	char src_addr[18], dst_addr[18];
+	int err;
+
+	if (!dbus_connection_get_object_user_data(conn, path, (void *) &nc))
+		return -ENOENT;
+
+	ba2str(&nc->dst, dst_addr);
+	role = bnep_name(nc->id);
+	snprintf(key, 32, "%s#%s", dst_addr, role);
+
+	ba2str(&nc->src, src_addr);
+	create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "network");
+
+	err = textfile_del(filename, key);
+
+	return err;
+}
+
+gboolean connection_is_connected(DBusConnection *conn, const char *path)
+{
+	struct network_conn *nc;
+
+	if (!dbus_connection_get_object_user_data(conn, path, (void *) &nc))
+		return FALSE;
+
+	return (nc->state == CONNECTED);
+}

Modified: bluez-utils/branches/upstream/current/network/connection.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/connection.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/connection.h (original)
+++ bluez-utils/branches/upstream/current/network/connection.h Wed Jul  4 13:37:57 2007
@@ -23,7 +23,10 @@
 
 int connection_register(DBusConnection *conn, const char *path, bdaddr_t *src,
 		bdaddr_t *dst, uint16_t id, const char *name, const char *desc);
-int connection_store(DBusConnection *conn, const char *path);
+int connection_store(DBusConnection *conn, const char *path,
+			gboolean default_path);
+int connection_remove_stored(DBusConnection *conn, const char *path);
 int connection_find_data(DBusConnection *conn, const char *path,
 			const char *pattern);
 gboolean connection_has_pending(DBusConnection *conn, const char *path);
+gboolean connection_is_connected(DBusConnection *conn, const char *path);

Modified: bluez-utils/branches/upstream/current/network/manager.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/manager.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/manager.c (original)
+++ bluez-utils/branches/upstream/current/network/manager.c Wed Jul  4 13:37:57 2007
@@ -45,7 +45,6 @@
 #include "logging.h"
 #include "textfile.h"
 
-#define NETWORK_PATH "/org/bluez/network"
 #define NETWORK_MANAGER_INTERFACE "org.bluez.network.Manager"
 
 #include "error.h"
@@ -54,8 +53,6 @@
 #include "server.h"
 #include "connection.h"
 #include "common.h"
-
-#define MAX_PATH_LENGTH		64 /* D-Bus path */
 
 struct pending_reply {
 	DBusConnection	*conn;
@@ -70,6 +67,7 @@
 
 static GSList *server_paths	= NULL;	/* Network registered servers paths */
 static GSList *connection_paths	= NULL;	/* Network registered connections paths */
+static int default_index = -1;		/* Network default connection path index */
 
 static DBusConnection *connection = NULL;
 
@@ -139,6 +137,27 @@
 	return send_message_and_unref(conn, reply);
 }
 
+static const char * last_connection_used(DBusConnection *conn)
+{
+	const char *path = NULL;
+	GSList *l;
+	int i;
+
+	for (i = g_slist_length (connection_paths) -1; i > -1; i--) {
+		path = g_slist_nth_data (connection_paths, i);
+		if (connection_is_connected(conn, path))
+			break;
+	}
+
+	/* No connection connected fallback to last connection */
+	if (i == -1) {
+		l = g_slist_last(connection_paths);
+		path = l->data;
+	}
+
+	return path;
+}
+
 static DBusHandlerResult remove_path(DBusConnection *conn,
 					DBusMessage *msg, GSList **list,
 					const char *sname)
@@ -161,8 +180,20 @@
 	if (!l)
 		return err_does_not_exist(conn, msg, "Path doesn't exist");
 
-	if (*list == connection_paths && connection_has_pending (conn, path))
-		return err_failed(conn, msg, "Connection is Busy");
+	/* Remove references from the storage */
+	if (*list == connection_paths) {
+		if (connection_has_pending(conn, path))
+			return err_failed(conn, msg, "Connection is Busy");
+
+		connection_remove_stored(conn, path);
+		/* Reset default connection */
+		if (l == g_slist_nth(*list, default_index)) {
+			const char *dpath;
+
+			dpath = last_connection_used(conn);
+			connection_store(conn, dpath, TRUE);
+		}
+	}
 
 	g_free(l->data);
 	*list = g_slist_remove(*list, l->data);
@@ -171,8 +202,6 @@
 	if (!reply)
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-	/* Remove the nap or gn file from the file system */
-	server_remove_stored(conn, path);
 	if (!dbus_connection_destroy_object_path(conn, path))
 		error("Network path unregister failed");
 
@@ -246,7 +275,7 @@
 		goto fail;
 	}
 
-	connection_store(pr->conn, pr->path);
+	connection_store(pr->conn, pr->path, FALSE);
 	connection_paths = g_slist_append(connection_paths, g_strdup(pr->path));
 
 	create_path(pr->conn, pr->msg, pr->path, "ConnectionCreated");
@@ -373,57 +402,6 @@
 	return list_paths(conn, msg, server_paths);
 }
 
-static DBusHandlerResult create_server(DBusConnection *conn,
-					DBusMessage *msg, void *data)
-{
-	char path[MAX_PATH_LENGTH];
-	DBusError derr;
-	const char *str;
-	bdaddr_t src;
-	uint16_t id;
-	int dev_id;
-
-	dbus_error_init(&derr);
-	if (!dbus_message_get_args(msg, &derr,
-				DBUS_TYPE_STRING, &str,
-				DBUS_TYPE_INVALID)) {
-		err_invalid_args(conn, msg, derr.message);
-		dbus_error_free(&derr);
-		return DBUS_HANDLER_RESULT_HANDLED;
-	}
-
-	id = bnep_service_id(str);
-	if ((id != BNEP_SVC_GN) && (id != BNEP_SVC_NAP))
-		return err_invalid_args(conn, msg, "Not supported");
-
-	snprintf(path, MAX_PATH_LENGTH, NETWORK_PATH"/server/%s%d",
-							bnep_name(id), net_uid++);
-
-	if (g_slist_find_custom(server_paths, path,
-				(GCompareFunc) strcmp)) {
-		err_already_exists(conn, msg, "Server Already exists");
-		return DBUS_HANDLER_RESULT_HANDLED;
-	}
-
-	bacpy(&src, BDADDR_ANY);
-
-	dev_id = hci_get_route(NULL);
-
-	if (dev_id >= 0)
-		hci_devba(dev_id, &src);
-
-	if (server_register(conn, path, &src, id) < 0)
-		return err_failed(conn, msg,
-				"D-Bus path registration failed");
-
-	if (bacmp(&src, BDADDR_ANY) != 0)
-		server_store(conn, path);
-
-	server_paths = g_slist_append(server_paths, g_strdup(path));
-
-	return create_path(conn, msg, path, "ServerCreated");
-}
-
 static DBusHandlerResult find_server(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
@@ -463,16 +441,28 @@
 	return send_message_and_unref(conn, reply);
 }
 
-static DBusHandlerResult remove_server(DBusConnection *conn,
-					DBusMessage *msg, void *data)
-{
-	return remove_path(conn, msg, &server_paths, "ServerRemoved");
-}
-
 static DBusHandlerResult list_connections(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
 	return list_paths(conn, msg, connection_paths);
+}
+
+static GSList * find_connection_pattern(DBusConnection *conn,
+					const char *pattern)
+{
+	const char *path;
+	GSList *list;
+
+	if (pattern == NULL)
+		return NULL;
+
+	for (list = connection_paths; list; list = list->next) {
+		path = (const char *) list->data;
+		if (connection_find_data(conn, path, pattern) == 0)
+			break;
+	}
+
+	return list;
 }
 
 static DBusHandlerResult find_connection(DBusConnection *conn,
@@ -493,16 +483,14 @@
 		return DBUS_HANDLER_RESULT_HANDLED;
 	}
 
-	for (list = connection_paths; list; list = list->next) {
-		path = (const char *) list->data;
-		if (connection_find_data(conn, path, pattern) == 0)
-			break;
-	}
+	list = find_connection_pattern(conn, pattern);
 
 	if (list == NULL) {
 		err_failed(conn, msg, "No such connection");
 		return DBUS_HANDLER_RESULT_HANDLED;
 	}
+
+	path = list->data;
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
@@ -524,6 +512,8 @@
 	bdaddr_t src;
 	uint16_t id;
 	int dev_id;
+	char key[32];
+	GSList *l;
 
 	dbus_error_init(&derr);
 	if (!dbus_message_get_args(msg, &derr,
@@ -538,6 +528,17 @@
 	id = bnep_service_id(str);
 	if ((id != BNEP_SVC_GN) && (id != BNEP_SVC_NAP))
 		return err_invalid_args(conn, msg, "Not supported");
+
+	snprintf(key, 32, "%s#%s", addr, bnep_name(id));
+
+	/* Checks if the connection was already been made */
+	for (l = connection_paths; l; l = l->next) {
+		if (connection_find_data(conn, l->data, key) == 0) {
+			err_already_exists(conn, msg,
+						"Connection Already exists");
+			return DBUS_HANDLER_RESULT_HANDLED;
+		}
+	}
 
 	bacpy(&src, BDADDR_ANY);
 	dev_id = hci_get_route(NULL);
@@ -570,6 +571,118 @@
 	return remove_path(conn, msg, &connection_paths, "ConnectionRemoved");
 }
 
+static DBusHandlerResult last_connection(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	const char *path;
+	DBusMessage *reply;
+
+	if (connection_paths == NULL ||
+		g_slist_length (connection_paths) == 0) {
+		err_does_not_exist(conn, msg, "No such connection");
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	path = last_connection_used(conn);
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,
+					DBUS_TYPE_INVALID);
+
+	return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult default_connection(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	const char *path;
+	DBusMessage *reply;
+
+	if (connection_paths == NULL ||
+		g_slist_length (connection_paths) == 0) {
+		err_does_not_exist(conn, msg, "No such connection");
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	path = g_slist_nth_data (connection_paths, default_index);
+
+	if (path == NULL) {
+		path = last_connection_used(conn);
+		connection_store(conn, path, TRUE);
+	}
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,
+					DBUS_TYPE_INVALID);
+
+	return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult change_default_connection(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	const char *path;
+	const char *pattern;
+	DBusMessage *reply;
+	DBusError derr;
+	GSList *list;
+
+	dbus_error_init(&derr);
+	if (!dbus_message_get_args(msg, &derr,
+				DBUS_TYPE_STRING, &pattern,
+				DBUS_TYPE_INVALID)) {
+		err_invalid_args(conn, msg, derr.message);
+		dbus_error_free(&derr);
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	if (connection_paths == NULL ||
+		g_slist_length (connection_paths) == 0) {
+		err_does_not_exist(conn, msg, "No such connection");
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	list = g_slist_find_custom(connection_paths, pattern, (GCompareFunc) strcmp);
+
+	/* Find object path via pattern */
+	if (list == NULL) {
+		list = find_connection_pattern(conn, pattern);
+
+		if (list == NULL) {
+			err_failed(conn, msg, "No such connection");
+			return DBUS_HANDLER_RESULT_HANDLED;
+		}
+		else
+			path = list->data;
+	}
+	else
+		path = list->data;
+
+	default_index = g_slist_position (connection_paths, list);
+	connection_store(connection, path, TRUE);
+
+	dbus_connection_emit_signal(connection, NETWORK_PATH,
+					NETWORK_MANAGER_INTERFACE,
+					"DefaultConnectionChanged",
+					DBUS_TYPE_STRING, &path,
+					DBUS_TYPE_INVALID);
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,
+					DBUS_TYPE_INVALID);
+
+	return send_message_and_unref(conn, reply);
+}
+
 static void manager_unregister(DBusConnection *conn, void *data)
 {
 	info("Unregistered manager path");
@@ -644,22 +757,117 @@
 
 	if (connection_register(connection, path, src,
 				&dst, id, name, ptr) == 0) {
-		connection_paths = g_slist_append(connection_paths,
-							g_strdup(path));
+		char *rpath = g_strdup(path);
+		connection_paths = g_slist_append(connection_paths, rpath);
+		dbus_connection_emit_signal(connection, NETWORK_PATH,
+						NETWORK_MANAGER_INTERFACE,
+						"ConnectionCreated",
+						DBUS_TYPE_STRING, &rpath,
+						DBUS_TYPE_INVALID);
 	}
 
 	g_free(name);
 }
 
-static void register_stored(void)
-{
-	char dirname[PATH_MAX + 1];
+static void register_connections_stored(const char *adapter)
+{
+	char filename[PATH_MAX + 1];
+	char *pattern;
+	struct stat s;
+	GSList *list;
+	bdaddr_t src;
+	bdaddr_t default_src;
+	int dev_id;
+
+	create_name(filename, PATH_MAX, STORAGEDIR, adapter, "network");
+
+	str2ba(adapter, &src);
+
+	bacpy(&default_src, BDADDR_ANY);
+	dev_id = hci_get_route(NULL);
+	if (dev_id < 0)
+		hci_devba(dev_id, &default_src);
+
+	if (stat (filename, &s) == 0 && (s.st_mode & __S_IFREG)) {
+		textfile_foreach(filename, parse_stored_connection, &src);
+		pattern = textfile_get(filename, "default");
+
+		list = find_connection_pattern(connection, pattern);
+		if (list != NULL)
+			default_index = g_slist_position(connection_paths, list);
+		else if (bacmp(&src, &default_src) == 0) {
+			list = g_slist_last(connection_paths);
+			if (list == NULL)
+				return;
+			default_index = g_slist_position(connection_paths, list);
+			connection_store(connection, list->data, TRUE);
+		}
+	}
+}
+
+static void register_server(uint16_t id)
+{
+	char path[MAX_PATH_LENGTH];
+	bdaddr_t src;
+	int dev_id;
+
+	snprintf(path, MAX_PATH_LENGTH, NETWORK_PATH"/%s", bnep_name(id));
+
+	if (g_slist_find_custom(server_paths, path,
+				(GCompareFunc) strcmp))
+		return;
+
+	bacpy(&src, BDADDR_ANY);
+
+	dev_id = hci_get_route(NULL);
+
+	if (dev_id >= 0)
+		hci_devba(dev_id, &src);
+
+	if (server_register(connection, path, &src, id) < 0)
+		return;
+
+	if (bacmp(&src, BDADDR_ANY) != 0)
+		server_store(connection, path);
+
+	server_paths = g_slist_append(server_paths, g_strdup(path));
+}
+
+static void register_servers_stored(const char *adapter, const char *profile)
+{
 	char filename[PATH_MAX + 1];
 	char path[MAX_PATH_LENGTH];
+	uint16_t id;
+	struct stat s;
+	bdaddr_t src;
+
+	if (strcmp(profile, "nap") == 0)
+		id = BNEP_SVC_NAP;
+	else if (strcmp(profile, "gn") == 0)
+		id = BNEP_SVC_GN;
+	else
+		id = BNEP_SVC_PANU;
+
+	create_name(filename, PATH_MAX, STORAGEDIR, adapter, profile);
+
+	str2ba(adapter, &src);
+
+	if (stat (filename, &s) == 0 && (s.st_mode & __S_IFREG)) {
+		snprintf(path, MAX_PATH_LENGTH,
+			NETWORK_PATH"/%s", profile);
+		if (server_register_from_file(connection, path,
+			&src, id, filename) == 0) {
+			server_paths = g_slist_append(server_paths,
+						g_strdup(path));
+		}
+	}
+}
+
+static void register_stored(void)
+{
+	char dirname[PATH_MAX + 1];
 	struct dirent *de;
 	DIR *dir;
-	struct stat s;
-	bdaddr_t src;
 
 	snprintf(dirname, PATH_MAX, "%s", STORAGEDIR);
 
@@ -672,38 +880,16 @@
 			continue;
 
 		/* Connection objects */
-		create_name(filename, PATH_MAX, STORAGEDIR,
-						de->d_name, "network");
-
-		str2ba(de->d_name, &src);
-
-
-		if (stat (filename, &s) == 0 && (s.st_mode & __S_IFREG))
-			textfile_foreach(filename, parse_stored_connection, &src);
+		register_connections_stored(de->d_name);
 
 		/* NAP objects */
-		create_name(filename, PATH_MAX, STORAGEDIR, de->d_name, "nap");
-		if (stat (filename, &s) == 0 && (s.st_mode & __S_IFREG)) {
-			snprintf(path, MAX_PATH_LENGTH,
-					NETWORK_PATH"/server/nap%d", net_uid++);
-
-			if (server_register_from_file(connection, path,
-					&src, BNEP_SVC_NAP, filename) == 0)
-				server_paths = g_slist_append(server_paths,
-								g_strdup(path));
-		}
+		register_servers_stored(de->d_name, "nap");
 
 		/* GN objects */
-		create_name(filename, PATH_MAX, STORAGEDIR, de->d_name, "gn");
-		if (stat (filename, &s) == 0 && (s.st_mode & __S_IFREG)) {
-			snprintf(path, MAX_PATH_LENGTH,
-					NETWORK_PATH"/server/gn%d", net_uid++);
-
-			if (server_register_from_file(connection, path,
-					&src, BNEP_SVC_GN, filename) == 0)
-				server_paths = g_slist_append(server_paths,
-								g_strdup(path));
-		}
+		register_servers_stored(de->d_name, "gn");
+
+		/* PANU objects */
+		register_servers_stored(de->d_name, "panu");
 	}
 
 	closedir(dir);
@@ -711,13 +897,14 @@
 
 static DBusMethodVTable manager_methods[] = {
 	{ "ListServers",	list_servers,		"",	"as"	},
-	{ "CreateServer",	create_server,		"s",	"s"	},
 	{ "FindServer",		find_server,		"s",	"s"	},
-	{ "RemoveServer",	remove_server,		"s",	""	},
 	{ "ListConnections",	list_connections,	"",	"as"	},
 	{ "FindConnection",	find_connection,	"s",	"s"	},
 	{ "CreateConnection",	create_connection,	"ss",	"s"	},
 	{ "RemoveConnection",	remove_connection,	"s",	""	},
+	{ "LastConnection",	last_connection,	"",	"s"	},
+	{ "DefaultConnection",	default_connection,	"",	"s"	},
+	{ "ChangeDefaultConnection", change_default_connection, "s", "s"},
 	{ NULL, NULL, NULL, NULL }
 };
 
@@ -726,6 +913,7 @@
 	{ "ServerRemoved",	"s"	},
 	{ "ConnectionCreated",	"s"	},
 	{ "ConnectionRemoved",	"s"	},
+	{ "DefaultConnectionChanged", "s" },
 	{ NULL, NULL }
 };
 
@@ -766,6 +954,15 @@
 
 	register_stored();
 
+	/* PAN user server */
+	register_server(BNEP_SVC_PANU);
+
+	/* Group Network server */
+	register_server(BNEP_SVC_GN);
+
+	/* Network Access Point server */
+	register_server(BNEP_SVC_NAP);
+
 	return 0;
 }
 

Modified: bluez-utils/branches/upstream/current/network/manager.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/manager.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/manager.h (original)
+++ bluez-utils/branches/upstream/current/network/manager.h Wed Jul  4 13:37:57 2007
@@ -21,6 +21,9 @@
  *
  */
 
+#define MAX_PATH_LENGTH 64 /* D-Bus path */
+#define NETWORK_PATH "/org/bluez/network"
+
 int network_init(DBusConnection *conn);
 void network_exit(void);
 

Modified: bluez-utils/branches/upstream/current/network/network-api.txt
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/network-api.txt?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/network-api.txt (original)
+++ bluez-utils/branches/upstream/current/network/network-api.txt Wed Jul  4 13:37:57 2007
@@ -20,6 +20,7 @@
 			                 org.bluez.network.Error.Failed
 
 		void RemoveServer(string path)
+
 			Removes the network server object for given path.
 
 			Possible errors: org.bluez.network.Error.DoesNotExist
@@ -50,8 +51,8 @@
 
 			Removes a network connection object for a given path.
 
-			Possible errors:org.bluez.network.Error.DoesNotExist
-					org.bluez.network.Error.Failed
+			Possible errors: org.bluez.network.Error.DoesNotExist
+			                 org.bluez.network.Error.Failed
 
 		array{string} ListConnections()
 
@@ -61,18 +62,37 @@
 
 			Returns connection path.
 
-			Possible errors:org.bluez.network.Error.DoesNotExist
-					org.bluez.network.Error.Failed
-
-Signals
-
-		void ServerCreated(string path)
+			Possible errors: org.bluez.network.Error.DoesNotExist
+			                 org.bluez.network.Error.Failed
+
+		string LastConnection()
+
+			Returns last connected connection path, if none is connected
+			fallback to last created connection.
+
+			Possible errors: org.bluez.network.Error.DoesNotExist
+
+		string DefaultConnection()
+
+			Returns default connection path.
+
+			Possible errors: org.bluez.network.Error.DoesNotExist
+
+		string ChangeDefaultConnection(string pattern)
+
+			Changes default connection path.
+
+			Possible errors: org.bluez.network.Error.DoesNotExist
+
+Signals		void ServerCreated(string path)
 
 		void ServerRemoved(string path)
 
 		void ConnectionCreated(string path)
 
 		void ConnectionRemoved(string path)
+
+		void DefaultConnectionChanged(string path)
 
 
 Network Server hierarchy (experimental)
@@ -127,7 +147,6 @@
 
 			Returns the server properties.
 
-
 Signals		void Enabled()
 
 		void Disabled()
@@ -178,11 +197,13 @@
 			Possible errors: org.bluez.network.Error.ConnectionAttemptFailed
 			                 org.bluez.network.Error.Failed
 
-		string CancelConnect()
+		void CancelConnect()
 
 			Abort connection attempt in case of errors or
 			timeouts in the client.
 
+			Possible errors: org.bluez.network.Error.Failed
+
 		void Disconnect()
 
 			Disconnects to host.

Modified: bluez-utils/branches/upstream/current/network/server.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/server.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/server.c (original)
+++ bluez-utils/branches/upstream/current/network/server.c Wed Jul  4 13:37:57 2007
@@ -59,11 +59,13 @@
 #include "manager.h"
 #include "server.h"
 
+static GIOChannel *bnep_io;
+
 /* Pending Authorization */
 struct pending_auth {
-	char				*addr;	/* Bluetooth Address */
-	GIOChannel			*io;	/* BNEP connection setup io channel */
-	int 				attempts; /* BNEP setup conn requests counter */
+	char			*addr;		/* Bluetooth Address */
+	GIOChannel		*io;		/* BNEP connection setup io channel */
+	int			attempts;	/* BNEP setup conn requests counter */
 };
 
 /* Main server structure */
@@ -72,12 +74,12 @@
 	char			*iface;		/* Routing interface */
 	char			*name;		/* Server service name */
 	char			*range;		/* IP Address range */
-	char			*path; 		/* D-Bus path */
-	dbus_bool_t		secure;
+	char			*path;		/* D-Bus path */
+	gboolean		enable;		/* Enable flag*/
+	gboolean		secure;		/* Security flag*/
 	uint32_t		record_id;	/* Service record id */
 	uint16_t		id;		/* Service class identifier */
-	GIOChannel		*io;		/* GIOChannel when listening */
-	DBusConnection 		*conn;		/* D-Bus connection */
+	DBusConnection		*conn;		/* D-Bus connection */
 	struct pending_auth	*pauth;		/* Pending incomming connection/authorization */
 };
 
@@ -92,8 +94,10 @@
 	ba2str(src, addr);
 	if (id == BNEP_SVC_NAP)
 		create_name(filename, PATH_MAX, STORAGEDIR, addr, "nap");
-	else
+	else if (id == BNEP_SVC_GN)
 		create_name(filename, PATH_MAX, STORAGEDIR, addr, "gn");
+	else if (id == BNEP_SVC_PANU)
+		create_name(filename, PATH_MAX, STORAGEDIR, addr, "panu");
 
 	return textfile_put(filename, key, value);
 }
@@ -380,7 +384,9 @@
 static gboolean connect_setup_event(GIOChannel *chan,
 					GIOCondition cond, gpointer data)
 {
-	struct network_server *ns = data;
+	DBusConnection *conn = data;
+	struct network_server *ns;
+	char path[MAX_PATH_LENGTH];
 	struct bnep_setup_conn_req *req;
 	unsigned char pkt[BNEP_MTU];
 	gsize n;
@@ -437,7 +443,10 @@
 	/* Getting source service: considering 2 bytes size */
 	role = ntohs(bt_get_unaligned((uint16_t *) pservice));
 
-	if (role != BNEP_SVC_PANU) {
+	snprintf(path, MAX_PATH_LENGTH, NETWORK_PATH"/%s", bnep_name(role));
+	dbus_connection_get_object_user_data(conn, path, (void *) &ns);
+
+	if (ns == NULL || ns->enable == FALSE) {
 		response = BNEP_CONN_INVALID_SRC;
 		goto reply;
 	}
@@ -532,7 +541,7 @@
 	return TRUE;
 }
 
-static int l2cap_listen(struct network_server *ns)
+int server_init(DBusConnection *conn, gboolean secure)
 {
 	struct l2cap_options l2o;
 	struct sockaddr_l2 l2a;
@@ -578,7 +587,7 @@
 	}
 
 	/* Set link mode */
-	lm = (ns->secure ? L2CAP_LM_SECURE : 0);
+	lm = (secure ? L2CAP_LM_SECURE : 0);
 	if (lm && setsockopt(sk, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm)) < 0) {
 		err = errno;
 		error("Failed to set link mode. %s(%d)",
@@ -592,11 +601,11 @@
 		goto fail;
 	}
 
-	ns->io = g_io_channel_unix_new(sk);
-	g_io_channel_set_close_on_unref(ns->io, FALSE);
-
-	g_io_add_watch(ns->io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-							connect_event, ns);
+	bnep_io = g_io_channel_unix_new(sk);
+	g_io_channel_set_close_on_unref(bnep_io, FALSE);
+
+	g_io_add_watch(bnep_io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+							connect_event, conn);
 
 	return 0;
 fail:
@@ -762,8 +771,7 @@
 		return -EIO;
 	}
 
-	err = l2cap_listen(ns);
-	if (err < 0)
+	if (bnep_io == NULL && (err = server_init(ns->conn, ns->secure)) < 0)
 		return -err;
 
 	return 0;
@@ -776,7 +784,7 @@
 	DBusMessage *reply;
 	int err;
 
-	if (ns->io)
+	if (ns->enable)
 		return err_already_exists(conn, msg, "Server already enabled");
 
 	if (bacmp(&ns->src, BDADDR_ANY) == 0) {
@@ -816,7 +824,7 @@
 	if (!reply)
 		return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-	if (!ns->io)
+	if (!ns->enable)
 		return err_failed(conn, msg, "Not enabled");
 
 	/* Remove the service record */
@@ -825,9 +833,7 @@
 		ns->record_id = 0;
 	}
 
-	g_io_channel_close(ns->io);
-	g_io_channel_unref(ns->io);
-	ns->io = NULL;
+	ns->enable = FALSE;
 
 	store_property(&ns->src, ns->id, "enabled", "0");
 
@@ -865,13 +871,15 @@
 		g_free(ns->name);
 	ns->name = g_strdup(name);
 
-	if (ns->io) {
+	if (ns->enable) {
 		if (update_server_record(ns) < 0) {
 			dbus_message_unref(reply);
 			return err_failed(conn, msg,
 				"Service record attribute update failed");
 		}
 	}
+
+	store_property(&ns->src, ns->id, "name", ns->name);
 
 	return send_message_and_unref(conn, reply);
 }
@@ -955,7 +963,7 @@
 	}
 
 	ns->secure = secure;
-	if (ns->io) {
+	if (ns->enable) {
 		if (update_server_record(ns) < 0) {
 			dbus_message_unref(reply);
 			return err_failed(conn, msg,
@@ -963,6 +971,8 @@
 		}
 	}
 
+	store_property(&ns->src, ns->id, "secure", "1");
+
 	return send_message_and_unref(conn, reply);
 }
 
@@ -1039,11 +1049,6 @@
 	if (ns->conn)
 		dbus_connection_unref(ns->conn);
 
-	if (ns->io) {
-		g_io_channel_close(ns->io);
-		g_io_channel_unref(ns->io);
-	}
-
 	g_free(ns);
 }
 
@@ -1054,6 +1059,12 @@
 	info("Unregistered server path:%s", ns->path);
 
 	server_free(ns);
+
+	if (bnep_io != NULL) {
+		g_io_channel_close(bnep_io);
+		g_io_channel_unref(bnep_io);
+		bnep_io = NULL;
+	}
 }
 
 static DBusMethodVTable server_methods[] = {
@@ -1081,10 +1092,7 @@
 {
 	struct network_server *ns;
 
-	if (!conn)
-		return -EINVAL;
-
-	if (!path)
+	if (!conn || !path)
 		return -EINVAL;
 
 	ns = g_new0(struct network_server, 1);
@@ -1109,8 +1117,10 @@
 	/* Setting a default name */
 	if (id == BNEP_SVC_NAP)
 		ns->name = g_strdup("BlueZ NAP service");
+	else if (id == BNEP_SVC_GN)
+		ns->name = g_strdup("BlueZ GN service");
 	else
-		ns->name = g_strdup("BlueZ GN service");
+		ns->name = g_strdup("BlueZ PANU service");
 
 	ns->path = g_strdup(path);
 	ns->id = id;
@@ -1193,8 +1203,10 @@
 	ba2str(&ns->src, addr);
 	if (ns->id == BNEP_SVC_NAP)
 		create_name(filename, PATH_MAX, STORAGEDIR, addr, "nap");
+	else if (ns->id == BNEP_SVC_GN)
+		create_name(filename, PATH_MAX, STORAGEDIR, addr, "gn");
 	else
-		create_name(filename, PATH_MAX, STORAGEDIR, addr, "gn");
+		create_name(filename, PATH_MAX, STORAGEDIR, addr, "panu");
 
 	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
@@ -1208,25 +1220,9 @@
 
 	textfile_put(filename, "secure", ns->secure ? "1": "0");
 
+	textfile_put(filename, "enabled", ns->enable ? "1": "0");
+
 	return 0;
-}
-
-int server_remove_stored(DBusConnection *conn, const char *path)
-{
-	struct network_server *ns;
-	char filename[PATH_MAX + 1];
-	char addr[18];
-
-	if (!dbus_connection_get_object_user_data(conn, path, (void *) &ns))
-		return -ENOENT;
-
-	ba2str(&ns->src, addr);
-	if (ns->id == BNEP_SVC_NAP)
-		create_name(filename, PATH_MAX, STORAGEDIR, addr, "nap");
-	else
-		create_name(filename, PATH_MAX, STORAGEDIR, addr, "gn");
-
-	return remove(filename);
 }
 
 int server_find_data(DBusConnection *conn,

Modified: bluez-utils/branches/upstream/current/network/server.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/server.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/server.h (original)
+++ bluez-utils/branches/upstream/current/network/server.h Wed Jul  4 13:37:57 2007
@@ -21,12 +21,13 @@
  *
  */
 
+
 int server_register(DBusConnection *conn, const char *path,
 					bdaddr_t *src, uint16_t id);
 int server_register_from_file(DBusConnection *conn, const char *path,
 			const bdaddr_t *src, uint16_t id, const char *filename);
 
 int server_store(DBusConnection *conn, const char *path);
-int server_remove_stored(DBusConnection *conn, const char *path);
+
 int server_find_data(DBusConnection *conn, const char *path,
 			const char *pattern);

Modified: bluez-utils/branches/upstream/current/network/test-network
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/test-network?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/test-network (original)
+++ bluez-utils/branches/upstream/current/network/test-network Wed Jul  4 13:37:57 2007
@@ -23,3 +23,9 @@
 						'org.bluez.network.Server')
 except:
 	pass
+
+try:
+	panu = dbus.Interface(bus.get_object(conn, network.LastConnection()),
+						'org.bluez.network.Connection')
+except:
+	pass

Modified: bluez-utils/branches/upstream/current/rfcomm/main.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/rfcomm/main.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/rfcomm/main.c (original)
+++ bluez-utils/branches/upstream/current/rfcomm/main.c Wed Jul  4 13:37:57 2007
@@ -59,6 +59,7 @@
 static int encryption = 0;
 static int secure = 0;
 static int master = 0;
+static int linger = 0;
 
 static char *rfcomm_state[] = {
 	"unknown",
@@ -100,7 +101,7 @@
 
 	if (flags & (1 << RFCOMM_TTY_ATTACHED))
 		strcat(str, "tty-attached");
-	
+
 	strcat(str, "]");
 	return str;
 }
@@ -170,7 +171,6 @@
 			fprintf(stderr, "Can't find a config entry for rfcomm%d\n", dev);
 			return -EFAULT;
 		}
-		
 	} else {
 		str2ba(argv[1], &req.dst);
 
@@ -265,7 +265,7 @@
 	int i;
 	pid_t pid;
 	char **cmdargv;
-       
+
 	cmdargv = malloc((argc + 1) * sizeof(char*));
 	if (!cmdargv)
 		return;
@@ -357,13 +357,22 @@
 		return;
 	}
 
-	if (bind(sk, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
+	if (linger) {
+		struct linger l = { .l_onoff = 1, .l_linger = linger };
+
+		if (setsockopt(sk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {
+			perror("Can't set linger option");
+			return;
+		}
+	}
+
+	if (bind(sk, (struct sockaddr *) &laddr, sizeof(laddr)) < 0) {
 		perror("Can't bind RFCOMM socket");
 		close(sk);
 		return;
 	}
 
-	if (connect(sk, (struct sockaddr *)&raddr, sizeof(raddr)) < 0) {
+	if (connect(sk, (struct sockaddr *) &raddr, sizeof(raddr)) < 0) {
 		perror("Can't connect RFCOMM socket");
 		close(sk);
 		return;
@@ -393,6 +402,11 @@
 
 	snprintf(devname, MAXPATHLEN - 1, "/dev/rfcomm%d", dev);
 	while ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
+		if (errno == EACCES) {
+			perror("Can't open RFCOMM device");
+			goto release;
+		}
+
 		snprintf(devname, MAXPATHLEN - 1, "/dev/bluetooth/rfcomm/%d", dev);
 		if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
 			if (try--) {
@@ -401,14 +415,7 @@
 				continue;
 			}
 			perror("Can't open RFCOMM device");
-
-			memset(&req, 0, sizeof(req));
-			req.dev_id = dev;
-			req.flags = (1 << RFCOMM_HANGUP_NOW);
-			ioctl(ctl, RFCOMMRELEASEDEV, &req);
-
-			close(sk);
-			return;
+			goto release;
 		}
 	}
 
@@ -457,6 +464,15 @@
 	printf("Disconnected\n");
 
 	close(fd);
+	return;
+
+release:
+	memset(&req, 0, sizeof(req));
+	req.dev_id = dev;
+	req.flags = (1 << RFCOMM_HANGUP_NOW);
+	ioctl(ctl, RFCOMMRELEASEDEV, &req);
+
+	close(sk);
 }
 
 static void cmd_listen(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
@@ -517,6 +533,16 @@
 		return;
 	}
 
+	if (linger) {
+		struct linger l = { .l_onoff = 1, .l_linger = linger };
+
+		if (setsockopt(nsk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {
+			perror("Can't set linger option");
+			close(nsk);
+			return;
+		}
+	}
+
 	memset(&req, 0, sizeof(req));
 	req.dev_id = dev;
 	req.flags = (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP);
@@ -534,6 +560,11 @@
 
 	snprintf(devname, MAXPATHLEN - 1, "/dev/rfcomm%d", dev);
 	while ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
+		if (errno == EACCES) {
+			perror("Can't open RFCOMM device");
+			goto release;
+		}
+
 		snprintf(devname, MAXPATHLEN - 1, "/dev/bluetooth/rfcomm/%d", dev);
 		if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
 			if (try--) {
@@ -542,14 +573,7 @@
 				continue;
 			}
 			perror("Can't open RFCOMM device");
-
-			memset(&req, 0, sizeof(req));
-			req.dev_id = dev;
-			req.flags = (1 << RFCOMM_HANGUP_NOW);
-			ioctl(ctl, RFCOMMRELEASEDEV, &req);
-
-			close(sk);
-			return;
+			goto release;
 		}
 	}
 
@@ -606,6 +630,15 @@
 	printf("Disconnected\n");
 
 	close(fd);
+	return;
+
+release:
+	memset(&req, 0, sizeof(req));
+	req.dev_id = dev;
+	req.flags = (1 << RFCOMM_HANGUP_NOW);
+	ioctl(ctl, RFCOMMRELEASEDEV, &req);
+
+	close(sk);
 }
 
 static void cmd_watch(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
@@ -694,7 +727,6 @@
 	printf("\n");
 }
 
-
 static struct option main_options[] = {
 	{ "help",	0, 0, 'h' },
 	{ "device",	1, 0, 'i' },
@@ -704,6 +736,7 @@
 	{ "encrypt",	0, 0, 'E' },
 	{ "secure",	0, 0, 'S' },
 	{ "master",	0, 0, 'M' },
+	{ "linger",	1, 0, 'L' },
 	{ 0, 0, 0, 0 }
 };
 
@@ -714,7 +747,7 @@
 
 	bacpy(&bdaddr, BDADDR_ANY);
 
-	while ((opt = getopt_long(argc, argv, "+i:f:rahAESM", main_options, NULL)) != -1) {
+	while ((opt = getopt_long(argc, argv, "+i:f:rahAESML:", main_options, NULL)) != -1) {
 		switch(opt) {
 		case 'i':
 			if (strncmp(optarg, "hci", 3) == 0)
@@ -726,6 +759,7 @@
 		case 'f':
 			rfcomm_config_file = strdup(optarg);
 			break;
+
 		case 'r':
 			rfcomm_raw_tty = 1;
 			break;
@@ -752,6 +786,10 @@
 
 		case 'M':
 			master = 1;
+			break;
+
+		case 'L':
+			linger = atoi(optarg);
 			break;
 
 		default:

Modified: bluez-utils/branches/upstream/current/rfcomm/rfcomm.1
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/rfcomm/rfcomm.1?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/rfcomm/rfcomm.1 (original)
+++ bluez-utils/branches/upstream/current/rfcomm/rfcomm.1 Wed Jul  4 13:37:57 2007
@@ -48,7 +48,7 @@
 .BI -r
 Switch TTY into raw mode (doesn't work with "bind").
 .TP
-.BI -f " [file]"
+.BI -f " <file>"
 Specify alternate config file.
 .TP
 .BI -i " <hciX> | <bdaddr>"
@@ -78,6 +78,9 @@
 .TP
 .BI -M
 Become the master of a piconet
+.TP
+.BI -L " <seconds>"
+Set linger timeout
 .SH COMMANDS
 .TP
 .BI show " <dev>"

Modified: bluez-utils/branches/upstream/current/sdpd/main.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/sdpd/main.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/sdpd/main.c (original)
+++ bluez-utils/branches/upstream/current/sdpd/main.c Wed Jul  4 13:37:57 2007
@@ -68,7 +68,6 @@
 	{ "help",	0, 0, 'h' },
 	{ "nodaemon",	0, 0, 'n' },
 	{ "mtu",	1, 0, 'm' },
-	{ "public",	0, 0, 'p' },
 	{ "master",	0, 0, 'M' },
 	{ 0, 0, 0, 0}
 };
@@ -80,7 +79,7 @@
 	uint32_t flags = SDP_SERVER_COMPAT;
 	int opt, daemonize = 1, debug = 0;
 
-	while ((opt = getopt_long(argc, argv, "ndm:pM", main_options, NULL)) != -1) {
+	while ((opt = getopt_long(argc, argv, "ndm:M", main_options, NULL)) != -1) {
 		switch (opt) {
 		case 'n':
 			daemonize = 0;
@@ -92,10 +91,6 @@
 
 		case 'm':
 			mtu = atoi(optarg);
-			break;
-
-		case 'p':
-			flags |= SDP_SERVER_PUBLIC;
 			break;
 
 		case 'M':

Modified: bluez-utils/branches/upstream/current/sdpd/sdpd.8
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/sdpd/sdpd.8?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/sdpd/sdpd.8 (original)
+++ bluez-utils/branches/upstream/current/sdpd/sdpd.8 Wed Jul  4 13:37:57 2007
@@ -1,4 +1,4 @@
-.\" $Header: /cvsroot/bluez/utils/sdpd/sdpd.8,v 1.3 2007/01/24 06:11:43 holtmann Exp $
+.\" $Header: /cvsroot/bluez/utils/sdpd/sdpd.8,v 1.4 2007/05/22 11:43:30 holtmann Exp $
 .\"
 .\"	transcript compatibility for postscript use.
 .\"
@@ -70,8 +70,6 @@
 Enable debugging output.
 .IP "\fB-m <mtu>\fP" 10
 Set maximum MTU to use on the L2CAP channel.
-.IP "\fB-p\fP" 10
-Register server record in public browse group.
  
 .SH "BUGS" 
 .PP 

Modified: bluez-utils/branches/upstream/current/sdpd/sdpd.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/sdpd/sdpd.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/sdpd/sdpd.h (original)
+++ bluez-utils/branches/upstream/current/sdpd/sdpd.h Wed Jul  4 13:37:57 2007
@@ -44,8 +44,8 @@
 int service_update_req(sdp_req_t *req, sdp_buf_t *rsp);
 int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp);
 
-void register_public_browse_group(int public);
-void register_server_service(int public);
+void register_public_browse_group(void);
+void register_server_service(void);
 void register_device_id(const uint16_t vendor, const uint16_t product,
 						const uint16_t version);
 
@@ -80,7 +80,6 @@
 
 #define SDP_SERVER_COMPAT (1 << 0)
 #define SDP_SERVER_MASTER (1 << 1)
-#define SDP_SERVER_PUBLIC (1 << 2)
 
 int start_sdp_server(uint16_t mtu, const char *did, uint32_t flags);
 void stop_sdp_server(void);

Modified: bluez-utils/branches/upstream/current/sdpd/server.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/sdpd/server.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/sdpd/server.c (original)
+++ bluez-utils/branches/upstream/current/sdpd/server.c Wed Jul  4 13:37:57 2007
@@ -57,7 +57,7 @@
  * l2cap and unix sockets over which discovery and registration clients
  * access us respectively
  */
-static int init_server(uint16_t mtu, int master, int public, int compat)
+static int init_server(uint16_t mtu, int master, int compat)
 {
 	struct l2cap_options opts;
 	struct sockaddr_l2 l2addr;
@@ -65,10 +65,10 @@
 	socklen_t optlen;
 
 	/* Register the public browse group root */
-	register_public_browse_group(public);
+	register_public_browse_group();
 
 	/* Register the SDP server's service record */
-	register_server_service(public);
+	register_server_service();
 
 	/* Create L2CAP socket */
 	l2cap_sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
@@ -104,6 +104,7 @@
 			return -1;
 		}
 
+		opts.omtu = mtu;
 		opts.imtu = mtu;
 
 		if (setsockopt(l2cap_sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
@@ -220,11 +221,10 @@
 {
 	int compat = flags & SDP_SERVER_COMPAT;
 	int master = flags & SDP_SERVER_MASTER;
-	int public = flags & SDP_SERVER_PUBLIC;
 
 	info("Starting SDP server");
 
-	if (init_server(mtu, master, public, compat) < 0) {
+	if (init_server(mtu, master, compat) < 0) {
 		error("Server initialization failed");
 		return -1;
 	}

Modified: bluez-utils/branches/upstream/current/sdpd/service.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/sdpd/service.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/sdpd/service.c (original)
+++ bluez-utils/branches/upstream/current/sdpd/service.c Wed Jul  4 13:37:57 2007
@@ -69,51 +69,27 @@
 	sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d);
 }
 
-static void add_lang_attr(sdp_record_t *r)
-{
-	sdp_lang_attr_t base_lang;
-	sdp_list_t *langs = 0;
-
-	base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
-	// UTF-8 MIBenum (http://www.iana.org/assignments/character-sets)
-	base_lang.encoding = 106;
-	base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
-	langs = sdp_list_append(0, &base_lang);
-	sdp_set_lang_attr(r, langs);
-	sdp_list_free(langs, 0);
-}
-
-void register_public_browse_group(int public)
+void register_public_browse_group(void)
 {
 	sdp_list_t *browselist;
 	uuid_t bgscid, pbgid;
 	sdp_data_t *sdpdata;
 	sdp_record_t *browse = sdp_record_alloc();
 
-	if (public) {
-		browse->handle = sdp_next_handle();
-		if (browse->handle < 0x10000)
-			return;
-	} else
-		browse->handle = SDP_SERVER_RECORD_HANDLE + 1;
+	browse->handle = SDP_SERVER_RECORD_HANDLE + 1;
 
 	sdp_record_add(BDADDR_ANY, browse);
 	sdpdata = sdp_data_alloc(SDP_UINT32, &browse->handle);
 	sdp_attr_add(browse, SDP_ATTR_RECORD_HANDLE, sdpdata);
-
-	add_lang_attr(browse);
-	sdp_set_info_attr(browse, "Public Browse Group Root", "BlueZ",
-					"Root of public browse hierarchy");
 
 	sdp_uuid16_create(&bgscid, BROWSE_GRP_DESC_SVCLASS_ID);
 	browselist = sdp_list_append(0, &bgscid);
 	sdp_set_service_classes(browse, browselist);
 	sdp_list_free(browselist, 0);
 
-	if (public) {
-		sdp_uuid16_create(&pbgid, PUBLIC_BROWSE_GROUP);
-		sdp_set_group_id(browse, pbgid);
-	}
+	sdp_uuid16_create(&pbgid, PUBLIC_BROWSE_GROUP);
+	sdp_attr_add_new(browse, SDP_ATTR_GROUP_ID,
+				SDP_UUID16, &pbgid.value.uuid16);
 }
 
 /*
@@ -122,17 +98,14 @@
  * discovery clients. This method constructs a service record
  * and stores it in the repository
  */
-void register_server_service(int public)
-{
-	int i;
-	sdp_list_t *classIDList, *browseList;
-	sdp_list_t *access_proto = 0;
-	uuid_t l2cap, classID, browseGroupId, sdpSrvUUID;
+void register_server_service(void)
+{
+	sdp_list_t *classIDList;
+	uuid_t classID;
 	void **versions, **versionDTDs;
 	uint8_t dtd;
-	uint16_t version, port;
-	sdp_data_t *pData, *port_data, *version_data;
-	sdp_list_t *pd, *seq;
+	sdp_data_t *pData;
+	int i;
 
 	server = sdp_record_alloc();
 	server->pattern = NULL;
@@ -143,13 +116,6 @@
 	sdp_record_add(BDADDR_ANY, server);
 	sdp_attr_add(server, SDP_ATTR_RECORD_HANDLE,
 				sdp_data_alloc(SDP_UINT32, &server->handle));
-
-	/*
-	 * Add all attributes to service record. (No need to commit since we 
-	 * are the server and this record is already in the database.)
-	 */
-	add_lang_attr(server);
-	sdp_set_info_attr(server, "SDP Server", "BlueZ", "Bluetooth service discovery server");
 
 	sdp_uuid16_create(&classID, SDP_SERVER_SVCLASS_ID);
 	classIDList = sdp_list_append(0, &classID);
@@ -179,33 +145,6 @@
 	free(versionDTDs);
 	sdp_attr_add(server, SDP_ATTR_VERSION_NUM_LIST, pData);
 
-	sdp_uuid16_create(&sdpSrvUUID, SDP_UUID);
-	sdp_set_service_id(server, sdpSrvUUID);
-
-	sdp_uuid16_create(&l2cap, L2CAP_UUID);
-	pd = sdp_list_append(0, &l2cap);
-	port = SDP_PSM;
-	port_data = sdp_data_alloc(SDP_UINT16, &port);
-	pd = sdp_list_append(pd, port_data);
-	version = 1;
-	version_data = sdp_data_alloc(SDP_UINT16, &version);
-	pd = sdp_list_append(pd, version_data);
-	seq = sdp_list_append(0, pd);
-
-	access_proto = sdp_list_append(0, seq);
-	sdp_set_access_protos(server, access_proto);
-	sdp_list_free(access_proto, free);
-	sdp_data_free(port_data);
-	sdp_data_free(version_data);
-	sdp_list_free(pd, 0);
-
-	if (public) {
-		sdp_uuid16_create(&browseGroupId, PUBLIC_BROWSE_GROUP);
-		browseList = sdp_list_append(0, &browseGroupId);
-		sdp_set_browse_groups(server, browseList);
-		sdp_list_free(browseList, 0);
-	}
-
 	update_db_timestamp();
 }
 

Modified: bluez-utils/branches/upstream/current/serial/Makefile.am
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/Makefile.am?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/serial/Makefile.am (original)
+++ bluez-utils/branches/upstream/current/serial/Makefile.am Wed Jul  4 13:37:57 2007
@@ -10,7 +10,9 @@
 
 service_PROGRAMS = bluetoothd-service-serial
 
-bluetoothd_service_serial_SOURCES = main.c manager.h manager.c
+bluetoothd_service_serial_SOURCES = main.c \
+		manager.h manager.c port.h port.c \
+		error.h error.c storage.h storage.c
 
 LDADD = $(top_builddir)/common/libhelper.a \
                 @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@

Modified: bluez-utils/branches/upstream/current/serial/Makefile.in
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/Makefile.in?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/serial/Makefile.in (original)
+++ bluez-utils/branches/upstream/current/serial/Makefile.in Wed Jul  4 13:37:57 2007
@@ -53,9 +53,11 @@
 servicePROGRAMS_INSTALL = $(INSTALL_PROGRAM)
 PROGRAMS = $(service_PROGRAMS)
 am__bluetoothd_service_serial_SOURCES_DIST = main.c manager.h \
-	manager.c
+	manager.c port.h port.c error.h error.c storage.h storage.c
 @SERIALSERVICE_TRUE at am_bluetoothd_service_serial_OBJECTS =  \
- at SERIALSERVICE_TRUE@	main.$(OBJEXT) manager.$(OBJEXT)
+ at SERIALSERVICE_TRUE@	main.$(OBJEXT) manager.$(OBJEXT) \
+ at SERIALSERVICE_TRUE@	port.$(OBJEXT) error.$(OBJEXT) \
+ at SERIALSERVICE_TRUE@	storage.$(OBJEXT)
 bluetoothd_service_serial_OBJECTS =  \
 	$(am_bluetoothd_service_serial_OBJECTS)
 bluetoothd_service_serial_LDADD = $(LDADD)
@@ -258,7 +260,10 @@
 @CONFIGFILES_TRUE@@SERIALSERVICE_TRUE at confdir = $(sysconfdir)/bluetooth
 @CONFIGFILES_TRUE@@SERIALSERVICE_TRUE at conf_DATA = serial.service
 @SERIALSERVICE_TRUE at servicedir = $(libdir)/bluetooth
- at SERIALSERVICE_TRUE@bluetoothd_service_serial_SOURCES = main.c manager.h manager.c
+ at SERIALSERVICE_TRUE@bluetoothd_service_serial_SOURCES = main.c \
+ at SERIALSERVICE_TRUE@		manager.h manager.c port.h port.c \
+ at SERIALSERVICE_TRUE@		error.h error.c storage.h storage.c
+
 @SERIALSERVICE_TRUE at LDADD = $(top_builddir)/common/libhelper.a \
 @SERIALSERVICE_TRUE@                @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
 
@@ -337,8 +342,11 @@
 distclean-compile:
 	-rm -f *.tab.c
 
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/error.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/main.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/manager.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/port.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/storage.Po at am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \

Added: bluez-utils/branches/upstream/current/serial/error.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/error.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/serial/error.c (added)
+++ bluez-utils/branches/upstream/current/serial/error.c Wed Jul  4 13:37:57 2007
@@ -1,0 +1,98 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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 "error.h"
+
+#define SERIAL_ERROR_INTERFACE		"org.bluez.serial.Error"
+
+DBusHandlerResult err_connection_canceled(DBusConnection *conn,
+						DBusMessage *msg)
+{
+	return send_message_and_unref(conn,
+			dbus_message_new_error(msg,
+			SERIAL_ERROR_INTERFACE".ConnectionCanceled",
+			"Connection creation canceled"));
+}
+
+DBusHandlerResult err_connection_failed(DBusConnection *conn,
+				DBusMessage *msg, const char *str)
+{
+	return send_message_and_unref(conn,
+			dbus_message_new_error(msg,
+			SERIAL_ERROR_INTERFACE".ConnectionAttemptFailed", str));
+}
+
+DBusHandlerResult err_connection_in_progress(DBusConnection *conn,
+							DBusMessage *msg)
+{
+	return send_message_and_unref(conn,
+			dbus_message_new_error(msg,
+			SERIAL_ERROR_INTERFACE".ConnectionInProgress",
+			"Connection creation in progress"));
+}
+
+DBusHandlerResult err_connection_not_in_progress(DBusConnection *conn,
+							DBusMessage *msg)
+{
+	return send_message_and_unref(conn,
+			dbus_message_new_error(msg,
+			SERIAL_ERROR_INTERFACE".ConnectionNotInProgress",
+			"Connection creation not in progress"));
+}
+
+DBusHandlerResult err_does_not_exist(DBusConnection *conn,
+				DBusMessage *msg, const char *str)
+{
+	return send_message_and_unref(conn,
+			dbus_message_new_error(msg,
+				SERIAL_ERROR_INTERFACE ".DoesNotExist", str));
+}
+
+DBusHandlerResult err_failed(DBusConnection *conn,
+			DBusMessage *msg, const char *str)
+{
+	return send_message_and_unref(conn,
+			dbus_message_new_error(msg,
+				SERIAL_ERROR_INTERFACE ".Failed", str));
+}
+
+DBusHandlerResult err_invalid_args(DBusConnection *conn,
+				DBusMessage *msg, const char *str)
+{
+	return send_message_and_unref(conn,
+			dbus_message_new_error(msg,
+				SERIAL_ERROR_INTERFACE ".InvalidArguments", str));
+}
+
+DBusHandlerResult err_not_supported(DBusConnection *conn,
+						DBusMessage *msg)
+{
+	return send_message_and_unref(conn,
+			dbus_message_new_error(msg,
+			SERIAL_ERROR_INTERFACE ".NotSupported",
+			"The service is not supported by the remote device"));
+}

Added: bluez-utils/branches/upstream/current/serial/error.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/error.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/serial/error.h (added)
+++ bluez-utils/branches/upstream/current/serial/error.h Wed Jul  4 13:37:57 2007
@@ -1,0 +1,41 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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
+ *
+ */
+
+#include <dbus.h>
+
+DBusHandlerResult err_connection_canceled(DBusConnection *conn,
+						DBusMessage *msg);
+DBusHandlerResult err_connection_failed(DBusConnection *conn,
+				DBusMessage *msg, const char *str);
+DBusHandlerResult err_connection_in_progress(DBusConnection *conn,
+							DBusMessage *msg);
+DBusHandlerResult err_connection_not_in_progress(DBusConnection *conn,
+							DBusMessage *msg);
+DBusHandlerResult err_does_not_exist(DBusConnection *conn,
+				DBusMessage *msg, const char *str);
+DBusHandlerResult err_failed(DBusConnection *conn,
+			DBusMessage *msg, const char *str);
+DBusHandlerResult err_invalid_args(DBusConnection *conn,
+				DBusMessage *msg, const char *str);
+DBusHandlerResult err_not_supported(DBusConnection *conn,
+						DBusMessage *msg);

Modified: bluez-utils/branches/upstream/current/serial/manager.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/manager.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/serial/manager.c (original)
+++ bluez-utils/branches/upstream/current/serial/manager.c Wed Jul  4 13:37:57 2007
@@ -25,6 +25,8 @@
 #include <config.h>
 #endif
 
+#include <ctype.h>
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdint.h>
@@ -46,36 +48,31 @@
 #include "dbus.h"
 #include "dbus-helper.h"
 #include "logging.h"
-
+#include "textfile.h"
+
+#include "error.h"
+#include "port.h"
+#include "storage.h"
 #include "manager.h"
 
-#define SERIAL_MANAGER_PATH		"/org/bluez/serial"
-#define SERIAL_MANAGER_INTERFACE	"org.bluez.serial.Manager"
-#define SERIAL_ERROR_INTERFACE		"org.bluez.serial.Error"
-
 #define BASE_UUID			"00000000-0000-1000-8000-00805F9B34FB"
 
 /* Waiting for udev to create the device node */
-#define MAX_OPEN_TRIES  5
-#define OPEN_WAIT       300  /* ms */
-
-struct rfcomm_node {
-	int16_t         id;	/* RFCOMM device id */
-	char		*name;	/* RFCOMM device name */
-	DBusConnection  *conn;	/* for name listener handling */
-	char		*owner; /* Bus name */
-	GIOChannel	*io;	/* Connected node IO Channel */
-	guint		io_id;	/* IO Channel ID  */
-};
+#define MAX_OPEN_TRIES 		5
+#define OPEN_WAIT		300	/* ms */
 
 struct pending_connect {
 	DBusConnection	*conn;
 	DBusMessage	*msg;
+	DBusPendingCall *pcall;		/* Pending get handles/records */
 	char		*bda;		/* Destination address  */
 	char		*adapter_path;	/* Adapter D-Bus path   */
 	char		*pattern;	/* Connection request pattern */
 	bdaddr_t	src;
 	uint8_t		channel;
+	guint		io_id;		/* GIOChannel watch id */
+	GIOChannel	*io;		/* GIOChannel for RFCOMM connect */
+	char		*dev;		/* tty device name */
 	int		id;		/* RFCOMM device id */
 	int		ntries;		/* Open attempts */
 	int 		canceled;	/* Operation canceled */
@@ -101,7 +98,6 @@
 };
 
 static DBusConnection *connection = NULL;
-static GSList *connected_nodes = NULL;
 static GSList *pending_connects = NULL;
 static int rfcomm_ctl = -1;
 
@@ -117,35 +113,17 @@
 		g_free(pc->pattern);
 	if (pc->adapter_path)
 		g_free(pc->adapter_path);
+	if (pc->pcall)
+		dbus_pending_call_unref(pc->pcall);
+	if (pc->dev)
+		g_free(pc->dev);
+	if (pc->io_id > 0)
+		g_source_remove(pc->io_id);
+	if (pc->io) {
+		g_io_channel_close(pc->io);
+		g_io_channel_unref(pc->io);
+	}
 	g_free(pc);
-}
-
-static void rfcomm_node_free(struct rfcomm_node *node)
-{
-	if (node->name)
-		g_free(node->name);
-	if (node->conn)
-		dbus_connection_unref(node->conn);
-	if (node->owner)
-		g_free(node->owner);
-	if (node->io) {
-		g_source_remove(node->io_id);
-		g_io_channel_unref(node->io);
-	}
-	g_free(node);
-}
-
-static struct rfcomm_node *find_node_by_name(const char *name)
-{
-	GSList *l;
-
-	for (l = connected_nodes; l != NULL; l = l->next) {
-		struct rfcomm_node *node = l->data;
-		if (!strcmp(node->name, name))
-			return node;
-	}
-
-	return NULL;
 }
 
 static struct pending_connect *find_pending_connect_by_pattern(const char *bda,
@@ -164,6 +142,119 @@
 	return NULL;
 }
 
+static void transaction_owner_exited(const char *name, void *data)
+{
+	GSList *l, *tmp = NULL;
+	debug("transaction owner %s exited", name);
+
+	/* Clean all pending calls that belongs to this owner */
+	for (l = pending_connects; l != NULL; l = l->next) {
+		struct pending_connect *pc = l->data;
+		if (strcmp(name, dbus_message_get_sender(pc->msg)) != 0) {
+			tmp = g_slist_append(tmp, pc);
+			continue;
+		}
+
+		if (pc->pcall)
+			dbus_pending_call_cancel(pc->pcall);
+
+		if (pc->id >= 0)
+			rfcomm_release(pc->id);
+
+		pending_connect_free(pc);
+	}
+
+	g_slist_free(pending_connects);
+	pending_connects = tmp;
+}
+
+static void pending_connect_remove(struct pending_connect *pc)
+{
+	/* Remove the connection request owner */
+	name_listener_remove(pc->conn, dbus_message_get_sender(pc->msg),
+				(name_cb_t) transaction_owner_exited, NULL);
+
+	pending_connects = g_slist_remove(pending_connects, pc);
+	pending_connect_free(pc);
+}
+
+static void open_notify(int fd, int err, struct pending_connect *pc)
+{
+	DBusMessage *reply;
+	bdaddr_t dst;
+
+	if (err) {
+		/* Max tries exceeded */
+		rfcomm_release(pc->id);
+		err_connection_failed(pc->conn, pc->msg, strerror(err));
+		return;
+	}
+
+	if (pc->canceled) {
+		rfcomm_release(pc->id);
+		err_connection_canceled(pc->conn, pc->msg);
+		return;
+	}
+
+	/* Reply to the requestor */
+	reply = dbus_message_new_method_return(pc->msg);
+	dbus_message_append_args(reply,
+			DBUS_TYPE_STRING, &pc->dev,
+			DBUS_TYPE_INVALID);
+	send_message_and_unref(pc->conn, reply);
+
+	/* Send the D-Bus signal */
+	dbus_connection_emit_signal(pc->conn, SERIAL_MANAGER_PATH,
+			SERIAL_MANAGER_INTERFACE, "ServiceConnected" ,
+			DBUS_TYPE_STRING, &pc->dev,
+			DBUS_TYPE_INVALID);
+
+	str2ba(pc->bda, &dst);
+
+	/* Add the RFCOMM connection listener */
+	port_add_listener(pc->conn, pc->id, &dst, fd,
+			pc->dev, dbus_message_get_sender(pc->msg));
+}
+
+static gboolean open_continue(struct pending_connect *pc)
+{
+	int fd;
+
+	if (!g_slist_find(pending_connects, pc))
+		return FALSE; /* Owner exited */
+
+	fd = open(pc->dev, O_RDONLY | O_NOCTTY);
+	if (fd < 0) {
+		int err = errno;
+		error("Could not open %s: %s (%d)",
+				pc->dev, strerror(err), err);
+		if (++pc->ntries >= MAX_OPEN_TRIES) {
+			/* Reporting error */
+			open_notify(fd, err, pc);
+			pending_connect_remove(pc);
+			return FALSE;
+		}
+		return TRUE;
+	}
+	/* Connection succeeded */
+	open_notify(fd, 0, pc);
+	pending_connect_remove(pc);
+	return FALSE;
+}
+
+int port_open(struct pending_connect *pc)
+{
+	int fd;
+
+	fd = open(pc->dev, O_RDONLY | O_NOCTTY);
+	if (fd < 0) {
+		g_timeout_add(OPEN_WAIT, (GSourceFunc) open_continue, pc);
+		return -EINPROGRESS;
+	}
+
+	return fd;
+}
+
 static uint16_t str2class(const char *pattern)
 {
 	int i;
@@ -176,98 +267,19 @@
 	return 0;
 }
 
-static DBusHandlerResult err_connection_failed(DBusConnection *conn,
-					DBusMessage *msg, const char *str)
-{
-	return send_message_and_unref(conn,
-			dbus_message_new_error(msg,
-			SERIAL_ERROR_INTERFACE".ConnectionAttemptFailed", str));
-}
-
-static DBusHandlerResult err_connection_canceled(DBusConnection *conn,
-							DBusMessage *msg)
-{
-	return send_message_and_unref(conn,
-			dbus_message_new_error(msg,
-			SERIAL_ERROR_INTERFACE".ConnectionCanceled",
-			"Connection creation canceled"));
-}
-
-static DBusHandlerResult err_connection_in_progress(DBusConnection *conn,
-							DBusMessage *msg)
-{
-	return send_message_and_unref(conn,
-			dbus_message_new_error(msg,
-			SERIAL_ERROR_INTERFACE".ConnectionInProgress",
-			"Connection creation in progress"));
-}
-
-static DBusHandlerResult err_connection_not_in_progress(DBusConnection *conn,
-							DBusMessage *msg)
-{
-	return send_message_and_unref(conn,
-			dbus_message_new_error(msg,
-			SERIAL_ERROR_INTERFACE".ConnectionNotInProgress",
-			"Connection creation not in progress"));
-}
-
-static DBusHandlerResult err_does_not_exist(DBusConnection *conn,
-					DBusMessage *msg, const char *str)
-{
-	return send_message_and_unref(conn,
-			dbus_message_new_error(msg,
-				SERIAL_ERROR_INTERFACE ".DoesNotExist", str));
-}
-
-static DBusHandlerResult err_failed(DBusConnection *conn,
-				DBusMessage *msg, const char *str)
-{
-	return send_message_and_unref(conn,
-			dbus_message_new_error(msg,
-				SERIAL_ERROR_INTERFACE ".Failed", str));
-}
-
-static DBusHandlerResult err_invalid_args(DBusConnection *conn,
-					DBusMessage *msg, const char *str)
-{
-	return send_message_and_unref(conn,
-			dbus_message_new_error(msg,
-				SERIAL_ERROR_INTERFACE ".InvalidArguments", str));
-}
-
-static DBusHandlerResult err_not_authorized(DBusConnection *conn,
-							DBusMessage *msg)
-{
-	return send_message_and_unref(conn,
-			dbus_message_new_error(msg,
-			SERIAL_ERROR_INTERFACE ".NotAuthorized",
-			"Owner not allowed"));
-}
-
-static DBusHandlerResult err_not_supported(DBusConnection *conn,
-							DBusMessage *msg)
-{
-	return send_message_and_unref(conn,
-			dbus_message_new_error(msg,
-			SERIAL_ERROR_INTERFACE ".NotSupported",
-			"The service is not supported by the remote device"));
-}
-
-static int rfcomm_release(int16_t id)
+int rfcomm_release(int16_t id)
 {
 	struct rfcomm_dev_req req;
 
 	memset(&req, 0, sizeof(req));
 	req.dev_id = id;
 
-#if 0
 	/*
 	 * We are hitting a kernel bug inside RFCOMM code when
 	 * RFCOMM_HANGUP_NOW bit is set on request's flags passed to
 	 * ioctl(RFCOMMRELEASEDEV)!
 	 */
 	req.flags = (1 << RFCOMM_HANGUP_NOW);
-#endif
 
 	if (ioctl(rfcomm_ctl, RFCOMMRELEASEDEV, &req) < 0) {
 		int err = errno;
@@ -279,168 +291,62 @@
 	return 0;
 }
 
-static void connect_service_exited(const char *name, struct rfcomm_node *node)
-{
-	debug("Connect requestor %s exited. Releasing %s node",
-						name, node->name);
-
-	rfcomm_release(node->id);
-
-	dbus_connection_emit_signal(node->conn, SERIAL_MANAGER_PATH,
-			SERIAL_MANAGER_INTERFACE, "ServiceDisconnected" ,
-			DBUS_TYPE_STRING, &node->name,
-			DBUS_TYPE_INVALID); 
-
-	connected_nodes = g_slist_remove(connected_nodes, node);
-	rfcomm_node_free(node);
-} 
-
-static gboolean rfcomm_disconnect_cb(GIOChannel *io,
-		GIOCondition cond, struct rfcomm_node *node) 
-{
-	debug("RFCOMM node %s was disconnected", node->name);
-
-	if (cond & (G_IO_ERR | G_IO_HUP))
-		g_io_channel_close(io);
-
-	name_listener_remove(node->conn, node->owner,
-			(name_cb_t) connect_service_exited, node);
-
-	dbus_connection_emit_signal(node->conn, SERIAL_MANAGER_PATH,
-			SERIAL_MANAGER_INTERFACE, "ServiceDisconnected" ,
-			DBUS_TYPE_STRING, &node->name,
-			DBUS_TYPE_INVALID); 
-
-	connected_nodes = g_slist_remove(connected_nodes, node);
-	rfcomm_node_free(node);
-
-	return FALSE;
-}
-
-static int add_rfcomm_node(GIOChannel *io, int id, const char *name,
-				DBusConnection *conn, const char *owner)
-{
-	struct rfcomm_node *node;
-
-	node = g_new0(struct rfcomm_node, 1);
-	node->id	= id;
-	node->name	= g_strdup(name);
-	node->conn	= dbus_connection_ref(conn);
-	node->owner	= g_strdup(owner);
-	node->io	= io;
-
-	node->io_id = g_io_add_watch(io, G_IO_ERR | G_IO_NVAL | G_IO_HUP,
-					(GIOFunc) rfcomm_disconnect_cb, node);
-
-	connected_nodes = g_slist_append(connected_nodes, node);
-
-	return name_listener_add(node->conn, owner,
-			(name_cb_t) connect_service_exited, node);
-}
-
-static gboolean rfcomm_connect_cb_continue(struct pending_connect *pc)
-{
-	const char *owner = dbus_message_get_sender(pc->msg);
-	DBusMessage *reply;
-	char node_name[16];
-	const char *pname = node_name;
-	int fd;
-
-	if (pc->canceled) {
-		rfcomm_release(pc->id);
-		err_connection_canceled(pc->conn, pc->msg);
-		goto fail;
-	}
-
-	/* Check if the caller is still present */
-	if (!dbus_bus_name_has_owner(pc->conn, owner, NULL)) {
-		error("Connect requestor %s exited", owner);
-		rfcomm_release(pc->id);
-		goto fail;
-	}
-
-	snprintf(node_name, sizeof(node_name), "/dev/rfcomm%d", pc->id);
-	fd = open(node_name, O_RDONLY | O_NOCTTY);
-	if (fd < 0) {
+static int rfcomm_bind(bdaddr_t *src, bdaddr_t *dst, int16_t dev_id, uint8_t ch)
+{
+	struct rfcomm_dev_req req;
+	int id;
+
+	memset(&req, 0, sizeof(req));
+	req.dev_id = dev_id;
+	req.flags = 0;
+	bacpy(&req.src, src);
+	bacpy(&req.dst, dst);
+	req.channel = ch;
+
+	id = ioctl(rfcomm_ctl, RFCOMMCREATEDEV, &req);
+	if (id < 0) {
 		int err = errno;
-		error("Could not open %s: %s (%d)",
-				node_name, strerror(err), err);
-		if (++pc->ntries >= MAX_OPEN_TRIES) {
-			rfcomm_release(pc->id);
-			err_connection_failed(pc->conn, pc->msg, strerror(err));
-			goto fail;
-		}
-		return TRUE;
-	}
-
-	add_rfcomm_node(g_io_channel_unix_new(fd), pc->id,
-				node_name, pc->conn, owner);
-
-	/* Reply to the requestor */
-	reply = dbus_message_new_method_return(pc->msg);
-	dbus_message_append_args(reply,
-			DBUS_TYPE_STRING, &pname,
-			DBUS_TYPE_INVALID);
-	send_message_and_unref(pc->conn, reply);
-
-	/* Send the D-Bus signal */
-	dbus_connection_emit_signal(pc->conn, SERIAL_MANAGER_PATH,
-			SERIAL_MANAGER_INTERFACE, "ServiceConnected" ,
-			DBUS_TYPE_STRING, &pname,
-			DBUS_TYPE_INVALID); 
-
-fail:
-	pending_connects = g_slist_remove(pending_connects, pc);
-	pending_connect_free(pc);
-
-	return FALSE;
+		error("RFCOMMCREATEDEV failed: %s (%d)", strerror(err), err);
+		return -err;
+	}
+
+	return id;
 }
 
 static gboolean rfcomm_connect_cb(GIOChannel *chan,
 		GIOCondition cond, struct pending_connect *pc)
 {
-	DBusMessage *reply;
-	char node_name[16];
-	const char *pname = node_name;
 	struct rfcomm_dev_req req;
-	int sk, err, fd, close_chan = 1;
+	int sk, err, fd, ret;
+	socklen_t len;
 
 	if (pc->canceled) {
 		err_connection_canceled(pc->conn, pc->msg);
 		goto fail;
 	}
 
+	if (cond & G_IO_NVAL) {
+		/* Avoid close invalid file descriptor */
+		g_io_channel_unref(pc->io);
+		pc->io = NULL;
+		err_connection_canceled(pc->conn, pc->msg);
+		goto fail;
+	}
+
 	sk = g_io_channel_unix_get_fd(chan);
-
-	if (cond & G_IO_NVAL) {
-		close_chan = 0;
-		err_connection_failed(pc->conn, pc->msg,
-				"File descriptor is not open");
-		goto fail;
-	}
-
-	if (cond & (G_IO_ERR | G_IO_HUP)) {
-		socklen_t len;
-		int ret;
-
-		len = sizeof(ret);
-		if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {
-			err = errno;
-			error("getsockopt(SO_ERROR): %s (%d)",
-						strerror(err), err);
-			err_connection_failed(pc->conn,
-					pc->msg, strerror(err));
-			goto fail;
-		}
-
-		if (ret != 0) {
-			error("connect(): %s (%d)", strerror(ret), ret);
-			err_connection_failed(pc->conn, pc->msg, strerror(ret));
-			goto fail;
-		}
-
-		error("Hangup on rfcomm socket");
-		err_connection_canceled(pc->conn, pc->msg);
+	len = sizeof(ret);
+	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {
+		err = errno;
+		error("getsockopt(SO_ERROR): %s (%d)",
+				strerror(err), err);
+		err_connection_failed(pc->conn,
+				pc->msg, strerror(err));
+		goto fail;
+	}
+
+	if (ret != 0) {
+		error("connect(): %s (%d)", strerror(ret), ret);
+		err_connection_failed(pc->conn, pc->msg, strerror(ret));
 		goto fail;
 	}
 
@@ -460,49 +366,25 @@
 		err_connection_failed(pc->conn, pc->msg, strerror(err));
 		goto fail;
 	}
-
-
-	snprintf(node_name, sizeof(node_name), "/dev/rfcomm%d", pc->id);
-
-	fd = open(node_name, O_RDONLY | O_NOCTTY);
-	if (fd < 0) {
-		g_timeout_add(OPEN_WAIT,
-			(GSourceFunc) rfcomm_connect_cb_continue, pc);
-		g_io_channel_close(chan);
+	pc->dev	= g_new0(char, 16);
+	snprintf(pc->dev, 16, "/dev/rfcomm%d", pc->id);
+
+	/* Addressing connect port */
+	fd = port_open(pc);
+	if (fd < 0)
+		/* Open in progress: Wait the callback */
 		return FALSE;
-	}
-
-	add_rfcomm_node(g_io_channel_unix_new(fd), pc->id, node_name,
-				pc->conn, dbus_message_get_sender(pc->msg));
-
-	/* Reply to the requestor */
-	reply = dbus_message_new_method_return(pc->msg);
-	dbus_message_append_args(reply,
-			DBUS_TYPE_STRING, &pname,
-			DBUS_TYPE_INVALID);
-	send_message_and_unref(pc->conn, reply);
-
-	/* Send the D-Bus signal */
-	dbus_connection_emit_signal(pc->conn, SERIAL_MANAGER_PATH,
-			SERIAL_MANAGER_INTERFACE, "ServiceConnected" ,
-			DBUS_TYPE_STRING, &pname,
-			DBUS_TYPE_INVALID); 
-
+
+	open_notify(fd, 0, pc);
 fail:
-	pending_connects = g_slist_remove(pending_connects, pc);
-	pending_connect_free(pc);
-
-	if (close_chan)
-		g_io_channel_close(chan);
-
+	pending_connect_remove(pc);
 	return FALSE;
 }
 
 static int rfcomm_connect(struct pending_connect *pc)
 {
 	struct sockaddr_rc addr;
-	GIOChannel *io;
-	int sk, err = 0;
+	int sk, err;
 
 	sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
 	if (sk < 0)
@@ -514,13 +396,12 @@
 	addr.rc_channel	= 0;
 
 	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0)
-		return -errno;
+		goto fail;
 
 	if (set_nonblocking(sk) < 0)
-		return -errno;
-
-	io = g_io_channel_unix_new(sk);
-
+		goto fail;
+
+	pc->io = g_io_channel_unix_new(sk);
 	addr.rc_family	= AF_BLUETOOTH;
 	str2ba(pc->bda, &addr.rc_bdaddr);
 	addr.rc_channel	= pc->channel;
@@ -528,20 +409,26 @@
 	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 		/* BlueZ returns EAGAIN eventhough it should return EINPROGRESS */
 		if (!(errno == EAGAIN || errno == EINPROGRESS)) {
-			err = errno;
-			error("connect() failed: %s (%d)", strerror(err), err);
+			error("connect() failed: %s (%d)",
+					strerror(errno), errno);
 			goto fail;
 		}
 
 		debug("Connect in progress");
-		g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_NVAL | G_IO_HUP,
-						(GIOFunc) rfcomm_connect_cb, pc);
+		pc->io_id = g_io_add_watch(pc->io,
+				G_IO_OUT | G_IO_ERR | G_IO_NVAL | G_IO_HUP,
+				(GIOFunc) rfcomm_connect_cb, pc);
 	} else {
 		debug("Connect succeeded with first try");
-		(void) rfcomm_connect_cb(io, G_IO_OUT, pc);
-	}
+		(void) rfcomm_connect_cb(pc->io, G_IO_OUT, pc);
+	}
+
+	return 0;
 fail:
-	g_io_channel_unref(io);
+	err = errno;
+	close(sk);
+	errno = err;
+
 	return -err;
 }
 
@@ -549,7 +436,7 @@
 {
 	struct pending_connect *pc = data;
 	DBusMessage *reply = dbus_pending_call_steal_reply(call);
-	sdp_record_t *rec;
+	sdp_record_t *rec = NULL;
 	const uint8_t *rec_bin;
 	sdp_list_t *protos;
 	DBusError derr;
@@ -597,7 +484,6 @@
 	}
 
 	if (len != scanned || (sdp_get_access_protos(rec, &protos) < 0)) {
-		sdp_record_free(rec);
 		err_not_supported(pc->conn, pc->msg);
 		goto fail;
 	}
@@ -606,35 +492,76 @@
 	sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
 	sdp_list_free(protos, NULL);
 
-	sdp_record_free(rec);
-
 	if (ch < 1 || ch > 30) {
 		error("Channel out of range: %d", ch);
 		err_not_supported(pc->conn, pc->msg);
 		goto fail;
 	}
-
-	pc->channel = ch;
-	err = rfcomm_connect(pc);
-	if (err < 0) {
-		error("RFCOMM connection failed");
-		err_connection_failed(pc->conn, pc->msg, strerror(-err));
-		goto fail;
-	}
-
+	if (dbus_message_has_member(pc->msg, "CreatePort")) {
+		char path[MAX_PATH_LENGTH], port_name[16];
+		const char *ppath = path;
+		sdp_data_t *d;
+		char *svcname = NULL;
+		DBusMessage *reply;
+		bdaddr_t dst;
+
+		str2ba(pc->bda, &dst);
+		err = rfcomm_bind(&pc->src, &dst, -1, ch);
+		if (err < 0) {
+			err_failed(pc->conn, pc->msg, strerror(-err));
+			goto fail;
+		}
+		snprintf(port_name, sizeof(port_name), "/dev/rfcomm%d", err);
+
+		d = sdp_data_get(rec, SDP_ATTR_SVCNAME_PRIMARY);
+		if (d) {
+			svcname = g_new0(char, d->unitSize);
+			snprintf(svcname, d->unitSize, "%.*s",
+					d->unitSize, d->val.str);
+		}
+
+		port_store(&pc->src, &dst, err, ch, svcname);
+		if (svcname)
+			g_free(svcname);
+
+		port_register(pc->conn, err, &dst, port_name, path);
+
+		reply = dbus_message_new_method_return(pc->msg);
+		dbus_message_append_args(reply,
+				DBUS_TYPE_STRING, &ppath,
+				DBUS_TYPE_INVALID);
+		send_message_and_unref(pc->conn, reply);
+
+		dbus_connection_emit_signal(pc->conn, SERIAL_MANAGER_PATH,
+				SERIAL_MANAGER_INTERFACE, "PortCreated" ,
+				DBUS_TYPE_STRING, &ppath,
+				DBUS_TYPE_INVALID);
+	} else {
+		/* ConnectService */
+		pc->channel = ch;
+		err = rfcomm_connect(pc);
+		if (err < 0) {
+			error("RFCOMM connection failed");
+			err_connection_failed(pc->conn, pc->msg, strerror(-err));
+			goto fail;
+		}
+
+		/* Wait the connect callback */
+		goto done;
+	}
+
+fail:
+	pending_connect_remove(pc);
+done:
+	if (rec)
+		sdp_record_free(rec);
 	dbus_message_unref(reply);
-	return;
-fail:
-	dbus_message_unref(reply);
-	pending_connects = g_slist_remove(pending_connects, pc);
-	pending_connect_free(pc);
 }
 
 static int get_record(struct pending_connect *pc, uint32_t handle,
 					DBusPendingCallNotifyFunction cb)
 {
 	DBusMessage *msg;
-	DBusPendingCall *pending;
 
 	msg = dbus_message_new_method_call("org.bluez", pc->adapter_path,
 			"org.bluez.Adapter", "GetRemoteServiceRecord");
@@ -646,14 +573,13 @@
 			DBUS_TYPE_UINT32, &handle,
 			DBUS_TYPE_INVALID);
 
-	if (dbus_connection_send_with_reply(pc->conn, msg, &pending, -1) == FALSE) {
+	if (dbus_connection_send_with_reply(pc->conn, msg, &pc->pcall, -1) == FALSE) {
 		error("Can't send D-Bus message.");
 		return -1;
 	}
 
-	dbus_pending_call_set_notify(pending, cb, pc, NULL);
+	dbus_pending_call_set_notify(pc->pcall, cb, pc, NULL);
 	dbus_message_unref(msg);
-	dbus_pending_call_unref(pending);
 
 	return 0;
 }
@@ -708,15 +634,13 @@
 	return;
 fail:
 	dbus_message_unref(reply);
-	pending_connects = g_slist_remove(pending_connects, pc);
-	pending_connect_free(pc);
+	pending_connect_remove(pc);
 }
 
 static int get_handles(struct pending_connect *pc, const char *uuid,
 					DBusPendingCallNotifyFunction cb)
 {
 	DBusMessage *msg;
-	DBusPendingCall *pending;
 
 	msg = dbus_message_new_method_call("org.bluez", pc->adapter_path,
 				"org.bluez.Adapter", "GetRemoteServiceHandles");
@@ -728,30 +652,72 @@
 			DBUS_TYPE_STRING, &uuid,
 			DBUS_TYPE_INVALID);
 
-	if (dbus_connection_send_with_reply(pc->conn, msg, &pending, -1) == FALSE) {
+	if (dbus_connection_send_with_reply(pc->conn, msg, &pc->pcall, -1) == FALSE) {
 		error("Can't send D-Bus message.");
 		return -1;
 	}
 
-	dbus_pending_call_set_notify(pending, cb, pc, NULL);
+	dbus_pending_call_set_notify(pc->pcall, cb, pc, NULL);
 	dbus_message_unref(msg);
-	dbus_pending_call_unref(pending);
 
 	return 0;
 }
 
-static DBusHandlerResult connect_service(DBusConnection *conn,
-					DBusMessage *msg, void *data)
-{
-	struct pending_connect *pending, *pc;
-	DBusError derr;
-	bdaddr_t src;
-	const char *bda, *pattern;
+static int pattern2uuid128(const char *pattern, char *uuid, size_t size)
+{
+	uint16_t cls;
+
+	/* Friendly name */
+	cls = str2class(pattern);
+	if (cls) {
+		uuid_t uuid16, uuid128;
+
+		sdp_uuid16_create(&uuid16, cls);
+		sdp_uuid16_to_uuid128(&uuid128, &uuid16);
+		sdp_uuid2strn(&uuid128, uuid, size);
+		return 0;
+	}
+
+	/* UUID 128*/
+	if ((strlen(pattern) == 36) &&
+		(strncasecmp(BASE_UUID, pattern, 3) == 0) &&
+		(strncasecmp(BASE_UUID + 8, pattern + 8, 28) == 0)) {
+
+		strncpy(uuid, pattern, size);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int pattern2long(const char *pattern, long *pval)
+{
 	char *endptr;
 	long val;
+
+	errno = 0;
+	val = strtol(pattern, &endptr, 0);
+	if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
+			(errno != 0 && val == 0) || (pattern == endptr)) {
+		return -EINVAL;
+	}
+
+	*pval = val;
+
+	return 0;
+}
+
+static DBusHandlerResult create_port(DBusConnection *conn,
+				DBusMessage *msg, void *data)
+{
+	struct pending_connect *pending, *pc;
+	DBusMessage *reply;
+	DBusError derr;
+	bdaddr_t src, dst;
+	char path[MAX_PATH_LENGTH], port_name[16], uuid[37];
+	const char *bda, *pattern, *ppath = path;
+	long val;
 	int dev_id, err;
-	uint16_t cls;
-	char tmp[37];
 
 	dbus_error_init(&derr);
 	if (!dbus_message_get_args(msg, &derr,
@@ -776,56 +742,30 @@
 	pc->conn = dbus_connection_ref(conn);
 	pc->msg = dbus_message_ref(msg);
 	pc->bda = g_strdup(bda);
+	pc->id = -1;
 	pc->pattern = g_strdup(pattern);
 	pc->adapter_path = g_malloc0(16);
 	snprintf(pc->adapter_path, 16, "/org/bluez/hci%d", dev_id);
 
-	memset(tmp, 0, sizeof(tmp));
-
-	/* Friendly name */
-	cls = str2class(pattern);
-	if (cls) {
-		uuid_t uuid16, uuid128;
-
-		sdp_uuid16_create(&uuid16, cls);
-		sdp_uuid16_to_uuid128(&uuid128, &uuid16);
-		sdp_uuid2strn(&uuid128, tmp, sizeof(tmp));
-
-		if (get_handles(pc, tmp, handles_reply) < 0) {
+	memset(uuid, 0, sizeof(uuid));
+
+	/* Friendly name or uuid128 */
+	if (pattern2uuid128(pattern, uuid, sizeof(uuid)) == 0) {
+		if (get_handles(pc, uuid, handles_reply) < 0) {
 			pending_connect_free(pc);
 			return err_not_supported(conn, msg);
 		}
 		pending_connects = g_slist_append(pending_connects, pc);
+		name_listener_add(conn, dbus_message_get_sender(msg),
+				(name_cb_t) transaction_owner_exited, NULL);
 		return DBUS_HANDLER_RESULT_HANDLED;
 	}
 
-	/* UUID 128*/
-	if (strlen(pattern) == 36) {
-		strcpy(tmp, pattern);
-		tmp[4] = '0';
-		tmp[5] = '0';
-		tmp[6] = '0';
-		tmp[7] = '0';
-
-		if (strcasecmp(BASE_UUID, tmp) != 0) {
-			pending_connect_free(pc);
-			return err_invalid_args(conn, msg, "invalid UUID");
-		}
-
-		if (get_handles(pc, pattern, handles_reply) < 0) {
-			pending_connect_free(pc);
-			return err_not_supported(conn, msg);
-		}
-		pending_connects = g_slist_append(pending_connects, pc);
-		return DBUS_HANDLER_RESULT_HANDLED;
-	}
-
-	errno = 0;
-	val = strtol(pattern, &endptr, 0);
-	if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
-			(errno != 0 && val == 0) || (pattern == endptr)) {
+	/* Record handle or channel */
+	err = pattern2long(pattern, &val);
+	if (err < 0) {
 		pending_connect_free(pc);
-		return err_invalid_args(conn, msg, "Invalid pattern");
+		return err_invalid_args(conn, msg, "invalid pattern");
 	}
 
 	/* Record handle: starts at 0x10000 */
@@ -841,7 +781,188 @@
 			return err_not_supported(conn, msg);
 		}
 		pending_connects = g_slist_append(pending_connects, pc);
+		name_listener_add(conn, dbus_message_get_sender(msg),
+				(name_cb_t) transaction_owner_exited, NULL);
 		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	pending_connect_free(pc);
+	/* RFCOMM Channel range: 1 - 30 */
+	if (val < 1 || val > 30)
+		return err_invalid_args(conn, msg,
+				"invalid RFCOMM channel");
+
+	str2ba(bda, &dst);
+	err = rfcomm_bind(&src, &dst, -1, val);
+	if (err < 0)
+		return err_failed(conn, msg, strerror(-err));
+
+	snprintf(port_name, sizeof(port_name), "/dev/rfcomm%d", err);
+	port_store(&src, &dst, err, val, NULL);
+	port_register(conn, err, &dst, port_name, path);
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+	dbus_message_append_args(reply,
+			DBUS_TYPE_STRING, &ppath,
+			DBUS_TYPE_INVALID);
+	send_message_and_unref(conn, reply);
+
+	dbus_connection_emit_signal(conn, SERIAL_MANAGER_PATH,
+			SERIAL_MANAGER_INTERFACE, "PortCreated" ,
+			DBUS_TYPE_STRING, &ppath,
+			DBUS_TYPE_INVALID);
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult list_ports(DBusConnection *conn,
+				DBusMessage *msg, void *data)
+{
+	DBusMessage *reply;
+	DBusMessageIter iter, iter_array;
+	char **dev;
+	int i;
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	dbus_message_iter_init_append(reply, &iter);
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_TYPE_STRING_AS_STRING, &iter_array);
+
+	if (!dbus_connection_list_registered(conn, SERIAL_MANAGER_PATH, &dev))
+		goto done;
+
+	for (i = 0; dev[i]; i++) {
+		char dev_path[MAX_PATH_LENGTH];
+		const char *ppath = dev_path;
+
+		snprintf(dev_path, sizeof(dev_path), "%s/%s",
+				SERIAL_MANAGER_PATH, dev[i]);
+		dbus_message_iter_append_basic(&iter_array,
+					DBUS_TYPE_STRING, &ppath);
+	}
+
+	dbus_free_string_array(dev);
+done:
+	dbus_message_iter_close_container(&iter, &iter_array);
+
+	return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult remove_port(DBusConnection *conn,
+				DBusMessage *msg, void *data)
+{
+	struct rfcomm_dev_info di;
+	DBusError derr;
+	const char *path;
+	int16_t id;
+
+	dbus_error_init(&derr);
+	if (!dbus_message_get_args(msg, &derr,
+				DBUS_TYPE_STRING, &path,
+				DBUS_TYPE_INVALID)) {
+		err_invalid_args(conn, msg, derr.message);
+		dbus_error_free(&derr);
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	if (sscanf(path, SERIAL_MANAGER_PATH"/rfcomm%hd", &id) != 1)
+		return err_does_not_exist(conn, msg, "Invalid RFCOMM node");
+
+	di.id = id;
+	if (ioctl(rfcomm_ctl, RFCOMMGETDEVINFO, &di) < 0)
+		return err_does_not_exist(conn, msg, "Invalid RFCOMM node");
+	port_delete(&di.src, &di.dst, id);
+
+	if (port_unregister(path) < 0)
+		return err_does_not_exist(conn, msg, "Invalid RFCOMM node");
+
+	send_message_and_unref(conn,
+			dbus_message_new_method_return(msg)); 
+
+	dbus_connection_emit_signal(conn, SERIAL_MANAGER_PATH,
+			SERIAL_MANAGER_INTERFACE, "PortRemoved" ,
+			DBUS_TYPE_STRING, &path,
+			DBUS_TYPE_INVALID);
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult connect_service(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct pending_connect *pending, *pc;
+	DBusError derr;
+	bdaddr_t src;
+	const char *bda, *pattern;
+	long val;
+	int dev_id, err;
+	char uuid[37];
+
+	dbus_error_init(&derr);
+	if (!dbus_message_get_args(msg, &derr,
+				DBUS_TYPE_STRING, &bda,
+				DBUS_TYPE_STRING, &pattern,
+				DBUS_TYPE_INVALID)) {
+		err_invalid_args(conn, msg, derr.message);
+		dbus_error_free(&derr);
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	pending = find_pending_connect_by_pattern(bda, pattern);
+	if (pending)
+		return err_connection_in_progress(conn, msg);
+
+	dev_id = hci_get_route(NULL);
+	if ((dev_id < 0) ||  (hci_devba(dev_id, &src) < 0))
+		return err_failed(conn, msg, "Adapter not available");
+
+	pc = g_new0(struct pending_connect, 1);
+	bacpy(&pc->src, &src);
+	pc->conn = dbus_connection_ref(conn);
+	pc->msg = dbus_message_ref(msg);
+	pc->bda = g_strdup(bda);
+	pc->id = -1;
+	pc->pattern = g_strdup(pattern);
+	pc->adapter_path = g_malloc0(16);
+	snprintf(pc->adapter_path, 16, "/org/bluez/hci%d", dev_id);
+
+	memset(uuid, 0, sizeof(uuid));
+
+	/* Friendly name or uuid128 */
+	if (pattern2uuid128(pattern, uuid, sizeof(uuid)) == 0) {
+		if (get_handles(pc, uuid, handles_reply) < 0) {
+			pending_connect_free(pc);
+			return err_not_supported(conn, msg);
+		}
+		pending_connects = g_slist_append(pending_connects, pc);
+		goto done;
+	}
+
+	/* Record handle or channel */
+	err = pattern2long(pattern, &val);
+	if (err < 0) {
+		pending_connect_free(pc);
+		return err_invalid_args(conn, msg, "invalid pattern");
+	}
+
+	/* Record handle: starts at 0x10000 */
+	if (strncasecmp("0x", pattern, 2) == 0) {
+		if (val < 0x10000) {
+			pending_connect_free(pc);
+			return err_invalid_args(conn, msg,
+					"invalid record handle");
+		}
+
+		if (get_record(pc, val, record_reply) < 0) {
+			pending_connect_free(pc);
+			return err_not_supported(conn, msg);
+		}
+		pending_connects = g_slist_append(pending_connects, pc);
+		goto done;
 	}
 
 	/* RFCOMM Channel range: 1 - 30 */
@@ -863,17 +984,19 @@
 		pending_connect_free(pc);
 		return err_connection_failed(conn, msg, strerr);
 	}
+done:
+	name_listener_add(conn, dbus_message_get_sender(msg),
+			(name_cb_t) transaction_owner_exited, NULL);
+
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
 static DBusHandlerResult disconnect_service(DBusConnection *conn,
 					DBusMessage *msg, void *data)
 {
-	DBusMessage *reply;
 	DBusError derr;
-	struct rfcomm_node *node;
 	const char *name;
-	int err;
+	int err, id;
 
 	dbus_error_init(&derr);
 	if (!dbus_message_get_args(msg, &derr,
@@ -884,34 +1007,22 @@
 		return DBUS_HANDLER_RESULT_HANDLED;
 	}
 
-	node = find_node_by_name(name);
-	if (!node)
-		return err_does_not_exist(conn, msg, "Invalid node");
-
-	if (strcmp(node->owner, dbus_message_get_sender(msg)) != 0)
-		return err_not_authorized(conn, msg);
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
-	err = rfcomm_release(node->id);
-	if (err < 0) {
-		dbus_message_unref(reply);
-		return err_failed(conn, msg, strerror(-err));
-	}
+	if (sscanf(name, "/dev/rfcomm%d", &id) != 1)
+		return err_invalid_args(conn, msg, "invalid RFCOMM node");
+
+	err = port_remove_listener(dbus_message_get_sender(msg), name);
+	if (err < 0)
+		return err_does_not_exist(conn, msg, "Invalid RFCOMM node");
+
+	send_message_and_unref(conn,
+			dbus_message_new_method_return(msg));
 
 	dbus_connection_emit_signal(conn, SERIAL_MANAGER_PATH,
 			SERIAL_MANAGER_INTERFACE, "ServiceDisconnected" ,
-			DBUS_TYPE_STRING, &node->name,
-			DBUS_TYPE_INVALID); 
-
-	name_listener_remove(node->conn, node->owner,
-			(name_cb_t) connect_service_exited, node);
-	connected_nodes = g_slist_remove(connected_nodes, node);
-	rfcomm_node_free(node);
-
-	return send_message_and_unref(conn, reply);
+			DBUS_TYPE_STRING, &name,
+			DBUS_TYPE_INVALID);
+
+	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
 static DBusHandlerResult cancel_connect_service(DBusConnection *conn,
@@ -947,12 +1058,8 @@
 
 static void manager_unregister(DBusConnection *conn, void *data)
 {
-	if (connected_nodes) {
-		g_slist_foreach(connected_nodes,
-				(GFunc) rfcomm_node_free, NULL);
-		g_slist_free(connected_nodes);
-		connected_nodes = NULL;
-	}
+	char **dev;
+	int i;
 
 	if (pending_connects) {
 		g_slist_foreach(pending_connects,
@@ -960,9 +1067,27 @@
 		g_slist_free(pending_connects);
 		pending_connects = NULL;
 	}
+
+	/* Unregister all paths in serial hierarchy */
+	if (!dbus_connection_list_registered(conn, SERIAL_MANAGER_PATH, &dev))
+		return;
+
+	for (i = 0; dev[i]; i++) {
+		char dev_path[MAX_PATH_LENGTH];
+
+		snprintf(dev_path, sizeof(dev_path), "%s/%s", SERIAL_MANAGER_PATH,
+				dev[i]);
+
+		dbus_connection_destroy_object_path(conn, dev_path);
+	}
+
+	dbus_free_string_array(dev);
 }
 
 static DBusMethodVTable manager_methods[] = {
+	{ "CreatePort",			create_port,		"ss",	"s"	},
+	{ "ListPorts",			list_ports,		"",	"as"	},
+	{ "RemovePort",			remove_port,		"s",	""	},
 	{ "ConnectService",		connect_service,	"ss",	"s"	},
 	{ "DisconnectService",		disconnect_service,	"s",	""	},
 	{ "CancelConnectService",	cancel_connect_service,	"ss",	""	},
@@ -972,8 +1097,61 @@
 static DBusSignalVTable manager_signals[] = {
 	{ "ServiceConnected",		"s"	},
 	{ "ServiceDisconnected",	"s"	},
+	{ "PortCreated",		"s"	},
+	{ "PortRemoved",		"s"	},
 	{ NULL, NULL }
 };
+
+static void parse_port(char *key, char *value, void *data)
+{
+	char port_name[16], dst_addr[18];
+	char *src_addr = data;
+	bdaddr_t dst, src;
+	int ch, id;
+
+	memset(dst_addr, 0, sizeof(dst_addr));
+	if (sscanf(key,"%17s#%d", dst_addr, &id) != 2)
+		return;
+
+	if (sscanf(value,"%d:", &ch) != 1)
+		return;
+
+	str2ba(dst_addr, &dst);
+	str2ba(src_addr, &src);
+
+	if (rfcomm_bind(&src, &dst, id, ch) < 0)
+		return;
+
+	snprintf(port_name, sizeof(port_name), "/dev/rfcomm%d", id);
+
+	if (port_register(connection, id, &dst, port_name, NULL) < 0) {
+		rfcomm_release(id);
+		return;
+	}
+}
+
+static void register_stored_ports(void)
+{
+	char filename[PATH_MAX + 1];
+	struct dirent *de;
+	DIR *dir;
+
+	snprintf(filename, PATH_MAX, "%s", STORAGEDIR);
+
+	dir = opendir(filename);
+	if (!dir)
+		return;
+
+	while ((de = readdir(dir)) != NULL) {
+		if (!isdigit(de->d_name[0]))
+			continue;
+		snprintf(filename, PATH_MAX, "%s/%s/serial", STORAGEDIR, de->d_name);
+
+		textfile_foreach(filename, parse_port, de->d_name);
+	}
+
+	closedir(dir);
+}
 
 int serial_init(DBusConnection *conn)
 {
@@ -1005,6 +1183,8 @@
 
 	info("Registered manager path:%s", SERIAL_MANAGER_PATH);
 
+	register_stored_ports();
+
 	return 0;
 }
 

Modified: bluez-utils/branches/upstream/current/serial/manager.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/manager.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/serial/manager.h (original)
+++ bluez-utils/branches/upstream/current/serial/manager.h Wed Jul  4 13:37:57 2007
@@ -21,5 +21,11 @@
  *
  */
 
+#define SERIAL_MANAGER_PATH		"/org/bluez/serial"
+#define SERIAL_MANAGER_INTERFACE	"org.bluez.serial.Manager"
+
+#define MAX_PATH_LENGTH			32
+
 int serial_init(DBusConnection *conn);
 void serial_exit(void);
+int rfcomm_release(int16_t id);

Added: bluez-utils/branches/upstream/current/serial/port.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/port.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/serial/port.c (added)
+++ bluez-utils/branches/upstream/current/serial/port.c Wed Jul  4 13:37:57 2007
@@ -1,0 +1,300 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+#include "dbus.h"
+#include "dbus-helper.h"
+#include "logging.h"
+
+#include "error.h"
+#include "manager.h"
+#include "port.h"
+
+#define SERIAL_PORT_INTERFACE	"org.bluez.serial.Port"
+
+struct rfcomm_node {
+	int16_t		id;	/* RFCOMM device id */
+	bdaddr_t	dst;	/* Destination address */
+	char		*name;	/* RFCOMM device name */
+	DBusConnection	*conn;	/* for name listener handling */
+	char		*owner; /* Bus name */
+	GIOChannel	*io;	/* Connected node IO Channel */
+	guint		io_id;	/* IO Channel ID */
+};
+
+static GSList *connected_nodes = NULL;
+static GSList *bound_nodes = NULL;
+
+static struct rfcomm_node *find_node_by_name(GSList *nodes, const char *name)
+{
+	GSList *l;
+
+	for (l = nodes; l != NULL; l = l->next) {
+		struct rfcomm_node *node = l->data;
+		if (!strcmp(node->name, name))
+			return node;
+	}
+
+	return NULL;
+}
+
+static DBusHandlerResult port_get_address(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct rfcomm_node *node = data;
+	DBusMessage *reply;
+	char bda[18];
+	const char *pbda = bda;
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	ba2str(&node->dst, bda);
+	dbus_message_append_args(reply,
+			DBUS_TYPE_STRING, &pbda,
+			DBUS_TYPE_INVALID);
+	return send_message_and_unref(conn, reply);
+
+}
+
+static DBusHandlerResult port_get_info(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct rfcomm_node *node = data;
+	DBusMessage *reply;
+	DBusMessageIter iter, dict;
+	char bda[18];
+	const char *pbda = bda;
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, 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);
+
+	dbus_message_iter_append_dict_entry(&dict, "name",
+			DBUS_TYPE_STRING, &node->name);
+
+	ba2str(&node->dst, bda);
+	dbus_message_iter_append_dict_entry(&dict, "address",
+			DBUS_TYPE_STRING, &pbda);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	return send_message_and_unref(conn, reply);
+}
+
+static DBusMethodVTable port_methods[] = {
+	{ "GetAddress",	port_get_address,	"",	"s"	},
+	{ "GetInfo",	port_get_info,		"",	"{sv}"	},
+	{ NULL, NULL, NULL, NULL },
+};
+
+static DBusSignalVTable port_signals[] = {
+	{ NULL, NULL }
+};
+
+static void rfcomm_node_free(struct rfcomm_node *node)
+{
+	if (node->name)
+		g_free(node->name);
+	if (node->conn)
+		dbus_connection_unref(node->conn);
+	if (node->owner)
+		g_free(node->owner);
+	if (node->io) {
+		g_source_remove(node->io_id);
+		g_io_channel_close(node->io);
+		g_io_channel_unref(node->io);
+	}
+	rfcomm_release(node->id);
+	g_free(node);
+}
+
+static void connection_owner_exited(const char *name, struct rfcomm_node *node)
+{
+	debug("Connect requestor %s exited. Releasing %s node",
+						name, node->name);
+
+	dbus_connection_emit_signal(node->conn, SERIAL_MANAGER_PATH,
+			SERIAL_MANAGER_INTERFACE, "ServiceDisconnected" ,
+			DBUS_TYPE_STRING, &node->name,
+			DBUS_TYPE_INVALID);
+
+	connected_nodes = g_slist_remove(connected_nodes, node);
+	rfcomm_node_free(node);
+}
+
+static gboolean rfcomm_disconnect_cb(GIOChannel *io,
+		GIOCondition cond, struct rfcomm_node *node)
+{
+	debug("RFCOMM node %s was disconnected", node->name);
+
+	name_listener_remove(node->conn, node->owner,
+			(name_cb_t) connection_owner_exited, node);
+
+	dbus_connection_emit_signal(node->conn, SERIAL_MANAGER_PATH,
+			SERIAL_MANAGER_INTERFACE, "ServiceDisconnected" ,
+			DBUS_TYPE_STRING, &node->name,
+			DBUS_TYPE_INVALID);
+
+	connected_nodes = g_slist_remove(connected_nodes, node);
+	rfcomm_node_free(node);
+
+	return FALSE;
+}
+
+static void port_handler_unregister(DBusConnection *conn, void *data)
+{
+	struct rfcomm_node *node = data;
+
+	debug("Unregistered serial port: %s", node->name);
+
+	bound_nodes = g_slist_remove(bound_nodes, node);
+	rfcomm_node_free(node);
+}
+
+int port_add_listener(DBusConnection *conn, int16_t id, bdaddr_t *dst,
+			int fd, const char *name, const char *owner)
+{
+	struct rfcomm_node *node;
+
+	node = g_new0(struct rfcomm_node, 1);
+	bacpy(&node->dst, dst);
+	node->id	= id;
+	node->name	= g_strdup(name);
+	node->conn	= dbus_connection_ref(conn);
+	node->owner	= g_strdup(owner);
+	node->io 	= g_io_channel_unix_new(fd);
+	node->io_id = g_io_add_watch(node->io, G_IO_ERR | G_IO_NVAL | G_IO_HUP,
+					(GIOFunc) rfcomm_disconnect_cb, node);
+
+	connected_nodes = g_slist_append(connected_nodes, node);
+
+	/* Service connection listener */
+	return name_listener_add(conn, owner,
+			(name_cb_t) connection_owner_exited, node);
+}
+
+int port_remove_listener(const char *owner, const char *name)
+{
+	struct rfcomm_node *node;
+
+	node = find_node_by_name(connected_nodes, name);
+	if (!node)
+		return -ENOENT;
+	if (strcmp(node->owner, owner) != 0)
+		return -EPERM;
+
+	name_listener_remove(node->conn, owner,
+			(name_cb_t) connection_owner_exited, node);
+
+	connected_nodes = g_slist_remove(connected_nodes, node);
+	rfcomm_node_free(node);
+
+	return 0;
+}
+
+int port_register(DBusConnection *conn, int16_t id, bdaddr_t *dst,
+					const char *name, char *ppath)
+{
+	char path[MAX_PATH_LENGTH];
+	struct rfcomm_node *node;
+
+	node = g_new0(struct rfcomm_node, 1);
+	bacpy(&node->dst, dst);
+	node->id	= id;
+	node->name	= g_strdup(name);
+	node->conn	= dbus_connection_ref(conn);
+
+	snprintf(path, MAX_PATH_LENGTH, "%s/rfcomm%hd", SERIAL_MANAGER_PATH, id);
+
+	if (!dbus_connection_create_object_path(conn, path, node,
+						port_handler_unregister)) {
+		error("D-Bus failed to register %s path", path);
+		rfcomm_node_free(node);
+		return -1;
+	}
+
+	if (!dbus_connection_register_interface(conn, path,
+				SERIAL_PORT_INTERFACE,
+				port_methods,
+				port_signals, NULL)) {
+		error("D-Bus failed to register %s interface",
+				SERIAL_PORT_INTERFACE);
+		dbus_connection_destroy_object_path(conn, path);
+		return -1;
+	}
+
+	info("Registered RFCOMM:%s, path:%s", name, path);
+
+	if (ppath)
+		strcpy(ppath, path);
+
+	bound_nodes = g_slist_append(bound_nodes, node);
+
+	return 0;
+}
+
+int port_unregister(const char *path)
+{
+	struct rfcomm_node *node;
+	char name[16];
+	int16_t id;
+
+	if (sscanf(path, SERIAL_MANAGER_PATH"/rfcomm%hd", &id) != 1)
+		return -ENOENT;
+
+	snprintf(name, sizeof(name), "/dev/rfcomm%hd", id);
+	node = find_node_by_name(bound_nodes, name);
+	if (!node)
+		return -ENOENT;
+
+	dbus_connection_destroy_object_path(node->conn, path);
+
+	return 0;
+}

Added: bluez-utils/branches/upstream/current/serial/port.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/port.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/serial/port.h (added)
+++ bluez-utils/branches/upstream/current/serial/port.h Wed Jul  4 13:37:57 2007
@@ -1,0 +1,32 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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
+ *
+ */
+
+int port_add_listener(DBusConnection *conn, int16_t id, bdaddr_t *dst,
+			int fd, const char *name, const char *owner);
+
+int port_remove_listener(const char *owner, const char *name);
+
+int port_register(DBusConnection *conn, int16_t id, bdaddr_t *dst,
+					const char *name, char *ppath);
+
+int port_unregister(const char *path);

Modified: bluez-utils/branches/upstream/current/serial/serial-api.txt
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/serial-api.txt?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/serial/serial-api.txt (original)
+++ bluez-utils/branches/upstream/current/serial/serial-api.txt Wed Jul  4 13:37:57 2007
@@ -14,9 +14,11 @@
 
 			Creates a serial port object.
 
-			Possible errors:org.bluez.serial.Error.AlreadyExists
+			Possible errors:org.bluez.serial.Error.InvalidArguments
+					org.bluez.serial.Error.ConnectionCanceled
+					org.bluez.serial.Error.ConnectionInProgress
+					org.bluez.serial.Error.ConnectionAttemptFailed
 					org.bluez.serial.Error.NotSupported
-					org.bluez.serial.Error.ConnectionAttemptFailed
 					org.bluez.serial.Error.Failed
 
 		void RemovePort(string path) [experimental]
@@ -24,7 +26,6 @@
 			Removes the serial port object for given path.
 
 			Possible errors:org.bluez.serial.Error.DoesNotExist
-					org.bluez.serial.Error.Failed
 
 		array{string} ListPorts() [experimental]
 
@@ -37,9 +38,11 @@
 			device for it. The RFCOMM TTY device is returned.
 
 			Possible errors:org.bluez.serial.Error.InvalidArguments
+					org.bluez.serial.Error.ConnectionCanceled
 					org.bluez.serial.Error.ConnectionInProgress
+					org.bluez.serial.Error.ConnectionAttemptFailed
 					org.bluez.serial.Error.NotSupported
-					org.bluez.serial.Error.ConnectionAttemptFailed
+					org.bluez.serial.Error.Failed
 
 		void CancelConnectService(string address, string pattern)
 
@@ -54,8 +57,7 @@
 			created via the ConnectService method.
 
 			Possible errors:org.bluez.serial.Error.InvalidArguments
-					org.bluez.serial.Error.NotAuthorized
-					org.bluez.serial.Error.Failed
+					org.bluez.serial.Error.DoesNotExist
 
 Signals		void PortCreated(string path) [experimental]
 
@@ -70,22 +72,12 @@
 =============================
 
 Interface	org.bluez.serial.Port
-Object path	/org/bluez/serial/port*
+Object path	/org/bluez/serial/rfcomm*
 
 Methods		string GetAddress() [experimental]
 
 			Returns the Bluetooth address of the ending point.
 
-		string Connect() [experimental]
+		string GetInfo() [experimental]
 
-			Connects to remote device associated to the port
-			object.
-
-			Possible errors:org.bluez.serial.Error.ConnectionAttemptFailed
-					org.bluez.serial.Error.Failed
-
-		void Disconnect() [experimental]
-
-			Disconnects from remote device.
-
-			Possible errors:org.bluez.serial.Error.Failed
+			Returns the port properties.

Added: bluez-utils/branches/upstream/current/serial/storage.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/storage.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/serial/storage.c (added)
+++ bluez-utils/branches/upstream/current/serial/storage.c Wed Jul  4 13:37:57 2007
@@ -1,0 +1,84 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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 <unistd.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include <glib.h>
+
+#include "logging.h"
+#include "textfile.h"
+
+#include "storage.h"
+
+int port_delete(bdaddr_t *src, bdaddr_t *dst, int16_t id)
+{
+	char filename[PATH_MAX + 1];
+	char src_addr[18], dst_addr[18];
+	char key[32];
+
+	ba2str(src, src_addr);
+	ba2str(dst, dst_addr);
+
+	create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "serial");
+	snprintf(key, sizeof(key), "%s#%hd", dst_addr, id);
+
+	return textfile_del(filename, key);
+}
+
+int port_store(bdaddr_t *src, bdaddr_t *dst, int16_t id,
+			uint8_t ch, const char *svcname)
+{
+	char filename[PATH_MAX + 1];
+	char src_addr[18], dst_addr[18];
+	char key[32];
+	char *value;
+	int size, err;
+
+	if (!svcname)
+		svcname = "Bluetooth RFCOMM port";
+
+	ba2str(src, src_addr);
+	ba2str(dst, dst_addr);
+
+	create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "serial");
+	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+	size = strlen(svcname) + 3;
+	value = g_malloc0(size);
+
+	snprintf(key, 32, "%s#%hd", dst_addr, id);
+	snprintf(value, size, "%d:%s", ch, svcname);
+
+	err = textfile_put(filename, key, value);
+	g_free(value);
+
+	return err;
+}

Added: bluez-utils/branches/upstream/current/serial/storage.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/storage.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/serial/storage.h (added)
+++ bluez-utils/branches/upstream/current/serial/storage.h Wed Jul  4 13:37:57 2007
@@ -1,0 +1,26 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel at 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
+ *
+ */
+
+int port_delete(bdaddr_t *src, bdaddr_t *dst, int16_t id);
+int port_store(bdaddr_t *src, bdaddr_t *dst, int16_t id,
+			uint8_t ch, const char *svcname);

Modified: bluez-utils/branches/upstream/current/test/apitest
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/test/apitest?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/test/apitest (original)
+++ bluez-utils/branches/upstream/current/test/apitest Wed Jul  4 13:37:57 2007
@@ -145,7 +145,8 @@
                 for path in dev_signals_filter:
                     self.bus.add_signal_receiver(self.dev_signal_handler,
                                              signal, 'org.bluez.Adapter',
-                                             'org.bluez', path)
+                                             'org.bluez', path,
+                                             message_keyword='dbus_message')
         except dbus.DBusException, e:
             print 'Failed to setup signal handler for device path: %s' % e
             sys.exit(1)
@@ -179,7 +180,7 @@
         for cmd in dev_cmds:
             print '\t%s' % cmd
 
-    @dbus.decorators.explicitly_pass_message
+    #@dbus.decorators.explicitly_pass_message
     def dev_signal_handler(*args, **keywords):
         dbus_message = keywords["dbus_message"]
         print '%s - %s: ' % (dbus_message.get_member(), dbus_message.get_path()),
@@ -187,7 +188,7 @@
             print '%s   ' % arg,
         print
 
-    @dbus.decorators.explicitly_pass_message
+    #@dbus.decorators.explicitly_pass_message
     def mgr_signal_handler(*args, **keywords):
         dbus_message = keywords["dbus_message"]
         print '%s: ' % dbus_message.get_member()
@@ -414,7 +415,7 @@
             self.dbus_dev_sig_setup()
             print 'Listening for events...'
 
-        if self.cmd in mgr_cmds:
+        elif self.cmd in mgr_cmds:
             try:
                 self.dbus_mgr_setup()
             except dbus.DBusException, e:

Modified: bluez-utils/branches/upstream/current/test/l2test.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/test/l2test.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/test/l2test.c (original)
+++ bluez-utils/branches/upstream/current/test/l2test.c Wed Jul  4 13:37:57 2007
@@ -348,6 +348,7 @@
 	}
 
 	/* Set new options */
+	opts.omtu = omtu;
 	opts.imtu = imtu;
 	if (flowctl)
 		opts.mode = 2;

Modified: bluez-utils/branches/upstream/current/tools/csr.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/tools/csr.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/tools/csr.c (original)
+++ bluez-utils/branches/upstream/current/tools/csr.c Wed Jul  4 13:37:57 2007
@@ -358,6 +358,7 @@
 	{ 2622, "Marcel 3 (2005-10-27)"	},
 	{ 3326, "Marcel 4 (2006-06-16)"	},
 	{ 3612, "Marcel 5 (2006-10-24)"	},
+	{ 4509, "Marcel 6 (2007-06-11)"	},
 	{  195, "Sniff 1 (2001-11-27)"	},
 	{  220, "Sniff 2 (2002-01-03)"	},
 	{  269, "Sniff 3 (2002-02-22)"	},

Modified: bluez-utils/branches/upstream/current/tools/hciattach.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/tools/hciattach.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/tools/hciattach.c (original)
+++ bluez-utils/branches/upstream/current/tools/hciattach.c Wed Jul  4 13:37:57 2007
@@ -951,6 +951,29 @@
 		return -1;
 	}
 
+	if (u->bdaddr != NULL) {
+		/* Set BD_ADDR */
+		memset(cmd, 0, sizeof(cmd));
+		memset(resp, 0, sizeof(resp));
+		cmd[0] = HCI_COMMAND_PKT;
+		cmd[1] = 0x01;
+		cmd[2] = 0xfc;
+		cmd[3] = 0x06;
+		str2ba(u->bdaddr, (bdaddr_t *) (cmd + 4));
+
+		/* Send command */
+		if (write(fd, cmd, 10) != 10) {
+			fprintf(stderr, "Failed to write BD_ADDR command\n");
+			return -1;
+		}
+
+		/* Read reply */
+		if ((n = read_hci_event(fd, resp, 10)) < 0) {
+			fprintf(stderr, "Failed to set BD_ADDR\n");
+			return -1;
+		}
+	}
+
 	/* Read the local version info */
 	memset(cmd, 0, sizeof(cmd));
 	memset(resp, 0, sizeof(resp));
@@ -983,7 +1006,7 @@
 	/* Send command */
 	if (write(fd, cmd, 4) != 4) {
 		fprintf(stderr, "Failed to write \"read local supported "
-			"commands\" command\n");
+						"commands\" command\n");
 		return -1;
 	}
 
@@ -1010,11 +1033,11 @@
 		cmd[5] = 0xfa;
 		break;
 	case 460800:
-		cmd[4] = 0x11;
+		cmd[4] = 0x22;
 		cmd[5] = 0xfd;
 		break;
 	case 921600:
-		cmd[4] = 0x65;
+		cmd[4] = 0x55;
 		cmd[5] = 0xff;
 		break;
 	default:
@@ -1103,7 +1126,7 @@
 	{ "billionton", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0,        NULL, bcsp     },
 
 	/* Broadcom BCM2035 */
-	{ "bcm2035",    0x0A5C, 0x2035, HCI_UART_H4,   115200, 115200, 0,        NULL, bcm2035  },
+	{ "bcm2035",    0x0A5C, 0x2035, HCI_UART_H4,   115200, 460800, FLOW_CTL, NULL, bcm2035  },
 
 	{ NULL, 0 }
 };

Modified: bluez-utils/branches/upstream/current/tools/hcitool.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/tools/hcitool.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/tools/hcitool.c (original)
+++ bluez-utils/branches/upstream/current/tools/hcitool.c Wed Jul  4 13:37:57 2007
@@ -905,9 +905,11 @@
 	}
 
 	if ((di.features[7] & LMP_EXT_FEAT) && (features[7] & LMP_EXT_FEAT)) {
-		if (hci_read_remote_ext_features(dd, handle, 0, &max_page, features, 20000) == 0)
+		if (hci_read_remote_ext_features(dd, handle, 0,
+					&max_page, features, 20000) == 0)
 			if (max_page > 0)
-				printf("\tExtended features: %d pages\n", max_page);
+				printf("\tExtended features: %d page%s\n",
+					max_page, max_page > 1 ? "s" : "");
 	}
 
 	if (cc) {

Modified: bluez-utils/branches/upstream/current/tools/sdptool.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/tools/sdptool.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/tools/sdptool.c (original)
+++ bluez-utils/branches/upstream/current/tools/sdptool.c Wed Jul  4 13:37:57 2007
@@ -755,10 +755,12 @@
 	sdp_list_t *attrid_list;
 	uint32_t range = 0x0000ffff;
 	sdp_record_t *rec;
+	int ret;
 
 	/* Get the old SDP record */
 	attrid_list = sdp_list_append(NULL, &range);
 	rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attrid_list);
+	sdp_list_free(attrid_list, NULL);
 
 	if (!rec) {
 		printf("Service get request failed.\n");
@@ -794,11 +796,11 @@
 	}
 
 	/* Update on the server */
-	if (sdp_device_record_update(sess, &interface, rec)) {
+	ret = sdp_device_record_update(sess, &interface, rec);
+	if (ret < 0)
 		printf("Service Record update failed (%d).\n", errno);
-		return -1;
-	}
-	return 0;
+	sdp_record_free(rec);
+	return ret;
 }
 
 static struct option set_options[] = {
@@ -867,11 +869,12 @@
 	uint8_t uuid16 = SDP_UUID16;
 	uint8_t uint32 = SDP_UINT32;
 	uint8_t str8 = SDP_TEXT_STR8;
-	int i;
+	int i, ret = 0;
 
 	/* Get the old SDP record */
 	attrid_list = sdp_list_append(NULL, &range);
 	rec = sdp_service_attr_req(session, handle, SDP_ATTR_REQ_RANGE, attrid_list);
+	sdp_list_free(attrid_list, NULL);
 
 	if (!rec) {
 		printf("Service get request failed.\n");
@@ -919,10 +922,9 @@
 		sdp_attr_replace(rec, attrib, pSequenceHolder);
 
 		/* Update on the server */
-		if (sdp_device_record_update(session, &interface, rec)) {
+		ret = sdp_device_record_update(session, &interface, rec);
+		if (ret < 0)
 			printf("Service Record update failed (%d).\n", errno);
-			return -1;
-		}
 	} else
 		printf("Failed to create pSequenceHolder\n");
 
@@ -932,8 +934,11 @@
 
 	free(dtdArray);
 	free(valueArray);
-
-	return 0;
+	free(allocArray);
+
+	sdp_record_free(rec);
+
+	return ret;
 }
 
 static struct option seq_options[] = {




More information about the Pkg-bluetooth-commits mailing list