From 07e687ad7e9544fe2ad086f16f041989532fdd92 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Mon, 3 May 2010 13:16:04 -0300 Subject: [PATCH] obexd: Add sort function for PullvCardListing Listing object can be sorted using three approaches: alphabetical, Indexed or Phonetical. When Order parameter is not given, the default order is Indexed. --- obexd/plugins/pbap.c | 130 +++++++++++++++++++++++++++++++++---------- 1 file changed, 100 insertions(+), 30 deletions(-) diff --git a/obexd/plugins/pbap.c b/obexd/plugins/pbap.c index fa03633d3..058452410 100644 --- a/obexd/plugins/pbap.c +++ b/obexd/plugins/pbap.c @@ -148,8 +148,6 @@ static const guint8 PBAP_TARGET[TARGET_SIZE] = { 0x79, 0x61, 0x35, 0xF0, 0xF0, 0xC5, 0x11, 0xD8, 0x09, 0x66, 0x08, 0x00, 0x20, 0x0C, 0x9A, 0x66 }; -typedef int (*cache_sort_f) (struct cache_entry *entry, gpointer user_data); -typedef void (*cache_element_f) (struct cache_entry *entry, gpointer user_data); typedef int (*cache_entry_find_f) (const struct cache_entry *entry, const gchar *value); @@ -275,40 +273,70 @@ static void cache_entry_notify(const gchar *id, guint32 handle, cache->entries = g_slist_append(cache->entries, entry); } -static void cache_ready_notify(gpointer user_data) +static int alpha_sort(gconstpointer a, gconstpointer b) { - struct pbap_session *pbap = user_data; - cache_entry_find_f find; - gchar *searchval; - GSList *l; + const struct cache_entry *e1 = a; + const struct cache_entry *e2 = b; - if (pbap->params->maxlistcount == 0) { - /* Ignore all other parameter and return PhoneBookSize */ - gchar aparam[4]; - struct aparam_header *hdr = (struct aparam_header *) aparam; - guint16 size = g_slist_length(pbap->cache.entries); + return g_strcmp0(e1->name, e2->name); +} - hdr->tag = PHONEBOOKSIZE_TAG; - hdr->len = PHONEBOOKSIZE_LEN; - memcpy(hdr->val, &size, sizeof(size)); +static int phonetical_sort(gconstpointer a, gconstpointer b) +{ + const struct cache_entry *e1 = a; + const struct cache_entry *e2 = b; - pbap->buffer = g_string_new_len(aparam, sizeof(aparam)); - goto done; - } + /* + * SOUND attribute is optinal. Keep the order + * when this attribute is not available. + */ + if (!e1->sound) + return 1; - pbap->buffer = g_string_new(VCARD_LISTING_BEGIN); - l = g_slist_nth(pbap->cache.entries, - pbap->params->liststartoffset); + return g_strcmp0(e1->sound, e2->sound); +} + +static int indexed_sort(gconstpointer a, gconstpointer b) +{ + const struct cache_entry *e1 = a; + const struct cache_entry *e2 = b; + + return (e1->handle - e2->handle); +} + +static GSList *sort_entries(GSList *l, uint8_t order, uint8_t search_attrib, + const char *value) +{ + GSList *sorted = NULL; + cache_entry_find_f find; + GCompareFunc sort; + char *searchval; + + /* + * Default sorter is "Indexed". Some backends doesn't inform the index, + * for this case a sequential internal index is assigned. + * 0x00 = indexed + * 0x01 = alphanumeric + * 0x02 = phonetic + */ + switch (order) { + case 0x01: + sort = alpha_sort; + break; + case 0x02: + sort = phonetical_sort; + break; + default: + sort = indexed_sort; + break; + } /* - * FIXME: See PBAP spec section 5.3.4.1 - * Order{Alphabetical | Indexed | Phonetical} not yet implemented - * * This implementation checks if the given field CONTAINS the * search value(case insensitive). Name is the default field * when the attribute is not provided. */ - switch (pbap->params->searchattrib) { + switch (search_attrib) { case 1: /* Number */ find = entry_tel_find; @@ -322,21 +350,63 @@ static void cache_ready_notify(gpointer user_data) break; } - searchval = g_utf8_strdown((gchar *) pbap->params->searchval, -1); + searchval = value ? g_utf8_strdown(value, -1) : NULL; for (; l; l = l->next) { - const struct cache_entry *entry = l->data; + struct cache_entry *entry = l->data; if (searchval && !find(entry, (const gchar *) searchval)) continue; - g_string_append_printf(pbap->buffer, - VCARD_LISTING_ELEMENT, - entry->handle, entry->name); + sorted = g_slist_insert_sorted(sorted, entry, sort); } g_free(searchval); + + return sorted; +} + +static void cache_ready_notify(void *user_data) +{ + struct pbap_session *pbap = user_data; + GSList *sorted; + GSList *l; + uint16_t max = pbap->params->maxlistcount; + + if (max == 0) { + /* Ignore all other parameter and return PhoneBookSize */ + char aparam[4]; + struct aparam_header *hdr = (struct aparam_header *) aparam; + uint16_t size = htons(g_slist_length(pbap->cache.entries)); + + hdr->tag = PHONEBOOKSIZE_TAG; + hdr->len = PHONEBOOKSIZE_LEN; + memcpy(hdr->val, &size, sizeof(size)); + + pbap->buffer = g_string_new_len(aparam, sizeof(aparam)); + goto done; + } + + /* Computing off set considering first entry of the phonebook */ + l = g_slist_nth(pbap->cache.entries, pbap->params->liststartoffset); + + /* + * Don't free the sorted list content: this list contains + * only the reference for the "real" cache entry. + */ + sorted = sort_entries(l, pbap->params->order, + pbap->params->searchattrib, + (const char *) pbap->params->searchval); + + pbap->buffer = g_string_new(VCARD_LISTING_BEGIN); + for (l = sorted; l && max; l = l->next, max--) { + const struct cache_entry *entry = l->data; + g_string_append_printf(pbap->buffer, VCARD_LISTING_ELEMENT, + entry->handle, entry->name); + } + pbap->buffer = g_string_append(pbap->buffer, VCARD_LISTING_END); + g_slist_free(sorted); done: if (!pbap->cache.valid) { pbap->cache.valid = TRUE; -- 2.47.3