Linux bluetooth development
 help / color / mirror / Atom feed
* [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

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

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(-)

diff --git a/audio/headset.c b/audio/headset.c
index 97ae4fd..52d0ce8 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -958,7 +958,7 @@ static int headset_set_gain(struct audio_device *device, uint16_t gain, char typ
 	case HEADSET_GAIN_SPEAKER:
 		if (slc->sp_gain == gain) {
 			DBG("Ignoring no-change in speaker gain");
-			return 0;
+			return -EALREADY;
 		}
 		name = "SpeakerGainChanged";
 		property = "SpeakerGain";
@@ -967,7 +967,7 @@ static int headset_set_gain(struct audio_device *device, uint16_t gain, char typ
 	case HEADSET_GAIN_MICROPHONE:
 		if (slc->mic_gain == gain) {
 			DBG("Ignoring no-change in microphone gain");
-			return 0;
+			return -EALREADY;
 		}
 		name = "MicrophoneGainChanged";
 		property = "MicrophoneGain";
@@ -1004,7 +1004,7 @@ static int signal_gain_setting(struct audio_device *device, const char *buf)
 	gain = (dbus_uint16_t) strtol(&buf[7], NULL, 10);
 
 	err = headset_set_gain(device, gain, buf[5]);
-	if (err < 0)
+	if (err < 0 && err != -EALREADY)
 		return err;
 
 	return headset_send(hs, "\r\nOK\r\n");
@@ -1887,10 +1887,14 @@ static DBusMessage *hs_set_gain(DBusConnection *conn,
 		return btd_error_not_connected(msg);
 
 	err = headset_set_gain(device, gain, type);
-	if (err < 0)
+	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");
+	}
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
-- 
1.7.1


^ permalink raw reply related

* [PATCH] Fix not calling SetConfiguration on hfp/hsp endpoints before connected
From: Luiz Augusto von Dentz @ 2010-12-16 14:13 UTC (permalink / raw)
  To: linux-bluetooth

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(-)

diff --git a/audio/media.c b/audio/media.c
index 0e6ccc9..b28bb33 100644
--- a/audio/media.c
+++ b/audio/media.c
@@ -151,16 +151,13 @@ static void headset_state_changed(struct audio_device *dev,
 
 	switch (new_state) {
 	case HEADSET_STATE_DISCONNECTED:
-		if (old_state != HEADSET_STATE_CONNECTING)
-			media_endpoint_clear_configuration(endpoint);
+		media_endpoint_clear_configuration(endpoint);
+		break;
 	case HEADSET_STATE_CONNECTING:
+		media_endpoint_set_configuration(endpoint, dev, NULL, 0,
+						headset_setconf_cb, dev);
 		break;
 	case HEADSET_STATE_CONNECTED:
-		if (old_state != HEADSET_STATE_PLAY_IN_PROGRESS &&
-				old_state != HEADSET_STATE_PLAYING)
-			media_endpoint_set_configuration(endpoint, dev, NULL,
-							0, headset_setconf_cb,
-									dev);
 		break;
 	case HEADSET_STATE_PLAY_IN_PROGRESS:
 		break;
-- 
1.7.1


^ permalink raw reply related

* [PATCH] Further optimalization of PBAP tracker queries
From: Radoslaw Jablonski @ 2010-12-16 11:55 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 | 1242 +++++++++++++++++++++++++------------------
 1 files changed, 712 insertions(+), 530 deletions(-)

diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
index cdc1008..befca7a 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 . } "		\
@@ -1302,21 +1421,66 @@ 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)
+{
+	gchar **num_parts;
+	gchar *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
+			return;
+
+		if (num_parts[1])
+			number = num_parts[1];
+		else
+			return;
+	}
+
+	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);
+
+	g_strfreev(num_parts);
+}
+
 static void contact_add_numbers(struct phonebook_contact *contact,
 								char **reply)
 {
-	add_phone_number(contact, reply[COL_PHONE_NUMBER],
+	gchar **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) {
+		DBG("aff numbers[0] %s", aff_numbers[0]);
+		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)
@@ -1332,9 +1496,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],
+	gchar **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)
@@ -1351,32 +1535,30 @@ static void contact_add_addresses(struct phonebook_contact *contact,
 								char **reply)
 {
 
-	char *main_addr, *other_addr;
+	gchar **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,
@@ -1667,7 +1849,7 @@ int 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

* Re: [PATCH 2/4] remove error_common_reply()
From: Johan Hedberg @ 2010-12-16  9:30 UTC (permalink / raw)
  To: Gustavo F. Padovan; +Cc: linux-bluetooth
In-Reply-To: <1292450823-17640-2-git-send-email-padovan@profusion.mobi>

Hi Gustavo,

On Wed, Dec 15, 2010, Gustavo F. Padovan wrote:
> Remove old dbus error report function. This patch doesn't make things
> really really better, but is a start.
> ---
>  audio/gateway.c |   18 ++++++++++--------
>  audio/headset.c |   37 +++++++++++++++----------------------
>  audio/sink.c    |    7 ++++---
>  audio/source.c  |    7 ++++---
>  src/error.c     |   18 ------------------
>  src/error.h     |    3 ---
>  6 files changed, 33 insertions(+), 57 deletions(-)

Thanks. This patch has been pushed upstream. The other two will have to
wait since I can't apply them before the first one has been fixed.

Johan

^ permalink raw reply

* Re: [PATCH 1/4] add btd_error_agent_not_assigned()
From: Johan Hedberg @ 2010-12-16  9:29 UTC (permalink / raw)
  To: Gustavo F. Padovan; +Cc: linux-bluetooth
In-Reply-To: <1292450823-17640-1-git-send-email-padovan@profusion.mobi>

Hi Gustavo,

On Wed, Dec 15, 2010, Gustavo F. Padovan wrote:
> +DBusMessage *btd_error_agent_not_assigned(DBusMessage *msg)
> +{
> +	return g_dbus_create_error(msg, ERROR_INTERFACE ".AgentNotAssigned",
> +					"Agent Not Assigned");
> +}
> +

Could we make this AgentNotAvailable instead?

Johan

^ permalink raw reply

* Re: [PATCH] Fix crash while reading from mapped file
From: Luiz Augusto von Dentz @ 2010-12-16  9:28 UTC (permalink / raw)
  To: Anderson Lizardo
  Cc: Lukasz Pawlik, Bastien Nocera, Johan Hedberg, linux-bluetooth
In-Reply-To: <AANLkTim5y+g0n2-k8XMHE4kU-N-n-p4DvHVGg045Aoys@mail.gmail.com>

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.


-- 
Luiz Augusto von Dentz
Computer Engineer

^ permalink raw reply

* Re: [PATCH] Fix memory leak of gattrib commands queue
From: Johan Hedberg @ 2010-12-16  9:25 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <1292443209-31156-1-git-send-email-claudio.takahasi@openbossa.org>

Hi Claudio,

On Wed, Dec 15, 2010, Claudio Takahasi wrote:
> ---
>  attrib/gattrib.c |    1 +
>  1 files changed, 1 insertions(+), 0 deletions(-)
> 
> diff --git a/attrib/gattrib.c b/attrib/gattrib.c
> index 4ed29d9..eace01b 100644
> --- a/attrib/gattrib.c
> +++ b/attrib/gattrib.c
> @@ -177,6 +177,7 @@ void g_attrib_unref(GAttrib *attrib)
>  	while ((c = g_queue_pop_head(attrib->queue)))
>  		command_destroy(c);
>  
> +	g_queue_free(attrib->queue);
>  	attrib->queue = NULL;
>  
>  	for (l = attrib->events; l; l = l->next)

Pushed upstream. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH 2/5] Change CreatePairedDevice to support LE devices
From: Johan Hedberg @ 2010-12-16  9:24 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,

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?

> 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?

> --- 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

^ permalink raw reply

* Re: [PATCH 1/5] Implement cancel primary discovery session
From: Johan Hedberg @ 2010-12-16  9:15 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <1292442852-26457-1-git-send-email-claudio.takahasi@openbossa.org>

Hi Claudio,

On Wed, Dec 15, 2010, Claudio Takahasi wrote:
> Extend bt_cancel_discovery function to cancel an ongoing Discover
> All Primary Services procedure.
> ---
>  src/device.c      |   11 +++----
>  src/glib-helper.c |   73 ++++++++++++++++++++++++++++++++++++++++++-----------
>  2 files changed, 63 insertions(+), 21 deletions(-)

Thanks. This patch has been pushed upstream.

Johan

^ permalink raw reply

* Re: [RFC] Bluetooth: Use non-flushable pb flag by default for ACL data on capable chipsets.
From: Andrei Emeltchenko @ 2010-12-16  9:00 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:
>
> On Tue, 14 Dec 2010, Gustavo F. Padovan wrote:
>
>> Hi Andrei,
>>
>> * Emeltchenko Andrei <Andrei.Emeltchenko.news@gmail.com> [2010-12-13
>> 16:38:25 +0200]:
>>
>>> 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).
>
> This is a great feature to add, not only for A2DP.  Both ERTM and streaming
> mode only really make sense on unreliable links.
>
>>> 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             |   33
>>> +++++++++++++++++++++++++++++++--
>>>  6 files changed, 45 insertions(+), 4 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)
>>
>> IMHO lmp_flush_capable() makes more sense. We can avoid things like
>> (!lmp_no_flush_capable(dev)) and add two negatives in the same comparison.
>>
>>>
>>>  /* ----- 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
>>
>> Not using this anywhere.
>>
>>>
>>>  /* 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..c7f25c2 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);
>>
>> I also agree that l2cap commands should be non-flushable. Just pass
>> ACL_START_NO_FLUSH to hci_send_acl() here.

Gustavo if the controller does not support non flushable packets we
may have bug here.

>> You should add this check to l2cap_do_send() instead.

This is done for data packets.

>>>  }
>>>
>>>  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 */
>>> @@ -2098,6 +2106,20 @@ 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;
>>> +               }
>>> +
>>> +               l2cap_pi(sk)->flushable = opt;
>
> Does it make sense to check the HCI device for flush capability here? If the
> HCI device is not capable, this option should remain false. This would also
> let the application use getsockopt() to find out if the link is really
> flushable or not.

