Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH] Fix crash while reading from mapped file
From: Luiz Augusto von Dentz @ 2010-12-17  9:29 UTC (permalink / raw)
  To: Anderson Lizardo
  Cc: Lukasz Pawlik, Bastien Nocera, Johan Hedberg, linux-bluetooth
In-Reply-To: <AANLkTik+R_pBHTjqmcHxOcz3VpNcBsefgbGbtD3iaOVr@mail.gmail.com>

Hi,

On Thu, Dec 16, 2010 at 11:28 AM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> Hi,
>
> On Wed, Dec 15, 2010 at 8:19 PM, Anderson Lizardo
> <anderson.lizardo@openbossa.org> wrote:
>> On Tue, Dec 14, 2010 at 2:20 PM, Lukasz Pawlik <lucas.pawlik@gmail.com> wrote:
>>> Hi,
>>>
>>>> If somebody can explain what that code is supposed to do, then writing a
>>>> glib-ish version should be trivial, without having to duplicate the
>>>> contents again. Then again, using something like:
>>>> g_mapped_file_new ();
>>>> g_strsplit ();
>>>> g_mapped_file_unref ();
>>>
>>> That won't fix anything since g_mapped_file_new uses mmap function so
>>> contents may not be zero-terminated and we want use string function
>>> next.
>>
>> What about using g_strstr_len() instead of strpbrk() on the original
>> code? See http://library.gnome.org/devel/glib/unstable/glib-String-Utility-Functions.html#g-strstr-len
>
> That looks to be a good replacement for strpbrk, probably 1 line patch.

I guess we cannot use any of glib functions here since textfile.c is
also used in some tools which doesn't link with glib, so if we don't
want to add this dependency to the than we need some other way to fix
it.

What about this:

diff --git a/src/textfile.c b/src/textfile.c
index 2429cc7..2e4c642 100644
--- a/src/textfile.c
+++ b/src/textfile.c
@@ -394,7 +394,7 @@ int textfile_foreach(const char *pathname,
textfile_cb func, void *data)
                goto unlock;
        }

