summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/phonebook-ebook.c293
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;
}