Thanks for the hint, I will add the check here and return -EINVAL then.

>> You are not using this flushable value anywhere. Something is wrong here.
>
> I agree - like Gustavo mentioned above, l2cap_do_send() needs to be checking
> l2cap_pi(sk)->flushable and setting the flags in hci_send_acl()
> appropriately.

Yes, I have lost one chunk when reformatting patches against different branches.

The lost chunk is below:

diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index c7f25c2..f7260ad 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1458,10 +1458,16 @@ 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;

        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(pi->conn->hcon, skb, flags);
 }

 static void l2cap_streaming_send(struct sock *sk)

> 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)
>
> --
> Mat Martineau
> Employee of Qualcomm Innovation Center, Inc.
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
>

^ permalink raw reply related

* Re: HFP: typo in error path?
From: Daniel Wagner @ 2010-12-16  7:21 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20101216071015.GA32193@jh-x301>

Hi Johan,

On Thu, Dec 16, 2010 at 09:10:15AM +0200, Johan Hedberg wrote:
> > 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.
> 
> Actually the current code is correct. This is the callback for SCO (like
> the function name suggests) so when SCO gets closed there's a transition
> from PLAYING to CONNECTED (meaning RFCOMM but no SCO). You can see the
> full set of state values in audio/gateway.h.

Thanks for the clarification, that make perfectly sense now :)

cheers,
daniel

^ permalink raw reply

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

Hi Daniel,

On Thu, Dec 16, 2010, Daniel Wagner wrote:
> 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.

Actually the current code is correct. This is the callback for SCO (like
the function name suggests) so when SCO gets closed there's a transition
from PLAYING to CONNECTED (meaning RFCOMM but no SCO). You can see the
full set of state values in audio/gateway.h.

Johan

^ permalink raw reply

* HFP: typo in error path?
From: Daniel Wagner @ 2010-12-16  6:42 UTC (permalink / raw)
  To: linux-bluetooth

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.

cheers,
daniel

^ permalink raw reply


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