-       size = st.st_size;
+       size = st.st_size + 1;

        map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
        if (!map || map == MAP_FAILED) {

It will probably use 1 more page if the file size is multiple of the
page size but it seems correct if you compare to e.g. malloc, well if
the possibility of the extra page is too much than we need our own
version of g_strstr_len/strpbrk_len like the following:

http://www.google.com/codesearch/p?hl=en#cZwlSNS7aEw/external/bluetooth/glib/glib/gstrfuncs.c&q=g_strstr_len&d=4

-- 
Luiz Augusto von Dentz
Computer Engineer

^ permalink raw reply related

* Re: [RFC] Bluetooth: Use non-flushable pb flag by default for ACL data on capable chipsets.
From: Andrei Emeltchenko @ 2010-12-17  7:48 UTC (permalink / raw)
  To: Mat Martineau; +Cc: Gustavo F. Padovan, linux-bluetooth
In-Reply-To: <alpine.DEB.2.00.1012160741390.15684@linux-sea-02>

Hi,

On Thu, Dec 16, 2010 at 7:03 PM, Mat Martineau <mathewm@codeaurora.org> wrote:
>> <skipped>
>>>
>>> There is one more thing missing:  Even though there is an L2CAP socket
>>> option to set flush_to, and the flush_to is passed around during L2CAP
>>> configuration, there is no use of the "Write Automatic Flush Timeout" HCI
>>> command to tell the baseband what the flush timeout is!  Since the flush
>>> timeout is shared across all connections on the ACL, how should BlueZ
>>> handle
>>> the case where different flush timeouts are set on connections that share
>>> the same ACL?  (My guess is that either the longest or shortest timeout
>>> should be used, but there are good arguments either way)
>>
>> I would suggest bluetoothd to take care about setting Flush Timeout. There
>> is of course possibility to have sockopt for timeout and send HCI command
>> but this looks like a dirty hack.
>>
>> I think bluetoothd can read compare and write new flush timeout value.
>
> There is *already* a sockopt for flush timeout (flush_to in l2cap_options,
> it was added before 2005), but it is not terribly useful because it does not
> configure the baseband.

Yes, I just check, that code is just dummy code and only used to set dummy
value in L2CAP configuration phase with no actual use.

If I execute command like:
#Write Automatic Flush Timeout
~# hcitool cmd 0x03 0x0028 0x01 0x00 0xa0 0x0
#for handle 0x0001 to 100ms

it will still report old value through that kernel interface.

> One more piece of background information: The spec requires the default
> flush timeout to be infinite, so if no "Write Automatic Flush Timeout"
> command is sent, none of this flush code will accomplish anything.  Android
> has customized their version of BlueZ to send this command for A2DP
> connections, with certain BR/EDR basebands.

I believe they do it right way.

> I don't have any major objection to managing this setting from bluetoothd.
>  My only minor objection is that it requires an application to manipulate
> the setting via DBus instead of using the existing sockopt - it would be
> confusing to have both available, but I suppose the sockopt could be
> deprecated or made read-only.  The flush timeout would seem to fit well as a
> device property.

I would remove it at all, but of course it can be done as read-only.

Regards,
Andrei

^ permalink raw reply

* Fwd: Initialization script for CC2540 Low energy dev kit
From: José Luís @ 2010-12-16 23:01 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <AANLkTi=81AdVX-F8Z=eDnMbc7S2mWK0s=BFLujmEU0x8@mail.gmail.com>

Hi people,

I'm trying to start with Low energy CC2540 Mini Development kit of TI on Linux,
but I can't get the usb dongle work properly. When I try to attach the hci
interface to the device with the command:

hciattach /dev/ttyACM0 texas 57600 flow

I got the message:

Found a Texas Instruments' chip!
Firmware file : /lib/firmware/TIInit_0.2.0.bts
can't open firmware file: No such file or directory
Warning: cannot find BTS file: /lib/firmware/TIInit_0.2.0.bts
Device setup complete

I would like to know where I can found this firmware initialization
script (TIInit_0.2.0.bts) or a driver to make this dongle work.
I'm using the git master version of bluez, and kernel 2.6.37-rc1+
of vcgomes git tree (git://git.infradead.org/users/vcgomes/linux-2.6.git devel)

More information:
lsusb shows:
Bus 004 Device 004: ID 0451:16aa Texas Instruments, Inc.
dmesg:
[ 8125.944210] usb 4-2: new full speed USB device using uhci_hcd and address 4
[ 8126.106197] cdc_acm 4-2:1.0: This device cannot do calls on its
own. It is not a modem.
[ 8126.106267] cdc_acm 4-2:1.0: ttyACM1: USB ACM device

hcitool lescan, returns:
Enable scan failed: Connection timed out
with the following hcidump:
hcidump -X
HCI sniffer - Bluetooth packet analyzer ver 0.17
device: hci0 snap_len: 1028 filter: 0xffffffff
< HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7
  0000: 01 10 00 10 00 00 00                              .......
> HCI Event: Command Complete (0x0e) plen 4
    LE Set Scan Parameters (0x08|0x000b) ncmd 1
    0000: 00                                                .
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2
  0000: 01 00


Thanks for any tip in advance

[]'s

--
José Luís do Nascimento
Signove - Seamless Technologies for Life!
Home page: http://www.signove.com

^ permalink raw reply

* Re: [PATCH 2/5] Change CreatePairedDevice to support LE devices
From: Brian Gix @ 2010-12-16 22:42 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth, Sheldon Demario
In-Reply-To: <1292442852-26457-2-git-send-email-claudio.takahasi@openbossa.org>

Hi Claudio,

On Wed, 2010-12-15 at 16:54 -0300, Claudio Takahasi wrote:
> From: Sheldon Demario <sheldon.demario@openbossa.org>
> 
> CreatePairedDevice implements now the same behaviour of CreateDevice,
> triggering Discover All Primary Services when needed. SMP negotiation
> starts when the link is established. LE capable kernel is required to
> test this method properly.

What is your plan for handling single mode LE (remote) devices which
have privacy enabled (random addresses). This impacts connection
establishment, and SM pairing, as the remote device's addr type must
be known at that time, and handled differently.

> 
> Limitation: For dual mode devices, Discover All Primary Services is not
> being executed after SDP search if GATT record is found.
> ---
>  src/adapter.c     |   46 ++++++++++++++++++++++++---
>  src/device.c      |   89 +++++++++++++++++++++++++++-------------------------
>  src/device.h      |    7 +++-
>  src/glib-helper.c |    5 ++-
>  src/glib-helper.h |    3 ++
>  5 files changed, 98 insertions(+), 52 deletions(-)
> 
> diff --git a/src/adapter.c b/src/adapter.c
> index 2ff59a0..c1fddce 100644
> --- a/src/adapter.c
> +++ b/src/adapter.c
> @@ -1611,7 +1611,11 @@ static DBusMessage *create_device(DBusConnection *conn,
>  		return reply;
>  	}
>  
> -	err = device_browse(device, conn, msg, NULL, FALSE);
> +	if (type != DEVICE_TYPE_LE)
> +		err = device_browse_sdp(device, conn, msg, NULL, FALSE);
> +	else
> +		err = device_browse_primary(device, conn, msg, BT_IO_SEC_LOW);
> +
>  	if (err < 0) {
>  		adapter_remove_device(conn, adapter, device, TRUE);
>  		return btd_error_failed(msg, strerror(-err));
> @@ -1642,6 +1646,8 @@ static DBusMessage *create_paired_device(DBusConnection *conn,
>  	struct btd_device *device;
>  	const gchar *address, *agent_path, *capability, *sender;
>  	uint8_t cap;
> +	device_type_t type;
> +	int err;
>  
>  	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
>  					DBUS_TYPE_OBJECT_PATH, &agent_path,
> @@ -1666,12 +1672,40 @@ static DBusMessage *create_paired_device(DBusConnection *conn,
>  	if (cap == IO_CAPABILITY_INVALID)
>  		return btd_error_invalid_args(msg);
>  
> -	device = adapter_get_device(conn, adapter, address);
> -	if (!device)
> -		return btd_error_failed(msg,
> -				"Unable to create a new device object");
> +	device = adapter_find_device(adapter, address);
> +	if (!device) {
> +		struct remote_dev_info *dev, match;
> +
> +		memset(&match, 0, sizeof(struct remote_dev_info));
> +		str2ba(address, &match.bdaddr);
> +		match.name_status = NAME_ANY;
> +
> +		dev = adapter_search_found_devices(adapter, &match);
> +		if (dev && dev->flags)
> +			type = flags2type(dev->flags);
> +		else
> +			type = DEVICE_TYPE_BREDR;
> +
> +		if (type == DEVICE_TYPE_LE &&
> +					!event_is_connectable(dev->evt_type))
> +			return btd_error_failed(msg,
> +					"Device is not connectable");
> +
> +		device = adapter_create_device(conn, adapter, address, type);
> +		if (!device)
> +			return NULL;
> +	} else
> +		type = device_get_type(device);
> +
> +	if (type != DEVICE_TYPE_LE)
> +		return device_create_bonding(device, conn, msg,
> +							agent_path, cap);
>  
> -	return device_create_bonding(device, conn, msg, agent_path, cap);
> +	err = device_browse_primary(device, conn, msg, BT_IO_SEC_HIGH);
> +	if (err < 0)
> +		return btd_error_failed(msg, strerror(-err));
> +
> +	return NULL;
>  }
>  
>  static gint device_path_cmp(struct btd_device *device, const gchar *path)
> diff --git a/src/device.c b/src/device.c
> index d20a6d4..cf3b146 100644
> --- a/src/device.c
> +++ b/src/device.c
> @@ -586,7 +586,7 @@ static DBusMessage *discover_services(DBusConnection *conn,
>  		return btd_error_invalid_args(msg);
>  
>  	if (strlen(pattern) == 0) {
> -		err = device_browse(device, conn, msg, NULL, FALSE);
> +		err = device_browse_sdp(device, conn, msg, NULL, FALSE);
>  		if (err < 0)
>  			goto fail;
>  	} else {
> @@ -597,7 +597,7 @@ static DBusMessage *discover_services(DBusConnection *conn,
>  
>  		sdp_uuid128_to_uuid(&uuid);
>  
> -		err = device_browse(device, conn, msg, &uuid, FALSE);
> +		err = device_browse_sdp(device, conn, msg, &uuid, FALSE);
>  		if (err < 0)
>  			goto fail;
>  	}
> @@ -988,6 +988,11 @@ void device_get_name(struct btd_device *device, char *name, size_t len)
>  	strncpy(name, device->name, len);
>  }
>  
> +device_type_t device_get_type(struct btd_device *device)
> +{
> +	return device->type;
> +}
> +
>  void device_remove_bonding(struct btd_device *device)
>  {
>  	char filename[PATH_MAX + 1];
> @@ -1540,41 +1545,62 @@ done:
>  	browse_request_free(req);
>  }
>  
> -static struct browse_req *browse_primary(struct btd_device *device, int *err)
> +int device_browse_primary(struct btd_device *device, DBusConnection *conn,
> +				DBusMessage *msg, BtIOSecLevel sec_level)
>  {
>  	struct btd_adapter *adapter = device->adapter;
>  	struct browse_req *req;
>  	bdaddr_t src;
> -	int ret;
> +	int err;
> +
> +	if (device->browse)
> +		return -EBUSY;
>  
>  	req = g_new0(struct browse_req, 1);
>  	req->device = btd_device_ref(device);
>  
>  	adapter_get_address(adapter, &src);
>  
> -	ret = bt_discover_primary(&src, &device->bdaddr, -1, primary_cb, req,
> -									NULL);
> -
> -	if (ret < 0) {
> +	err = bt_discover_primary(&src, &device->bdaddr, -1, primary_cb, req,
> +								sec_level, NULL);
> +	if (err < 0) {
>  		browse_request_free(req);
> -		if (err)
> -			*err = ret;
> +		return err;
> +	}
>  
> -		return NULL;
> +	if (conn == NULL)
> +		conn = get_dbus_connection();
> +
> +	req->conn = dbus_connection_ref(conn);
> +	device->browse = req;
> +
> +	if (msg) {
> +		const char *sender = dbus_message_get_sender(msg);
> +
> +		req->msg = dbus_message_ref(msg);
> +		/* Track the request owner to cancel it
> +		 * automatically if the owner exits */
> +		req->listener_id = g_dbus_add_disconnect_watch(conn,
> +						sender,
> +						discover_services_req_exit,
> +						req, NULL);
>  	}
>  
> -	return req;
> +	return err;
>  }
>  
> -static struct browse_req *browse_sdp(struct btd_device *device, uuid_t *search,
> -						gboolean reverse, int *err)
> +int device_browse_sdp(struct btd_device *device, DBusConnection *conn,
> +			DBusMessage *msg, uuid_t *search, gboolean reverse)
>  {
>  	struct btd_adapter *adapter = device->adapter;
>  	struct browse_req *req;
>  	bt_callback_t cb;
>  	bdaddr_t src;
>  	uuid_t uuid;
> -	int ret;
> +	int err;
> +
> +	if (device->browse)
> +		return -EBUSY;
>  
>  	adapter_get_address(adapter, &src);
>  
> @@ -1589,34 +1615,11 @@ static struct browse_req *browse_sdp(struct btd_device *device, uuid_t *search,
>  		cb = browse_cb;
>  	}
>  
> -	ret = bt_search_service(&src, &device->bdaddr, &uuid, cb, req, NULL);
> -	if (ret < 0) {
> +	err = bt_search_service(&src, &device->bdaddr, &uuid, cb, req, NULL);
> +	if (err < 0) {
>  		browse_request_free(req);
> -		if (err)
> -			*err = ret;
> -
> -		return NULL;
> -	}
> -
> -	return req;
> -}
> -
> -int device_browse(struct btd_device *device, DBusConnection *conn,
> -			DBusMessage *msg, uuid_t *search, gboolean reverse)
> -{
> -	struct browse_req *req;
> -	int err = 0;
> -
> -	if (device->browse)
> -		return -EBUSY;
> -
> -	if (device->type == DEVICE_TYPE_LE)
> -		req = browse_primary(device, &err);
> -	else
> -		req = browse_sdp(device, search, reverse, &err);
> -
> -	if (req == NULL)
>  		return err;
> +	}
>  
>  	if (conn == NULL)
>  		conn = get_dbus_connection();
> @@ -1719,7 +1722,7 @@ static gboolean start_discovery(gpointer user_data)
>  {
>  	struct btd_device *device = user_data;
>  
> -	device_browse(device, NULL, NULL, NULL, TRUE);
> +	device_browse_sdp(device, NULL, NULL, NULL, TRUE);
>  
>  	device->discov_timer = 0;
>  
> @@ -2051,7 +2054,7 @@ void device_bonding_complete(struct btd_device *device, uint8_t status)
>  			device->discov_timer = 0;
>  		}
>  
> -		device_browse(device, bonding->conn, bonding->msg,
> +		device_browse_sdp(device, bonding->conn, bonding->msg,
>  				NULL, FALSE);
>  
>  		bonding_request_free(bonding);
> diff --git a/src/device.h b/src/device.h
> index 784e931..cafa529 100644
> --- a/src/device.h
> +++ b/src/device.h
> @@ -24,6 +24,8 @@
>  
>  #define DEVICE_INTERFACE	"org.bluez.Device"
>  
> +#include "btio.h"
> +
>  struct btd_device;
>  
>  typedef enum {
> @@ -46,9 +48,12 @@ struct btd_device *device_create(DBusConnection *conn,
>  				const gchar *address, device_type_t type);
>  void device_set_name(struct btd_device *device, const char *name);
>  void device_get_name(struct btd_device *device, char *name, size_t len);
> +device_type_t device_get_type(struct btd_device *device);
>  void device_remove(struct btd_device *device, gboolean remove_stored);
>  gint device_address_cmp(struct btd_device *device, const gchar *address);
> -int device_browse(struct btd_device *device, DBusConnection *conn,
> +int device_browse_primary(struct btd_device *device, DBusConnection *conn,
> +				DBusMessage *msg, BtIOSecLevel sec_level);
> +int device_browse_sdp(struct btd_device *device, DBusConnection *conn,
>  			DBusMessage *msg, uuid_t *search, gboolean reverse);
>  void device_probe_drivers(struct btd_device *device, GSList *profiles);
>  const sdp_record_t *btd_device_get_record(struct btd_device *device,
> diff --git a/src/glib-helper.c b/src/glib-helper.c
> index 6505249..edc46d8 100644
> --- a/src/glib-helper.c
> +++ b/src/glib-helper.c
> @@ -520,6 +520,7 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
>  
>  int bt_discover_primary(const bdaddr_t *src, const bdaddr_t *dst, int psm,
>  					bt_primary_t cb, void *user_data,
> +					BtIOSecLevel sec_level,
>  					bt_destroy_t destroy)
>  {
>  	struct gattrib_context *ctxt;
> @@ -541,14 +542,14 @@ int bt_discover_primary(const bdaddr_t *src, const bdaddr_t *dst, int psm,
>  				BT_IO_OPT_SOURCE_BDADDR, src,
>  				BT_IO_OPT_DEST_BDADDR, dst,
>  				BT_IO_OPT_CID, GATT_CID,
> -				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
> +				BT_IO_OPT_SEC_LEVEL, sec_level,
>  				BT_IO_OPT_INVALID);
>  	else
>  		io = bt_io_connect(BT_IO_L2CAP, connect_cb, ctxt, NULL, &gerr,
>  				BT_IO_OPT_SOURCE_BDADDR, src,
>  				BT_IO_OPT_DEST_BDADDR, dst,
>  				BT_IO_OPT_PSM, psm,
> -				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
> +				BT_IO_OPT_SEC_LEVEL, sec_level,
>  				BT_IO_OPT_INVALID);
>  
>  	if (io == NULL) {
> diff --git a/src/glib-helper.h b/src/glib-helper.h
> index 5bb20a6..a16de6c 100644
> --- a/src/glib-helper.h
> +++ b/src/glib-helper.h
> @@ -21,6 +21,8 @@
>   *
>   */
>  
> +#include "btio.h"
> +
>  typedef void (*bt_callback_t) (sdp_list_t *recs, int err, gpointer user_data);
>  typedef void (*bt_primary_t) (GSList *l, int err, gpointer user_data);
>  typedef void (*bt_destroy_t) (gpointer user_data);
> @@ -35,6 +37,7 @@ int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst);
>  
>  int bt_discover_primary(const bdaddr_t *src, const bdaddr_t *dst, int psm,
>  					bt_primary_t cb, void *user_data,
> +					BtIOSecLevel sec_level,
>  					bt_destroy_t destroy);
>  
>  gchar *bt_uuid2string(uuid_t *uuid);


^ permalink raw reply

* Hci layer not getting event header from BT firmware
From: ashwath narasimhan @ 2010-12-16 21:13 UTC (permalink / raw)
  To: linux-bluetooth

Hi,
 I am facing an intermittent issue and would really appreciate if
someone could throw some light, or atleast point me in the right
direction.

Issue:  I reboot my hardware multiple (say 20) times and each time, I
perform hciattach ( eg: hciattach /dev/ttyHS2 any 921600) in linux
terminal prompt. There is this one or two times when hciconfig after
the hci attach shows the BD address as 00:00:00:00:00:00 and the
interface as DOWN and I have to restart the hardware to actually see
this go UP again.

Hardware used:  tegra Harmony platform from nvidia

BT chip used :  Bluecore 4 CSR

Software : ubuntu 9.10, 2.6.32.25 #1 SMP PREEMPT arm7l GNU/Linux

Architecture : ARM

Protocol: H4, communicates using UART.

Modules: BT driver and stack is built as part of kernel.


Detailed Description: Upon debugging further - I found that, as soon
as "hciattach" was issued,  the h4_recv() function in the Hci layer
seems to be getting a packet of type HCI_EVENT_PKT (0x04) in the good
case. This is the first packet that is received after the vendor
packet (0xff) and this happens before hci_request for opcodes like
0x1003, 0x1001, 0x1005, 0x1009, 0xc14, 0xc25, 0xc05, 0xc18, 0xc16 are
sent. In the failed case it neither receives the vendor packet (0xff),
nor the event packet (0x04). I dumped the received buffer's hex values
for the good and bad cases. In good case, the length was 35 bytes and
this includes the vendor packet header and the event packet header. In
the failed case, the length was 31 bytes and I didn't receive the
vendor or event packet headers. Another interesting observation is
that the content of the buffers matched in the good and failed cases
barring data from bytes 1st to 5th.
The hci_request eventually times out and hence the interface is never
up. Why is this happening, and why do I not receive the same values in
some cases? Am I looking in right path?

I am not subscribed to the list, so please "reply" to this email.
Appreciate your help and time.

Thanks,
Ashwath

^ permalink raw reply

* Re: [PATCH 2/5] Change CreatePairedDevice to support LE devices
From: Johan Hedberg @ 2010-12-16 21:01 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth, Sheldon Demario
In-Reply-To: <AANLkTikQOsuUH5NdmBgu47AJLcKMyQ08nRRruj+X8Lfc@mail.gmail.com>

Hi Claudio,

On Thu, Dec 16, 2010, Claudio Takahasi wrote:
> Currently, the purpose are service search functions and UUIDs utility functions.
> glib-helper was originally created to implement some utility functions
> to manage connections and sdp search abstractions.
> Connection functions were moved/removed when btio was created. I have
> two suggestions to try cleanup the code:
> 1. keep only sdp functions that use GLib types and rename the file to
> gsdp or other convenient name
> 2. Or create a btd_device_search/cancel functions(moving them to
> device.c) and try to remove glib-helper from the source tree, in the
> worst case keep only functions to manipulate UUIDs
> 
> The bt_discover_primary can be moved to gatt.c if we split the
> discover cancel function.
> bt_discover_services() can be removed, there isn't reference in code.
> 
> Which approach do you prefer? Any other suggestion?

Considering that around 90% of the file is SDP stuff right now I think
option 1 sounds better. I.e. rename the file to something SDP related as
well as create some more appropriate namespace for its public functions
than bt_*

Johan

^ permalink raw reply

* Re: [PATCH 1/2] drivers:staging: ti-st: remove bt_drv
From: Greg KH @ 2010-12-16 20:24 UTC (permalink / raw)
  To: pavan_savoy; +Cc: gregkh, linux-kernel, padovan, marcel, linux-bluetooth
In-Reply-To: <1292328400-7649-2-git-send-email-pavan_savoy@ti.com>

On Tue, Dec 14, 2010 at 06:06:39AM -0600, pavan_savoy@ti.com wrote:
> From: Pavan Savoy <pavan_savoy@ti.com>
> 
> Remove the BT driver from the staging folder.
> This is to update the staging folder with the
> latest BT driver.
> 
> Signed-off-by: Pavan Savoy <pavan_savoy@ti.com>
> ---
>  drivers/staging/ti-st/Kconfig   |   14 -

Deleting this file will break the build at this patch, right?  Care to
just make it empty instead and then add the needed data to it in the
next patch?

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH] Add AVDTP SRC stream send buffer size verification
From: Johan Hedberg @ 2010-12-16 19:47 UTC (permalink / raw)
  To: Dmitriy Paliy; +Cc: linux-bluetooth
In-Reply-To: <1292406533-18574-2-git-send-email-dmitriy.paliy@nokia.com>

Hi Dmitriy,

On Wed, Dec 15, 2010, Dmitriy Paliy wrote:
> Functions get_send_buffer_size and set_send_buffer_size are added to
> avdpt.c.
> 
> get_send_buffer_size returns size of send buffer for a given socket
> on success or error code on failure. set_send_buffer_size sets size
> of send buffer for a given socket, and returns 0 on success or error
> code on failure.
> 
> Size of send buffer for L2CAP socket for SRC AVDTP stream is verified
> during establishment of a new transport channel. If the size is less
> than twice of outgoing L2CAP MTU, then it is considered as being
> insufficient to handle streaming data reliably.
> 
> In this case buffer size is increased to be twice of MTU size. Such
> fixes some IOP problems with car-kits that use large MTU for music
> playback.
> ---
>  audio/avdtp.c |   53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 53 insertions(+), 0 deletions(-)

Thanks. The patch has been pushed upstream.

Johan

^ permalink raw reply

* Re: [PATCH 1/3] add btd_error_agent_not_available()
From: Johan Hedberg @ 2010-12-16 19:45 UTC (permalink / raw)
  To: Gustavo F. Padovan; +Cc: linux-bluetooth
In-Reply-To: <1292522289-15173-1-git-send-email-padovan@profusion.mobi>

Hi Gustavo,

On Thu, Dec 16, 2010, Gustavo F. Padovan wrote:
> ---
>  audio/gateway.c |    3 +--
>  src/adapter.c   |    3 +--
>  src/error.c     |    6 ++++++
>  src/error.h     |    1 +
>  4 files changed, 9 insertions(+), 4 deletions(-)

All three patches have been pushed upstream. Thanks.

In the future could you please start your summary lines with a capital
letter so we keep the commit history consistent. I went ahead and
changed them manually this time.

Johan

^ permalink raw reply

* [PATCH 3/3] covert more dbus errors to btd_error_*
From: Gustavo F. Padovan @ 2010-12-16 17:58 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1292522289-15173-2-git-send-email-padovan@profusion.mobi>

---
 audio/headset.c |   10 ++--------
 serial/port.c   |    8 +-------
 serial/proxy.c  |   12 ++----------
 src/adapter.c   |   10 ++--------
 4 files changed, 7 insertions(+), 33 deletions(-)

diff --git a/audio/headset.c b/audio/headset.c
index af75f8b..72bf5b6 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -1872,14 +1872,8 @@ static DBusMessage *hs_set_gain(DBusConnection *conn,
 		return btd_error_not_connected(msg);
 
 	err = headset_set_gain(device, gain, type);
-	if (err < 0) {
-		/* Ignore if nothing has changed */
-		if (err == -EALREADY)
-			return dbus_message_new_method_return(msg);
-		return g_dbus_create_error(msg, ERROR_INTERFACE
-						".InvalidArgument",
-						"Must be less than or equal to 15");
-	}
+	if (err < 0)
+		return btd_error_invalid_args(msg);
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
diff --git a/serial/port.c b/serial/port.c
index 33450b3..233e317 100644
--- a/serial/port.c
+++ b/serial/port.c
@@ -234,12 +234,6 @@ void port_release_all(void)
 	g_slist_free(devices);
 }
 
-static inline DBusMessage *failed(DBusMessage *msg, const char *description)
-{
-	return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
-							"%s", description);
-}
-
 static void open_notify(int fd, int err, struct serial_port *port)
 {
 	struct serial_device *device = port->device;
@@ -495,7 +489,7 @@ static DBusMessage *port_connect(DBusConnection *conn,
 	}
 
 	if (port->listener_id)
-		return failed(msg, "Port already in use");
+		return btd_error_failed(msg, "Port already in use");
 
 	port->listener_id = g_dbus_add_disconnect_watch(conn,
 						dbus_message_get_sender(msg),
diff --git a/serial/proxy.c b/serial/proxy.c
index 20aea7d..b1ee65e 100644
--- a/serial/proxy.c
+++ b/serial/proxy.c
@@ -131,12 +131,6 @@ static void proxy_free(struct serial_proxy *prx)
 	g_free(prx);
 }
 
-static inline DBusMessage *failed(DBusMessage *msg, const char *description)
-{
-	return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
-							"%s", description);
-}
-
 static void add_lang_attr(sdp_record_t *r)
 {
 	sdp_lang_attr_t base_lang;
@@ -551,9 +545,7 @@ static DBusMessage *proxy_enable(DBusConnection *conn,
 	int err;
 
 	err = enable_proxy(prx);
-	if (err == -EALREADY)
-		return failed(msg, "Already enabled");
-	else if (err < 0)
+	if (err < 0)
 		return btd_error_failed(msg, strerror(-err));
 
 	return dbus_message_new_method_return(msg);
@@ -565,7 +557,7 @@ static DBusMessage *proxy_disable(DBusConnection *conn,
 	struct serial_proxy *prx = data;
 
 	if (!prx->io)
-		return failed(msg, "Not enabled");
+		return btd_error_failed(msg, "Not enabled");
 
 	/* Remove the watches and unregister the record */
 	disable_proxy(prx);
diff --git a/src/adapter.c b/src/adapter.c
index cd53455..5118306 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -140,12 +140,6 @@ struct btd_adapter {
 static void adapter_set_pairable_timeout(struct btd_adapter *adapter,
 					guint interval);
 
-static inline DBusMessage *not_in_progress(DBusMessage *msg, const char *str)
-{
-	return g_dbus_create_error(msg, ERROR_INTERFACE ".NotInProgress",
-								"%s", str);
-}
-
 static int found_device_cmp(const struct remote_dev_info *d1,
 			const struct remote_dev_info *d2)
 {
@@ -1226,7 +1220,7 @@ static DBusMessage *get_properties(DBusConnection *conn,
 	ba2str(&adapter->bdaddr, srcaddr);
 
 	if (check_address(srcaddr) < 0)
-		return adapter_not_ready(msg);
+		return btd_error_invalid_args(msg);
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
@@ -1505,7 +1499,7 @@ static DBusMessage *cancel_device_creation(DBusConnection *conn,
 
 	device = adapter_find_device(adapter, address);
 	if (!device || !device_is_creating(device, NULL))
-		return not_in_progress(msg, "Device creation not in progress");
+		return btd_error_does_not_exist(msg);
 
 	if (!device_is_creating(device, sender))
 		return btd_error_not_authorized(msg);
-- 
1.7.3.2


^ permalink raw reply related

* [PATCH 2/3] add btd_error_not_ready()
From: Gustavo F. Padovan @ 2010-12-16 17:58 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1292522289-15173-1-git-send-email-padovan@profusion.mobi>

---
 audio/headset.c |    3 +--
 src/adapter.c   |   16 +++++-----------
 src/error.c     |    6 ++++++
 src/error.h     |    1 +
 4 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/audio/headset.c b/audio/headset.c
index 01f91db..af75f8b 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -1696,8 +1696,7 @@ static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
 		return btd_error_already_connected(msg);
 
 	if (hs->hfp_handle && !ag.telephony_ready)
-		return g_dbus_create_error(msg, ERROR_INTERFACE ".NotReady",
-					"Telephony subsystem not ready");
+		return btd_error_not_ready(msg);
 
 	device->auto_connect = FALSE;
 
diff --git a/src/adapter.c b/src/adapter.c
index a36d2b1..cd53455 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -140,12 +140,6 @@ struct btd_adapter {
 static void adapter_set_pairable_timeout(struct btd_adapter *adapter,
 					guint interval);
 
-static inline DBusMessage *adapter_not_ready(DBusMessage *msg)
-{
-	return g_dbus_create_error(msg, ERROR_INTERFACE ".NotReady",
-			"Adapter is not ready");
-}
-
 static inline DBusMessage *not_in_progress(DBusMessage *msg, const char *str)
 {
 	return g_dbus_create_error(msg, ERROR_INTERFACE ".NotInProgress",
@@ -554,7 +548,7 @@ static DBusMessage *set_pairable(DBusConnection *conn, DBusMessage *msg,
 	int err;
 
 	if (adapter->scan_mode == SCAN_DISABLED)
-		return adapter_not_ready(msg);
+		return btd_error_not_ready(msg);
 
 	if (pairable == adapter->pairable)
 		goto done;
@@ -1166,7 +1160,7 @@ static DBusMessage *adapter_start_discovery(DBusConnection *conn,
 	int err;
 
 	if (!adapter->up)
-		return adapter_not_ready(msg);
+		return btd_error_not_ready(msg);
 
 	req = find_session(adapter->disc_sessions, sender);
 	if (req) {
@@ -1198,7 +1192,7 @@ static DBusMessage *adapter_stop_discovery(DBusConnection *conn,
 	const char *sender = dbus_message_get_sender(msg);
 
 	if (!adapter->up)
-		return adapter_not_ready(msg);
+		return btd_error_not_ready(msg);
 
 	req = find_session(adapter->disc_sessions, sender);
 	if (!req)
@@ -1575,7 +1569,7 @@ static DBusMessage *create_device(DBusConnection *conn,
 		return btd_error_invalid_args(msg);
 
 	if (!adapter->up)
-		return adapter_not_ready(msg);
+		return btd_error_not_ready(msg);
 
 	if (adapter_find_device(adapter, address))
 		return btd_error_already_exists(msg);
@@ -1652,7 +1646,7 @@ static DBusMessage *create_paired_device(DBusConnection *conn,
 		return btd_error_invalid_args(msg);
 
 	if (!adapter->up)
-		return adapter_not_ready(msg);
+		return btd_error_not_ready(msg);
 
 	sender = dbus_message_get_sender(msg);
 	if (adapter->agent &&
diff --git a/src/error.c b/src/error.c
index ebfc614..c2d9baa 100644
--- a/src/error.c
+++ b/src/error.c
@@ -103,6 +103,12 @@ DBusMessage *btd_error_agent_not_available(DBusMessage *msg)
 					"Agent Not Available");
 }
 
+DBusMessage *btd_error_not_ready(DBusMessage *msg)
+{
+	return g_dbus_create_error(msg, ERROR_INTERFACE ".NotReady",
+					"Resource Not Ready");
+}
+
 DBusMessage *btd_error_failed(DBusMessage *msg, const char *str)
 {
 	return g_dbus_create_error(msg, ERROR_INTERFACE
diff --git a/src/error.h b/src/error.h
index ffd4332..cdb8919 100644
--- a/src/error.h
+++ b/src/error.h
@@ -39,4 +39,5 @@ DBusMessage *btd_error_does_not_exist(DBusMessage *msg);
 DBusMessage *btd_error_not_authorized(DBusMessage *msg);
 DBusMessage *btd_error_no_such_adapter(DBusMessage *msg);
 DBusMessage *btd_error_agent_not_available(DBusMessage *msg);
+DBusMessage *btd_error_not_ready(DBusMessage *msg);
 DBusMessage *btd_error_failed(DBusMessage *msg, const char *str);
-- 
1.7.3.2


^ permalink raw reply related

* [PATCH 1/3] add btd_error_agent_not_available()
From: Gustavo F. Padovan @ 2010-12-16 17:58 UTC (permalink / raw)
  To: linux-bluetooth

---
 audio/gateway.c |    3 +--
 src/adapter.c   |    3 +--
 src/error.c     |    6 ++++++
 src/error.h     |    1 +
 4 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/audio/gateway.c b/audio/gateway.c
index 655047d..43a4b02 100644
--- a/audio/gateway.c
+++ b/audio/gateway.c
@@ -369,8 +369,7 @@ static DBusMessage *ag_connect(DBusConnection *conn, DBusMessage *msg,
 	int err;
 
 	if (!gw->agent)
-		return g_dbus_create_error(msg, ERROR_INTERFACE
-				".Failed", "Agent not assigned");
+		return btd_error_agent_not_available(msg);
 
 	err = get_records(au_dev);
 	if (err < 0)
diff --git a/src/adapter.c b/src/adapter.c
index 2ff59a0..a36d2b1 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1412,8 +1412,7 @@ static DBusMessage *request_session(DBusConnection *conn,
 	int err;
 
 	if (!adapter->agent)
-		return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
-						"No agent registered");
+		return btd_error_agent_not_available(msg);
 
 	if (!adapter->mode_sessions)
 		adapter->global_mode = adapter->mode;
diff --git a/src/error.c b/src/error.c
index 1ee98c8..ebfc614 100644
--- a/src/error.c
+++ b/src/error.c
@@ -97,6 +97,12 @@ DBusMessage *btd_error_no_such_adapter(DBusMessage *msg)
 					"No such adapter");
 }
 
+DBusMessage *btd_error_agent_not_available(DBusMessage *msg)
+{
+	return g_dbus_create_error(msg, ERROR_INTERFACE ".AgentNotAvailable",
+					"Agent Not Available");
+}
+
 DBusMessage *btd_error_failed(DBusMessage *msg, const char *str)
 {
 	return g_dbus_create_error(msg, ERROR_INTERFACE
diff --git a/src/error.h b/src/error.h
index f346c07..ffd4332 100644
--- a/src/error.h
+++ b/src/error.h
@@ -38,4 +38,5 @@ DBusMessage *btd_error_in_progress(DBusMessage *msg);
 DBusMessage *btd_error_does_not_exist(DBusMessage *msg);
 DBusMessage *btd_error_not_authorized(DBusMessage *msg);
 DBusMessage *btd_error_no_such_adapter(DBusMessage *msg);
+DBusMessage *btd_error_agent_not_available(DBusMessage *msg);
 DBusMessage *btd_error_failed(DBusMessage *msg, const char *str);
-- 
1.7.3.2


^ permalink raw reply related

* Re: [PATCH 1/5] Bluetooth: Add error handling for managment command handlers
From: Johan Hedberg @ 2010-12-16 17:31 UTC (permalink / raw)
  To: Gustavo F. Padovan; +Cc: linux-bluetooth
In-Reply-To: <20101216165242.GC5927@vigoh>

[-- Attachment #1: Type: text/plain, Size: 357 bytes --]

Hi Gustavo,

On Thu, Dec 16, 2010, Gustavo F. Padovan wrote:
> > +	if (err < 0)
> > +		goto done;
> > +
> >  	err = msglen;
> 
> 
> I think
> 	if (!err)
> 		err = msglen;
> 
> 
> is better.

Agreed. Here's an updated patch. I used "err == 0" since that seems to
be more common at least in Marcel's user space projects for non-boolean
variable tests.

Johan

[-- Attachment #2: 0001-Bluetooth-Add-error-handling-for-managment-command-h.patch --]
[-- Type: text/x-diff, Size: 1740 bytes --]

>From 1b37152df73d9480382263f3e17c3856e8f403f3 Mon Sep 17 00:00:00 2001
From: Johan Hedberg <johan.hedberg@nokia.com>
Date: Fri, 10 Dec 2010 12:06:16 +0200
Subject: [PATCH] Bluetooth: Add error handling for managment command handlers

The command handlers for bluetooth management messaging should be able
to report errors (such as memory allocation failures) to the higher
levels in the call stack.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
 net/bluetooth/mgmt.c |   11 +++++++----
 1 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index d15bf67..e336fc1 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -29,7 +29,7 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/mgmt.h>
 
-static void cmd_status(struct sock *sk, u16 cmd, u8 status)
+static int cmd_status(struct sock *sk, u16 cmd, u8 status)
 {
 	struct sk_buff *skb;
 	struct mgmt_hdr *hdr;
@@ -39,7 +39,7 @@ static void cmd_status(struct sock *sk, u16 cmd, u8 status)
 
 	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
 	if (!skb)
-		return;
+		return -ENOMEM;
 
 	hdr = (void *) skb_put(skb, sizeof(*hdr));
 
@@ -52,6 +52,8 @@ static void cmd_status(struct sock *sk, u16 cmd, u8 status)
 
 	if (sock_queue_rcv_skb(sk, skb) < 0)
 		kfree_skb(skb);
+
+	return 0;
 }
 
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
@@ -87,11 +89,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 	switch (opcode) {
 	default:
 		BT_DBG("Unknown op %u", opcode);
-		cmd_status(sk, opcode, 0x01);
+		err = cmd_status(sk, opcode, 0x01);
 		break;
 	}
 
-	err = msglen;
+	if (err == 0)
+		err = msglen;
 
 done:
 	kfree(buf);
-- 
1.7.2.3


^ permalink raw reply related

* [PATCH v3] Bluetooth: Fix __hci_request synchronization for hci_open_dev
From: johan.hedberg @ 2010-12-16 17:16 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

The initialization function used by hci_open_dev (hci_init_req) sends
many different HCI commands. The __hci_request function should only
return when all of these commands have completed (or a timeout occurs).
Several of these commands cause hci_req_complete to be called which
causes __hci_request to return prematurely.

This patch fixes the issue by adding a new hdev->req_last_cmd variable
which is set during the initialization procedure. The hci_req_complete
function will no longer mark the request as complete until the command
matching hdev->req_last_cmd completes.

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
v3: This version makes the last command of the request completely
generic so that __hci_request can be used for other multi-HCI command
purposes besides the init sequence (something that will be needed in the
future). The need for the HCI_CLOSE flag also goes away with this patch
so the original patch for that can be ignored.

 include/net/bluetooth/hci_core.h |    3 ++-
 net/bluetooth/hci_core.c         |   10 +++++++---
 net/bluetooth/hci_event.c        |   33 +++++++++++++++++++++++----------
 3 files changed, 32 insertions(+), 14 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 3786ee8..aad10e2 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -129,6 +129,7 @@ struct hci_dev {
 	wait_queue_head_t	req_wait_q;
 	__u32			req_status;
 	__u32			req_result;
+	int			req_last_cmd;
 
 	struct inquiry_cache	inq_cache;
 	struct hci_conn_hash	conn_hash;
@@ -693,6 +694,6 @@ struct hci_sec_filter {
 #define hci_req_lock(d)		mutex_lock(&d->req_lock)
 #define hci_req_unlock(d)	mutex_unlock(&d->req_lock)
 
-void hci_req_complete(struct hci_dev *hdev, int result);
+void hci_req_complete(struct hci_dev *hdev, int cmd, int result);
 
 #endif /* __HCI_CORE_H */
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 1a4ec97..f60e68b 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -91,9 +91,12 @@ static void hci_notify(struct hci_dev *hdev, int event)
 
 /* ---- HCI requests ---- */
 
-void hci_req_complete(struct hci_dev *hdev, int result)
+void hci_req_complete(struct hci_dev *hdev, int cmd, int result)
 {
-	BT_DBG("%s result 0x%2.2x", hdev->name, result);
+	BT_DBG("%s command %d result 0x%2.2x", hdev->name, cmd, result);
+
+	if (hdev->req_last_cmd && cmd != hdev->req_last_cmd)
+		return;
 
 	if (hdev->req_status == HCI_REQ_PEND) {
 		hdev->req_result = result;
@@ -149,7 +152,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
 		break;
 	}
 
-	hdev->req_status = hdev->req_result = 0;
+	hdev->req_last_cmd = hdev->req_status = hdev->req_result = 0;
 
 	BT_DBG("%s end: err %d", hdev->name, err);
 
@@ -252,6 +255,7 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 	/* Connection accept timeout ~20 secs */
 	param = cpu_to_le16(0x7d00);
 	hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
+	hdev->req_last_cmd = HCI_OP_WRITE_CA_TIMEOUT;
 }
 
 static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 8923b36..3810017 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -58,7 +58,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
 
 	clear_bit(HCI_INQUIRY, &hdev->flags);
 
-	hci_req_complete(hdev, status);
+	hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
 
 	hci_conn_check_pending(hdev);
 }
@@ -174,7 +174,7 @@ static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *s
 	if (!status)
 		hdev->link_policy = get_unaligned_le16(sent);
 
-	hci_req_complete(hdev, status);
+	hci_req_complete(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, status);
 }
 
 static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
@@ -183,7 +183,7 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
 
 	BT_DBG("%s status 0x%x", hdev->name, status);
 
-	hci_req_complete(hdev, status);
+	hci_req_complete(hdev, HCI_OP_RESET, status);
 }
 
 static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -235,7 +235,7 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
 			clear_bit(HCI_AUTH, &hdev->flags);
 	}
 
-	hci_req_complete(hdev, status);
+	hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status);
 }
 
 static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
@@ -258,7 +258,7 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
 			clear_bit(HCI_ENCRYPT, &hdev->flags);
 	}
 
-	hci_req_complete(hdev, status);
+	hci_req_complete(hdev, HCI_OP_WRITE_ENCRYPT_MODE, status);
 }
 
 static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
@@ -285,7 +285,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
 			set_bit(HCI_PSCAN, &hdev->flags);
 	}
 
-	hci_req_complete(hdev, status);
+	hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
 }
 
 static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
@@ -383,7 +383,7 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
 
 	BT_DBG("%s status 0x%x", hdev->name, status);
 
-	hci_req_complete(hdev, status);
+	hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status);
 }
 
 static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
@@ -536,7 +536,16 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
 	if (!rp->status)
 		bacpy(&hdev->bdaddr, &rp->bdaddr);
 
-	hci_req_complete(hdev, rp->status);
+	hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status);
+}
+
+static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+
+	BT_DBG("%s status 0x%x", hdev->name, status);
+
+	hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status);
 }
 
 static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
@@ -544,7 +553,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 	BT_DBG("%s status 0x%x", hdev->name, status);
 
 	if (status) {
-		hci_req_complete(hdev, status);
+		hci_req_complete(hdev, HCI_OP_INQUIRY, status);
 
 		hci_conn_check_pending(hdev);
 	} else
@@ -871,7 +880,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
 
 	clear_bit(HCI_INQUIRY, &hdev->flags);
 
-	hci_req_complete(hdev, status);
+	hci_req_complete(hdev, HCI_OP_INQUIRY, status);
 
 	hci_conn_check_pending(hdev);
 }
@@ -1379,6 +1388,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
 		hci_cc_read_bd_addr(hdev, skb);
 		break;
 
+	case HCI_OP_WRITE_CA_TIMEOUT:
+		hci_cc_write_ca_timeout(hdev, skb);
+		break;
+
 	default:
 		BT_DBG("%s opcode 0x%x", hdev->name, opcode);
 		break;
-- 
1.7.2.3


^ permalink raw reply related

* Re: [PATCH 2/5] Change CreatePairedDevice to support LE devices
From: Claudio Takahasi @ 2010-12-16 17:16 UTC (permalink / raw)
  To: Claudio Takahasi, linux-bluetooth, Sheldon Demario
In-Reply-To: <20101216092432.GB4322@jh-x301>

Hi Johan,

On Thu, Dec 16, 2010 at 6:24 AM, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> Hi,
>
> On Wed, Dec 15, 2010, Claudio Takahasi wrote:
>> CreatePairedDevice implements now the same behaviour of CreateDevice,
>> triggering Discover All Primary Services when needed. SMP negotiation
>> starts when the link is established. LE capable kernel is required to
>> test this method properly.
>>
>> Limitation: For dual mode devices, Discover All Primary Services is not
>> being executed after SDP search if GATT record is found.
>> ---
>>  src/adapter.c     |   46 ++++++++++++++++++++++++---
>>  src/device.c      |   89 +++++++++++++++++++++++++++-------------------------
>>  src/device.h      |    7 +++-
>>  src/glib-helper.c |    5 ++-
>>  src/glib-helper.h |    3 ++
>>  5 files changed, 98 insertions(+), 52 deletions(-)
>
> Couple of issue here:
>
>> @@ -1642,6 +1646,8 @@ static DBusMessage *create_paired_device(DBusConnection *conn,
>>       struct btd_device *device;
>>       const gchar *address, *agent_path, *capability, *sender;
>>       uint8_t cap;
>> +     device_type_t type;
>> +     int err;
>>
>>       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
>>                                       DBUS_TYPE_OBJECT_PATH, &agent_path,
>> @@ -1666,12 +1672,40 @@ static DBusMessage *create_paired_device(DBusConnection *conn,
>>       if (cap == IO_CAPABILITY_INVALID)
>>               return btd_error_invalid_args(msg);
>>
>> -     device = adapter_get_device(conn, adapter, address);
>> -     if (!device)
>> -             return btd_error_failed(msg,
>> -                             "Unable to create a new device object");
>> +     device = adapter_find_device(adapter, address);
>> +     if (!device) {
>> +             struct remote_dev_info *dev, match;
>> +
>> +             memset(&match, 0, sizeof(struct remote_dev_info));
>> +             str2ba(address, &match.bdaddr);
>> +             match.name_status = NAME_ANY;
>> +
>> +             dev = adapter_search_found_devices(adapter, &match);
>> +             if (dev && dev->flags)
>> +                     type = flags2type(dev->flags);
>> +             else
>> +                     type = DEVICE_TYPE_BREDR;
>> +
>> +             if (type == DEVICE_TYPE_LE &&
>> +                                     !event_is_connectable(dev->evt_type))
>> +                     return btd_error_failed(msg,
>> +                                     "Device is not connectable");
>> +
>> +             device = adapter_create_device(conn, adapter, address, type);
>> +             if (!device)
>> +                     return NULL;
>> +     } else
>> +             type = device_get_type(device);
>> +
>> +     if (type != DEVICE_TYPE_LE)
>> +             return device_create_bonding(device, conn, msg,
>> +                                                     agent_path, cap);
>>
>> -     return device_create_bonding(device, conn, msg, agent_path, cap);
>> +     err = device_browse_primary(device, conn, msg, BT_IO_SEC_HIGH);
>> +     if (err < 0)
>> +             return btd_error_failed(msg, strerror(-err));
>> +
>> +     return NULL;
>>  }
>
> I don't really like the way this makes the create_paired_device function
> quite long. Could you maybe refactor the if (!device) branch into a
> separate function?
ok. We will try. Maybe it will be possible to create a common function
to move shared code between CreateDevice and CreatePairedDevice.

>
>> diff --git a/src/device.h b/src/device.h
>> index 784e931..cafa529 100644
>> --- a/src/device.h
>> +++ b/src/device.h
>> @@ -24,6 +24,8 @@
>>
>>  #define DEVICE_INTERFACE     "org.bluez.Device"
>>
>> +#include "btio.h"
>> +
>
> Includes should be the first thing after the copyright/license comments
> in the file. However, to keep a clear visibility of potential circular
> dependencies Marcel has requested this kind of inclusion of an internal
> header file from within an internal header file to be avoided. Instead
> make sure you include btio.h from early enough in the respective .c
> file. You could also reconsider if you really need BtIOSecLevel here.
> Maybe a "gboolean secure" flag would be enough?
For now a boolean is enough, we can change it to boolean.

>
>> --- a/src/glib-helper.h
>> +++ b/src/glib-helper.h
>> @@ -21,6 +21,8 @@
>>   *
>>   */
>>
>> +#include "btio.h"
>> +
>
> Same here.
>
> I'm feeling a little bit ambivalent about your additions to
> glib-helper.c. It never had a clearly defined scope and I had been
> hoping to get rid of it completely. However now it seems you guys are
> constantly adding new stuff there. Is it really so that you can't find a
> more specific location for these functions? Could you describe in one or
> two sentences the purpose and scope that you think the glib-helper.c
> functions have?
>
> Johan
>

Currently, the purpose are service search functions and UUIDs utility functions.
glib-helper was originally created to implement some utility functions
to manage connections and sdp search abstractions.
Connection functions were moved/removed when btio was created. I have
two suggestions to try cleanup the code:
1. keep only sdp functions that use GLib types and rename the file to
gsdp or other convenient name
2. Or create a btd_device_search/cancel functions(moving them to
device.c) and try to remove glib-helper from the source tree, in the
worst case keep only functions to manipulate UUIDs

The bt_discover_primary can be moved to gatt.c if we split the
discover cancel function.
bt_discover_services() can be removed, there isn't reference in code.

Which approach do you prefer? Any other suggestion?

Regards,
Claudio

^ permalink raw reply

* Re: [RFC] Bluetooth: Use non-flushable pb flag by default for ACL data on capable chipsets.
From: Mat Martineau @ 2010-12-16 17:03 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: Gustavo F. Padovan, linux-bluetooth
In-Reply-To: <AANLkTi=Kfm9jV0HA=Sa9=hs1meXthrpZEzn5-czTaSO+@mail.gmail.com>


On Thu, 16 Dec 2010, Andrei Emeltchenko wrote:

> Hi,
>
> On Wed, Dec 15, 2010 at 6:35 PM, Mat Martineau <mathewm@codeaurora.org> wrote:
> <skipped>
>> There is one more thing missing:  Even though there is an L2CAP socket
>> option to set flush_to, and the flush_to is passed around during L2CAP
>> configuration, there is no use of the "Write Automatic Flush Timeout" HCI
>> command to tell the baseband what the flush timeout is!  Since the flush
>> timeout is shared across all connections on the ACL, how should BlueZ handle
>> the case where different flush timeouts are set on connections that share
>> the same ACL?  (My guess is that either the longest or shortest timeout
>> should be used, but there are good arguments either way)
>
> I would suggest bluetoothd to take care about setting Flush Timeout. 
> There is of course possibility to have sockopt for timeout and send 
> HCI command but this looks like a dirty hack.
>
> I think bluetoothd can read compare and write new flush timeout value.

There is *already* a sockopt for flush timeout (flush_to in 
l2cap_options, it was added before 2005), but it is not terribly 
useful because it does not configure the baseband.

One more piece of background information: The spec requires the 
default flush timeout to be infinite, so if no "Write Automatic Flush 
Timeout" command is sent, none of this flush code will accomplish 
anything.  Android has customized their version of BlueZ to send this 
command for A2DP connections, with certain BR/EDR basebands.

I don't have any major objection to managing this setting from 
bluetoothd.  My only minor objection is that it requires an 
application to manipulate the setting via DBus instead of using the 
existing sockopt - it would be confusing to have both available, but I 
suppose the sockopt could be deprecated or made read-only.  The flush 
timeout would seem to fit well as a device property.


--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum


^ permalink raw reply

* Re: [PATCH 1/5] Bluetooth: Add error handling for managment command handlers
From: Gustavo F. Padovan @ 2010-12-16 16:52 UTC (permalink / raw)
  To: johan.hedberg; +Cc: linux-bluetooth
In-Reply-To: <1292267227-22028-2-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

* johan.hedberg@gmail.com <johan.hedberg@gmail.com> [2010-12-13 21:07:03 +0200]:

> From: Johan Hedberg <johan.hedberg@nokia.com>
> 
> The command handlers for bluetooth management messaging should be able
> to report errors (such as memory allocation failures) to the higher
> levels in the call stack.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
> ---
>  net/bluetooth/mgmt.c |   11 ++++++++---
>  1 files changed, 8 insertions(+), 3 deletions(-)
> 
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index d15bf67..7ea5489 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -29,7 +29,7 @@
>  #include <net/bluetooth/hci_core.h>
>  #include <net/bluetooth/mgmt.h>
>  
> -static void cmd_status(struct sock *sk, u16 cmd, u8 status)
> +static int cmd_status(struct sock *sk, u16 cmd, u8 status)
>  {
>  	struct sk_buff *skb;
>  	struct mgmt_hdr *hdr;
> @@ -39,7 +39,7 @@ static void cmd_status(struct sock *sk, u16 cmd, u8 status)
>  
>  	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
>  	if (!skb)
> -		return;
> +		return -ENOMEM;
>  
>  	hdr = (void *) skb_put(skb, sizeof(*hdr));
>  
> @@ -52,6 +52,8 @@ static void cmd_status(struct sock *sk, u16 cmd, u8 status)
>  
>  	if (sock_queue_rcv_skb(sk, skb) < 0)
>  		kfree_skb(skb);
> +
> +	return 0;
>  }
>  
>  int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
> @@ -87,10 +89,13 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
>  	switch (opcode) {
>  	default:
>  		BT_DBG("Unknown op %u", opcode);
> -		cmd_status(sk, opcode, 0x01);
> +		err = cmd_status(sk, opcode, 0x01);
>  		break;
>  	}
>  
> +	if (err < 0)
> +		goto done;
> +
>  	err = msglen;


I think
	if (!err)
		err = msglen;


is better.


-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply

* Re: HFP: typo in error path?
From: Gustavo F. Padovan @ 2010-12-16 16:09 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: linux-bluetooth
In-Reply-To: <20101216064231.GA2033@candlejack.bmw-carit.intra>

Hi Daniel,

* Daniel Wagner <wagi@monom.org> [2010-12-16 07:42:31 +0100]:

> Hi,
> 
> I'm reading a bit through the code and try to understand how the HF
> role in HFP is implemented. I found following in audio/gateway.c:
> 
> static gboolean sco_io_cb(GIOChannel *chan, GIOCondition cond,
> 			struct audio_device *dev)
> {
> 	struct gateway *gw = dev->gateway;
> 
> 	if (cond & G_IO_NVAL)
> 		return FALSE;
> 
> 	if (cond & (G_IO_ERR | G_IO_HUP)) {
> 		DBG("sco connection is released");
> 		g_io_channel_shutdown(gw->sco, TRUE, NULL);
> 		g_io_channel_unref(gw->sco);
> 		gw->sco = NULL;
> 		change_state(dev, GATEWAY_STATE_CONNECTED);
> 		return FALSE;
> 	}
> 
> 	return TRUE;
> }
> 
> I don't really understand what's going on here, but just from the
> naming I think the change_state call should be
> GATEWAY_STATE_DISCONNECTED. If my assumation is correct I can spin a
> patch.

GATEWAY_STATE_CONNECTED means that we have Service Level Connection with the
Phone, then if a new call arrives we change to the GATEWAY_STATE_PLAYING
state to signal that we have audio, but if for some reason the SCO link fails
we just go back to the GATEWAY_STATE_CONNECTED state because we still have the
SLC running. So your assumption is wrong. ;)

-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply

* Re: [PATCH v3] Further optimalization of PBAP tracker queries
From: Johan Hedberg @ 2010-12-16 15:06 UTC (permalink / raw)
  To: Radoslaw Jablonski; +Cc: linux-bluetooth
In-Reply-To: <1292511423-3140-1-git-send-email-ext-jablonski.radoslaw@nokia.com>

Hi Radek,

On Thu, Dec 16, 2010, Radoslaw Jablonski wrote:
> Now emails, addresses and telephone numbers of the same type
> (work/home/other) are concatenated into sigle strings - this
> gains huge difference in speed of queries when there are a lot
> of contacts in database. Also changed functions for splitting
> these fields on our backend side.
> ---
>  plugins/phonebook-tracker.c | 1241 +++++++++++++++++++++++++------------------
>  1 files changed, 711 insertions(+), 530 deletions(-)

Thanks. The patch has been pushed upstream.

Johan

^ permalink raw reply

* [PATCH v3] Further optimalization of PBAP tracker queries
From: Radoslaw Jablonski @ 2010-12-16 14:57 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Radoslaw Jablonski

Now emails, addresses and telephone numbers of the same type
(work/home/other) are concatenated into sigle strings - this
gains huge difference in speed of queries when there are a lot
of contacts in database. Also changed functions for splitting
these fields on our backend side.
---
 plugins/phonebook-tracker.c | 1241 +++++++++++++++++++++++++------------------
 1 files changed, 711 insertions(+), 530 deletions(-)

diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
index 0a023aa..59221cb 100644
--- a/plugins/phonebook-tracker.c
+++ b/plugins/phonebook-tracker.c
@@ -46,103 +46,111 @@
 #define AFFILATION_HOME "Home"
 #define AFFILATION_WORK "Work"
 #define ADDR_FIELD_AMOUNT 7
-#define PULL_QUERY_COL_AMOUNT 40
+#define PULL_QUERY_COL_AMOUNT 26
 #define COUNT_QUERY_COL_AMOUNT 1
 
-#define COL_PHONE_NUMBER 0
+#define COL_PHONE_AFF 0 /* work/home phone numbers */
 #define COL_FULL_NAME 1
 #define COL_FAMILY_NAME 2
 #define COL_GIVEN_NAME 3
 #define COL_ADDITIONAL_NAME 4
 #define COL_NAME_PREFIX 5
 #define COL_NAME_SUFFIX 6
-#define COL_EMAIL 7
-#define COL_CELL_NUMBER 8
-
-#define COL_ADDR_POBOX 9
-#define COL_ADDR_EXT 10
-#define COL_ADDR_STREET 11
-#define COL_ADDR_LOCALITY 12
-#define COL_ADDR_REGION 13
-#define COL_ADDR_CODE 14
-#define COL_ADDR_COUNTRY 15
-
-#define COL_FAX_NUMBER 16
-#define COL_AFF_TYPE 17
-#define COL_BIRTH_DATE 18
-#define COL_NICKNAME 19
-#define COL_URL 20
-#define COL_PHOTO 21
-
-#define COL_ORG_NAME 22
-#define COL_ORG_DEPARTMENT 23
-#define COL_ORG_ROLE 24
-
-#define COL_UID 25
-#define COL_TITLE 26
-#define COL_OTHER_NUMBER 27
-
-#define COL_OTHER_ADDR_POBOX 28
-#define COL_OTHER_ADDR_EXT 29
-#define COL_OTHER_ADDR_STREET 30
-#define COL_OTHER_ADDR_LOCALITY 31
-#define COL_OTHER_ADDR_REGION 32
-#define COL_OTHER_ADDR_CODE 33
-#define COL_OTHER_ADDR_COUNTRY 34
-
-#define COL_OTHER_EMAIL 35
-#define COL_DATE 36
-#define COL_SENT 37
-#define COL_ANSWERED 38
-#define CONTACTS_ID_COL 39
+#define COL_EMAIL_CONTACT 7 /*email's for other category */
+#define COL_ADDR_AFF 8 /* addresses from affilation */
+#define COL_ADDR_CONTACT 9 /* addresses from contacts */
+#define COL_PHONE_CONTACT 10 /* phone numbers from contact's */
+#define COL_BIRTH_DATE 11
+#define COL_NICKNAME 12
+#define COL_URL 13
+#define COL_PHOTO 14
+#define COL_ORG_ROLE 15
+#define COL_UID 16
+#define COL_TITLE 17
+#define COL_AFF_TYPE 18
+#define COL_ORG_NAME 19
+#define COL_ORG_DEPARTMENT 20
+#define COL_EMAIL_AFF 21 /* email's from affilation (work/home) */
+#define COL_DATE 22
+#define COL_SENT 23
+#define COL_ANSWERED 24
+#define CONTACTS_ID_COL 25
 #define CONTACT_ID_PREFIX "contact:"
 
+#define FAX_NUM_TYPE "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#FaxNumber"
+#define MOBILE_NUM_TYPE "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#CellPhoneNumber"
+
+#define MAIN_DELIM "\30" /* Main delimiter between phones, addresses, emails*/
+#define SUB_DELIM "\31" /* Delimiter used in telephone number strings*/
+#define MAX_FIELDS 100 /* Max amount of fields to be concatenated at once*/
+
 #define CONTACTS_QUERY_ALL						\
-	"SELECT nco:phoneNumber(?v) nco:fullname(?c) "			\
-	"nco:nameFamily(?c) nco:nameGiven(?c) "				\
-	"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) "		\
-	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) ?vc "		\
-	"nco:pobox(?p) nco:extendedAddress(?p) "			\
-	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) ?f ?affType "		\
-	"nco:birthDate(?c) nco:nickname(?c) nco:url(?c) "		\
-	"?file nco:fullname(?o) nco:department(?a) "			\
-	"nco:role(?a) nco:contactUID(?c) "				\
-	"nco:title(?a) ?t nco:pobox(?po) nco:extendedAddress(?po) "	\
-	"nco:streetAddress(?po) nco:locality(?po) nco:region(?po) "	\
-	"nco:postalcode(?po) nco:country(?po) nco:emailAddress(?eo) "	\
-	"\"NOTACALL\" \"false\" \"false\" ?c "				\
-	"WHERE { "							\
-		"?c a nco:PersonContact . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-	"OPTIONAL { ?c nco:hasPhoneNumber ?h . "			\
-		"OPTIONAL {"						\
-		"?h a nco:FaxNumber ; "					\
-		"nco:phoneNumber ?f . "					\
-		"}"							\
-		"OPTIONAL {"						\
-		"?h a nco:CellPhoneNumber ; "				\
-		"nco:phoneNumber ?vc"					\
-		"}"							\
-		"OPTIONAL {"						\
-		"?h a nco:VoicePhoneNumber ; "				\
-		"nco:phoneNumber ?t"					\
-		"}"							\
-	"}"								\
-	"OPTIONAL { "							\
-		"?c nco:hasAffiliation ?a . "				\
-		"OPTIONAL { ?a rdfs:label ?affType .}"			\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:hasPhoneNumber ?v . } "	\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-	"} "								\
-	"OPTIONAL { ?c nco:hasPostalAddress ?po . } "			\
-	"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "			\
-	"}"
+"SELECT "								\
+"(SELECT GROUP_CONCAT("							\
+"nco:phoneNumber(?number), \"\30\")"					\
+"WHERE {"								\
+"	?_role nco:hasPhoneNumber ?number"				\
+"}) "									\
+"nco:fullname(?_contact) "						\
+"nco:nameFamily(?_contact) "						\
+"nco:nameGiven(?_contact) "						\
+"nco:nameAdditional(?_contact) "					\
+"nco:nameHonorificPrefix(?_contact) "					\
+"nco:nameHonorificSuffix(?_contact) "					\
+"(SELECT GROUP_CONCAT(?emailaddress_other, \"\30\") " 			\
+	"WHERE {"							\
+	"?_contact nco:hasEmailAddress "				\
+			"[nco:emailAddress ?emailaddress_other]"	\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \";\","	\
+"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:locality(?aff_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:region(?aff_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:country(?aff_addr), \"\") ),\";\")"		\
+"WHERE {"								\
+"?_role nco:hasPostalAddress ?aff_addr"					\
+"}) "									\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+"tracker:coalesce(nco:pobox(?oth_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:extendedAddress(?oth_addr), \"\"), \";\","	\
+"tracker:coalesce(nco:streetAddress(?oth_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:locality(?oth_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:region(?oth_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:postalcode(?oth_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:country(?oth_addr), \"\") ),\"\30\")"		\
+"WHERE {"								\
+"	?_contact nco:hasPostalAddress ?oth_addr"			\
+"}) "									\
+"(SELECT GROUP_CONCAT(fn:concat(rdf:type(?contact_number),"		\
+"\"\31\", nco:phoneNumber(?contact_number)), \"\30\")"			\
+"WHERE {"								\
+"	?_contact nco:hasPhoneNumber ?contact_number"			\
+"}) "									\
+"nco:birthDate(?_contact) "						\
+"nco:nickname(?_contact) "						\
+"nco:url(?_contact) "							\
+"nie:url(nco:photo(?_contact)) "					\
+"nco:role(?_role) "							\
+"nco:contactUID(?_contact) "						\
+"nco:title(?_role) "							\
+"rdfs:label(?_role) "							\
+"nco:fullname(nco:org(?_role))"						\
+"nco:department(?_role) "						\
+"(SELECT GROUP_CONCAT(?emailaddress, \"\30\")"				\
+"WHERE {"								\
+"	?_role nco:hasEmailAddress [ nco:emailAddress ?emailaddress ]"	\
+"}) "									\
+"\"NOTACALL\" \"false\" \"false\" "					\
+"?_contact "								\
+"WHERE {"								\
+"	?_contact a nco:PersonContact ;"				\
+"	nco:nameFamily ?_key ."						\
+"	OPTIONAL {?_contact nco:hasAffiliation ?_role .}"		\
+"}"									\
+"ORDER BY ?_key tracker:id(?_contact)"
 
 #define CONTACTS_QUERY_ALL_LIST						\
 	"SELECT ?c nco:nameFamily(?c) "					\
@@ -159,84 +167,114 @@
 	"} GROUP BY ?c"
 
 #define MISSED_CALLS_QUERY						\
-	"SELECT nco:phoneNumber(?ap) nco:fullname(?c) "			\
-	"nco:nameFamily(?c) nco:nameGiven(?c) "				\
-	"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) "		\
-	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) ?vc "		\
-	"nco:pobox(?p) nco:extendedAddress(?p) "			\
-	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) \"\" ?affType "		\
-	"nco:birthDate(?c) nco:nickname(?c) nco:url(?c) "		\
-	"?file nco:fullname(?o) nco:department(?a) "			\
-	"nco:role(?a) nco:contactUID(?c) "				\
-	"nco:title(?a) nco:phoneNumber(?t) nco:pobox(?po) nco:extendedAddress(?po) "	\
-	"nco:streetAddress(?po) nco:locality(?po) nco:region(?po) "	\
-	"nco:postalcode(?po) nco:country(?po) nco:emailAddress(?eo) "	\
-	"nmo:receivedDate(?call) "					\
-	"nmo:isSent(?call) nmo:isAnswered(?call) ?x "			\
+"SELECT "								\
+"(SELECT nco:phoneNumber(?role_number) "				\
+	"WHERE {"							\
+	"?_role nco:hasPhoneNumber ?role_number "			\
+	"FILTER (?role_number = ?_number)"				\
+"} GROUP BY nco:phoneNumber(?role_number) ) "				\
+	"nco:fullname(?_contact) "					\
+	"nco:nameFamily(?_contact) "					\
+	"nco:nameGiven(?_contact) "					\
+	"nco:nameAdditional(?_contact) "				\
+	"nco:nameHonorificPrefix(?_contact) "				\
+	"nco:nameHonorificSuffix(?_contact) "				\
+"(SELECT GROUP_CONCAT(?emailaddress_other, \"\30\") " 			\
+	"WHERE {"							\
+	"?_contact nco:hasEmailAddress "				\
+			"[nco:emailAddress ?emailaddress_other]"	\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?aff_addr), \"\") ),\";\")"	\
+	"WHERE {"							\
+	"?_role nco:hasPostalAddress ?aff_addr"				\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?oth_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?oth_addr), \"\") ),\"\30\")"	\
+	"WHERE {"							\
+	"?_contact nco:hasPostalAddress ?oth_addr"			\
+	"}) "								\
+"(SELECT fn:concat(rdf:type(?contact_number),"				\
+	"\"\31\", nco:phoneNumber(?contact_number))"			\
+	"WHERE {"							\
+	"{"								\
+"		?_contact nco:hasPhoneNumber ?contact_number . "	\
+"		FILTER (?contact_number = ?_number) "			\
+"	} UNION { "							\
+"		?_unb_contact nco:hasPhoneNumber ?contact_number . "	\
+"	} "								\
+"}GROUP BY nco:phoneNumber(?contact_number) ) "				\
+	"nco:birthDate(?_contact) "					\
+	"nco:nickname(?_contact) "					\
+	"nco:url(?_contact) "						\
+	"nie:url(nco:photo(?_contact)) "				\
+	"nco:role(?_role) "						\
+	"nco:contactUID(?_contact) "					\
+	"nco:title(?_role) "						\
+	"rdfs:label(?_role) "						\
+	"nco:fullname(nco:org(?_role)) "				\
+	"nco:department(?_role) "					\
+"(SELECT GROUP_CONCAT(?emailaddress, \"\30\") "				\
 	"WHERE { "							\
-	"{ "								\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false ; "					\
-		"nmo:isAnswered false . "				\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasPhoneNumber ?t . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL { "						\
-			"?t a nco:CellPhoneNumber ; "			\
-				"nco:phoneNumber ?vc . "		\
-		"} "							\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-		"OPTIONAL { "						\
-			"?c nco:hasAffiliation ?a . "			\
-			"OPTIONAL { ?a nco:title ?title } "		\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:org ?o . } "			\
-		"} "							\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?ap . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false ; "					\
-		"nmo:isAnswered false . "				\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasAffiliation ?a . "				\
-		"?a nco:hasPhoneNumber ?ap . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL {?a rdfs:label ?affType . }"			\
-		"OPTIONAL {?a nco:hasEmailAddress ?e . } "		\
-		"OPTIONAL {?a nco:hasPostalAddress ?p . }"		\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-		"OPTIONAL { ?a nco:title ?title } "			\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false ; "					\
-		"nmo:isAnswered false . "				\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasPhoneNumber ?t . } "			\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasAffiliation ?a . "			\
-			"?a nco:hasPhoneNumber ?t . } "			\
-		"FILTER ( !bound(?c) && !bound(?a) ) . "		\
-	"} "								\
-	"} ORDER BY DESC(nmo:receivedDate(?call)) "
+	"?_role nco:hasEmailAddress [ nco:emailAddress ?emailaddress ] "\
+	"}) "								\
+	"nmo:receivedDate(?_call) "					\
+	"nmo:isSent(?_call) "						\
+	"nmo:isAnswered(?_call) "					\
+	"fn:concat(tracker:coalesce(?_ncontact, \"\"),"			\
+	"tracker:coalesce(?_unb_contact, \"\"))"			\
+	" "								\
+"WHERE { "								\
+"{ "									\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_ncontact ; "					\
+	"nmo:isAnswered false ;"					\
+	"nmo:isSent false . "						\
+	"?_contact a nco:PersonContact ; "				\
+	"nco:hasPhoneNumber ?_number . "				\
+	"OPTIONAL { ?_contact nco:hasAffiliation ?_role .} "		\
+	"?_contact nco:nameFamily ?_key ."				\
+"} UNION { "								\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_ncontact ; "					\
+	"nmo:isAnswered false ;"					\
+	"nmo:isSent false . "						\
+	"?_contact a nco:PersonContact . "				\
+	"?_contact nco:nameFamily ?_key . "				\
+	"?_contact nco:hasAffiliation ?_role . "			\
+	"?_role nco:hasPhoneNumber ?_number . "				\
+"} UNION { "								\
+	"?_unb_contact a nco:Contact . "				\
+	"?_unb_contact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_unb_contact ; "					\
+	"nmo:isAnswered false ;"					\
+	"nmo:isSent false . "						\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasPhoneNumber ?_number . } "				\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasAffiliation ?_role . "					\
+	"?_role nco:hasPhoneNumber ?_number. } "			\
+	"FILTER ( !bound(?_contact) && !bound(?_role) ) "		\
+"} "									\
+"} "									\
+"ORDER BY DESC(nmo:sentDate(?_call)) "
 
 
 #define MISSED_CALLS_LIST						\
@@ -275,85 +313,114 @@
 	"} GROUP BY ?call ORDER BY DESC(nmo:receivedDate(?call))"
 
 #define INCOMING_CALLS_QUERY						\
-	"SELECT nco:phoneNumber(?ap) nco:fullname(?c) "			\
-	"nco:nameFamily(?c) nco:nameGiven(?c) "				\
-	"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) "		\
-	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) ?vc "		\
-	"nco:pobox(?p) nco:extendedAddress(?p) "			\
-	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) \"\" ?affType "		\
-	"nco:birthDate(?c) nco:nickname(?c) nco:url(?c) "		\
-	"?file nco:fullname(?o) nco:department(?a) "			\
-	"nco:role(?a) nco:contactUID(?c) "				\
-	"nco:title(?a) nco:phoneNumber(?t) nco:pobox(?po) "		\
-	"nco:extendedAddress(?po) "					\
-	"nco:streetAddress(?po) nco:locality(?po) nco:region(?po) "	\
-	"nco:postalcode(?po) nco:country(?po) nco:emailAddress(?eo) "	\
-	"nmo:receivedDate(?call) "					\
-	"nmo:isSent(?call) nmo:isAnswered(?call) ?x "			\
+"SELECT "								\
+"(SELECT nco:phoneNumber(?role_number) "				\
+	"WHERE {"							\
+"	?_role nco:hasPhoneNumber ?role_number"				\
+"	FILTER (?role_number = ?_number)"				\
+"} GROUP BY nco:phoneNumber(?role_number) ) "				\
+	"nco:fullname(?_contact) "					\
+	"nco:nameFamily(?_contact) "					\
+	"nco:nameGiven(?_contact) "					\
+	"nco:nameAdditional(?_contact) "				\
+	"nco:nameHonorificPrefix(?_contact) "				\
+	"nco:nameHonorificSuffix(?_contact) "				\
+"(SELECT GROUP_CONCAT(?emailaddress_other, \"\30\") " 			\
+	"WHERE {"							\
+	"?_contact nco:hasEmailAddress "				\
+			"[nco:emailAddress ?emailaddress_other]"	\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?aff_addr), \"\") ),\";\")"	\
+	"WHERE {"							\
+	"?_role nco:hasPostalAddress ?aff_addr"				\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?oth_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?oth_addr), \"\") ),\"\30\")"	\
+	"WHERE {"							\
+	"?_contact nco:hasPostalAddress ?oth_addr"			\
+	"}) "								\
+"(SELECT fn:concat(rdf:type(?contact_number),"				\
+	"\"\31\", nco:phoneNumber(?contact_number))"			\
+	"WHERE {"							\
+	"{"								\
+"		?_contact nco:hasPhoneNumber ?contact_number . "	\
+"		FILTER (?contact_number = ?_number) "			\
+"	} UNION { "							\
+"		?_unb_contact nco:hasPhoneNumber ?contact_number . "	\
+"	} "								\
+	"}GROUP BY nco:phoneNumber(?contact_number) ) "			\
+	"nco:birthDate(?_contact) "					\
+	"nco:nickname(?_contact) "					\
+	"nco:url(?_contact) "						\
+	"nie:url(nco:photo(?_contact)) "				\
+	"nco:role(?_role) "						\
+	"nco:contactUID(?_contact) "					\
+	"nco:title(?_role) "						\
+	"rdfs:label(?_role) "						\
+	"nco:fullname(nco:org(?_role)) "				\
+	"nco:department(?_role) "					\
+"(SELECT GROUP_CONCAT(?emailaddress, \"\30\") "				\
 	"WHERE { "							\
-	"{ "								\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false ; "					\
-		"nmo:isAnswered true . "				\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasPhoneNumber ?t . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL { "						\
-			"?t a nco:CellPhoneNumber ; "			\
-				"nco:phoneNumber ?vc . "		\
-		"} "							\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-		"OPTIONAL { "						\
-			"?c nco:hasAffiliation ?a . "			\
-			"OPTIONAL { ?a nco:title ?title } "		\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:org ?o . } "			\
-		"} "							\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?ap . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false ; "					\
-		"nmo:isAnswered true . "				\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasAffiliation ?a . "				\
-		"?a nco:hasPhoneNumber ?ap . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL {?a rdfs:label ?affType . }"			\
-		"OPTIONAL {?a nco:hasEmailAddress ?e . } "		\
-		"OPTIONAL {?a nco:hasPostalAddress ?p . }"		\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-		"OPTIONAL { ?a nco:title ?title } "			\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false ; "					\
-		"nmo:isAnswered true . "				\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasPhoneNumber ?t . } "			\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasAffiliation ?a . "			\
-			"?a nco:hasPhoneNumber ?t . } "			\
-		"FILTER ( !bound(?c) && !bound(?a) ) . "		\
-	"} "								\
-	"} ORDER BY DESC(nmo:receivedDate(?call)) "
+	"?_role nco:hasEmailAddress [ nco:emailAddress ?emailaddress ] "\
+	"}) "								\
+	"nmo:receivedDate(?_call) "					\
+	"nmo:isSent(?_call) "						\
+	"nmo:isAnswered(?_call) "					\
+	"fn:concat(tracker:coalesce(?_ncontact, \"\"),"			\
+	"tracker:coalesce(?_unb_contact, \"\"))"			\
+	" "								\
+"WHERE { "								\
+"{ "									\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_ncontact ; "					\
+	"nmo:isAnswered true ;"						\
+	"nmo:isSent false . "						\
+	"?_contact a nco:PersonContact ; "				\
+	"nco:hasPhoneNumber ?_number . "				\
+	"OPTIONAL { ?_contact nco:hasAffiliation ?_role .} "		\
+	"?_contact nco:nameFamily ?_key ."				\
+"} UNION { "								\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_ncontact ; "					\
+	"nmo:isAnswered true ;"						\
+	"nmo:isSent false . "						\
+	"?_contact a nco:PersonContact . "				\
+	"?_contact nco:nameFamily ?_key . "				\
+	"?_contact nco:hasAffiliation ?_role . "			\
+	"?_role nco:hasPhoneNumber ?_number . "				\
+"} UNION { "								\
+	"?_unb_contact a nco:Contact . "				\
+	"?_unb_contact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_unb_contact ; "					\
+	"nmo:isAnswered true ;"						\
+	"nmo:isSent false . "						\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasPhoneNumber ?_number . } "				\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasAffiliation ?_role . "					\
+	"?_role nco:hasPhoneNumber ?_number. } "			\
+	"FILTER ( !bound(?_contact) && !bound(?_role) ) "		\
+"} "									\
+"} "\
+"ORDER BY DESC(nmo:sentDate(?_call)) "
 
 #define INCOMING_CALLS_LIST						\
 	"SELECT ?c nco:nameFamily(?c) "					\
@@ -391,82 +458,111 @@
 	"} GROUP BY ?call ORDER BY DESC(nmo:receivedDate(?call))"
 
 #define OUTGOING_CALLS_QUERY						\
-	"SELECT nco:phoneNumber(?ap) nco:fullname(?c) "			\
-	"nco:nameFamily(?c) nco:nameGiven(?c) "				\
-	"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) "		\
-	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) ?vc "		\
-	"nco:pobox(?p) nco:extendedAddress(?p) "			\
-	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) \"\" ?affType "		\
-	"nco:birthDate(?c) nco:nickname(?c) nco:url(?c) "		\
-	"?file nco:fullname(?o) nco:department(?a) "			\
-	"nco:role(?a) nco:contactUID(?c) "				\
-	"nco:title(?a) nco:phoneNumber(?t) nco:pobox(?po) "		\
-	"nco:extendedAddress(?po) "					\
-	"nco:streetAddress(?po) nco:locality(?po) nco:region(?po) "	\
-	"nco:postalcode(?po) nco:country(?po) nco:emailAddress(?eo) "	\
-	"nmo:receivedDate(?call) "					\
-	"nmo:isSent(?call) nmo:isAnswered(?call) ?x "			\
+"SELECT "								\
+"(SELECT nco:phoneNumber(?role_number) "				\
+	"WHERE {"							\
+"	?_role nco:hasPhoneNumber ?role_number"				\
+"	FILTER (?role_number = ?_number)"				\
+"} GROUP BY nco:phoneNumber(?role_number) ) "				\
+	"nco:fullname(?_contact) "					\
+	"nco:nameFamily(?_contact) "					\
+	"nco:nameGiven(?_contact) "					\
+	"nco:nameAdditional(?_contact) "				\
+	"nco:nameHonorificPrefix(?_contact) "				\
+	"nco:nameHonorificSuffix(?_contact) "				\
+"(SELECT GROUP_CONCAT(?emailaddress_other, \"\30\") " 			\
+	"WHERE {"							\
+	"?_contact nco:hasEmailAddress "				\
+			"[nco:emailAddress ?emailaddress_other]"	\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?aff_addr), \"\") ),\";\")"	\
+	"WHERE {"							\
+	"?_role nco:hasPostalAddress ?aff_addr"				\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?oth_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?oth_addr), \"\") ),\"\30\")"	\
+	"WHERE {"							\
+	"?_contact nco:hasPostalAddress ?oth_addr"			\
+	"}) "								\
+"(SELECT fn:concat(rdf:type(?contact_number),"				\
+	"\"\31\", nco:phoneNumber(?contact_number))"			\
+	"WHERE {"							\
+	"{"								\
+"		?_contact nco:hasPhoneNumber ?contact_number . "	\
+"		FILTER (?contact_number = ?_number) "			\
+"	} UNION { "							\
+"		?_unb_contact nco:hasPhoneNumber ?contact_number . "	\
+"	} "								\
+	"}GROUP BY nco:phoneNumber(?contact_number) ) "			\
+	"nco:birthDate(?_contact) "					\
+	"nco:nickname(?_contact) "					\
+	"nco:url(?_contact) "						\
+	"nie:url(nco:photo(?_contact)) "				\
+	"nco:role(?_role) "						\
+	"nco:contactUID(?_contact) "					\
+	"nco:title(?_role) "						\
+	"rdfs:label(?_role) "						\
+	"nco:fullname(nco:org(?_role)) "				\
+	"nco:department(?_role) "					\
+"(SELECT GROUP_CONCAT(?emailaddress, \"\30\") "				\
 	"WHERE { "							\
