2011-07-05 20:53:18

by Bartosz Szatkowski

[permalink] [raw]
Subject: [PATCH obexd 1/5 v2] Change EDS backend to support multiple ebooks

Until now only default ebook was used, this patch change this behaviour
so each function is run on all available (active) ebooks and merging
results from each of them.
---
plugins/phonebook-ebook.c | 293 ++++++++++++++++++++++++++++++---------------
1 files changed, 196 insertions(+), 97 deletions(-)

diff --git a/plugins/phonebook-ebook.c b/plugins/phonebook-ebook.c
index 82019da..067bcc7 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -45,17 +45,20 @@
#define QUERY_NAME "(contains \"given_name\" \"%s\")"
#define QUERY_PHONE "(contains \"phone\" \"%s\")"

-
struct query_context {
- gboolean completed;
const struct apparam_field *params;
phonebook_cb contacts_cb;
phonebook_entry_cb entry_cb;
phonebook_cache_ready_cb ready_cb;
+ EBookQuery *query;
+ int count;
+ GString *buf;
+ char *id;
+ unsigned queued_calls;
void *user_data;
};

-static EBook *ebook = NULL;
+static GSList *ebooks = NULL;

static char *attribute_mask[] = {
/* 0 */ "VERSION",
@@ -91,6 +94,19 @@ static char *attribute_mask[] = {

};

+static void free_query_context(struct query_context *data)
+{
+ g_free(data->id);
+
+ if (data->buf != NULL)
+ g_string_free(data->buf, TRUE);
+
+ if (data->query != NULL)
+ e_book_query_unref(data->query);
+
+ g_free(data);
+}
+
static char *evcard_to_string(EVCard *evcard, unsigned int format,
uint64_t filter)
{
@@ -99,7 +115,8 @@ static char *evcard_to_string(EVCard *evcard, unsigned int format,
char *vcard;

if (!filter)
- return e_vcard_to_string(evcard, format);
+ return e_vcard_to_string(evcard, EVC_FORMAT_VCARD_30);
+ /* XXX There is no support for VCARD 2.1 at this time */

/*
* Mandatory attributes for vCard 2.1 are VERSION ,N and TEL.
@@ -136,24 +153,20 @@ static char *evcard_to_string(EVCard *evcard, unsigned int format,
return vcard;
}

-static void ebookpull_cb(EBook *book, EBookStatus estatus, GList *contacts,
+static void ebookpull_cb(EBook *book, const GError *gerr, GList *contacts,
void *user_data)
{
struct query_context *data = user_data;
- GString *string = g_string_new("");
- unsigned int count = 0, maxcount;
GList *l;
+ unsigned int count = data->count, maxcount;

- if (estatus == E_BOOK_ERROR_CANCELLED) {
- error("E-Book operation was cancelled: status %d", estatus);
- goto fail;
- }
-
- if (estatus != E_BOOK_ERROR_OK) {
- error("E-Book query failed: status %d", estatus);
+ if (gerr != NULL) {
+ error("E-Book query failed: %s", gerr->message);
goto done;
}

+ DBG("");
+
/*
* When MaxListCount is zero, PCE wants to know the number of used
* indexes in the phonebook of interest. All other parameters that
@@ -161,7 +174,7 @@ static void ebookpull_cb(EBook *book, EBookStatus estatus, GList *contacts,
*/
maxcount = data->params->maxlistcount;
if (maxcount == 0) {
- count = g_list_length(contacts);
+ count += g_list_length(contacts);
goto done;
}

@@ -177,45 +190,36 @@ static void ebookpull_cb(EBook *book, EBookStatus estatus, GList *contacts,
vcard = evcard_to_string(evcard, data->params->format,
data->params->filter);

- string = g_string_append(string, vcard);
- string = g_string_append(string, "\r\n");
+ data->buf = g_string_append(data->buf, vcard);
+ data->buf = g_string_append(data->buf, "\r\n");
g_free(vcard);
}
- DBG("collected %d vcards", count);
-

done:
- data->completed = TRUE;
- data->contacts_cb(string->str, string->len, count, 0, TRUE,
- data->user_data);
+ g_list_free_full(contacts, g_object_unref);

-fail:
- g_string_free(string, TRUE);
+ DBG("collected %d vcards", count);

- if (data->completed)
- g_free(data);
+ data->queued_calls--;
+ if (data->queued_calls == 0)
+ data->contacts_cb(data->buf->str, data->buf->len, count, 0,
+ TRUE, data->user_data);
}

-static void ebook_entry_cb(EBook *book, EBookStatus estatus,
- EContact *contact, void *user_data)
+static void ebook_entry_cb(EBook *book, const GError *gerr,
+ EContact *contact, void *user_data)
{
struct query_context *data = user_data;
EVCard *evcard;
char *vcard;
size_t len;

- if (estatus == E_BOOK_ERROR_CANCELLED) {
- error("E-Book operation was cancelled: status %d", estatus);
- goto fail;
+ if (gerr != NULL) {
+ error("E-Book query failed: %s", gerr->message);
+ goto done;
}

- data->completed = TRUE;
-
- if (estatus != E_BOOK_ERROR_OK) {
- error("E-Book query failed: status %d", estatus);
- data->contacts_cb(NULL, 0, 1, 0, TRUE, data->user_data);
- goto fail;
- }
+ DBG("");

evcard = E_VCARD(contact);

@@ -224,13 +228,21 @@ static void ebook_entry_cb(EBook *book, EBookStatus estatus,

len = vcard ? strlen(vcard) : 0;

+ data->count++;
data->contacts_cb(vcard, len, 1, 0, TRUE, data->user_data);

g_free(vcard);
+ g_object_unref(contact);

-fail:
- if (data->completed)
- g_free(data);
+done:
+ data->queued_calls--;
+ if (data->queued_calls == 0) {
+ if (data->count == 0)
+ data->contacts_cb(NULL, 0, 1, 0, TRUE,
+ data->user_data);
+
+ free_query_context(data);
+ }
}

static char *evcard_name_attribute_to_string(EVCard *evcard)
@@ -263,24 +275,19 @@ static char *evcard_name_attribute_to_string(EVCard *evcard)
return g_string_free(name, FALSE);
}

-static void cache_cb(EBook *book, EBookStatus estatus, GList *contacts,
+static void cache_cb(EBook *book, const GError *gerr, GList *contacts,
void *user_data)
{
struct query_context *data = user_data;
GList *l;

- if (estatus == E_BOOK_ERROR_CANCELLED) {
- error("E-Book operation was cancelled: status %d", estatus);
- goto fail;
- }
-
- data->completed = TRUE;
-
- if (estatus != E_BOOK_ERROR_OK) {
- error("E-Book query failed: status %d", estatus);
+ if (gerr != NULL) {
+ error("E-Book operation failed: %s", gerr->message);
goto done;
}

+ DBG("");
+
for (l = contacts; l; l = g_list_next(l)) {
EContact *contact = E_CONTACT(l->data);
EVCard *evcard = E_VCARD(contact);
@@ -295,61 +302,132 @@ static void cache_cb(EBook *book, EBookStatus estatus, GList *contacts,
if (!attrib)
continue;

- uid = e_vcard_attribute_get_value(attrib);
+ uid = e_vcard_attribute_get_value(attrib);
if (!uid)
continue;

attrib = e_vcard_get_attribute(evcard, EVC_TEL);
if (!attrib)
- continue;
-
- tel = e_vcard_attribute_get_value(attrib);
+ tel = e_vcard_attribute_get_value(attrib);
+ else
+ tel = g_strdup("");

data->entry_cb(uid, PHONEBOOK_INVALID_HANDLE, name, NULL,
tel, data->user_data);
+
g_free(name);
g_free(uid);
g_free(tel);
}
+
done:
- data->ready_cb(data->user_data);
+ g_list_free_full(contacts, g_object_unref);
+
+ data->queued_calls--;
+ if (data->queued_calls == 0)
+ data->ready_cb(data->user_data);
+}
+
+static int traverse_sources(GSList *sources, char *default_src) {
+ GError *gerr;
+ int status;
+
+ while (sources != NULL) {
+ EBook *ebook = e_book_new(E_SOURCE(sources->data), &gerr);
+ if (ebook == NULL) {
+ error("Can't create user's address book: %s",
+ gerr->message);
+
+ status = -EIO;
+ goto fail;
+ }
+
+ if (g_strcmp0(default_src, e_source_get_uri(
+ E_SOURCE(sources->data))) == 0) {
+ sources = sources->next;
+
+ continue;
+ }
+
+ if (e_book_open(ebook, FALSE, &gerr) == FALSE) {
+ error("Can't open e-book address book: %s",
+ gerr->message);
+
+ status = -EIO;
+ goto fail;
+ }
+
+ if (default_src == NULL)
+ default_src = e_source_get_uri(E_SOURCE(sources->data));
+
+ DBG("%s address book opened",
+ e_source_peek_name(sources->data));
+
+ ebooks = g_slist_append(ebooks, ebook);
+
+ sources = sources->next;
+ }
+
+ return 0;

fail:
- if (data->completed)
- g_free(data);
+ g_error_free(gerr);
+
+ return status;
}

int phonebook_init(void)
{
- GError *gerr = NULL;
+ GError *gerr;
+ ESourceList *src_list;
+ GSList *list;
+ gchar *default_src = NULL;
+ int status = 0;

- if (ebook)
+ if (ebooks)
return 0;

g_type_init();

- ebook = e_book_new_default_addressbook(&gerr);
- if (!ebook) {
- error("Can't create user's default address book: %s",
- gerr->message);
+ if (e_book_get_addressbooks(&src_list, &gerr) == FALSE) {
+ error("Can't list user's address books: %s", gerr->message);
g_error_free(gerr);
- return -EIO;
+
+ status = -EIO;
+ goto fail;
}

- if (!e_book_open(ebook, FALSE, &gerr)) {
- error("Can't open e-book address book: %s", gerr->message);
- g_error_free(gerr);
- return -EIO;
+ list = e_source_list_peek_groups(src_list);
+ while (list) {
+ ESourceGroup *group = E_SOURCE_GROUP(list->data);
+
+ GSList *sources = e_source_group_peek_sources(group);
+
+ status = traverse_sources(sources, default_src);
+ if (status != 0)
+ goto fail;
+
+ list = list->next;
}

- return 0;
+ return status;
+
+fail:
+ g_slist_free_full(ebooks, g_object_unref);
+ g_object_unref(src_list);
+
+ return status;
}

void phonebook_exit(void)
{
- if (ebook)
- g_object_unref(ebook);
- ebook = NULL;
+ DBG("");
+
+ if (ebooks == NULL)
+ return;
+
+ g_slist_free_full(ebooks, g_object_unref);
+ ebooks = NULL;
}

char *phonebook_set_folder(const char *current_folder,
@@ -440,13 +518,10 @@ void phonebook_req_finalize(void *request)
{
struct query_context *data = request;

- if (!data)
- return;
+ DBG("");

- if (!data->completed) {
- data->completed = TRUE;
- e_book_cancel_async_op(ebook, NULL);
- }
+ if (data != NULL && data->queued_calls == 0)
+ free_query_context(data);
}

void *phonebook_pull(const char *name, const struct apparam_field *params,
@@ -458,6 +533,7 @@ void *phonebook_pull(const char *name, const struct apparam_field *params,
data->contacts_cb = cb;
data->params = params;
data->user_data = user_data;
+ data->buf = g_string_new("");

if (err)
*err = 0;
@@ -468,15 +544,26 @@ void *phonebook_pull(const char *name, const struct apparam_field *params,
int phonebook_pull_read(void *request)
{
struct query_context *data = request;
- EBookQuery *query;
+ gboolean ret;
+ GSList *ebook;

if (!data)
return -ENOENT;

- query = e_book_query_any_field_contains("");
- e_book_async_get_contacts(ebook, query, ebookpull_cb, data);
+ data->query = e_book_query_any_field_contains("");

- e_book_query_unref(query);
+ ebook = ebooks;
+ while (ebook != NULL) {
+ ret = e_book_get_contacts_async(ebook->data, data->query,
+ ebookpull_cb, data);
+ if (ret == TRUE)
+ data->queued_calls++;
+
+ ebook = ebook->next;
+ }
+
+ if (data->queued_calls == 0)
+ return -ENOENT;

return 0;
}
@@ -485,22 +572,28 @@ void *phonebook_get_entry(const char *folder, const char *id,
const struct apparam_field *params,
phonebook_cb cb, void *user_data, int *err)
{
+ gboolean ret;
struct query_context *data;
+ GSList *ebook;

data = g_new0(struct query_context, 1);
data->contacts_cb = cb;
data->params = params;
data->user_data = user_data;
+ data->id = g_strdup(id);

- if (e_book_async_get_contact(ebook, id, ebook_entry_cb, data)) {
- g_free(data);
- if (err)
- *err = -ENOENT;
- return NULL;
+ ebook = ebooks;
+ while (ebook != NULL) {
+ ret = e_book_get_contact_async(ebook->data, data->id,
+ ebook_entry_cb, data);
+ if (ret == TRUE)
+ data->queued_calls++;
+
+ ebook = ebook->next;
}

if (err)
- *err = 0;
+ *err = (data->queued_calls == 0 ? -ENOENT : 0);

return data;
}
@@ -511,31 +604,37 @@ void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
struct query_context *data;
EBookQuery *query;
gboolean ret;
+ GSList *ebook;

if (g_strcmp0("/telecom/pb", name) != 0) {
if (err)
*err = -ENOENT;
+
return NULL;
}

+ DBG("");
+
query = e_book_query_any_field_contains("");

data = g_new0(struct query_context, 1);
data->entry_cb = entry_cb;
data->ready_cb = ready_cb;
data->user_data = user_data;
+ data->query = query;

- ret = e_book_async_get_contacts(ebook, query, cache_cb, data);
- e_book_query_unref(query);
- if (ret != FALSE) {
- g_free(data);
- if (err)
- *err = -EFAULT;
- return NULL;
+ ebook = ebooks;
+ while (ebook != NULL) {
+ ret = e_book_get_contacts_async(ebook->data, query,
+ cache_cb, data);
+ if (ret == TRUE)
+ data->queued_calls++;
+
+ ebook = ebook->next;
}

if (err)
- *err = 0;
+ *err = (data->queued_calls == 0 ? -ENOENT : 0);

return data;
}
--
1.7.5.3



2011-07-11 09:34:08

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH obexd 1/5 v2] Change EDS backend to support multiple ebooks

Hi Bartosz,

On Tue, Jul 05, 2011, Bartosz Szatkowski wrote:
> Until now only default ebook was used, this patch change this behaviour
> so each function is run on all available (active) ebooks and merging
> results from each of them.
> ---
> plugins/phonebook-ebook.c | 293 ++++++++++++++++++++++++++++++---------------
> 1 files changed, 196 insertions(+), 97 deletions(-)

All five patches have been applied. Thanks.

Johan

2011-07-05 20:53:22

by Bartosz Szatkowski

[permalink] [raw]
Subject: [PATCH obexd 5/5 v2] Add proper finishing/canceling requests

---
plugins/phonebook-ebook.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/plugins/phonebook-ebook.c b/plugins/phonebook-ebook.c
index 181585a..b51d34d 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -517,9 +517,17 @@ done:
void phonebook_req_finalize(void *request)
{
struct query_context *data = request;
+ GSList *ebook = ebooks;

DBG("");

+ while (ebook != NULL) {
+ if (e_book_cancel(ebook->data, NULL) == TRUE)
+ data->queued_calls--;
+
+ ebook = ebook->next;
+ }
+
if (data != NULL && data->queued_calls == 0)
free_query_context(data);
}
--
1.7.5.3


2011-07-05 20:53:21

by Bartosz Szatkowski

[permalink] [raw]
Subject: [PATCH obexd 4/5 v2] Add 0.vcf (me contact) when generating cache

When pulling all contacts self is already present, but it have to
be manually added when generating cache.
---
plugins/phonebook-ebook.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/plugins/phonebook-ebook.c b/plugins/phonebook-ebook.c
index 97785b5..181585a 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -616,6 +616,13 @@ void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
EBookQuery *query;
gboolean ret;
GSList *ebook;
+ EContact *me;
+ EVCard *evcard;
+ GError *gerr;
+ EBook *eb;
+ EVCardAttribute *attrib;
+ char *uid, *tel, *cname;
+

if (g_strcmp0("/telecom/pb", name) != 0) {
if (err)
@@ -634,6 +641,39 @@ void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
data->user_data = user_data;
data->query = query;

+ /* Add 0.vcf */
+ if (e_book_get_self(&me, &eb, &gerr) == FALSE) {
+ g_error_free(gerr);
+ goto next;
+ }
+
+ evcard = E_VCARD(me);
+
+ cname = evcard_name_attribute_to_string(evcard);
+ if (!cname)
+ cname = g_strdup("");
+
+ attrib = e_vcard_get_attribute(evcard, EVC_UID);
+ uid = e_vcard_attribute_get_value(attrib);
+ if (!uid)
+ uid = g_strdup("");
+
+ attrib = e_vcard_get_attribute(evcard, EVC_TEL);
+ if (attrib)
+ tel = e_vcard_attribute_get_value(attrib);
+ else
+ tel = g_strdup("");
+
+ data->entry_cb(uid, 0, cname, NULL, tel, data->user_data);
+
+ data->count++;
+
+ g_free(cname);
+ g_free(uid);
+ g_free(tel);
+ g_object_unref(eb);
+
+next:
ebook = ebooks;
while (ebook != NULL) {
if (e_book_is_opened(ebook->data) == TRUE) {
--
1.7.5.3


2011-07-05 20:53:20

by Bartosz Szatkowski

[permalink] [raw]
Subject: [PATCH obexd 3/5 v2] Add checking ebook availability before processing

Some ebooks may be offline due to lack of internet connection or it may
require prior authorizations.
---
plugins/phonebook-ebook.c | 28 +++++++++++++++++-----------
1 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/plugins/phonebook-ebook.c b/plugins/phonebook-ebook.c
index 9c55860..97785b5 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -561,10 +561,12 @@ int phonebook_pull_read(void *request)

ebook = ebooks;
while (ebook != NULL) {
- ret = e_book_get_contacts_async(ebook->data, data->query,
- ebookpull_cb, data);
- if (ret == TRUE)
- data->queued_calls++;
+ if (e_book_is_opened(ebook->data) == TRUE) {
+ ret = e_book_get_contacts_async(ebook->data,
+ data->query, ebookpull_cb, data);
+ if (ret == TRUE)
+ data->queued_calls++;
+ }

ebook = ebook->next;
}
@@ -591,10 +593,12 @@ void *phonebook_get_entry(const char *folder, const char *id,

ebook = ebooks;
while (ebook != NULL) {
- ret = e_book_get_contact_async(ebook->data, data->id,
+ if (e_book_is_opened(ebook->data) == TRUE) {
+ ret = e_book_get_contact_async(ebook->data, data->id,
ebook_entry_cb, data);
- if (ret == TRUE)
- data->queued_calls++;
+ if (ret == TRUE)
+ data->queued_calls++;
+ }

ebook = ebook->next;
}
@@ -632,10 +636,12 @@ void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,

ebook = ebooks;
while (ebook != NULL) {
- ret = e_book_get_contacts_async(ebook->data, query,
- cache_cb, data);
- if (ret == TRUE)
- data->queued_calls++;
+ if (e_book_is_opened(ebook->data) == TRUE) {
+ ret = e_book_get_contacts_async(ebook->data, query,
+ cache_cb, data);
+ if (ret == TRUE)
+ data->queued_calls++;
+ }

ebook = ebook->next;
}
--
1.7.5.3


2011-07-05 20:53:19

by Bartosz Szatkowski

[permalink] [raw]
Subject: [PATCH obexd 2/5 v2] Add constraint on pulled path

EDS backend supports only phonebook (/telecom/pb.vcf).
---
plugins/phonebook-ebook.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/plugins/phonebook-ebook.c b/plugins/phonebook-ebook.c
index 067bcc7..9c55860 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -529,6 +529,13 @@ void *phonebook_pull(const char *name, const struct apparam_field *params,
{
struct query_context *data;

+ if (g_strcmp0("/telecom/pb.vcf", name) != 0) {
+ if (err)
+ *err = -ENOENT;
+
+ return NULL;
+ }
+
data = g_new0(struct query_context, 1);
data->contacts_cb = cb;
data->params = params;
--
1.7.5.3