-	"{ "								\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:to ?x ; "						\
-		"nmo:isSent true . "					\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasPhoneNumber ?t . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL { "						\
-			"?t a nco:CellPhoneNumber ; "			\
-				"nco:phoneNumber ?vc . "		\
-		"} "							\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-		"OPTIONAL { "						\
-			"?c nco:hasAffiliation ?a . "			\
-			"OPTIONAL { ?a nco:title ?title } "		\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:org ?o . } "			\
-		"} "							\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?ap . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:to ?x ; "						\
-		"nmo:isSent true . "					\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasAffiliation ?a . "				\
-		"?a nco:hasPhoneNumber ?ap . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL {?a rdfs:label ?affType . }"			\
-		"OPTIONAL {?a nco:hasEmailAddress ?e . } "		\
-		"OPTIONAL {?a nco:hasPostalAddress ?p . }"		\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-		"OPTIONAL { ?a nco:title ?title } "			\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:to ?x ; "						\
-		"nmo:isSent true . "					\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasPhoneNumber ?t . } "			\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasAffiliation ?a . "			\
-			"?a nco:hasPhoneNumber ?t . } "			\
-		"FILTER ( !bound(?c) && !bound(?a) ) . "		\
-	"} "								\
-	"} ORDER BY DESC(nmo:sentDate(?call)) "
+	"?_role nco:hasEmailAddress [ nco:emailAddress ?emailaddress ] "\
+	"}) "								\
+	"nmo:receivedDate(?_call) "					\
+	"nmo:isSent(?_call) "						\
+	"nmo:isAnswered(?_call) "					\
+	"fn:concat(tracker:coalesce(?_ncontact, \"\"),"			\
+	"tracker:coalesce(?_unb_contact, \"\"))"			\
+	" "								\
+"WHERE { "								\
+"{ "									\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:to ?_ncontact ; "						\
+	"nmo:isSent true . "						\
+	"?_contact a nco:PersonContact ; "				\
+	"nco:hasPhoneNumber ?_number . "				\
+	"OPTIONAL { ?_contact nco:hasAffiliation ?_role .} "		\
+	"?_contact nco:nameFamily ?_key ."				\
+"} UNION { "								\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:to ?_ncontact ; "						\
+	"nmo:isSent true . "						\
+	"?_contact a nco:PersonContact . "				\
+	"?_contact nco:nameFamily ?_key . "				\
+	"?_contact nco:hasAffiliation ?_role . "			\
+	"?_role nco:hasPhoneNumber ?_number . "				\
+"} UNION { "								\
+	"?_unb_contact a nco:Contact . "				\
+	"?_unb_contact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:to ?_unb_contact ; "					\
+	"nmo:isSent true . "						\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasPhoneNumber ?_number . } "				\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasAffiliation ?_role . "					\
+	"?_role nco:hasPhoneNumber ?_number. } "			\
+	"FILTER ( !bound(?_contact) && !bound(?_role) ) "		\
+"} "									\
+"} "									\
+"ORDER BY DESC(nmo:sentDate(?_call)) "
 
 #define OUTGOING_CALLS_LIST						\
 	"SELECT ?c nco:nameFamily(?c) "					\
@@ -501,139 +597,143 @@
 	"} GROUP BY ?call ORDER BY DESC(nmo:sentDate(?call))"
 
 #define COMBINED_CALLS_QUERY						\
-	"SELECT nco:phoneNumber(?ap) nco:fullname(?c) "			\
-	"nco:nameFamily(?c) nco:nameGiven(?c) "				\
-	"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) "		\
-	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) ?vc "		\
-	"nco:pobox(?p) nco:extendedAddress(?p) "			\
-	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) \"\" ?affType "		\
-	"nco:birthDate(?c) nco:nickname(?c) nco:url(?c) "		\
-	"?file nco:fullname(?o) nco:department(?a) "			\
-	"nco:role(?a) nco:contactUID(?c) "				\
-	"nco:title(?a) nco:phoneNumber(?t) nco:pobox(?po) "		\
-	"nco:extendedAddress(?po) "					\
-	"nco:streetAddress(?po) nco:locality(?po) nco:region(?po) "	\
-	"nco:postalcode(?po) nco:country(?po) nco:emailAddress(?eo) "	\
-	"nmo:receivedDate(?call) "					\
-	"nmo:isSent(?call) nmo:isAnswered(?call) ?x "			\
+"SELECT "								\
+"(SELECT nco:phoneNumber(?role_number) "				\
+	"WHERE {"							\
+"	?_role nco:hasPhoneNumber ?role_number"				\
+"	FILTER (?role_number = ?_number)"				\
+"} GROUP BY nco:phoneNumber(?role_number) ) "				\
+	"nco:fullname(?_contact) "					\
+	"nco:nameFamily(?_contact) "					\
+	"nco:nameGiven(?_contact) "					\
+	"nco:nameAdditional(?_contact) "				\
+	"nco:nameHonorificPrefix(?_contact) "				\
+	"nco:nameHonorificSuffix(?_contact) "				\
+"(SELECT GROUP_CONCAT(?emailaddress_other, \"\30\") " 			\
+	"WHERE {"							\
+	"?_contact nco:hasEmailAddress "				\
+			"[nco:emailAddress ?emailaddress_other]"	\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?aff_addr), \"\") ),\";\")"	\
+	"WHERE {"							\
+	"?_role nco:hasPostalAddress ?aff_addr"				\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?oth_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?oth_addr), \"\") ),\"\30\")"	\
+	"WHERE {"							\
+	"?_contact nco:hasPostalAddress ?oth_addr"			\
+	"}) "								\
+"(SELECT fn:concat(rdf:type(?contact_number),"				\
+	"\"\31\", nco:phoneNumber(?contact_number))"			\
+	"WHERE {"							\
+	"{"								\
+"		?_contact nco:hasPhoneNumber ?contact_number . "	\
+"		FILTER (?contact_number = ?_number) "			\
+"	} UNION { "							\
+"		?_unb_contact nco:hasPhoneNumber ?contact_number . "	\
+"	} "								\
+	"}GROUP BY nco:phoneNumber(?contact_number) ) "			\
+	"nco:birthDate(?_contact) "					\
+	"nco:nickname(?_contact) "					\
+	"nco:url(?_contact) "						\
+	"nie:url(nco:photo(?_contact)) "				\
+	"nco:role(?_role) "						\
+	"nco:contactUID(?_contact) "					\
+	"nco:title(?_role) "						\
+	"rdfs:label(?_role) "						\
+	"nco:fullname(nco:org(?_role)) "				\
+	"nco:department(?_role) "					\
+"(SELECT GROUP_CONCAT(?emailaddress, \"\30\") "				\
 	"WHERE { "							\
-	"{ "								\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:to ?x ; "						\
-		"nmo:isSent true . "					\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasPhoneNumber ?t . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL { "						\
-			"?t a nco:CellPhoneNumber ; "			\
-				"nco:phoneNumber ?vc . "		\
-		"} "							\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-		"OPTIONAL { "						\
-			"?c nco:hasAffiliation ?a . "			\
-			"OPTIONAL { ?a nco:title ?title } "		\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:org ?o . } "			\
-		"} "							\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?ap . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:to ?x ; "						\
-		"nmo:isSent true . "					\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasAffiliation ?a . "				\
-		"?a nco:hasPhoneNumber ?ap . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL {?a rdfs:label ?affType . }"			\
-		"OPTIONAL {?a nco:hasEmailAddress ?e . } "		\
-		"OPTIONAL {?a nco:hasPostalAddress ?p . }"		\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-		"OPTIONAL { ?a nco:title ?title } "			\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:to ?x ; "						\
-		"nmo:isSent true . "					\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasPhoneNumber ?t . } "			\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasAffiliation ?a . "			\
-			"?a nco:hasPhoneNumber ?t . } "			\
-		"FILTER ( !bound(?c) && !bound(?a) ) . "		\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false . "					\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasPhoneNumber ?t . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL { "						\
-			"?t a nco:CellPhoneNumber ; "			\
-				"nco:phoneNumber ?vc . "		\
-		"} "							\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-		"OPTIONAL { "						\
-			"?c nco:hasAffiliation ?a . "			\
-			"OPTIONAL { ?a nco:title ?title } "		\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:org ?o . } "			\
-		"} "							\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?ap . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false . "					\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasAffiliation ?a . "				\
-		"?a nco:hasPhoneNumber ?ap . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL {?a rdfs:label ?affType . }"			\
-		"OPTIONAL {?a nco:hasEmailAddress ?e . } "		\
-		"OPTIONAL {?a nco:hasPostalAddress ?p . }"		\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-		"OPTIONAL { ?a nco:title ?title } "			\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false . "					\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasPhoneNumber ?t . } "			\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasAffiliation ?a . "			\
-			"?a nco:hasPhoneNumber ?t . } "			\
-		"FILTER ( !bound(?c) && !bound(?a) ) . "		\
-	"} "								\
-	"} ORDER BY DESC(nmo:receivedDate(?call)) "
+	"?_role nco:hasEmailAddress [ nco:emailAddress ?emailaddress ] "\
+	"}) "								\
+	"nmo:receivedDate(?_call) "					\
+	"nmo:isSent(?_call) "						\
+	"nmo:isAnswered(?_call) "					\
+	"fn:concat(tracker:coalesce(?_ncontact, \"\"),"			\
+	"tracker:coalesce(?_unb_contact, \"\"))"			\
+	" "								\
+"WHERE { "								\
+"{ "									\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:to ?_ncontact ; "						\
+	"nmo:isSent true . "						\
+	"?_contact a nco:PersonContact ; "				\
+	"nco:hasPhoneNumber ?_number . "				\
+	"OPTIONAL { ?_contact nco:hasAffiliation ?_role .} "		\
+	"?_contact nco:nameFamily ?_key ."				\
+"} UNION { "								\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:to ?_ncontact ; "						\
+	"nmo:isSent true . "						\
+	"?_contact a nco:PersonContact . "				\
+	"?_contact nco:nameFamily ?_key . "				\
+	"?_contact nco:hasAffiliation ?_role . "			\
+	"?_role nco:hasPhoneNumber ?_number . "				\
+"} UNION { "								\
+	"?_unb_contact a nco:Contact . "				\
+	"?_unb_contact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:to ?_unb_contact ; "					\
+	"nmo:isSent true . "						\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasPhoneNumber ?_number . } "				\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasAffiliation ?_role . "					\
+	"?_role nco:hasPhoneNumber ?_number. } "			\
+	"FILTER ( !bound(?_contact) && !bound(?_role) ) "		\
+"} UNION { "								\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_ncontact ; "					\
+	"nmo:isSent false . "						\
+	"?_contact a nco:PersonContact ; "				\
+	"nco:hasPhoneNumber ?_number . "				\
+	"OPTIONAL { ?_contact nco:hasAffiliation ?_role .} "		\
+	"?_contact nco:nameFamily ?_key ."				\
+"} UNION { "								\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_ncontact ; "					\
+	"nmo:isSent false . "						\
+	"?_contact a nco:PersonContact . "				\
+	"?_contact nco:nameFamily ?_key . "				\
+	"?_contact nco:hasAffiliation ?_role . "			\
+	"?_role nco:hasPhoneNumber ?_number . "				\
+"} UNION { "								\
+	"?_unb_contact a nco:Contact . "				\
+	"?_unb_contact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_unb_contact ; "					\
+	"nmo:isSent false . "						\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasPhoneNumber ?_number . } "				\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasAffiliation ?_role . "					\
+	"?_role nco:hasPhoneNumber ?_number. } "			\
+	"FILTER ( !bound(?_contact) && !bound(?_role) ) "		\
+"} "									\
+"} "									\
+"ORDER BY DESC(nmo:sentDate(?_call)) "
 
 #define COMBINED_CALLS_LIST						\
 	"SELECT ?c nco:nameFamily(?c) nco:nameGiven(?c) "		\
@@ -690,58 +790,77 @@
 	"} GROUP BY ?call ORDER BY DESC(nmo:receivedDate(?call))"
 
 #define CONTACTS_QUERY_FROM_URI						\
-	"SELECT nco:phoneNumber(?v) nco:fullname(<%s>) "			\
-	"nco:nameFamily(<%s>) nco:nameGiven(<%s>) "				\
-	"nco:nameAdditional(<%s>) nco:nameHonorificPrefix(<%s>) "		\
-	"nco:nameHonorificSuffix(<%s>) nco:emailAddress(?e) ?vc "		\
-	"nco:pobox(?p) nco:extendedAddress(?p) "			\
-	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) ?f ?affType "		\
-	"nco:birthDate(<%s>) nco:nickname(<%s>) nco:url(<%s>) "		\
-	"?file nco:fullname(?o) nco:department(?a) "			\
-	"nco:role(?a) nco:contactUID(<%s>) "				\
-	"nco:title(?a) ?t nco:pobox(?po) nco:extendedAddress(?po) "	\
-	"nco:streetAddress(?po) nco:locality(?po) nco:region(?po) "	\
-	"nco:postalcode(?po) nco:country(?po) nco:emailAddress(?eo) "	\
-	"\"NOTACALL\" \"false\" \"false\" <%s> "				\
-	"WHERE { "							\
-		"<%s> a nco:PersonContact . "				\
-		"OPTIONAL { "						\
-			"<%s> a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-	"OPTIONAL { <%s> nco:hasPhoneNumber ?h . "			\
-		"OPTIONAL {"						\
-		"?h a nco:FaxNumber ; "					\
-		"nco:phoneNumber ?f . "					\
-		"}"							\
-		"OPTIONAL {"						\
-		"?h a nco:CellPhoneNumber ; "				\
-		"nco:phoneNumber ?vc"					\
-		"}"							\
-		"OPTIONAL {"						\
-		"?h a nco:VoicePhoneNumber ; "				\
-		"nco:phoneNumber ?t"					\
-		"}"							\
-	"}"								\
-	"OPTIONAL { "							\
-		"<%s> nco:hasAffiliation ?a . "				\
-		"OPTIONAL { ?a rdfs:label ?affType .}"			\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:hasPhoneNumber ?v . } "	\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-	"} "								\
-	"OPTIONAL { <%s> nco:hasPostalAddress ?po . } "			\
-	"OPTIONAL { <%s> nco:hasEmailAddress ?eo . } "			\
-	"}"
+"SELECT "								\
+"(SELECT GROUP_CONCAT("							\
+"nco:phoneNumber(?number), \"\30\")"					\
+"WHERE {"								\
+"	?_role nco:hasPhoneNumber ?number"				\
+"}) "									\
+"nco:fullname(<%s>) "							\
+"nco:nameFamily(<%s>) "							\
+"nco:nameGiven(<%s>) "							\
+"nco:nameAdditional(<%s>) "						\
+"nco:nameHonorificPrefix(<%s>) "					\
+"nco:nameHonorificSuffix(<%s>) "					\
+"(SELECT GROUP_CONCAT(?emailaddress_other, \"\30\")"			\
+"WHERE {"								\
+"	<%s> nco:hasEmailAddress [nco:emailAddress ?emailaddress_other]"\
+"}) "									\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \";\","	\
+"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:locality(?aff_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:region(?aff_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:country(?aff_addr), \"\") ),\";\")"		\
+"WHERE {"								\
+"?_role nco:hasPostalAddress ?aff_addr"					\
+"}) "									\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+"tracker:coalesce(nco:pobox(?oth_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:extendedAddress(?oth_addr), \"\"), \";\","	\
+"tracker:coalesce(nco:streetAddress(?oth_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:locality(?oth_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:region(?oth_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:postalcode(?oth_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:country(?oth_addr), \"\") ),\"\30\")"		\
+"WHERE {"								\
+"	<%s> nco:hasPostalAddress ?oth_addr"				\
+"}) "									\
+"(SELECT GROUP_CONCAT(fn:concat(rdf:type(?contact_number),"		\
+"\"\31\", nco:phoneNumber(?contact_number)), \"\30\")"			\
+"WHERE {"								\
+"	<%s> nco:hasPhoneNumber ?contact_number"			\
+"}) "									\
+"nco:birthDate(<%s>) "							\
+"nco:nickname(<%s>) "							\
+"nco:url(<%s>) "							\
+"nie:url(nco:photo(<%s>)) "						\
+"nco:role(?_role) "							\
+"nco:contactUID(<%s>) "							\
+"nco:title(?_role) "							\
+"rdfs:label(?_role) "							\
+"nco:fullname(nco:org(?_role))"						\
+"nco:department(?_role) "						\
+"(SELECT GROUP_CONCAT(?emailaddress, \"\30\")"				\
+"WHERE {"								\
+"	?_role nco:hasEmailAddress [ nco:emailAddress ?emailaddress ]"	\
+"}) "									\
+"\"NOTACALL\" \"false\" \"false\" "					\
+"<%s> "									\
+"WHERE {"								\
+"	<%s> a nco:PersonContact ;"					\
+"	nco:nameFamily ?_key ."						\
+"	OPTIONAL {<%s> nco:hasAffiliation ?_role .}"			\
+"}"									\
+"ORDER BY ?_key tracker:id(<%s>)"
 
 #define CONTACTS_OTHER_QUERY_FROM_URI					\
-	"SELECT \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" "\
-	"\"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" "	\
-	"\"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" "	\
-	"\"\" "								\
-	"nco:phoneNumber(?t) \"NOTACALL\" \"false\" \"false\" <%s> "	\
+	"SELECT \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" "	\
+	"fn:concat(\"TYPE_OTHER\", \"\31\", nco:phoneNumber(?t)) \"\" "	\
+	"\"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" "		\
+	" \"NOTACALL\" \"false\" \"false\" <%s> "	\
 	"WHERE { "							\
 		"<%s> a nco:Contact . "					\
 		"OPTIONAL { <%s> nco:hasPhoneNumber ?t . } "		\
@@ -1333,21 +1452,65 @@ static enum phonebook_number_type get_phone_type(const char *affilation)
 	return TEL_TYPE_OTHER;
 }
 
+static void add_main_number(struct phonebook_contact *contact, char *pnumber)
+{
+	char **num_parts;
+	char *type, *number;
+
+	/* For phone taken directly from contacts data, phone number string
+	 * is represented as number type and number string - those strings are
+	 * separated by SUB_DELIM string */
+	num_parts = g_strsplit(pnumber, SUB_DELIM, 2);
+
+	if (!num_parts)
+		return;
+
+	if (num_parts[0])
+		type = num_parts[0];
+	else
+		goto failed;
+
+	if (num_parts[1])
+		number = num_parts[1];
+	else
+		goto failed;
+
+	if (g_strrstr(type, FAX_NUM_TYPE))
+		add_phone_number(contact, number, TEL_TYPE_FAX);
+	else if (g_strrstr(type, MOBILE_NUM_TYPE))
+		add_phone_number(contact, number, TEL_TYPE_MOBILE);
+	else
+		add_phone_number(contact, number, TEL_TYPE_OTHER);
+
+failed:
+	g_strfreev(num_parts);
+}
+
 static void contact_add_numbers(struct phonebook_contact *contact,
 								char **reply)
 {
-	add_phone_number(contact, reply[COL_PHONE_NUMBER],
+	char **aff_numbers, **con_numbers;
+	int i;
+
+	/* Filling phonegit  numbers from contact's affilation */
+	aff_numbers = g_strsplit(reply[COL_PHONE_AFF], MAIN_DELIM, MAX_FIELDS);
+
+	if (aff_numbers)
+		for(i = 0;aff_numbers[i]; ++i)
+			add_phone_number(contact, aff_numbers[i],
 					get_phone_type(reply[COL_AFF_TYPE]));
-	add_phone_number(contact, reply[COL_FAX_NUMBER], TEL_TYPE_FAX);
-	add_phone_number(contact, reply[COL_CELL_NUMBER], TEL_TYPE_MOBILE);
 
-	if (g_strcmp0(reply[COL_OTHER_NUMBER], reply[COL_CELL_NUMBER]) == 0)
-		return;
+	g_strfreev(aff_numbers);
 
-	if (g_strcmp0(reply[COL_OTHER_NUMBER], reply[COL_PHONE_NUMBER]) == 0)
-		return;
+	/* Filling phone numbers directly from contact's struct */
+	con_numbers = g_strsplit(reply[COL_PHONE_CONTACT], MAIN_DELIM,
+								MAX_FIELDS);
 
-	add_phone_number(contact, reply[COL_OTHER_NUMBER], TEL_TYPE_OTHER);
+	if (con_numbers)
+		for(i = 0; con_numbers[i] != NULL; ++i)
+			add_main_number(contact, con_numbers[i]);
+
+	g_strfreev(con_numbers);
 }
 
 static enum phonebook_email_type get_email_type(const char *affilation)
@@ -1363,9 +1526,29 @@ static enum phonebook_email_type get_email_type(const char *affilation)
 static void contact_add_emails(struct phonebook_contact *contact,
 								char **reply)
 {
-	add_email(contact, reply[COL_EMAIL],
+	char **aff_emails, **con_emails;
+	int i;
+
+	/* Emails from affilation */
+	aff_emails = g_strsplit(reply[COL_EMAIL_AFF], MAIN_DELIM, MAX_FIELDS);
+
+	if (aff_emails)
+		for(i = 0; aff_emails[i] != NULL; ++i)
+			add_email(contact, aff_emails[i],
 					get_email_type(reply[COL_AFF_TYPE]));
-	add_email(contact, reply[COL_OTHER_EMAIL], EMAIL_TYPE_OTHER);
+
+	g_strfreev(aff_emails);
+
+	/* Emails taken directly from contact's data have always type OTHER */
+	con_emails = g_strsplit(reply[COL_EMAIL_CONTACT], MAIN_DELIM,
+								MAX_FIELDS);
+
+	if (con_emails)
+		for(i = 0; con_emails[i] != NULL; ++i)
+			add_email(contact, con_emails[i], EMAIL_TYPE_OTHER);
+
+	g_strfreev(con_emails);
+
 }
 
 static enum phonebook_address_type get_addr_type(const char *affilation)
@@ -1382,32 +1565,30 @@ static void contact_add_addresses(struct phonebook_contact *contact,
 								char **reply)
 {
 
-	char *main_addr, *other_addr;
+	char **aff_addr, **con_addr;
+	int i;
+
+	/* Addresses from affilation */
+	aff_addr = g_strsplit(reply[COL_ADDR_AFF], MAIN_DELIM,
+								MAX_FIELDS);
+
+	if (aff_addr)
+		for(i = 0; aff_addr[i] != NULL; ++i)
+			add_address(contact, aff_addr[i],
+					get_addr_type(reply[COL_AFF_TYPE]));
 
-	main_addr = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s",
-					reply[COL_ADDR_POBOX],
-					reply[COL_ADDR_EXT],
-					reply[COL_ADDR_STREET],
-					reply[COL_ADDR_LOCALITY],
-					reply[COL_ADDR_REGION],
-					reply[COL_ADDR_CODE],
-					reply[COL_ADDR_COUNTRY]);
+	g_strfreev(aff_addr);
 
-	other_addr = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s",
-					reply[COL_OTHER_ADDR_POBOX],
-					reply[COL_OTHER_ADDR_EXT],
-					reply[COL_OTHER_ADDR_STREET],
-					reply[COL_OTHER_ADDR_LOCALITY],
-					reply[COL_OTHER_ADDR_REGION],
-					reply[COL_OTHER_ADDR_CODE],
-					reply[COL_OTHER_ADDR_COUNTRY]);
+	/* Addresses from contact struct */
+	con_addr = g_strsplit(reply[COL_ADDR_CONTACT], MAIN_DELIM,
+								MAX_FIELDS);
 
-	add_address(contact, main_addr, get_addr_type(reply[COL_AFF_TYPE]));
+	if (con_addr)
+		for(i = 0; con_addr[i] != NULL; ++i)
+			add_address(contact, con_addr[i], ADDR_TYPE_OTHER);
 
-	add_address(contact, other_addr, ADDR_TYPE_OTHER);
+	g_strfreev(con_addr);
 
-	g_free(main_addr);
-	g_free(other_addr);
 }
 
 static void contact_add_organization(struct phonebook_contact *contact,
@@ -1722,7 +1903,7 @@ void *phonebook_get_entry(const char *folder, const char *id,
 	if (strncmp(id, CONTACT_ID_PREFIX, strlen(CONTACT_ID_PREFIX)) == 0)
 		query = g_strdup_printf(CONTACTS_QUERY_FROM_URI, id, id, id, id,
 						id, id, id, id, id, id, id, id,
-						id, id, id, id, id);
+						id, id, id, id, id, id);
 	else
 		query = g_strdup_printf(CONTACTS_OTHER_QUERY_FROM_URI,
 								id, id, id);
-- 
1.7.0.4


^ permalink raw reply related

* [RFCv2] Bluetooth: Use non-flushable by default L2CAP data packets
From: Emeltchenko Andrei @ 2010-12-16 14:54 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>

Modification of Nick Pelly <npelly@google.com> patch.

With Bluetooth 2.1 ACL packets can be flushable or non-flushable. This commit
makes ACL data packets non-flushable by default on compatible chipsets, and
adds the BT_FLUSHABLE socket option to explicitly request flushable ACL
data packets for a given L2CAP socket. This is useful for A2DP data which can
be safely discarded if it can not be delivered within a short time (while
other ACL data should not be discarded).

Note that making ACL data flushable has no effect unless the automatic flush
timeout for that ACL link is changed from its default of 0 (infinite).

Default packet types (for compatible chipsets):
Frame 34: 13 bytes on wire (104 bits), 13 bytes captured (104 bits)
Bluetooth HCI H4
Bluetooth HCI ACL Packet
    .... 0000 0000 0010 = Connection Handle: 0x0002
    ..00 .... .... .... = PB Flag: First Non-automatically Flushable Packet (0)
    00.. .... .... .... = BC Flag: Point-To-Point (0)
    Data Total Length: 8
Bluetooth L2CAP Packet

After setting BT_FLUSHABLE
(sock.setsockopt(274 /*SOL_BLUETOOTH*/, 8 /* BT_FLUSHABLE */, 1 /* flush */))
Frame 34: 13 bytes on wire (104 bits), 13 bytes captured (104 bits)
Bluetooth HCI H4
Bluetooth HCI ACL Packet
    .... 0000 0000 0010 = Connection Handle: 0x0002
    ..10 .... .... .... = PB Flag: First Automatically Flushable Packet (2)
    00.. .... .... .... = BC Flag: Point-To-Point (0)
    Data Total Length: 8
Bluetooth L2CAP Packet

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
---
 include/net/bluetooth/bluetooth.h |    5 ++++
 include/net/bluetooth/hci.h       |    2 +
 include/net/bluetooth/hci_core.h  |    1 +
 include/net/bluetooth/l2cap.h     |    2 +
 net/bluetooth/hci_core.c          |    6 +++-
 net/bluetooth/l2cap.c             |   48 ++++++++++++++++++++++++++++++++++--
 6 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 0c5e725..ed7d775 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -64,6 +64,11 @@ struct bt_security {
 
 #define BT_DEFER_SETUP	7
 
+#define BT_FLUSHABLE	8
+
+#define BT_FLUSHABLE_OFF	0
+#define BT_FLUSHABLE_ON		1
+
 #define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
 #define BT_ERR(fmt, arg...)  printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
 #define BT_DBG(fmt, arg...)  pr_debug("%s: " fmt "\n" , __func__ , ## arg)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 29a7a8c..333d5cb 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -150,6 +150,7 @@ enum {
 #define EDR_ESCO_MASK  (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5)
 
 /* ACL flags */
+#define ACL_START_NO_FLUSH	0x00
 #define ACL_CONT		0x01
 #define ACL_START		0x02
 #define ACL_ACTIVE_BCAST	0x04
@@ -193,6 +194,7 @@ enum {
 #define LMP_EDR_ESCO_3M	0x40
 #define LMP_EDR_3S_ESCO	0x80
 
+#define LMP_NO_FLUSH	0x01
 #define LMP_SIMPLE_PAIR	0x08
 
 /* Connection modes */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 1992fac..9778bc8 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -456,6 +456,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
 #define lmp_esco_capable(dev)      ((dev)->features[3] & LMP_ESCO)
 #define lmp_ssp_capable(dev)       ((dev)->features[6] & LMP_SIMPLE_PAIR)
+#define lmp_no_flush_capable(dev)  ((dev)->features[6] & LMP_NO_FLUSH)
 
 /* ----- HCI protocols ----- */
 struct hci_proto {
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 7ad25ca..af35711 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -75,6 +75,7 @@ struct l2cap_conninfo {
 #define L2CAP_LM_TRUSTED	0x0008
 #define L2CAP_LM_RELIABLE	0x0010
 #define L2CAP_LM_SECURE		0x0020
+#define L2CAP_LM_FLUSHABLE	0x0040
 
 /* L2CAP command codes */
 #define L2CAP_COMMAND_REJ	0x01
@@ -327,6 +328,7 @@ struct l2cap_pinfo {
 	__u8		sec_level;
 	__u8		role_switch;
 	__u8		force_reliable;
+	__u8		flushable;
 
 	__u8		conf_req[64];
 	__u8		conf_len;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 51c61f7..c0d776b 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1380,7 +1380,7 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
 
 	skb->dev = (void *) hdev;
 	bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
-	hci_add_acl_hdr(skb, conn->handle, flags | ACL_START);
+	hci_add_acl_hdr(skb, conn->handle, flags);
 
 	list = skb_shinfo(skb)->frag_list;
 	if (!list) {
@@ -1398,12 +1398,14 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
 		spin_lock_bh(&conn->data_q.lock);
 
 		__skb_queue_tail(&conn->data_q, skb);
+		flags &= ~ACL_START;
+		flags |= ACL_CONT;
 		do {
 			skb = list; list = list->next;
 
 			skb->dev = (void *) hdev;
 			bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
-			hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT);
+			hci_add_acl_hdr(skb, conn->handle, flags);
 
 			BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
 
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index c791fcd..efa60eb 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -362,13 +362,19 @@ static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
 static inline void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
 {
 	struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
+	u8 flags;
 
 	BT_DBG("code 0x%2.2x", code);
 
 	if (!skb)
 		return;
 
-	hci_send_acl(conn->hcon, skb, 0);
+	if (lmp_no_flush_capable(conn->hcon->hdev))
+		flags = ACL_START_NO_FLUSH;
+	else
+		flags = ACL_START;
+
+	hci_send_acl(conn->hcon, skb, flags);
 }
 
 static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
@@ -900,6 +906,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
 		pi->sec_level = l2cap_pi(parent)->sec_level;
 		pi->role_switch = l2cap_pi(parent)->role_switch;
 		pi->force_reliable = l2cap_pi(parent)->force_reliable;
+		pi->flushable = l2cap_pi(parent)->flushable;
 	} else {
 		pi->imtu = L2CAP_DEFAULT_MTU;
 		pi->omtu = 0;
@@ -915,6 +922,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
 		pi->sec_level = BT_SECURITY_LOW;
 		pi->role_switch = 0;
 		pi->force_reliable = 0;
+		pi->flushable = BT_FLUSHABLE_OFF;
 	}
 
 	/* Default config options */
@@ -1450,10 +1458,17 @@ static void l2cap_drop_acked_frames(struct sock *sk)
 static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
 {
 	struct l2cap_pinfo *pi = l2cap_pi(sk);
+	struct hci_conn *hcon = pi->conn->hcon;
+	u16 flags;
 
 	BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len);
 
-	hci_send_acl(pi->conn->hcon, skb, 0);
+	if (lmp_no_flush_capable(hcon->hdev) && !l2cap_pi(sk)->flushable)
+		flags = ACL_START_NO_FLUSH;
+	else
+		flags = ACL_START;
+
+	hci_send_acl(hcon, skb, flags);
 }
 
 static void l2cap_streaming_send(struct sock *sk)
@@ -2045,6 +2060,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
 static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
 {
 	struct sock *sk = sock->sk;
+	struct hci_conn *hcon = l2cap_pi(sk)->conn->hcon;
 	struct bt_security sec;
 	int len, err = 0;
 	u32 opt;
@@ -2098,6 +2114,26 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 		bt_sk(sk)->defer_setup = opt;
 		break;
 
+	case BT_FLUSHABLE:
+		if (get_user(opt, (u32 __user *) optval)) {
+			err = -EFAULT;
+			break;
+		}
+
+		if (opt > BT_FLUSHABLE_ON) {
+			err = -EINVAL;
+			break;
+		}
+
+		if (opt == BT_FLUSHABLE_OFF &&
+				!lmp_no_flush_capable(hcon->hdev)) {
+			err = -EINVAL;
+			break;
+		}
+
+		l2cap_pi(sk)->flushable = opt;
+		break;
+
 	default:
 		err = -ENOPROTOOPT;
 		break;
@@ -2237,6 +2273,12 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 
 		break;
 
+	case BT_FLUSHABLE:
+		if (put_user(l2cap_pi(sk)->flushable, (u32 __user *) optval))
+			err = -EFAULT;
+
+		break;
+
 	default:
 		err = -ENOPROTOOPT;
 		break;
@@ -4697,7 +4739,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
 
 	BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
 
-	if (flags & ACL_START) {
+	if (!(flags & ACL_CONT)) {
 		struct l2cap_hdr *hdr;
 		struct sock *sk;
 		u16 cid;
-- 
1.7.1


^ permalink raw reply related

* Re: [RFC] Bluetooth: Use non-flushable pb flag by default for ACL data on capable chipsets.
From: Andrei Emeltchenko @ 2010-12-16 14:40 UTC (permalink / raw)
  To: Mat Martineau; +Cc: Gustavo F. Padovan, linux-bluetooth
In-Reply-To: <alpine.DEB.2.00.1012150817580.12898@linux-sea-02>

Hi,

On Wed, Dec 15, 2010 at 6:35 PM, Mat Martineau <mathewm@codeaurora.org> wrote:
<skipped>
> There is one more thing missing:  Even though there is an L2CAP socket
> option to set flush_to, and the flush_to is passed around during L2CAP
> configuration, there is no use of the "Write Automatic Flush Timeout" HCI
> command to tell the baseband what the flush timeout is!  Since the flush
> timeout is shared across all connections on the ACL, how should BlueZ handle
> the case where different flush timeouts are set on connections that share
> the same ACL?  (My guess is that either the longest or shortest timeout
> should be used, but there are good arguments either way)

I would suggest bluetoothd to take care about setting Flush Timeout.
There is of course possibility to have sockopt for timeout and send HCI command
but this looks like a dirty hack.

I think bluetoothd can read compare and write new flush timeout value.

Regards,
Andrei

^ permalink raw reply

* Re: [PATCH] Fix sending duplicate speaker/microphone gains to the headset
From: Johan Hedberg @ 2010-12-16 14:33 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1292508801-15581-2-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On Thu, Dec 16, 2010, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
> 
> Current code only prevent duplicate D-Bus signals, so in case headset
> changes the volume a client may set the same volume level again which
> would be send as new volume level.
> 
> To fix this headset_set_gain now return -EALREADY if nothing has changed
> so code using it can just ignore the change instead of sending to remote
> device.
> ---
>  audio/headset.c |   12 ++++++++----
>  1 files changed, 8 insertions(+), 4 deletions(-)

This one has also been pushed upstream. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH] Fix not calling SetConfiguration on hfp/hsp endpoints before connected
From: Johan Hedberg @ 2010-12-16 14:32 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1292508801-15581-1-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On Thu, Dec 16, 2010, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
> 
> This cause some clients like PulseAudio to fail to find a proper
> transport since connected state is send before transport configuration
> is set.
> 
> To fix this now SetConfiguration is called early on when headset is still
> in connecting phase, this matches sink/source where SetConfiguration is
> also called before connected.
> ---
>  audio/media.c |   11 ++++-------
>  1 files changed, 4 insertions(+), 7 deletions(-)

Pushed upstream. Thanks.

Johan

^ permalink raw reply

* [PATCH v2] Further optimalization of PBAP tracker queries
From: Radoslaw Jablonski @ 2010-12-16 14:25 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Radoslaw Jablonski

Now emails, addresses and telephone numbers of the same type
(work/home/other) are concatenated into sigle strings - this
gains huge difference in speed of queries when there are a lot
of contacts in database. Also changed functions for splitting
these fields on our backend side.
---
 plugins/phonebook-tracker.c | 1240 +++++++++++++++++++++++++------------------
 1 files changed, 710 insertions(+), 530 deletions(-)

diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
index 0a023aa..7aa08e8 100644
--- a/plugins/phonebook-tracker.c
+++ b/plugins/phonebook-tracker.c
@@ -46,103 +46,111 @@
 #define AFFILATION_HOME "Home"
 #define AFFILATION_WORK "Work"
 #define ADDR_FIELD_AMOUNT 7
-#define PULL_QUERY_COL_AMOUNT 40
+#define PULL_QUERY_COL_AMOUNT 26
 #define COUNT_QUERY_COL_AMOUNT 1
 
-#define COL_PHONE_NUMBER 0
+#define COL_PHONE_AFF 0 /* work/home phone numbers */
 #define COL_FULL_NAME 1
 #define COL_FAMILY_NAME 2
 #define COL_GIVEN_NAME 3
 #define COL_ADDITIONAL_NAME 4
 #define COL_NAME_PREFIX 5
 #define COL_NAME_SUFFIX 6
-#define COL_EMAIL 7
-#define COL_CELL_NUMBER 8
-
-#define COL_ADDR_POBOX 9
-#define COL_ADDR_EXT 10
-#define COL_ADDR_STREET 11
-#define COL_ADDR_LOCALITY 12
-#define COL_ADDR_REGION 13
-#define COL_ADDR_CODE 14
-#define COL_ADDR_COUNTRY 15
-
-#define COL_FAX_NUMBER 16
-#define COL_AFF_TYPE 17
-#define COL_BIRTH_DATE 18
-#define COL_NICKNAME 19
-#define COL_URL 20
-#define COL_PHOTO 21
-
-#define COL_ORG_NAME 22
-#define COL_ORG_DEPARTMENT 23
-#define COL_ORG_ROLE 24
-
-#define COL_UID 25
-#define COL_TITLE 26
-#define COL_OTHER_NUMBER 27
-
-#define COL_OTHER_ADDR_POBOX 28
-#define COL_OTHER_ADDR_EXT 29
-#define COL_OTHER_ADDR_STREET 30
-#define COL_OTHER_ADDR_LOCALITY 31
-#define COL_OTHER_ADDR_REGION 32
-#define COL_OTHER_ADDR_CODE 33
-#define COL_OTHER_ADDR_COUNTRY 34
-
-#define COL_OTHER_EMAIL 35
-#define COL_DATE 36
-#define COL_SENT 37
-#define COL_ANSWERED 38
-#define CONTACTS_ID_COL 39
+#define COL_EMAIL_CONTACT 7 /*email's for other category */
+#define COL_ADDR_AFF 8 /* addresses from affilation */
+#define COL_ADDR_CONTACT 9 /* addresses from contacts */
+#define COL_PHONE_CONTACT 10 /* phone numbers from contact's */
+#define COL_BIRTH_DATE 11
+#define COL_NICKNAME 12
+#define COL_URL 13
+#define COL_PHOTO 14
+#define COL_ORG_ROLE 15
+#define COL_UID 16
+#define COL_TITLE 17
+#define COL_AFF_TYPE 18
+#define COL_ORG_NAME 19
+#define COL_ORG_DEPARTMENT 20
+#define COL_EMAIL_AFF 21 /* email's from affilation (work/home) */
+#define COL_DATE 22
+#define COL_SENT 23
+#define COL_ANSWERED 24
+#define CONTACTS_ID_COL 25
 #define CONTACT_ID_PREFIX "contact:"
 
+#define FAX_NUM_TYPE "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#FaxNumber"
+#define MOBILE_NUM_TYPE "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#CellPhoneNumber"
+
+#define MAIN_DELIM "\30" /* Main delimiter between phones, addresses, emails*/
+#define SUB_DELIM "\31" /* Delimiter used in telephone number strings*/
+#define MAX_FIELDS 100 /* Max amount of fields to be concatenated at once*/
+
 #define CONTACTS_QUERY_ALL						\
-	"SELECT nco:phoneNumber(?v) nco:fullname(?c) "			\
-	"nco:nameFamily(?c) nco:nameGiven(?c) "				\
-	"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) "		\
-	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) ?vc "		\
-	"nco:pobox(?p) nco:extendedAddress(?p) "			\
-	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) ?f ?affType "		\
-	"nco:birthDate(?c) nco:nickname(?c) nco:url(?c) "		\
-	"?file nco:fullname(?o) nco:department(?a) "			\
-	"nco:role(?a) nco:contactUID(?c) "				\
-	"nco:title(?a) ?t nco:pobox(?po) nco:extendedAddress(?po) "	\
-	"nco:streetAddress(?po) nco:locality(?po) nco:region(?po) "	\
-	"nco:postalcode(?po) nco:country(?po) nco:emailAddress(?eo) "	\
-	"\"NOTACALL\" \"false\" \"false\" ?c "				\
-	"WHERE { "							\
-		"?c a nco:PersonContact . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-	"OPTIONAL { ?c nco:hasPhoneNumber ?h . "			\
-		"OPTIONAL {"						\
-		"?h a nco:FaxNumber ; "					\
-		"nco:phoneNumber ?f . "					\
-		"}"							\
-		"OPTIONAL {"						\
-		"?h a nco:CellPhoneNumber ; "				\
-		"nco:phoneNumber ?vc"					\
-		"}"							\
-		"OPTIONAL {"						\
-		"?h a nco:VoicePhoneNumber ; "				\
-		"nco:phoneNumber ?t"					\
-		"}"							\
-	"}"								\
-	"OPTIONAL { "							\
-		"?c nco:hasAffiliation ?a . "				\
-		"OPTIONAL { ?a rdfs:label ?affType .}"			\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:hasPhoneNumber ?v . } "	\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-	"} "								\
-	"OPTIONAL { ?c nco:hasPostalAddress ?po . } "			\
-	"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "			\
-	"}"
+"SELECT "								\
+"(SELECT GROUP_CONCAT("							\
+"nco:phoneNumber(?number), \"\30\")"					\
+"WHERE {"								\
+"	?_role nco:hasPhoneNumber ?number"				\
+"}) "									\
+"nco:fullname(?_contact) "						\
+"nco:nameFamily(?_contact) "						\
+"nco:nameGiven(?_contact) "						\
+"nco:nameAdditional(?_contact) "					\
+"nco:nameHonorificPrefix(?_contact) "					\
+"nco:nameHonorificSuffix(?_contact) "					\
+"(SELECT GROUP_CONCAT(?emailaddress_other, \"\30\") " 			\
+	"WHERE {"							\
+	"?_contact nco:hasEmailAddress "				\
+			"[nco:emailAddress ?emailaddress_other]"	\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \";\","	\
+"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:locality(?aff_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:region(?aff_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:country(?aff_addr), \"\") ),\";\")"		\
+"WHERE {"								\
+"?_role nco:hasPostalAddress ?aff_addr"					\
+"}) "									\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+"tracker:coalesce(nco:pobox(?oth_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:extendedAddress(?oth_addr), \"\"), \";\","	\
+"tracker:coalesce(nco:streetAddress(?oth_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:locality(?oth_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:region(?oth_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:postalcode(?oth_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:country(?oth_addr), \"\") ),\"\30\")"		\
+"WHERE {"								\
+"	?_contact nco:hasPostalAddress ?oth_addr"			\
+"}) "									\
+"(SELECT GROUP_CONCAT(fn:concat(rdf:type(?contact_number),"		\
+"\"\31\", nco:phoneNumber(?contact_number)), \"\30\")"			\
+"WHERE {"								\
+"	?_contact nco:hasPhoneNumber ?contact_number"			\
+"}) "									\
+"nco:birthDate(?_contact) "						\
+"nco:nickname(?_contact) "						\
+"nco:url(?_contact) "							\
+"nie:url(nco:photo(?_contact)) "					\
+"nco:role(?_role) "							\
+"nco:contactUID(?_contact) "						\
+"nco:title(?_role) "							\
+"rdfs:label(?_role) "							\
+"nco:fullname(nco:org(?_role))"						\
+"nco:department(?_role) "						\
+"(SELECT GROUP_CONCAT(?emailaddress, \"\30\")"				\
+"WHERE {"								\
+"	?_role nco:hasEmailAddress [ nco:emailAddress ?emailaddress ]"	\
+"}) "									\
+"\"NOTACALL\" \"false\" \"false\" "					\
+"?_contact "								\
+"WHERE {"								\
+"	?_contact a nco:PersonContact ;"				\
+"	nco:nameFamily ?_key ."						\
+"	OPTIONAL {?_contact nco:hasAffiliation ?_role .}"		\
+"}"									\
+"ORDER BY ?_key tracker:id(?_contact)"
 
 #define CONTACTS_QUERY_ALL_LIST						\
 	"SELECT ?c nco:nameFamily(?c) "					\
@@ -159,84 +167,114 @@
 	"} GROUP BY ?c"
 
 #define MISSED_CALLS_QUERY						\
-	"SELECT nco:phoneNumber(?ap) nco:fullname(?c) "			\
-	"nco:nameFamily(?c) nco:nameGiven(?c) "				\
-	"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) "		\
-	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) ?vc "		\
-	"nco:pobox(?p) nco:extendedAddress(?p) "			\
-	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) \"\" ?affType "		\
-	"nco:birthDate(?c) nco:nickname(?c) nco:url(?c) "		\
-	"?file nco:fullname(?o) nco:department(?a) "			\
-	"nco:role(?a) nco:contactUID(?c) "				\
-	"nco:title(?a) nco:phoneNumber(?t) nco:pobox(?po) nco:extendedAddress(?po) "	\
-	"nco:streetAddress(?po) nco:locality(?po) nco:region(?po) "	\
-	"nco:postalcode(?po) nco:country(?po) nco:emailAddress(?eo) "	\
-	"nmo:receivedDate(?call) "					\
-	"nmo:isSent(?call) nmo:isAnswered(?call) ?x "			\
+"SELECT "								\
+"(SELECT nco:phoneNumber(?role_number) "				\
+	"WHERE {"							\
+	"?_role nco:hasPhoneNumber ?role_number "			\
+	"FILTER (?role_number = ?_number)"				\
+"} GROUP BY nco:phoneNumber(?role_number) ) "				\
+	"nco:fullname(?_contact) "					\
+	"nco:nameFamily(?_contact) "					\
+	"nco:nameGiven(?_contact) "					\
+	"nco:nameAdditional(?_contact) "				\
+	"nco:nameHonorificPrefix(?_contact) "				\
+	"nco:nameHonorificSuffix(?_contact) "				\
+"(SELECT GROUP_CONCAT(?emailaddress_other, \"\30\") " 			\
+	"WHERE {"							\
+	"?_contact nco:hasEmailAddress "				\
+			"[nco:emailAddress ?emailaddress_other]"	\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?aff_addr), \"\") ),\";\")"	\
+	"WHERE {"							\
+	"?_role nco:hasPostalAddress ?aff_addr"				\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?oth_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?oth_addr), \"\") ),\"\30\")"	\
+	"WHERE {"							\
+	"?_contact nco:hasPostalAddress ?oth_addr"			\
+	"}) "								\
+"(SELECT fn:concat(rdf:type(?contact_number),"				\
+	"\"\31\", nco:phoneNumber(?contact_number))"			\
+	"WHERE {"							\
+	"{"								\
+"		?_contact nco:hasPhoneNumber ?contact_number . "	\
+"		FILTER (?contact_number = ?_number) "			\
+"	} UNION { "							\
+"		?_unb_contact nco:hasPhoneNumber ?contact_number . "	\
+"	} "								\
+"}GROUP BY nco:phoneNumber(?contact_number) ) "				\
+	"nco:birthDate(?_contact) "					\
+	"nco:nickname(?_contact) "					\
+	"nco:url(?_contact) "						\
+	"nie:url(nco:photo(?_contact)) "				\
+	"nco:role(?_role) "						\
+	"nco:contactUID(?_contact) "					\
+	"nco:title(?_role) "						\
+	"rdfs:label(?_role) "						\
+	"nco:fullname(nco:org(?_role)) "				\
+	"nco:department(?_role) "					\
+"(SELECT GROUP_CONCAT(?emailaddress, \"\30\") "				\
 	"WHERE { "							\
-	"{ "								\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false ; "					\
-		"nmo:isAnswered false . "				\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasPhoneNumber ?t . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL { "						\
-			"?t a nco:CellPhoneNumber ; "			\
-				"nco:phoneNumber ?vc . "		\
-		"} "							\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-		"OPTIONAL { "						\
-			"?c nco:hasAffiliation ?a . "			\
-			"OPTIONAL { ?a nco:title ?title } "		\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:org ?o . } "			\
-		"} "							\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?ap . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false ; "					\
-		"nmo:isAnswered false . "				\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasAffiliation ?a . "				\
-		"?a nco:hasPhoneNumber ?ap . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL {?a rdfs:label ?affType . }"			\
-		"OPTIONAL {?a nco:hasEmailAddress ?e . } "		\
-		"OPTIONAL {?a nco:hasPostalAddress ?p . }"		\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-		"OPTIONAL { ?a nco:title ?title } "			\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false ; "					\
-		"nmo:isAnswered false . "				\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasPhoneNumber ?t . } "			\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasAffiliation ?a . "			\
-			"?a nco:hasPhoneNumber ?t . } "			\
-		"FILTER ( !bound(?c) && !bound(?a) ) . "		\
-	"} "								\
-	"} ORDER BY DESC(nmo:receivedDate(?call)) "
+	"?_role nco:hasEmailAddress [ nco:emailAddress ?emailaddress ] "\
+	"}) "								\
+	"nmo:receivedDate(?_call) "					\
+	"nmo:isSent(?_call) "						\
+	"nmo:isAnswered(?_call) "					\
+	"fn:concat(tracker:coalesce(?_ncontact, \"\"),"			\
+	"tracker:coalesce(?_unb_contact, \"\"))"			\
+	" "								\
+"WHERE { "								\
+"{ "									\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_ncontact ; "					\
+	"nmo:isAnswered false ;"					\
+	"nmo:isSent false . "						\
+	"?_contact a nco:PersonContact ; "				\
+	"nco:hasPhoneNumber ?_number . "				\
+	"OPTIONAL { ?_contact nco:hasAffiliation ?_role .} "		\
+	"?_contact nco:nameFamily ?_key ."				\
+"} UNION { "								\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_ncontact ; "					\
+	"nmo:isAnswered false ;"					\
+	"nmo:isSent false . "						\
+	"?_contact a nco:PersonContact . "				\
+	"?_contact nco:nameFamily ?_key . "				\
+	"?_contact nco:hasAffiliation ?_role . "			\
+	"?_role nco:hasPhoneNumber ?_number . "				\
+"} UNION { "								\
+	"?_unb_contact a nco:Contact . "				\
+	"?_unb_contact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_unb_contact ; "					\
+	"nmo:isAnswered false ;"					\
+	"nmo:isSent false . "						\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasPhoneNumber ?_number . } "				\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasAffiliation ?_role . "					\
+	"?_role nco:hasPhoneNumber ?_number. } "			\
+	"FILTER ( !bound(?_contact) && !bound(?_role) ) "		\
+"} "									\
+"} "									\
+"ORDER BY DESC(nmo:sentDate(?_call)) "
 
 
 #define MISSED_CALLS_LIST						\
@@ -275,85 +313,114 @@
 	"} GROUP BY ?call ORDER BY DESC(nmo:receivedDate(?call))"
 
 #define INCOMING_CALLS_QUERY						\
-	"SELECT nco:phoneNumber(?ap) nco:fullname(?c) "			\
-	"nco:nameFamily(?c) nco:nameGiven(?c) "				\
-	"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) "		\
-	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) ?vc "		\
-	"nco:pobox(?p) nco:extendedAddress(?p) "			\
-	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) \"\" ?affType "		\
-	"nco:birthDate(?c) nco:nickname(?c) nco:url(?c) "		\
-	"?file nco:fullname(?o) nco:department(?a) "			\
-	"nco:role(?a) nco:contactUID(?c) "				\
-	"nco:title(?a) nco:phoneNumber(?t) nco:pobox(?po) "		\
-	"nco:extendedAddress(?po) "					\
-	"nco:streetAddress(?po) nco:locality(?po) nco:region(?po) "	\
-	"nco:postalcode(?po) nco:country(?po) nco:emailAddress(?eo) "	\
-	"nmo:receivedDate(?call) "					\
-	"nmo:isSent(?call) nmo:isAnswered(?call) ?x "			\
+"SELECT "								\
+"(SELECT nco:phoneNumber(?role_number) "				\
+	"WHERE {"							\
+"	?_role nco:hasPhoneNumber ?role_number"				\
+"	FILTER (?role_number = ?_number)"				\
+"} GROUP BY nco:phoneNumber(?role_number) ) "				\
+	"nco:fullname(?_contact) "					\
+	"nco:nameFamily(?_contact) "					\
+	"nco:nameGiven(?_contact) "					\
+	"nco:nameAdditional(?_contact) "				\
+	"nco:nameHonorificPrefix(?_contact) "				\
+	"nco:nameHonorificSuffix(?_contact) "				\
+"(SELECT GROUP_CONCAT(?emailaddress_other, \"\30\") " 			\
+	"WHERE {"							\
+	"?_contact nco:hasEmailAddress "				\
+			"[nco:emailAddress ?emailaddress_other]"	\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?aff_addr), \"\") ),\";\")"	\
+	"WHERE {"							\
+	"?_role nco:hasPostalAddress ?aff_addr"				\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?oth_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?oth_addr), \"\") ),\"\30\")"	\
+	"WHERE {"							\
+	"?_contact nco:hasPostalAddress ?oth_addr"			\
+	"}) "								\
+"(SELECT fn:concat(rdf:type(?contact_number),"				\
+	"\"\31\", nco:phoneNumber(?contact_number))"			\
+	"WHERE {"							\
+	"{"								\
+"		?_contact nco:hasPhoneNumber ?contact_number . "	\
+"		FILTER (?contact_number = ?_number) "			\
+"	} UNION { "							\
+"		?_unb_contact nco:hasPhoneNumber ?contact_number . "	\
+"	} "								\
+	"}GROUP BY nco:phoneNumber(?contact_number) ) "			\
+	"nco:birthDate(?_contact) "					\
+	"nco:nickname(?_contact) "					\
+	"nco:url(?_contact) "						\
+	"nie:url(nco:photo(?_contact)) "				\
+	"nco:role(?_role) "						\
+	"nco:contactUID(?_contact) "					\
+	"nco:title(?_role) "						\
+	"rdfs:label(?_role) "						\
+	"nco:fullname(nco:org(?_role)) "				\
+	"nco:department(?_role) "					\
+"(SELECT GROUP_CONCAT(?emailaddress, \"\30\") "				\
 	"WHERE { "							\
-	"{ "								\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false ; "					\
-		"nmo:isAnswered true . "				\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasPhoneNumber ?t . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL { "						\
-			"?t a nco:CellPhoneNumber ; "			\
-				"nco:phoneNumber ?vc . "		\
-		"} "							\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-		"OPTIONAL { "						\
-			"?c nco:hasAffiliation ?a . "			\
-			"OPTIONAL { ?a nco:title ?title } "		\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:org ?o . } "			\
-		"} "							\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?ap . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false ; "					\
-		"nmo:isAnswered true . "				\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasAffiliation ?a . "				\
-		"?a nco:hasPhoneNumber ?ap . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL {?a rdfs:label ?affType . }"			\
-		"OPTIONAL {?a nco:hasEmailAddress ?e . } "		\
-		"OPTIONAL {?a nco:hasPostalAddress ?p . }"		\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-		"OPTIONAL { ?a nco:title ?title } "			\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false ; "					\
-		"nmo:isAnswered true . "				\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasPhoneNumber ?t . } "			\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasAffiliation ?a . "			\
-			"?a nco:hasPhoneNumber ?t . } "			\
-		"FILTER ( !bound(?c) && !bound(?a) ) . "		\
-	"} "								\
-	"} ORDER BY DESC(nmo:receivedDate(?call)) "
+	"?_role nco:hasEmailAddress [ nco:emailAddress ?emailaddress ] "\
+	"}) "								\
+	"nmo:receivedDate(?_call) "					\
+	"nmo:isSent(?_call) "						\
+	"nmo:isAnswered(?_call) "					\
+	"fn:concat(tracker:coalesce(?_ncontact, \"\"),"			\
+	"tracker:coalesce(?_unb_contact, \"\"))"			\
+	" "								\
+"WHERE { "								\
+"{ "									\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_ncontact ; "					\
+	"nmo:isAnswered true ;"						\
+	"nmo:isSent false . "						\
+	"?_contact a nco:PersonContact ; "				\
+	"nco:hasPhoneNumber ?_number . "				\
+	"OPTIONAL { ?_contact nco:hasAffiliation ?_role .} "		\
+	"?_contact nco:nameFamily ?_key ."				\
+"} UNION { "								\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_ncontact ; "					\
+	"nmo:isAnswered true ;"						\
+	"nmo:isSent false . "						\
+	"?_contact a nco:PersonContact . "				\
+	"?_contact nco:nameFamily ?_key . "				\
+	"?_contact nco:hasAffiliation ?_role . "			\
+	"?_role nco:hasPhoneNumber ?_number . "				\
+"} UNION { "								\
+	"?_unb_contact a nco:Contact . "				\
+	"?_unb_contact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_unb_contact ; "					\
+	"nmo:isAnswered true ;"						\
+	"nmo:isSent false . "						\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasPhoneNumber ?_number . } "				\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasAffiliation ?_role . "					\
+	"?_role nco:hasPhoneNumber ?_number. } "			\
+	"FILTER ( !bound(?_contact) && !bound(?_role) ) "		\
+"} "									\
+"} "\
+"ORDER BY DESC(nmo:sentDate(?_call)) "
 
 #define INCOMING_CALLS_LIST						\
 	"SELECT ?c nco:nameFamily(?c) "					\
@@ -391,82 +458,111 @@
 	"} GROUP BY ?call ORDER BY DESC(nmo:receivedDate(?call))"
 
 #define OUTGOING_CALLS_QUERY						\
-	"SELECT nco:phoneNumber(?ap) nco:fullname(?c) "			\
-	"nco:nameFamily(?c) nco:nameGiven(?c) "				\
-	"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) "		\
-	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) ?vc "		\
-	"nco:pobox(?p) nco:extendedAddress(?p) "			\
-	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) \"\" ?affType "		\
-	"nco:birthDate(?c) nco:nickname(?c) nco:url(?c) "		\
-	"?file nco:fullname(?o) nco:department(?a) "			\
-	"nco:role(?a) nco:contactUID(?c) "				\
-	"nco:title(?a) nco:phoneNumber(?t) nco:pobox(?po) "		\
-	"nco:extendedAddress(?po) "					\
-	"nco:streetAddress(?po) nco:locality(?po) nco:region(?po) "	\
-	"nco:postalcode(?po) nco:country(?po) nco:emailAddress(?eo) "	\
-	"nmo:receivedDate(?call) "					\
-	"nmo:isSent(?call) nmo:isAnswered(?call) ?x "			\
+"SELECT "								\
+"(SELECT nco:phoneNumber(?role_number) "				\
+	"WHERE {"							\
+"	?_role nco:hasPhoneNumber ?role_number"				\
+"	FILTER (?role_number = ?_number)"				\
+"} GROUP BY nco:phoneNumber(?role_number) ) "				\
+	"nco:fullname(?_contact) "					\
+	"nco:nameFamily(?_contact) "					\
+	"nco:nameGiven(?_contact) "					\
+	"nco:nameAdditional(?_contact) "				\
+	"nco:nameHonorificPrefix(?_contact) "				\
+	"nco:nameHonorificSuffix(?_contact) "				\
+"(SELECT GROUP_CONCAT(?emailaddress_other, \"\30\") " 			\
+	"WHERE {"							\
+	"?_contact nco:hasEmailAddress "				\
+			"[nco:emailAddress ?emailaddress_other]"	\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?aff_addr), \"\") ),\";\")"	\
+	"WHERE {"							\
+	"?_role nco:hasPostalAddress ?aff_addr"				\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?oth_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?oth_addr), \"\") ),\"\30\")"	\
+	"WHERE {"							\
+	"?_contact nco:hasPostalAddress ?oth_addr"			\
+	"}) "								\
+"(SELECT fn:concat(rdf:type(?contact_number),"				\
+	"\"\31\", nco:phoneNumber(?contact_number))"			\
+	"WHERE {"							\
+	"{"								\
+"		?_contact nco:hasPhoneNumber ?contact_number . "	\
+"		FILTER (?contact_number = ?_number) "			\
+"	} UNION { "							\
+"		?_unb_contact nco:hasPhoneNumber ?contact_number . "	\
+"	} "								\
+	"}GROUP BY nco:phoneNumber(?contact_number) ) "			\
+	"nco:birthDate(?_contact) "					\
+	"nco:nickname(?_contact) "					\
+	"nco:url(?_contact) "						\
+	"nie:url(nco:photo(?_contact)) "				\
+	"nco:role(?_role) "						\
+	"nco:contactUID(?_contact) "					\
+	"nco:title(?_role) "						\
+	"rdfs:label(?_role) "						\
+	"nco:fullname(nco:org(?_role)) "				\
+	"nco:department(?_role) "					\
+"(SELECT GROUP_CONCAT(?emailaddress, \"\30\") "				\
 	"WHERE { "							\
-	"{ "								\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:to ?x ; "						\
-		"nmo:isSent true . "					\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasPhoneNumber ?t . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL { "						\
-			"?t a nco:CellPhoneNumber ; "			\
-				"nco:phoneNumber ?vc . "		\
-		"} "							\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-		"OPTIONAL { "						\
-			"?c nco:hasAffiliation ?a . "			\
-			"OPTIONAL { ?a nco:title ?title } "		\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:org ?o . } "			\
-		"} "							\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?ap . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:to ?x ; "						\
-		"nmo:isSent true . "					\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasAffiliation ?a . "				\
-		"?a nco:hasPhoneNumber ?ap . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL {?a rdfs:label ?affType . }"			\
-		"OPTIONAL {?a nco:hasEmailAddress ?e . } "		\
-		"OPTIONAL {?a nco:hasPostalAddress ?p . }"		\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-		"OPTIONAL { ?a nco:title ?title } "			\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:to ?x ; "						\
-		"nmo:isSent true . "					\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasPhoneNumber ?t . } "			\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasAffiliation ?a . "			\
-			"?a nco:hasPhoneNumber ?t . } "			\
-		"FILTER ( !bound(?c) && !bound(?a) ) . "		\
-	"} "								\
-	"} ORDER BY DESC(nmo:sentDate(?call)) "
+	"?_role nco:hasEmailAddress [ nco:emailAddress ?emailaddress ] "\
+	"}) "								\
+	"nmo:receivedDate(?_call) "					\
+	"nmo:isSent(?_call) "						\
+	"nmo:isAnswered(?_call) "					\
+	"fn:concat(tracker:coalesce(?_ncontact, \"\"),"			\
+	"tracker:coalesce(?_unb_contact, \"\"))"			\
+	" "								\
+"WHERE { "								\
+"{ "									\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:to ?_ncontact ; "						\
+	"nmo:isSent true . "						\
+	"?_contact a nco:PersonContact ; "				\
+	"nco:hasPhoneNumber ?_number . "				\
+	"OPTIONAL { ?_contact nco:hasAffiliation ?_role .} "		\
+	"?_contact nco:nameFamily ?_key ."				\
+"} UNION { "								\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:to ?_ncontact ; "						\
+	"nmo:isSent true . "						\
+	"?_contact a nco:PersonContact . "				\
+	"?_contact nco:nameFamily ?_key . "				\
+	"?_contact nco:hasAffiliation ?_role . "			\
+	"?_role nco:hasPhoneNumber ?_number . "				\
+"} UNION { "								\
+	"?_unb_contact a nco:Contact . "				\
+	"?_unb_contact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:to ?_unb_contact ; "					\
+	"nmo:isSent true . "						\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasPhoneNumber ?_number . } "				\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasAffiliation ?_role . "					\
+	"?_role nco:hasPhoneNumber ?_number. } "			\
+	"FILTER ( !bound(?_contact) && !bound(?_role) ) "		\
+"} "									\
+"} "									\
+"ORDER BY DESC(nmo:sentDate(?_call)) "
 
 #define OUTGOING_CALLS_LIST						\
 	"SELECT ?c nco:nameFamily(?c) "					\
@@ -501,139 +597,143 @@
 	"} GROUP BY ?call ORDER BY DESC(nmo:sentDate(?call))"
 
 #define COMBINED_CALLS_QUERY						\
-	"SELECT nco:phoneNumber(?ap) nco:fullname(?c) "			\
-	"nco:nameFamily(?c) nco:nameGiven(?c) "				\
-	"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) "		\
-	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) ?vc "		\
-	"nco:pobox(?p) nco:extendedAddress(?p) "			\
-	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) \"\" ?affType "		\
-	"nco:birthDate(?c) nco:nickname(?c) nco:url(?c) "		\
-	"?file nco:fullname(?o) nco:department(?a) "			\
-	"nco:role(?a) nco:contactUID(?c) "				\
-	"nco:title(?a) nco:phoneNumber(?t) nco:pobox(?po) "		\
-	"nco:extendedAddress(?po) "					\
-	"nco:streetAddress(?po) nco:locality(?po) nco:region(?po) "	\
-	"nco:postalcode(?po) nco:country(?po) nco:emailAddress(?eo) "	\
-	"nmo:receivedDate(?call) "					\
-	"nmo:isSent(?call) nmo:isAnswered(?call) ?x "			\
+"SELECT "								\
+"(SELECT nco:phoneNumber(?role_number) "				\
+	"WHERE {"							\
+"	?_role nco:hasPhoneNumber ?role_number"				\
+"	FILTER (?role_number = ?_number)"				\
+"} GROUP BY nco:phoneNumber(?role_number) ) "				\
+	"nco:fullname(?_contact) "					\
+	"nco:nameFamily(?_contact) "					\
+	"nco:nameGiven(?_contact) "					\
+	"nco:nameAdditional(?_contact) "				\
+	"nco:nameHonorificPrefix(?_contact) "				\
+	"nco:nameHonorificSuffix(?_contact) "				\
+"(SELECT GROUP_CONCAT(?emailaddress_other, \"\30\") " 			\
+	"WHERE {"							\
+	"?_contact nco:hasEmailAddress "				\
+			"[nco:emailAddress ?emailaddress_other]"	\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?aff_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?aff_addr), \"\") ),\";\")"	\
+	"WHERE {"							\
+	"?_role nco:hasPostalAddress ?aff_addr"				\
+	"}) "								\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+	"tracker:coalesce(nco:pobox(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:extendedAddress(?oth_addr), \"\"), \";\","\
+	"tracker:coalesce(nco:streetAddress(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:locality(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:region(?oth_addr), \"\"), \";\","		\
+	"tracker:coalesce(nco:postalcode(?oth_addr), \"\"), \";\","	\
+	"tracker:coalesce(nco:country(?oth_addr), \"\") ),\"\30\")"	\
+	"WHERE {"							\
+	"?_contact nco:hasPostalAddress ?oth_addr"			\
+	"}) "								\
+"(SELECT fn:concat(rdf:type(?contact_number),"				\
+	"\"\31\", nco:phoneNumber(?contact_number))"			\
+	"WHERE {"							\
+	"{"								\
+"		?_contact nco:hasPhoneNumber ?contact_number . "	\
+"		FILTER (?contact_number = ?_number) "			\
+"	} UNION { "							\
+"		?_unb_contact nco:hasPhoneNumber ?contact_number . "	\
+"	} "								\
+	"}GROUP BY nco:phoneNumber(?contact_number) ) "			\
+	"nco:birthDate(?_contact) "					\
+	"nco:nickname(?_contact) "					\
+	"nco:url(?_contact) "						\
+	"nie:url(nco:photo(?_contact)) "				\
+	"nco:role(?_role) "						\
+	"nco:contactUID(?_contact) "					\
+	"nco:title(?_role) "						\
+	"rdfs:label(?_role) "						\
+	"nco:fullname(nco:org(?_role)) "				\
+	"nco:department(?_role) "					\
+"(SELECT GROUP_CONCAT(?emailaddress, \"\30\") "				\
 	"WHERE { "							\
-	"{ "								\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:to ?x ; "						\
-		"nmo:isSent true . "					\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasPhoneNumber ?t . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL { "						\
-			"?t a nco:CellPhoneNumber ; "			\
-				"nco:phoneNumber ?vc . "		\
-		"} "							\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-		"OPTIONAL { "						\
-			"?c nco:hasAffiliation ?a . "			\
-			"OPTIONAL { ?a nco:title ?title } "		\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:org ?o . } "			\
-		"} "							\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?ap . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:to ?x ; "						\
-		"nmo:isSent true . "					\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasAffiliation ?a . "				\
-		"?a nco:hasPhoneNumber ?ap . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL {?a rdfs:label ?affType . }"			\
-		"OPTIONAL {?a nco:hasEmailAddress ?e . } "		\
-		"OPTIONAL {?a nco:hasPostalAddress ?p . }"		\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-		"OPTIONAL { ?a nco:title ?title } "			\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:to ?x ; "						\
-		"nmo:isSent true . "					\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasPhoneNumber ?t . } "			\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasAffiliation ?a . "			\
-			"?a nco:hasPhoneNumber ?t . } "			\
-		"FILTER ( !bound(?c) && !bound(?a) ) . "		\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false . "					\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasPhoneNumber ?t . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL { "						\
-			"?t a nco:CellPhoneNumber ; "			\
-				"nco:phoneNumber ?vc . "		\
-		"} "							\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-		"OPTIONAL { "						\
-			"?c nco:hasAffiliation ?a . "			\
-			"OPTIONAL { ?a nco:title ?title } "		\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:org ?o . } "			\
-		"} "							\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?ap . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false . "					\
-		"?c a nco:PersonContact . "				\
-		"?c nco:hasAffiliation ?a . "				\
-		"?a nco:hasPhoneNumber ?ap . "				\
-		"OPTIONAL { "						\
-			"?c a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-		"OPTIONAL {?a rdfs:label ?affType . }"			\
-		"OPTIONAL {?a nco:hasEmailAddress ?e . } "		\
-		"OPTIONAL {?a nco:hasPostalAddress ?p . }"		\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-		"OPTIONAL { ?a nco:title ?title } "			\
-		"OPTIONAL { ?c nco:hasPostalAddress ?po . } "		\
-		"OPTIONAL { ?c nco:hasEmailAddress ?eo . } "		\
-	"} UNION { "							\
-		"?x a nco:Contact . "					\
-		"?x nco:hasPhoneNumber ?t . "				\
-		"?call a nmo:Call ; "					\
-		"nmo:from ?x ; "					\
-		"nmo:isSent false . "					\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasPhoneNumber ?t . } "			\
-		"OPTIONAL {?c a nco:PersonContact ; "			\
-			"nco:hasAffiliation ?a . "			\
-			"?a nco:hasPhoneNumber ?t . } "			\
-		"FILTER ( !bound(?c) && !bound(?a) ) . "		\
-	"} "								\
-	"} ORDER BY DESC(nmo:receivedDate(?call)) "
+	"?_role nco:hasEmailAddress [ nco:emailAddress ?emailaddress ] "\
+	"}) "								\
+	"nmo:receivedDate(?_call) "					\
+	"nmo:isSent(?_call) "						\
+	"nmo:isAnswered(?_call) "					\
+	"fn:concat(tracker:coalesce(?_ncontact, \"\"),"			\
+	"tracker:coalesce(?_unb_contact, \"\"))"			\
+	" "								\
+"WHERE { "								\
+"{ "									\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:to ?_ncontact ; "						\
+	"nmo:isSent true . "						\
+	"?_contact a nco:PersonContact ; "				\
+	"nco:hasPhoneNumber ?_number . "				\
+	"OPTIONAL { ?_contact nco:hasAffiliation ?_role .} "		\
+	"?_contact nco:nameFamily ?_key ."				\
+"} UNION { "								\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:to ?_ncontact ; "						\
+	"nmo:isSent true . "						\
+	"?_contact a nco:PersonContact . "				\
+	"?_contact nco:nameFamily ?_key . "				\
+	"?_contact nco:hasAffiliation ?_role . "			\
+	"?_role nco:hasPhoneNumber ?_number . "				\
+"} UNION { "								\
+	"?_unb_contact a nco:Contact . "				\
+	"?_unb_contact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:to ?_unb_contact ; "					\
+	"nmo:isSent true . "						\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasPhoneNumber ?_number . } "				\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasAffiliation ?_role . "					\
+	"?_role nco:hasPhoneNumber ?_number. } "			\
+	"FILTER ( !bound(?_contact) && !bound(?_role) ) "		\
+"} UNION { "								\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_ncontact ; "					\
+	"nmo:isSent false . "						\
+	"?_contact a nco:PersonContact ; "				\
+	"nco:hasPhoneNumber ?_number . "				\
+	"OPTIONAL { ?_contact nco:hasAffiliation ?_role .} "		\
+	"?_contact nco:nameFamily ?_key ."				\
+"} UNION { "								\
+	"?_ncontact a nco:Contact . "					\
+	"?_ncontact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_ncontact ; "					\
+	"nmo:isSent false . "						\
+	"?_contact a nco:PersonContact . "				\
+	"?_contact nco:nameFamily ?_key . "				\
+	"?_contact nco:hasAffiliation ?_role . "			\
+	"?_role nco:hasPhoneNumber ?_number . "				\
+"} UNION { "								\
+	"?_unb_contact a nco:Contact . "				\
+	"?_unb_contact nco:hasPhoneNumber ?_number . "			\
+	"?_call a nmo:Call ; "						\
+	"nmo:from ?_unb_contact ; "					\
+	"nmo:isSent false . "						\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasPhoneNumber ?_number . } "				\
+	"OPTIONAL {?_contact a nco:PersonContact ; "			\
+	"nco:hasAffiliation ?_role . "					\
+	"?_role nco:hasPhoneNumber ?_number. } "			\
+	"FILTER ( !bound(?_contact) && !bound(?_role) ) "		\
+"} "									\
+"} "									\
+"ORDER BY DESC(nmo:sentDate(?_call)) "
 
 #define COMBINED_CALLS_LIST						\
 	"SELECT ?c nco:nameFamily(?c) nco:nameGiven(?c) "		\
@@ -690,58 +790,77 @@
 	"} GROUP BY ?call ORDER BY DESC(nmo:receivedDate(?call))"
 
 #define CONTACTS_QUERY_FROM_URI						\
-	"SELECT nco:phoneNumber(?v) nco:fullname(<%s>) "			\
-	"nco:nameFamily(<%s>) nco:nameGiven(<%s>) "				\
-	"nco:nameAdditional(<%s>) nco:nameHonorificPrefix(<%s>) "		\
-	"nco:nameHonorificSuffix(<%s>) nco:emailAddress(?e) ?vc "		\
-	"nco:pobox(?p) nco:extendedAddress(?p) "			\
-	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) ?f ?affType "		\
-	"nco:birthDate(<%s>) nco:nickname(<%s>) nco:url(<%s>) "		\
-	"?file nco:fullname(?o) nco:department(?a) "			\
-	"nco:role(?a) nco:contactUID(<%s>) "				\
-	"nco:title(?a) ?t nco:pobox(?po) nco:extendedAddress(?po) "	\
-	"nco:streetAddress(?po) nco:locality(?po) nco:region(?po) "	\
-	"nco:postalcode(?po) nco:country(?po) nco:emailAddress(?eo) "	\
-	"\"NOTACALL\" \"false\" \"false\" <%s> "				\
-	"WHERE { "							\
-		"<%s> a nco:PersonContact . "				\
-		"OPTIONAL { "						\
-			"<%s> a nco:PersonContact ; nco:photo ?pht . "	\
-			"?pht a nfo:FileDataObject ; nie:url ?file . "	\
-		"} "							\
-	"OPTIONAL { <%s> nco:hasPhoneNumber ?h . "			\
-		"OPTIONAL {"						\
-		"?h a nco:FaxNumber ; "					\
-		"nco:phoneNumber ?f . "					\
-		"}"							\
-		"OPTIONAL {"						\
-		"?h a nco:CellPhoneNumber ; "				\
-		"nco:phoneNumber ?vc"					\
-		"}"							\
-		"OPTIONAL {"						\
-		"?h a nco:VoicePhoneNumber ; "				\
-		"nco:phoneNumber ?t"					\
-		"}"							\
-	"}"								\
-	"OPTIONAL { "							\
-		"<%s> nco:hasAffiliation ?a . "				\
-		"OPTIONAL { ?a rdfs:label ?affType .}"			\
-			"OPTIONAL { ?a nco:hasEmailAddress ?e . } "	\
-			"OPTIONAL { ?a nco:hasPostalAddress ?p . } "	\
-			"OPTIONAL { ?a nco:hasPhoneNumber ?v . } "	\
-		"OPTIONAL { ?a nco:org ?o . } "				\
-	"} "								\
-	"OPTIONAL { <%s> nco:hasPostalAddress ?po . } "			\
-	"OPTIONAL { <%s> nco:hasEmailAddress ?eo . } "			\
-	"}"
+"SELECT "								\
+"(SELECT GROUP_CONCAT("							\
+"nco:phoneNumber(?number), \"\30\")"					\
+"WHERE {"								\
+"	?_role nco:hasPhoneNumber ?number"				\
+"}) "									\
+"nco:fullname(<%s>) "							\
+"nco:nameFamily(<%s>) "							\
+"nco:nameGiven(<%s>) "							\
+"nco:nameAdditional(<%s>) "						\
+"nco:nameHonorificPrefix(<%s>) "					\
+"nco:nameHonorificSuffix(<%s>) "					\
+"(SELECT GROUP_CONCAT(?emailaddress_other, \"\30\")"			\
+"WHERE {"								\
+"	<%s> nco:hasEmailAddress [nco:emailAddress ?emailaddress_other]"\
+"}) "									\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \";\","	\
+"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:locality(?aff_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:region(?aff_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:country(?aff_addr), \"\") ),\";\")"		\
+"WHERE {"								\
+"?_role nco:hasPostalAddress ?aff_addr"					\
+"}) "									\
+"(SELECT GROUP_CONCAT(fn:concat("					\
+"tracker:coalesce(nco:pobox(?oth_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:extendedAddress(?oth_addr), \"\"), \";\","	\
+"tracker:coalesce(nco:streetAddress(?oth_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:locality(?oth_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:region(?oth_addr), \"\"), \";\","			\
+"tracker:coalesce(nco:postalcode(?oth_addr), \"\"), \";\","		\
+"tracker:coalesce(nco:country(?oth_addr), \"\") ),\"\30\")"		\
+"WHERE {"								\
+"	<%s> nco:hasPostalAddress ?oth_addr"				\
+"}) "									\
+"(SELECT GROUP_CONCAT(fn:concat(rdf:type(?contact_number),"		\
+"\"\31\", nco:phoneNumber(?contact_number)), \"\30\")"			\
+"WHERE {"								\
+"	<%s> nco:hasPhoneNumber ?contact_number"			\
+"}) "									\
+"nco:birthDate(<%s>) "							\
+"nco:nickname(<%s>) "							\
+"nco:url(<%s>) "							\
+"nie:url(nco:photo(<%s>)) "						\
+"nco:role(?_role) "							\
+"nco:contactUID(<%s>) "							\
+"nco:title(?_role) "							\
+"rdfs:label(?_role) "							\
+"nco:fullname(nco:org(?_role))"						\
+"nco:department(?_role) "						\
+"(SELECT GROUP_CONCAT(?emailaddress, \"\30\")"				\
+"WHERE {"								\
+"	?_role nco:hasEmailAddress [ nco:emailAddress ?emailaddress ]"	\
+"}) "									\
+"\"NOTACALL\" \"false\" \"false\" "					\
+"<%s> "									\
+"WHERE {"								\
+"	<%s> a nco:PersonContact ;"					\
+"	nco:nameFamily ?_key ."						\
+"	OPTIONAL {<%s> nco:hasAffiliation ?_role .}"			\
+"}"									\
+"ORDER BY ?_key tracker:id(<%s>)"
 
 #define CONTACTS_OTHER_QUERY_FROM_URI					\
-	"SELECT \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" "\
-	"\"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" "	\
-	"\"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" "	\
-	"\"\" "								\
-	"nco:phoneNumber(?t) \"NOTACALL\" \"false\" \"false\" <%s> "	\
+	"SELECT \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" "	\
+	"fn:concat(\"TYPE_OTHER\", \"\31\", nco:phoneNumber(?t)) \"\" "	\
+	"\"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" "		\
+	" \"NOTACALL\" \"false\" \"false\" <%s> "	\
 	"WHERE { "							\
 		"<%s> a nco:Contact . "					\
 		"OPTIONAL { <%s> nco:hasPhoneNumber ?t . } "		\
@@ -1333,21 +1452,64 @@ static enum phonebook_number_type get_phone_type(const char *affilation)
 	return TEL_TYPE_OTHER;
 }
 
+static void add_main_number(struct phonebook_contact *contact, char *pnumber)
+{
+	char **num_parts;
+	char *type, *number;
+
+	/* For phone taken directly from contacts data, phone number string
+	 * is represented as number type and number string - those strings are
+	 * separated by SUB_DELIM string */
+	num_parts = g_strsplit(pnumber, SUB_DELIM, 2);
+
+	if (num_parts) {
+		if (num_parts[0])
+			type = num_parts[0];
+		else
+			goto fail;
+
+		if (num_parts[1])
+			number = num_parts[1];
+		else
+			goto fail;
+	}
+
+	if (g_strrstr(type, FAX_NUM_TYPE))
+		add_phone_number(contact, number, TEL_TYPE_FAX);
+	else if (g_strrstr(type, MOBILE_NUM_TYPE))
+		add_phone_number(contact, number, TEL_TYPE_MOBILE);
+	else
+		add_phone_number(contact, number, TEL_TYPE_OTHER);
+
+fail:
+	g_strfreev(num_parts);
+}
+
 static void contact_add_numbers(struct phonebook_contact *contact,
 								char **reply)
 {
-	add_phone_number(contact, reply[COL_PHONE_NUMBER],
+	char **aff_numbers, **con_numbers;
+	int i;
+
+	/* Filling phone numbers from contact's affilation */
+	aff_numbers = g_strsplit(reply[COL_PHONE_AFF], MAIN_DELIM, MAX_FIELDS);
+
+	if (aff_numbers)
+		for(i = 0;aff_numbers[i]; ++i)
+			add_phone_number(contact, aff_numbers[i],
 					get_phone_type(reply[COL_AFF_TYPE]));
-	add_phone_number(contact, reply[COL_FAX_NUMBER], TEL_TYPE_FAX);
-	add_phone_number(contact, reply[COL_CELL_NUMBER], TEL_TYPE_MOBILE);
 
-	if (g_strcmp0(reply[COL_OTHER_NUMBER], reply[COL_CELL_NUMBER]) == 0)
-		return;
+	g_strfreev(aff_numbers);
 
-	if (g_strcmp0(reply[COL_OTHER_NUMBER], reply[COL_PHONE_NUMBER]) == 0)
-		return;
+	/* Filling phone numbers directly from contact's struct */
+	con_numbers = g_strsplit(reply[COL_PHONE_CONTACT], MAIN_DELIM,
+								MAX_FIELDS);
 
-	add_phone_number(contact, reply[COL_OTHER_NUMBER], TEL_TYPE_OTHER);
+	if (con_numbers)
+		for(i = 0; con_numbers[i] != NULL; ++i)
+			add_main_number(contact, con_numbers[i]);
+
+	g_strfreev(con_numbers);
 }
 
 static enum phonebook_email_type get_email_type(const char *affilation)
@@ -1363,9 +1525,29 @@ static enum phonebook_email_type get_email_type(const char *affilation)
 static void contact_add_emails(struct phonebook_contact *contact,
 								char **reply)
 {
-	add_email(contact, reply[COL_EMAIL],
+	char **aff_emails, **con_emails;
+	int i;
+
+	/* Emails from affilation */
+	aff_emails = g_strsplit(reply[COL_EMAIL_AFF], MAIN_DELIM, MAX_FIELDS);
+
+	if (aff_emails)
+		for(i = 0; aff_emails[i] != NULL; ++i)
+			add_email(contact, aff_emails[i],
 					get_email_type(reply[COL_AFF_TYPE]));
-	add_email(contact, reply[COL_OTHER_EMAIL], EMAIL_TYPE_OTHER);
+
+	g_strfreev(aff_emails);
+
+	/* Emails taken directly from contact's data have always type OTHER */
+	con_emails = g_strsplit(reply[COL_EMAIL_CONTACT], MAIN_DELIM,
+								MAX_FIELDS);
+
+	if (con_emails)
+		for(i = 0; con_emails[i] != NULL; ++i)
+			add_email(contact, con_emails[i], EMAIL_TYPE_OTHER);
+
+	g_strfreev(con_emails);
+
 }
 
 static enum phonebook_address_type get_addr_type(const char *affilation)
@@ -1382,32 +1564,30 @@ static void contact_add_addresses(struct phonebook_contact *contact,
 								char **reply)
 {
 
-	char *main_addr, *other_addr;
+	char **aff_addr, **con_addr;
+	int i;
+
+	/* Addresses from affilation */
+	aff_addr = g_strsplit(reply[COL_ADDR_AFF], MAIN_DELIM,
+								MAX_FIELDS);
+
+	if (aff_addr)
+		for(i = 0; aff_addr[i] != NULL; ++i)
+			add_address(contact, aff_addr[i],
+					get_addr_type(reply[COL_AFF_TYPE]));
 
-	main_addr = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s",
-					reply[COL_ADDR_POBOX],
-					reply[COL_ADDR_EXT],
-					reply[COL_ADDR_STREET],
-					reply[COL_ADDR_LOCALITY],
-					reply[COL_ADDR_REGION],
-					reply[COL_ADDR_CODE],
-					reply[COL_ADDR_COUNTRY]);
+	g_strfreev(aff_addr);
 
-	other_addr = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s",
-					reply[COL_OTHER_ADDR_POBOX],
-					reply[COL_OTHER_ADDR_EXT],
-					reply[COL_OTHER_ADDR_STREET],
-					reply[COL_OTHER_ADDR_LOCALITY],
-					reply[COL_OTHER_ADDR_REGION],
-					reply[COL_OTHER_ADDR_CODE],
-					reply[COL_OTHER_ADDR_COUNTRY]);
+	/* Addresses from contact struct */
+	con_addr = g_strsplit(reply[COL_ADDR_CONTACT], MAIN_DELIM,
+								MAX_FIELDS);
 
-	add_address(contact, main_addr, get_addr_type(reply[COL_AFF_TYPE]));
+	if (con_addr)
+		for(i = 0; con_addr[i] != NULL; ++i)
+			add_address(contact, con_addr[i], ADDR_TYPE_OTHER);
 
-	add_address(contact, other_addr, ADDR_TYPE_OTHER);
+	g_strfreev(con_addr);
 
-	g_free(main_addr);
-	g_free(other_addr);
 }
 
 static void contact_add_organization(struct phonebook_contact *contact,
@@ -1722,7 +1902,7 @@ void *phonebook_get_entry(const char *folder, const char *id,
 	if (strncmp(id, CONTACT_ID_PREFIX, strlen(CONTACT_ID_PREFIX)) == 0)
 		query = g_strdup_printf(CONTACTS_QUERY_FROM_URI, id, id, id, id,
 						id, id, id, id, id, id, id, id,
-						id, id, id, id, id);
+						id, id, id, id, id, id);
 	else
 		query = g_strdup_printf(CONTACTS_OTHER_QUERY_FROM_URI,
 								id, id, id);
-- 
1.7.0.4


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox