2011-07-04 21:51:37

by Bartosz Szatkowski

[permalink] [raw]
Subject: [PATCH obexd 1/5] 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 | 281 +++++++++++++++++++++++++++++----------------
1 files changed, 182 insertions(+), 99 deletions(-)

diff --git a/plugins/phonebook-ebook.c b/plugins/phonebook-ebook.c
index 82019da..f223965 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,116 @@ 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);

-fail:
- if (data->completed)
- g_free(data);
+ data->queued_calls--;
+ if (data->queued_calls == 0)
+ data->ready_cb(data->user_data);
}

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);
- g_error_free(gerr);
- return -EIO;
+ if (e_book_get_addressbooks(&src_list, &gerr) == FALSE) {
+ error("Can't list user's address books: %s", gerr->message);
+
+ 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);
+ 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;
+ }
+
+ list = list->next;
}

- return 0;
+ return status;
+
+fail:
+ g_error_free(gerr);
+ 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);
}

char *phonebook_set_folder(const char *current_folder,
@@ -440,13 +502,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 +517,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 +528,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("");
+
+ ebook = ebooks;
+ while (ebook != NULL) {
+ ret = e_book_get_contacts_async(ebook->data, data->query,
+ ebookpull_cb, data);
+ if (ret == TRUE)
+ data->queued_calls++;

- e_book_query_unref(query);
+ ebook = ebook->next;
+ }
+
+ if (data->queued_calls == 0)
+ return -ENOENT;

return 0;
}
@@ -485,22 +556,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 +588,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-05 11:40:59

by Bartosz Szatkowski

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

On Tue, Jul 5, 2011 at 12:33 PM, Luiz Augusto von Dentz
<[email protected]> wrote:
> Hi,
>
> On Tue, Jul 5, 2011 at 1:30 PM, Bartosz Szatkowski <[email protected]> wrote:
>> On Tue, Jul 5, 2011 at 12:13 PM, Luiz Augusto von Dentz
>> <[email protected]> wrote:
>>> Hi,
>>>
>>> On Tue, Jul 5, 2011 at 1:07 PM, Bartosz Szatkowski <[email protected]> wrote:
>>>> On Tue, Jul 5, 2011 at 11:58 AM, Luiz Augusto von Dentz
>>>> <[email protected]> wrote:
>>>>> Hi Bartosz,
>>>>>
>>>>> On Tue, Jul 5, 2011 at 12:00 PM, Bartosz Szatkowski <[email protected]> wrote:
>>>>>>
>>>>>> Don't know anything about it, but is there really any other choice?
>>>>>>
>>>>>
>>>>> I guess the idea is to use D-Bus directly, removing the ebook dependency.
>>>>>
>>>>> --
>>>>> Luiz Augusto von Dentz
>>>>>
>>>>
>>>> And what the "original" problems with libebook was? So i could test it
>>>> further. BTW I'v tested this backend and it's working fine - no
>>>> problem with obexd itself either ...
>>>
>>> iirc it uses dbus-glib which once initialized replaces the gdbus
>>> callbacks, in other words D-Bus signals and method calls stop working
>>> for anything that is not using dbus-glib.
>>>
>>>
>>> --
>>> Luiz Augusto von Dentz
>>>
>>
>> So for example signals would stop being emitted?
>
> It the receiving parts that becomes problematic, because the mainloop
> callbacks are know being handled by dbus-glib so any handler/watch
> using gdbus won't work.
>
>
> --
> Luiz Augusto von Dentz
>

I've checked it and manage to successfully registered agent in obexd
when libebook was in use -- so i believe its working just fine.

--
Pozdrowienia,
Bartosz Szatkowski

2011-07-05 10:33:51

by Luiz Augusto von Dentz

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

Hi,

On Tue, Jul 5, 2011 at 1:30 PM, Bartosz Szatkowski <[email protected]> wrote:
> On Tue, Jul 5, 2011 at 12:13 PM, Luiz Augusto von Dentz
> <[email protected]> wrote:
>> Hi,
>>
>> On Tue, Jul 5, 2011 at 1:07 PM, Bartosz Szatkowski <[email protected]> wrote:
>>> On Tue, Jul 5, 2011 at 11:58 AM, Luiz Augusto von Dentz
>>> <[email protected]> wrote:
>>>> Hi Bartosz,
>>>>
>>>> On Tue, Jul 5, 2011 at 12:00 PM, Bartosz Szatkowski <[email protected]> wrote:
>>>>>
>>>>> Don't know anything about it, but is there really any other choice?
>>>>>
>>>>
>>>> I guess the idea is to use D-Bus directly, removing the ebook dependency.
>>>>
>>>> --
>>>> Luiz Augusto von Dentz
>>>>
>>>
>>> And what the "original" problems with libebook was? So i could test it
>>> further. BTW I'v tested this backend and it's working fine - no
>>> problem with obexd itself either ...
>>
>> iirc it uses dbus-glib which once initialized replaces the gdbus
>> callbacks, in other words D-Bus signals and method calls stop working
>> for anything that is not using dbus-glib.
>>
>>
>> --
>> Luiz Augusto von Dentz
>>
>
> So for example signals would stop being emitted?

It the receiving parts that becomes problematic, because the mainloop
callbacks are know being handled by dbus-glib so any handler/watch
using gdbus won't work.


--
Luiz Augusto von Dentz

2011-07-05 10:30:35

by Bartosz Szatkowski

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

On Tue, Jul 5, 2011 at 12:13 PM, Luiz Augusto von Dentz
<[email protected]> wrote:
> Hi,
>
> On Tue, Jul 5, 2011 at 1:07 PM, Bartosz Szatkowski <[email protected]> wrote:
>> On Tue, Jul 5, 2011 at 11:58 AM, Luiz Augusto von Dentz
>> <[email protected]> wrote:
>>> Hi Bartosz,
>>>
>>> On Tue, Jul 5, 2011 at 12:00 PM, Bartosz Szatkowski <[email protected]> wrote:
>>>>
>>>> Don't know anything about it, but is there really any other choice?
>>>>
>>>
>>> I guess the idea is to use D-Bus directly, removing the ebook dependency.
>>>
>>> --
>>> Luiz Augusto von Dentz
>>>
>>
>> And what the "original" problems with libebook was? So i could test it
>> further. BTW I'v tested this backend and it's working fine - no
>> problem with obexd itself either ...
>
> iirc it uses dbus-glib which once initialized replaces the gdbus
> callbacks, in other words D-Bus signals and method calls stop working
> for anything that is not using dbus-glib.
>
>
> --
> Luiz Augusto von Dentz
>

So for example signals would stop being emitted?

--
Pozdrowienia,
Bartosz Szatkowski

2011-07-05 10:13:08

by Luiz Augusto von Dentz

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

Hi,

On Tue, Jul 5, 2011 at 1:07 PM, Bartosz Szatkowski <[email protected]> wrote:
> On Tue, Jul 5, 2011 at 11:58 AM, Luiz Augusto von Dentz
> <[email protected]> wrote:
>> Hi Bartosz,
>>
>> On Tue, Jul 5, 2011 at 12:00 PM, Bartosz Szatkowski <[email protected]> wrote:
>>>
>>> Don't know anything about it, but is there really any other choice?
>>>
>>
>> I guess the idea is to use D-Bus directly, removing the ebook dependency.
>>
>> --
>> Luiz Augusto von Dentz
>>
>
> And what the "original" problems with libebook was? So i could test it
> further. BTW I'v tested this backend and it's working fine - no
> problem with obexd itself either ...

iirc it uses dbus-glib which once initialized replaces the gdbus
callbacks, in other words D-Bus signals and method calls stop working
for anything that is not using dbus-glib.


--
Luiz Augusto von Dentz

2011-07-05 10:07:46

by Bartosz Szatkowski

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

On Tue, Jul 5, 2011 at 11:58 AM, Luiz Augusto von Dentz
<[email protected]> wrote:
> Hi Bartosz,
>
> On Tue, Jul 5, 2011 at 12:00 PM, Bartosz Szatkowski <[email protected]> wrote:
>>
>> Don't know anything about it, but is there really any other choice?
>>
>
> I guess the idea is to use D-Bus directly, removing the ebook dependency.
>
> --
> Luiz Augusto von Dentz
>

And what the "original" problems with libebook was? So i could test it
further. BTW I'v tested this backend and it's working fine - no
problem with obexd itself either ...

--
Pozdrowienia,
Bartosz Szatkowski

2011-07-05 09:58:24

by Luiz Augusto von Dentz

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

Hi Bartosz,

On Tue, Jul 5, 2011 at 12:00 PM, Bartosz Szatkowski <[email protected]> wrote:
>
> Don't know anything about it, but is there really any other choice?
>

I guess the idea is to use D-Bus directly, removing the ebook dependency.

--
Luiz Augusto von Dentz

2011-07-05 09:00:44

by Bartosz Szatkowski

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

T24gVHVlLCBKdWwgNSwgMjAxMSBhdCAxMDo0NSBBTSwgTHVpeiBBdWd1c3RvIHZvbiBEZW50ego8
bHVpei5kZW50ekBnbWFpbC5jb20+IHdyb3RlOgo+IEhpIEJhcnRvc3osCj4KPiBPbiBUdWUsIEp1
bCA1LCAyMDExIGF0IDEyOjUxIEFNLCBCYXJ0b3N6IFN6YXRrb3dza2kgPGJ1bGlzbGF3QGxpbnV4
LmNvbT4gd3JvdGU6Cj4+IFVudGlsIG5vdyBvbmx5IGRlZmF1bHQgZWJvb2sgd2FzIHVzZWQsIHRo
aXMgcGF0Y2ggY2hhbmdlIHRoaXMgYmVoYXZpb3VyCj4+IHNvIGVhY2ggZnVuY3Rpb24gaXMgcnVu
IG9uIGFsbCBhdmFpbGFibGUgKGFjdGl2ZSkgZWJvb2tzIGFuZCBtZXJnaW5nCj4+IHJlc3VsdHMg
ZnJvbSBlYWNoIG9mIHRoZW0uCj4+IC0tLQo+PiDCoHBsdWdpbnMvcGhvbmVib29rLWVib29rLmMg
fCDCoDI4MSArKysrKysrKysrKysrKysrKysrKysrKysrKysrKy0tLS0tLS0tLS0tLS0tLS0KPj4g
wqAxIGZpbGVzIGNoYW5nZWQsIDE4MiBpbnNlcnRpb25zKCspLCA5OSBkZWxldGlvbnMoLSkKPj4K
Pj4gZGlmZiAtLWdpdCBhL3BsdWdpbnMvcGhvbmVib29rLWVib29rLmMgYi9wbHVnaW5zL3Bob25l
Ym9vay1lYm9vay5jCj4+IGluZGV4IDgyMDE5ZGEuLmYyMjM5NjUgMTAwNjQ0Cj4+IC0tLSBhL3Bs
dWdpbnMvcGhvbmVib29rLWVib29rLmMKPj4gKysrIGIvcGx1Z2lucy9waG9uZWJvb2stZWJvb2su
Ywo+PiBAQCAtNDUsMTcgKzQ1LDIwIEBACj4+IMKgI2RlZmluZSBRVUVSWV9OQU1FICIoY29udGFp
bnMgXCJnaXZlbl9uYW1lXCIgXCIlc1wiKSIKPj4gwqAjZGVmaW5lIFFVRVJZX1BIT05FICIoY29u
dGFpbnMgXCJwaG9uZVwiIFwiJXNcIikiCj4+Cj4+IC0KPj4gwqBzdHJ1Y3QgcXVlcnlfY29udGV4
dCB7Cj4+IC0gwqAgwqAgwqAgZ2Jvb2xlYW4gY29tcGxldGVkOwo+PiDCoCDCoCDCoCDCoGNvbnN0
IHN0cnVjdCBhcHBhcmFtX2ZpZWxkICpwYXJhbXM7Cj4+IMKgIMKgIMKgIMKgcGhvbmVib29rX2Ni
IGNvbnRhY3RzX2NiOwo+PiDCoCDCoCDCoCDCoHBob25lYm9va19lbnRyeV9jYiBlbnRyeV9jYjsK
Pj4gwqAgwqAgwqAgwqBwaG9uZWJvb2tfY2FjaGVfcmVhZHlfY2IgcmVhZHlfY2I7Cj4+ICsgwqAg
wqAgwqAgRUJvb2tRdWVyeSAqcXVlcnk7Cj4+ICsgwqAgwqAgwqAgaW50IGNvdW50Owo+PiArIMKg
IMKgIMKgIEdTdHJpbmcgKmJ1ZjsKPj4gKyDCoCDCoCDCoCBjaGFyICppZDsKPj4gKyDCoCDCoCDC
oCB1bnNpZ25lZCBxdWV1ZWRfY2FsbHM7Cj4+IMKgIMKgIMKgIMKgdm9pZCAqdXNlcl9kYXRhOwo+
PiDCoH07Cj4+Cj4+IC1zdGF0aWMgRUJvb2sgKmVib29rID0gTlVMTDsKPj4gK3N0YXRpYyBHU0xp
c3QgKmVib29rcyA9IE5VTEw7Cj4+Cj4+IMKgc3RhdGljIGNoYXIgKmF0dHJpYnV0ZV9tYXNrW10g
PSB7Cj4+IMKgLyogMCAqLyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCJWRVJTSU9OIiwKPj4gQEAg
LTkxLDYgKzk0LDE5IEBAIHN0YXRpYyBjaGFyICphdHRyaWJ1dGVfbWFza1tdID0gewo+Pgo+PiDC
oH07Cj4+Cj4+ICtzdGF0aWMgdm9pZCBmcmVlX3F1ZXJ5X2NvbnRleHQoc3RydWN0IHF1ZXJ5X2Nv
bnRleHQgKmRhdGEpCj4+ICt7Cj4+ICsgwqAgwqAgwqAgZ19mcmVlKGRhdGEtPmlkKTsKPj4gKwo+
PiArIMKgIMKgIMKgIGlmIChkYXRhLT5idWYgIT0gTlVMTCkKPj4gKyDCoCDCoCDCoCDCoCDCoCDC
oCDCoCBnX3N0cmluZ19mcmVlKGRhdGEtPmJ1ZiwgVFJVRSk7Cj4+ICsKPj4gKyDCoCDCoCDCoCBp
ZiAoZGF0YS0+cXVlcnkgIT0gTlVMTCkKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBlX2Jvb2tf
cXVlcnlfdW5yZWYoZGF0YS0+cXVlcnkpOwo+PiArCj4+ICsgwqAgwqAgwqAgZ19mcmVlKGRhdGEp
Owo+PiArfQo+PiArCj4+IMKgc3RhdGljIGNoYXIgKmV2Y2FyZF90b19zdHJpbmcoRVZDYXJkICpl
dmNhcmQsIHVuc2lnbmVkIGludCBmb3JtYXQsCj4+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
dWludDY0X3QgZmlsdGVyKQo+PiDCoHsKPj4gQEAgLTk5LDcgKzExNSw4IEBAIHN0YXRpYyBjaGFy
ICpldmNhcmRfdG9fc3RyaW5nKEVWQ2FyZCAqZXZjYXJkLCB1bnNpZ25lZCBpbnQgZm9ybWF0LAo+
PiDCoCDCoCDCoCDCoGNoYXIgKnZjYXJkOwo+Pgo+PiDCoCDCoCDCoCDCoGlmICghZmlsdGVyKQo+
PiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHJldHVybiBlX3ZjYXJkX3RvX3N0cmluZyhldmNhcmQs
IGZvcm1hdCk7Cj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgcmV0dXJuIGVfdmNhcmRfdG9fc3Ry
aW5nKGV2Y2FyZCwgRVZDX0ZPUk1BVF9WQ0FSRF8zMCk7Cj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgLyogWFhYIFRoZXJlIGlzIG5vIHN1cHBvcnQgZm9yIFZDQVJEIDIuMSBhdCB0aGlzIHRpbWUg
Ki8KPj4KPj4gwqAgwqAgwqAgwqAvKgo+PiDCoCDCoCDCoCDCoCAqIE1hbmRhdG9yeSBhdHRyaWJ1
dGVzIGZvciB2Q2FyZCAyLjEgYXJlIFZFUlNJT04gLE4gYW5kIFRFTC4KPj4gQEAgLTEzNiwyNCAr
MTUzLDIwIEBAIHN0YXRpYyBjaGFyICpldmNhcmRfdG9fc3RyaW5nKEVWQ2FyZCAqZXZjYXJkLCB1
bnNpZ25lZCBpbnQgZm9ybWF0LAo+PiDCoCDCoCDCoCDCoHJldHVybiB2Y2FyZDsKPj4gwqB9Cj4+
Cj4+IC1zdGF0aWMgdm9pZCBlYm9va3B1bGxfY2IoRUJvb2sgKmJvb2ssIEVCb29rU3RhdHVzIGVz
dGF0dXMsIEdMaXN0ICpjb250YWN0cywKPj4gK3N0YXRpYyB2b2lkIGVib29rcHVsbF9jYihFQm9v
ayAqYm9vaywgY29uc3QgR0Vycm9yICpnZXJyLCBHTGlzdCAqY29udGFjdHMsCj4+IMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgdm9pZCAqdXNlcl9kYXRhKQo+PiDCoHsKPj4gwqAgwqAgwqAgwqBz
dHJ1Y3QgcXVlcnlfY29udGV4dCAqZGF0YSA9IHVzZXJfZGF0YTsKPj4gLSDCoCDCoCDCoCBHU3Ry
aW5nICpzdHJpbmcgPSBnX3N0cmluZ19uZXcoIiIpOwo+PiAtIMKgIMKgIMKgIHVuc2lnbmVkIGlu
dCBjb3VudCA9IDAsIG1heGNvdW50Owo+PiDCoCDCoCDCoCDCoEdMaXN0ICpsOwo+PiArIMKgIMKg
IMKgIHVuc2lnbmVkIGludCBjb3VudCA9IGRhdGEtPmNvdW50LCBtYXhjb3VudDsKPj4KPj4gLSDC
oCDCoCDCoCBpZiAoZXN0YXR1cyA9PSBFX0JPT0tfRVJST1JfQ0FOQ0VMTEVEKSB7Cj4+IC0gwqAg
wqAgwqAgwqAgwqAgwqAgwqAgZXJyb3IoIkUtQm9vayBvcGVyYXRpb24gd2FzIGNhbmNlbGxlZDog
c3RhdHVzICVkIiwgZXN0YXR1cyk7Cj4+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgZ290byBmYWls
Owo+PiAtIMKgIMKgIMKgIH0KPj4gLQo+PiAtIMKgIMKgIMKgIGlmIChlc3RhdHVzICE9IEVfQk9P
S19FUlJPUl9PSykgewo+PiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGVycm9yKCJFLUJvb2sgcXVl
cnkgZmFpbGVkOiBzdGF0dXMgJWQiLCBlc3RhdHVzKTsKPj4gKyDCoCDCoCDCoCBpZiAoZ2VyciAh
PSBOVUxMKSB7Cj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgZXJyb3IoIkUtQm9vayBxdWVyeSBm
YWlsZWQ6ICVzIiwgZ2Vyci0+bWVzc2FnZSk7Cj4+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgZ290
byBkb25lOwo+PiDCoCDCoCDCoCDCoH0KPj4KPj4gKyDCoCDCoCDCoCBEQkcoIiIpOwo+PiArCj4+
IMKgIMKgIMKgIMKgLyoKPj4gwqAgwqAgwqAgwqAgKiBXaGVuIE1heExpc3RDb3VudCBpcyB6ZXJv
LCBQQ0Ugd2FudHMgdG8ga25vdyB0aGUgbnVtYmVyIG9mIHVzZWQKPj4gwqAgwqAgwqAgwqAgKiBp
bmRleGVzIGluIHRoZSBwaG9uZWJvb2sgb2YgaW50ZXJlc3QuIEFsbCBvdGhlciBwYXJhbWV0ZXJz
IHRoYXQKPj4gQEAgLTE2MSw3ICsxNzQsNyBAQCBzdGF0aWMgdm9pZCBlYm9va3B1bGxfY2IoRUJv
b2sgKmJvb2ssIEVCb29rU3RhdHVzIGVzdGF0dXMsIEdMaXN0ICpjb250YWN0cywKPj4gwqAgwqAg
wqAgwqAgKi8KPj4gwqAgwqAgwqAgwqBtYXhjb3VudCA9IGRhdGEtPnBhcmFtcy0+bWF4bGlzdGNv
dW50Owo+PiDCoCDCoCDCoCDCoGlmIChtYXhjb3VudCA9PSAwKSB7Cj4+IC0gwqAgwqAgwqAgwqAg
wqAgwqAgwqAgY291bnQgPSBnX2xpc3RfbGVuZ3RoKGNvbnRhY3RzKTsKPj4gKyDCoCDCoCDCoCDC
oCDCoCDCoCDCoCBjb3VudCArPSBnX2xpc3RfbGVuZ3RoKGNvbnRhY3RzKTsKPj4gwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqBnb3RvIGRvbmU7Cj4+IMKgIMKgIMKgIMKgfQo+Pgo+PiBAQCAtMTc3LDQ1
ICsxOTAsMzYgQEAgc3RhdGljIHZvaWQgZWJvb2twdWxsX2NiKEVCb29rICpib29rLCBFQm9va1N0
YXR1cyBlc3RhdHVzLCBHTGlzdCAqY29udGFjdHMsCj4+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
dmNhcmQgPSBldmNhcmRfdG9fc3RyaW5nKGV2Y2FyZCwgZGF0YS0+cGFyYW1zLT5mb3JtYXQsCj4+
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgZGF0YS0+cGFyYW1zLT5maWx0ZXIpOwo+Pgo+PiAtIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIHN0cmluZyA9IGdfc3RyaW5nX2FwcGVuZChzdHJpbmcsIHZjYXJkKTsKPj4gLSDC
oCDCoCDCoCDCoCDCoCDCoCDCoCBzdHJpbmcgPSBnX3N0cmluZ19hcHBlbmQoc3RyaW5nLCAiXHJc
biIpOwo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGRhdGEtPmJ1ZiA9IGdfc3RyaW5nX2FwcGVu
ZChkYXRhLT5idWYsIHZjYXJkKTsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBkYXRhLT5idWYg
PSBnX3N0cmluZ19hcHBlbmQoZGF0YS0+YnVmLCAiXHJcbiIpOwo+PiDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoGdfZnJlZSh2Y2FyZCk7Cj4+IMKgIMKgIMKgIMKgfQo+PiAtIMKgIMKgIMKgIERCRygi
Y29sbGVjdGVkICVkIHZjYXJkcyIsIGNvdW50KTsKPj4gLQo+Pgo+PiDCoGRvbmU6Cj4+IC0gwqAg
wqAgwqAgZGF0YS0+Y29tcGxldGVkID0gVFJVRTsKPj4gLSDCoCDCoCDCoCBkYXRhLT5jb250YWN0
c19jYihzdHJpbmctPnN0ciwgc3RyaW5nLT5sZW4sIGNvdW50LCAwLCBUUlVFLAo+PiAtIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIGRhdGEtPnVzZXJfZGF0YSk7Cj4+ICsgwqAgwqAgwqAgZ19saXN0
X2ZyZWVfZnVsbChjb250YWN0cywgZ19vYmplY3RfdW5yZWYpOwo+Pgo+PiAtZmFpbDoKPj4gLSDC
oCDCoCDCoCBnX3N0cmluZ19mcmVlKHN0cmluZywgVFJVRSk7Cj4+ICsgwqAgwqAgwqAgREJHKCJj
b2xsZWN0ZWQgJWQgdmNhcmRzIiwgY291bnQpOwo+Pgo+PiAtIMKgIMKgIMKgIGlmIChkYXRhLT5j
b21wbGV0ZWQpCj4+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgZ19mcmVlKGRhdGEpOwo+PiArIMKg
IMKgIMKgIGRhdGEtPnF1ZXVlZF9jYWxscy0tOwo+PiArIMKgIMKgIMKgIGlmIChkYXRhLT5xdWV1
ZWRfY2FsbHMgPT0gMCkKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBkYXRhLT5jb250YWN0c19j
YihkYXRhLT5idWYtPnN0ciwgZGF0YS0+YnVmLT5sZW4sIGNvdW50LCAwLAo+PiArIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIFRSVUUsIGRhdGEtPnVzZXJfZGF0YSk7Cj4+IMKgfQo+Pgo+PiAtc3Rh
dGljIHZvaWQgZWJvb2tfZW50cnlfY2IoRUJvb2sgKmJvb2ssIEVCb29rU3RhdHVzIGVzdGF0dXMs
Cj4+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgRUNvbnRhY3QgKmNvbnRhY3Qs
IHZvaWQgKnVzZXJfZGF0YSkKPj4gK3N0YXRpYyB2b2lkIGVib29rX2VudHJ5X2NiKEVCb29rICpi
b29rLCBjb25zdCBHRXJyb3IgKmdlcnIsCj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgRUNvbnRhY3QgKmNvbnRhY3QsIHZvaWQgKnVzZXJfZGF0YSkKPj4g
wqB7Cj4+IMKgIMKgIMKgIMKgc3RydWN0IHF1ZXJ5X2NvbnRleHQgKmRhdGEgPSB1c2VyX2RhdGE7
Cj4+IMKgIMKgIMKgIMKgRVZDYXJkICpldmNhcmQ7Cj4+IMKgIMKgIMKgIMKgY2hhciAqdmNhcmQ7
Cj4+IMKgIMKgIMKgIMKgc2l6ZV90IGxlbjsKPj4KPj4gLSDCoCDCoCDCoCBpZiAoZXN0YXR1cyA9
PSBFX0JPT0tfRVJST1JfQ0FOQ0VMTEVEKSB7Cj4+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgZXJy
b3IoIkUtQm9vayBvcGVyYXRpb24gd2FzIGNhbmNlbGxlZDogc3RhdHVzICVkIiwgZXN0YXR1cyk7
Cj4+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgZ290byBmYWlsOwo+PiArIMKgIMKgIMKgIGlmIChn
ZXJyICE9IE5VTEwpIHsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBlcnJvcigiRS1Cb29rIHF1
ZXJ5IGZhaWxlZDogJXMiLCBnZXJyLT5tZXNzYWdlKTsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDC
oCBnb3RvIGRvbmU7Cj4+IMKgIMKgIMKgIMKgfQo+Pgo+PiAtIMKgIMKgIMKgIGRhdGEtPmNvbXBs
ZXRlZCA9IFRSVUU7Cj4+IC0KPj4gLSDCoCDCoCDCoCBpZiAoZXN0YXR1cyAhPSBFX0JPT0tfRVJS
T1JfT0spIHsKPj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCBlcnJvcigiRS1Cb29rIHF1ZXJ5IGZh
aWxlZDogc3RhdHVzICVkIiwgZXN0YXR1cyk7Cj4+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgZGF0
YS0+Y29udGFjdHNfY2IoTlVMTCwgMCwgMSwgMCwgVFJVRSwgZGF0YS0+dXNlcl9kYXRhKTsKPj4g
LSDCoCDCoCDCoCDCoCDCoCDCoCDCoCBnb3RvIGZhaWw7Cj4+IC0gwqAgwqAgwqAgfQo+PiArIMKg
IMKgIMKgIERCRygiIik7Cj4+Cj4+IMKgIMKgIMKgIMKgZXZjYXJkID0gRV9WQ0FSRChjb250YWN0
KTsKPj4KPj4gQEAgLTIyNCwxMyArMjI4LDIxIEBAIHN0YXRpYyB2b2lkIGVib29rX2VudHJ5X2Ni
KEVCb29rICpib29rLCBFQm9va1N0YXR1cyBlc3RhdHVzLAo+Pgo+PiDCoCDCoCDCoCDCoGxlbiA9
IHZjYXJkID8gc3RybGVuKHZjYXJkKSA6IDA7Cj4+Cj4+ICsgwqAgwqAgwqAgZGF0YS0+Y291bnQr
KzsKPj4gwqAgwqAgwqAgwqBkYXRhLT5jb250YWN0c19jYih2Y2FyZCwgbGVuLCAxLCAwLCBUUlVF
LCBkYXRhLT51c2VyX2RhdGEpOwo+Pgo+PiDCoCDCoCDCoCDCoGdfZnJlZSh2Y2FyZCk7Cj4+ICsg
wqAgwqAgwqAgZ19vYmplY3RfdW5yZWYoY29udGFjdCk7Cj4+Cj4+IC1mYWlsOgo+PiAtIMKgIMKg
IMKgIGlmIChkYXRhLT5jb21wbGV0ZWQpCj4+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgZ19mcmVl
KGRhdGEpOwo+PiArZG9uZToKPj4gKyDCoCDCoCDCoCBkYXRhLT5xdWV1ZWRfY2FsbHMtLTsKPj4g
KyDCoCDCoCDCoCBpZiAoZGF0YS0+cXVldWVkX2NhbGxzID09IDApIHsKPj4gKyDCoCDCoCDCoCDC
oCDCoCDCoCDCoCBpZiAoZGF0YS0+Y291bnQgPT0gMCkKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCBkYXRhLT5jb250YWN0c19jYihOVUxMLCAwLCAxLCAwLCBUUlVFLAo+PiAr
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIGRhdGEtPnVzZXJfZGF0YSk7Cj4+ICsKPj4gKyDCoCDCoCDCoCDCoCDCoCDC
oCDCoCBmcmVlX3F1ZXJ5X2NvbnRleHQoZGF0YSk7Cj4+ICsgwqAgwqAgwqAgfQo+PiDCoH0KPj4K
Pj4gwqBzdGF0aWMgY2hhciAqZXZjYXJkX25hbWVfYXR0cmlidXRlX3RvX3N0cmluZyhFVkNhcmQg
KmV2Y2FyZCkKPj4gQEAgLTI2MywyNCArMjc1LDE5IEBAIHN0YXRpYyBjaGFyICpldmNhcmRfbmFt
ZV9hdHRyaWJ1dGVfdG9fc3RyaW5nKEVWQ2FyZCAqZXZjYXJkKQo+PiDCoCDCoCDCoCDCoHJldHVy
biBnX3N0cmluZ19mcmVlKG5hbWUsIEZBTFNFKTsKPj4gwqB9Cj4+Cj4+IC1zdGF0aWMgdm9pZCBj
YWNoZV9jYihFQm9vayAqYm9vaywgRUJvb2tTdGF0dXMgZXN0YXR1cywgR0xpc3QgKmNvbnRhY3Rz
LAo+PiArc3RhdGljIHZvaWQgY2FjaGVfY2IoRUJvb2sgKmJvb2ssIGNvbnN0IEdFcnJvciAqZ2Vy
ciwgR0xpc3QgKmNvbnRhY3RzLAo+PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHZvaWQgKnVz
ZXJfZGF0YSkKPj4gwqB7Cj4+IMKgIMKgIMKgIMKgc3RydWN0IHF1ZXJ5X2NvbnRleHQgKmRhdGEg
PSB1c2VyX2RhdGE7Cj4+IMKgIMKgIMKgIMKgR0xpc3QgKmw7Cj4+Cj4+IC0gwqAgwqAgwqAgaWYg
KGVzdGF0dXMgPT0gRV9CT09LX0VSUk9SX0NBTkNFTExFRCkgewo+PiAtIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIGVycm9yKCJFLUJvb2sgb3BlcmF0aW9uIHdhcyBjYW5jZWxsZWQ6IHN0YXR1cyAlZCIs
IGVzdGF0dXMpOwo+PiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGdvdG8gZmFpbDsKPj4gLSDCoCDC
oCDCoCB9Cj4+IC0KPj4gLSDCoCDCoCDCoCBkYXRhLT5jb21wbGV0ZWQgPSBUUlVFOwo+PiAtCj4+
IC0gwqAgwqAgwqAgaWYgKGVzdGF0dXMgIT0gRV9CT09LX0VSUk9SX09LKSB7Cj4+IC0gwqAgwqAg
wqAgwqAgwqAgwqAgwqAgZXJyb3IoIkUtQm9vayBxdWVyeSBmYWlsZWQ6IHN0YXR1cyAlZCIsIGVz
dGF0dXMpOwo+PiArIMKgIMKgIMKgIGlmIChnZXJyICE9IE5VTEwpIHsKPj4gKyDCoCDCoCDCoCDC
oCDCoCDCoCDCoCBlcnJvcigiRS1Cb29rIG9wZXJhdGlvbiBmYWlsZWQ6ICVzIiwgZ2Vyci0+bWVz
c2FnZSk7Cj4+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgZ290byBkb25lOwo+PiDCoCDCoCDCoCDC
oH0KPj4KPj4gKyDCoCDCoCDCoCBEQkcoIiIpOwo+PiArCj4+IMKgIMKgIMKgIMKgZm9yIChsID0g
Y29udGFjdHM7IGw7IGwgPSBnX2xpc3RfbmV4dChsKSkgewo+PiDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoEVDb250YWN0ICpjb250YWN0ID0gRV9DT05UQUNUKGwtPmRhdGEpOwo+PiDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoEVWQ2FyZCAqZXZjYXJkID0gRV9WQ0FSRChjb250YWN0KTsKPj4gQEAgLTI5
NSw2MSArMzAyLDExNiBAQCBzdGF0aWMgdm9pZCBjYWNoZV9jYihFQm9vayAqYm9vaywgRUJvb2tT
dGF0dXMgZXN0YXR1cywgR0xpc3QgKmNvbnRhY3RzLAo+PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oGlmICghYXR0cmliKQo+PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGNvbnRp
bnVlOwo+Pgo+PiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHVpZCA9IMKgZV92Y2FyZF9hdHRyaWJ1
dGVfZ2V0X3ZhbHVlKGF0dHJpYik7Cj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgdWlkID0gZV92
Y2FyZF9hdHRyaWJ1dGVfZ2V0X3ZhbHVlKGF0dHJpYik7Cj4+IMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgaWYgKCF1aWQpCj4+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgY29udGlu
dWU7Cj4+Cj4+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgYXR0cmliID0gZV92Y2FyZF9nZXRfYXR0
cmlidXRlKGV2Y2FyZCwgRVZDX1RFTCk7Cj4+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgaWYgKCFh
dHRyaWIpCj4+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY29udGludWU7Cj4+
IC0KPj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCB0ZWwgPSDCoGVfdmNhcmRfYXR0cmlidXRlX2dl
dF92YWx1ZShhdHRyaWIpOwo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHRl
bCA9IGVfdmNhcmRfYXR0cmlidXRlX2dldF92YWx1ZShhdHRyaWIpOwo+PiArIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIGVsc2UKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCB0ZWwg
PSBnX3N0cmR1cCgiIik7Cj4+Cj4+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgZGF0YS0+ZW50cnlf
Y2IodWlkLCBQSE9ORUJPT0tfSU5WQUxJRF9IQU5ETEUsIG5hbWUsIE5VTEwsCj4+IMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgdGVsLCBkYXRhLT51c2VyX2RhdGEpOwo+PiArCj4+IMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgZ19mcmVlKG5hbWUpOwo+PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGdf
ZnJlZSh1aWQpOwo+PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGdfZnJlZSh0ZWwpOwo+PiDCoCDC
oCDCoCDCoH0KPj4gKwo+PiDCoGRvbmU6Cj4+IC0gwqAgwqAgwqAgZGF0YS0+cmVhZHlfY2IoZGF0
YS0+dXNlcl9kYXRhKTsKPj4gKyDCoCDCoCDCoCBnX2xpc3RfZnJlZV9mdWxsKGNvbnRhY3RzLCBn
X29iamVjdF91bnJlZik7Cj4+Cj4+IC1mYWlsOgo+PiAtIMKgIMKgIMKgIGlmIChkYXRhLT5jb21w
bGV0ZWQpCj4+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgZ19mcmVlKGRhdGEpOwo+PiArIMKgIMKg
IMKgIGRhdGEtPnF1ZXVlZF9jYWxscy0tOwo+PiArIMKgIMKgIMKgIGlmIChkYXRhLT5xdWV1ZWRf
Y2FsbHMgPT0gMCkKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBkYXRhLT5yZWFkeV9jYihkYXRh
LT51c2VyX2RhdGEpOwo+PiDCoH0KPj4KPj4gwqBpbnQgcGhvbmVib29rX2luaXQodm9pZCkKPj4g
wqB7Cj4+IC0gwqAgwqAgwqAgR0Vycm9yICpnZXJyID0gTlVMTDsKPj4gKyDCoCDCoCDCoCBHRXJy
b3IgKmdlcnI7Cj4+ICsgwqAgwqAgwqAgRVNvdXJjZUxpc3QgKnNyY19saXN0Owo+PiArIMKgIMKg
IMKgIEdTTGlzdCAqbGlzdDsKPj4gKyDCoCDCoCDCoCBnY2hhciAqZGVmYXVsdF9zcmMgPSBOVUxM
Owo+PiArIMKgIMKgIMKgIGludCBzdGF0dXMgPSAwOwo+Pgo+PiAtIMKgIMKgIMKgIGlmIChlYm9v
aykKPj4gKyDCoCDCoCDCoCBpZiAoZWJvb2tzKQo+PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHJl
dHVybiAwOwo+Pgo+PiDCoCDCoCDCoCDCoGdfdHlwZV9pbml0KCk7Cj4+Cj4+IC0gwqAgwqAgwqAg
ZWJvb2sgPSBlX2Jvb2tfbmV3X2RlZmF1bHRfYWRkcmVzc2Jvb2soJmdlcnIpOwo+PiAtIMKgIMKg
IMKgIGlmICghZWJvb2spIHsKPj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCBlcnJvcigiQ2FuJ3Qg
Y3JlYXRlIHVzZXIncyBkZWZhdWx0IGFkZHJlc3MgYm9vazogJXMiLAo+PiAtIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGdlcnItPm1lc3NhZ2UpOwo+PiAtIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIGdfZXJyb3JfZnJlZShnZXJyKTsKPj4gLSDCoCDCoCDCoCDCoCDC
oCDCoCDCoCByZXR1cm4gLUVJTzsKPj4gKyDCoCDCoCDCoCBpZiAoZV9ib29rX2dldF9hZGRyZXNz
Ym9va3MoJnNyY19saXN0LCAmZ2VycikgPT0gRkFMU0UpIHsKPj4gKyDCoCDCoCDCoCDCoCDCoCDC
oCDCoCBlcnJvcigiQ2FuJ3QgbGlzdCB1c2VyJ3MgYWRkcmVzcyBib29rczogJXMiLCBnZXJyLT5t
ZXNzYWdlKTsKPj4gKwo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHN0YXR1cyA9IC1FSU87Cj4+
ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgZ290byBmYWlsOwo+PiDCoCDCoCDCoCDCoH0KPj4KPj4g
LSDCoCDCoCDCoCBpZiAoIWVfYm9va19vcGVuKGVib29rLCBGQUxTRSwgJmdlcnIpKSB7Cj4+IC0g
wqAgwqAgwqAgwqAgwqAgwqAgwqAgZXJyb3IoIkNhbid0IG9wZW4gZS1ib29rIGFkZHJlc3MgYm9v
azogJXMiLCBnZXJyLT5tZXNzYWdlKTsKPj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCBnX2Vycm9y
X2ZyZWUoZ2Vycik7Cj4+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgcmV0dXJuIC1FSU87Cj4KPiBQ
bGVhc2UgY29uc2lkZXIgc3BsaXR0aW5nIHRoaXMgZnVuY3Rpb24gc2luY2UgaXQgaXMgYmVjb21p
bmcgdG9vIGJpZy4KCk9LLCBpIG1heSBwdXQgaXRlcmF0aW5nIG92ZXJ0IHRoaXMgZWJvb2tzIGlu
IG5ldyBmdW5jdGlvbi4KCj4KPj4gKyDCoCDCoCDCoCBsaXN0ID0gZV9zb3VyY2VfbGlzdF9wZWVr
X2dyb3VwcyhzcmNfbGlzdCk7Cj4+ICsgwqAgwqAgwqAgd2hpbGUgKGxpc3QpIHsKPj4gKyDCoCDC
oCDCoCDCoCDCoCDCoCDCoCBFU291cmNlR3JvdXAgKmdyb3VwID0gRV9TT1VSQ0VfR1JPVVAobGlz
dC0+ZGF0YSk7Cj4+ICsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBHU0xpc3QgKnNvdXJjZXMg
PSBlX3NvdXJjZV9ncm91cF9wZWVrX3NvdXJjZXMoZ3JvdXApOwo+PiArIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIHdoaWxlIChzb3VyY2VzICE9IE5VTEwpIHsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCBFQm9vayAqZWJvb2sgPSBlX2Jvb2tfbmV3KEVfU09VUkNFKHNvdXJjZXMt
PmRhdGEpLAo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgICZnZXJyKTsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBpZiAoZWJv
b2sgPT0gTlVMTCkgewo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIGVycm9yKCJDYW4ndCBjcmVhdGUgdXNlcidzIGFkZHJlc3MgYm9vazogJXMiLAo+PiAr
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGdlcnItPm1lc3NhZ2UpOwo+PiAr
Cj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgc3RhdHVz
ID0gLUVJTzsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCBnb3RvIGZhaWw7Cj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgfQo+PiAr
Cj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgaWYgKGdfc3RyY21wMChkZWZh
dWx0X3NyYywgZV9zb3VyY2VfZ2V0X3VyaSgKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBFX1NPVVJDRShzb3VyY2VzLT5kYXRhKSkp
ID09IDApIHsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCBzb3VyY2VzID0gc291cmNlcy0+bmV4dDsKPj4gKwo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGNvbnRpbnVlOwo+PiArIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIH0KPj4gKwo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIGlmIChlX2Jvb2tfb3BlbihlYm9vaywgRkFMU0UsICZnZXJyKSA9PSBGQUxTRSkgewo+PiAr
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGVycm9yKCJDYW4n
dCBvcGVuIGUtYm9vayBhZGRyZXNzIGJvb2s6ICVzIiwKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCBnZXJyLT5tZXNzYWdlKTsKPj4gKwo+PiArIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHN0YXR1cyA9IC1FSU87Cj4+ICsgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgZ290byBmYWlsOwo+PiArIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIH0KPj4gKwo+PiArIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIGlmIChkZWZhdWx0X3NyYyA9PSBOVUxMKQo+PiArIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGRlZmF1bHRfc3JjID0gZV9zb3Vy
Y2VfZ2V0X3VyaSgKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBFX1NPVVJDRShzb3VyY2VzLT5kYXRhKSk7Cj4+
ICsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBEQkcoIiVzIGFkZHJlc3Mg
Ym9vayBvcGVuZWQiLAo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIGVfc291cmNlX3BlZWtfbmFtZShzb3VyY2VzLT5kYXRhKSk7Cj4+
ICsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBlYm9va3MgPSBnX3NsaXN0
X2FwcGVuZChlYm9va3MsIGVib29rKTsKPj4gKwo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIHNvdXJjZXMgPSBzb3VyY2VzLT5uZXh0Owo+PiArIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIH0KPj4gKwo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGxpc3QgPSBsaXN0LT5uZXh0Owo+
PiDCoCDCoCDCoCDCoH0KPj4KPj4gLSDCoCDCoCDCoCByZXR1cm4gMDsKPj4gKyDCoCDCoCDCoCBy
ZXR1cm4gc3RhdHVzOwo+PiArCj4+ICtmYWlsOgo+PiArIMKgIMKgIMKgIGdfZXJyb3JfZnJlZShn
ZXJyKTsKPj4gKyDCoCDCoCDCoCBnX3NsaXN0X2ZyZWVfZnVsbChlYm9va3MsIGdfb2JqZWN0X3Vu
cmVmKTsKPj4gKyDCoCDCoCDCoCBnX29iamVjdF91bnJlZihzcmNfbGlzdCk7Cj4+ICsKPj4gKyDC
oCDCoCDCoCByZXR1cm4gc3RhdHVzOwo+PiDCoH0KPj4KPj4gwqB2b2lkIHBob25lYm9va19leGl0
KHZvaWQpCj4+IMKgewo+PiAtIMKgIMKgIMKgIGlmIChlYm9vaykKPj4gLSDCoCDCoCDCoCDCoCDC
oCDCoCDCoCBnX29iamVjdF91bnJlZihlYm9vayk7Cj4+IC0gwqAgwqAgwqAgZWJvb2sgPSBOVUxM
Owo+PiArIMKgIMKgIMKgIERCRygiIik7Cj4+ICsKPj4gKyDCoCDCoCDCoCBpZiAoZWJvb2tzID09
IE5VTEwpCj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgcmV0dXJuOwo+PiArCj4+ICsgwqAgwqAg
wqAgZ19zbGlzdF9mcmVlX2Z1bGwoZWJvb2tzLCBnX29iamVjdF91bnJlZik7Cj4+IMKgfQo+Pgo+
PiDCoGNoYXIgKnBob25lYm9va19zZXRfZm9sZGVyKGNvbnN0IGNoYXIgKmN1cnJlbnRfZm9sZGVy
LAo+PiBAQCAtNDQwLDEzICs1MDIsMTAgQEAgdm9pZCBwaG9uZWJvb2tfcmVxX2ZpbmFsaXplKHZv
aWQgKnJlcXVlc3QpCj4+IMKgewo+PiDCoCDCoCDCoCDCoHN0cnVjdCBxdWVyeV9jb250ZXh0ICpk
YXRhID0gcmVxdWVzdDsKPj4KPj4gLSDCoCDCoCDCoCBpZiAoIWRhdGEpCj4+IC0gwqAgwqAgwqAg
wqAgwqAgwqAgwqAgcmV0dXJuOwo+PiArIMKgIMKgIMKgIERCRygiIik7Cj4+Cj4+IC0gwqAgwqAg
wqAgaWYgKCFkYXRhLT5jb21wbGV0ZWQpIHsKPj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCBkYXRh
LT5jb21wbGV0ZWQgPSBUUlVFOwo+PiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGVfYm9va19jYW5j
ZWxfYXN5bmNfb3AoZWJvb2ssIE5VTEwpOwo+PiAtIMKgIMKgIMKgIH0KPj4gKyDCoCDCoCDCoCBp
ZiAoZGF0YSAhPSBOVUxMICYmIGRhdGEtPnF1ZXVlZF9jYWxscyA9PSAwKQo+PiArIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIGZyZWVfcXVlcnlfY29udGV4dChkYXRhKTsKPj4gwqB9Cj4+Cj4+IMKgdm9p
ZCAqcGhvbmVib29rX3B1bGwoY29uc3QgY2hhciAqbmFtZSwgY29uc3Qgc3RydWN0IGFwcGFyYW1f
ZmllbGQgKnBhcmFtcywKPj4gQEAgLTQ1OCw2ICs1MTcsNyBAQCB2b2lkICpwaG9uZWJvb2tfcHVs
bChjb25zdCBjaGFyICpuYW1lLCBjb25zdCBzdHJ1Y3QgYXBwYXJhbV9maWVsZCAqcGFyYW1zLAo+
PiDCoCDCoCDCoCDCoGRhdGEtPmNvbnRhY3RzX2NiID0gY2I7Cj4+IMKgIMKgIMKgIMKgZGF0YS0+
cGFyYW1zID0gcGFyYW1zOwo+PiDCoCDCoCDCoCDCoGRhdGEtPnVzZXJfZGF0YSA9IHVzZXJfZGF0
YTsKPj4gKyDCoCDCoCDCoCBkYXRhLT5idWYgPSBnX3N0cmluZ19uZXcoIiIpOwo+Pgo+PiDCoCDC
oCDCoCDCoGlmIChlcnIpCj4+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgKmVyciA9IDA7Cj4+IEBA
IC00NjgsMTUgKzUyOCwyNiBAQCB2b2lkICpwaG9uZWJvb2tfcHVsbChjb25zdCBjaGFyICpuYW1l
LCBjb25zdCBzdHJ1Y3QgYXBwYXJhbV9maWVsZCAqcGFyYW1zLAo+PiDCoGludCBwaG9uZWJvb2tf
cHVsbF9yZWFkKHZvaWQgKnJlcXVlc3QpCj4+IMKgewo+PiDCoCDCoCDCoCDCoHN0cnVjdCBxdWVy
eV9jb250ZXh0ICpkYXRhID0gcmVxdWVzdDsKPj4gLSDCoCDCoCDCoCBFQm9va1F1ZXJ5ICpxdWVy
eTsKPj4gKyDCoCDCoCDCoCBnYm9vbGVhbiByZXQ7Cj4+ICsgwqAgwqAgwqAgR1NMaXN0ICplYm9v
azsKPj4KPj4gwqAgwqAgwqAgwqBpZiAoIWRhdGEpCj4+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
cmV0dXJuIC1FTk9FTlQ7Cj4+Cj4+IC0gwqAgwqAgwqAgcXVlcnkgPSBlX2Jvb2tfcXVlcnlfYW55
X2ZpZWxkX2NvbnRhaW5zKCIiKTsKPj4gLSDCoCDCoCDCoCBlX2Jvb2tfYXN5bmNfZ2V0X2NvbnRh
Y3RzKGVib29rLCBxdWVyeSwgZWJvb2twdWxsX2NiLCBkYXRhKTsKPj4gKyDCoCDCoCDCoCBkYXRh
LT5xdWVyeSA9IGVfYm9va19xdWVyeV9hbnlfZmllbGRfY29udGFpbnMoIiIpOwo+PiArCj4+ICsg
wqAgwqAgwqAgZWJvb2sgPSBlYm9va3M7Cj4+ICsgwqAgwqAgwqAgd2hpbGUgKGVib29rICE9IE5V
TEwpIHsKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCByZXQgPSBlX2Jvb2tfZ2V0X2NvbnRhY3Rz
X2FzeW5jKGVib29rLT5kYXRhLCBkYXRhLT5xdWVyeSwKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCBlYm9va3B1bGxfY2IsIGRhdGEpOwo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGlmIChy
ZXQgPT0gVFJVRSkKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBkYXRhLT5x
dWV1ZWRfY2FsbHMrKzsKPj4KPj4gLSDCoCDCoCDCoCBlX2Jvb2tfcXVlcnlfdW5yZWYocXVlcnkp
Owo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGVib29rID0gZWJvb2stPm5leHQ7Cj4+ICsgwqAg
wqAgwqAgfQo+PiArCj4+ICsgwqAgwqAgwqAgaWYgKGRhdGEtPnF1ZXVlZF9jYWxscyA9PSAwKQo+
PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHJldHVybiAtRU5PRU5UOwo+Pgo+PiDCoCDCoCDCoCDC
oHJldHVybiAwOwo+PiDCoH0KPj4gQEAgLTQ4NSwyMiArNTU2LDI4IEBAIHZvaWQgKnBob25lYm9v
a19nZXRfZW50cnkoY29uc3QgY2hhciAqZm9sZGVyLCBjb25zdCBjaGFyICppZCwKPj4gwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBjb25zdCBzdHJ1Y3QgYXBw
YXJhbV9maWVsZCAqcGFyYW1zLAo+PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoHBob25lYm9va19jYiBjYiwgdm9pZCAqdXNlcl9kYXRhLCBpbnQgKmVycikK
Pj4gwqB7Cj4+ICsgwqAgwqAgwqAgZ2Jvb2xlYW4gcmV0Owo+PiDCoCDCoCDCoCDCoHN0cnVjdCBx
dWVyeV9jb250ZXh0ICpkYXRhOwo+PiArIMKgIMKgIMKgIEdTTGlzdCAqZWJvb2s7Cj4+Cj4+IMKg
IMKgIMKgIMKgZGF0YSA9IGdfbmV3MChzdHJ1Y3QgcXVlcnlfY29udGV4dCwgMSk7Cj4+IMKgIMKg
IMKgIMKgZGF0YS0+Y29udGFjdHNfY2IgPSBjYjsKPj4gwqAgwqAgwqAgwqBkYXRhLT5wYXJhbXMg
PSBwYXJhbXM7Cj4+IMKgIMKgIMKgIMKgZGF0YS0+dXNlcl9kYXRhID0gdXNlcl9kYXRhOwo+PiAr
IMKgIMKgIMKgIGRhdGEtPmlkID0gZ19zdHJkdXAoaWQpOwo+Pgo+PiAtIMKgIMKgIMKgIGlmIChl
X2Jvb2tfYXN5bmNfZ2V0X2NvbnRhY3QoZWJvb2ssIGlkLCBlYm9va19lbnRyeV9jYiwgZGF0YSkp
IHsKPj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCBnX2ZyZWUoZGF0YSk7Cj4+IC0gwqAgwqAgwqAg
wqAgwqAgwqAgwqAgaWYgKGVycikKPj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCAqZXJyID0gLUVOT0VOVDsKPj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCByZXR1cm4gTlVMTDsK
Pj4gKyDCoCDCoCDCoCBlYm9vayA9IGVib29rczsKPj4gKyDCoCDCoCDCoCB3aGlsZSAoZWJvb2sg
IT0gTlVMTCkgewo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHJldCA9IGVfYm9va19nZXRfY29u
dGFjdF9hc3luYyhlYm9vay0+ZGF0YSwgZGF0YS0+aWQsCj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgZWJvb2tfZW50cnlfY2IsIGRhdGEpOwo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGlm
IChyZXQgPT0gVFJVRSkKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBkYXRh
LT5xdWV1ZWRfY2FsbHMrKzsKPj4gKwo+PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGVib29rID0g
ZWJvb2stPm5leHQ7Cj4+IMKgIMKgIMKgIMKgfQo+Pgo+PiDCoCDCoCDCoCDCoGlmIChlcnIpCj4+
IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgKmVyciA9IDA7Cj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgKmVyciA9IChkYXRhLT5xdWV1ZWRfY2FsbHMgPT0gMCA/IC1FTk9FTlQgOiAwKTsKPj4KPj4g
wqAgwqAgwqAgwqByZXR1cm4gZGF0YTsKPj4gwqB9Cj4+IEBAIC01MTEsMzEgKzU4OCwzNyBAQCB2
b2lkICpwaG9uZWJvb2tfY3JlYXRlX2NhY2hlKGNvbnN0IGNoYXIgKm5hbWUsIHBob25lYm9va19l
bnRyeV9jYiBlbnRyeV9jYiwKPj4gwqAgwqAgwqAgwqBzdHJ1Y3QgcXVlcnlfY29udGV4dCAqZGF0
YTsKPj4gwqAgwqAgwqAgwqBFQm9va1F1ZXJ5ICpxdWVyeTsKPj4gwqAgwqAgwqAgwqBnYm9vbGVh
biByZXQ7Cj4+ICsgwqAgwqAgwqAgR1NMaXN0ICplYm9vazsKPj4KPj4gwqAgwqAgwqAgwqBpZiAo
Z19zdHJjbXAwKCIvdGVsZWNvbS9wYiIsIG5hbWUpICE9IDApIHsKPj4gwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqBpZiAoZXJyKQo+PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCpl
cnIgPSAtRU5PRU5UOwo+PiArCj4+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgcmV0dXJuIE5VTEw7
Cj4+IMKgIMKgIMKgIMKgfQo+Pgo+PiArIMKgIMKgIMKgIERCRygiIik7Cj4+ICsKPj4gwqAgwqAg
wqAgwqBxdWVyeSA9IGVfYm9va19xdWVyeV9hbnlfZmllbGRfY29udGFpbnMoIiIpOwo+Pgo+PiDC
oCDCoCDCoCDCoGRhdGEgPSBnX25ldzAoc3RydWN0IHF1ZXJ5X2NvbnRleHQsIDEpOwo+PiDCoCDC
oCDCoCDCoGRhdGEtPmVudHJ5X2NiID0gZW50cnlfY2I7Cj4+IMKgIMKgIMKgIMKgZGF0YS0+cmVh
ZHlfY2IgPSByZWFkeV9jYjsKPj4gwqAgwqAgwqAgwqBkYXRhLT51c2VyX2RhdGEgPSB1c2VyX2Rh
dGE7Cj4+ICsgwqAgwqAgwqAgZGF0YS0+cXVlcnkgPSBxdWVyeTsKPj4KPj4gLSDCoCDCoCDCoCBy
ZXQgPSBlX2Jvb2tfYXN5bmNfZ2V0X2NvbnRhY3RzKGVib29rLCBxdWVyeSwgY2FjaGVfY2IsIGRh
dGEpOwo+PiAtIMKgIMKgIMKgIGVfYm9va19xdWVyeV91bnJlZihxdWVyeSk7Cj4+IC0gwqAgwqAg
wqAgaWYgKHJldCAhPSBGQUxTRSkgewo+PiAtIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGdfZnJlZShk
YXRhKTsKPj4gLSDCoCDCoCDCoCDCoCDCoCDCoCDCoCBpZiAoZXJyKQo+PiAtIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgICplcnIgPSAtRUZBVUxUOwo+PiAtIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIHJldHVybiBOVUxMOwo+PiArIMKgIMKgIMKgIGVib29rID0gZWJvb2tzOwo+PiArIMKg
IMKgIMKgIHdoaWxlIChlYm9vayAhPSBOVUxMKSB7Cj4+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
cmV0ID0gZV9ib29rX2dldF9jb250YWN0c19hc3luYyhlYm9vay0+ZGF0YSwgcXVlcnksCj4+ICsg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY2FjaGVfY2IsIGRhdGEpOwo+PiArIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIGlmIChyZXQgPT0gVFJVRSkKPj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCBkYXRhLT5xdWV1ZWRfY2FsbHMrKzsKPj4gKwo+PiArIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIGVib29rID0gZWJvb2stPm5leHQ7Cj4+IMKgIMKgIMKgIMKgfQo+Pgo+PiDCoCDCoCDCoCDC
oGlmIChlcnIpCj4+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgKmVyciA9IDA7Cj4+ICsgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgKmVyciA9IChkYXRhLT5xdWV1ZWRfY2FsbHMgPT0gMCA/IC1FTk9FTlQg
OiAwKTsKPj4KPj4gwqAgwqAgwqAgwqByZXR1cm4gZGF0YTsKPj4gwqB9Cj4+IC0tCj4+IDEuNy41
LjMKPj4KPj4gLS0KPgo+IEJ0dywgYXJlIHdlIHN0aWxsIHVzaW5nIGxpYmVib29rPyBJIHRob3Vn
aCB0aGlzIGJyZWFrcyB0aGUgaW50ZWdyYXRpb24KPiB3aXRoIGdkYnVzLCBkb2Vzbid0IGl0Pwo+
Cj4KPgo+IC0tCj4gTHVpeiBBdWd1c3RvIHZvbiBEZW50ego+CgpEb24ndCBrbm93IGFueXRoaW5n
IGFib3V0IGl0LCBidXQgaXMgdGhlcmUgcmVhbGx5IGFueSBvdGhlciBjaG9pY2U/CgotLSAKUG96
ZHJvd2llbmlhLApCYXJ0b3N6IFN6YXRrb3dza2kK

2011-07-05 08:45:19

by Luiz Augusto von Dentz

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

Hi Bartosz,

On Tue, Jul 5, 2011 at 12:51 AM, Bartosz Szatkowski <[email protected]> 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 | ?281 +++++++++++++++++++++++++++++----------------
> ?1 files changed, 182 insertions(+), 99 deletions(-)
>
> diff --git a/plugins/phonebook-ebook.c b/plugins/phonebook-ebook.c
> index 82019da..f223965 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,116 @@ 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);
>
> -fail:
> - ? ? ? if (data->completed)
> - ? ? ? ? ? ? ? g_free(data);
> + ? ? ? data->queued_calls--;
> + ? ? ? if (data->queued_calls == 0)
> + ? ? ? ? ? ? ? data->ready_cb(data->user_data);
> ?}
>
> ?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);
> - ? ? ? ? ? ? ? g_error_free(gerr);
> - ? ? ? ? ? ? ? return -EIO;
> + ? ? ? if (e_book_get_addressbooks(&src_list, &gerr) == FALSE) {
> + ? ? ? ? ? ? ? error("Can't list user's address books: %s", gerr->message);
> +
> + ? ? ? ? ? ? ? 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;

Please consider splitting this function since it is becoming too big.

> + ? ? ? 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);
> + ? ? ? ? ? ? ? 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;
> + ? ? ? ? ? ? ? }
> +
> + ? ? ? ? ? ? ? list = list->next;
> ? ? ? ?}
>
> - ? ? ? return 0;
> + ? ? ? return status;
> +
> +fail:
> + ? ? ? g_error_free(gerr);
> + ? ? ? 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);
> ?}
>
> ?char *phonebook_set_folder(const char *current_folder,
> @@ -440,13 +502,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 +517,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 +528,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("");
> +
> + ? ? ? ebook = ebooks;
> + ? ? ? while (ebook != NULL) {
> + ? ? ? ? ? ? ? ret = e_book_get_contacts_async(ebook->data, data->query,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ebookpull_cb, data);
> + ? ? ? ? ? ? ? if (ret == TRUE)
> + ? ? ? ? ? ? ? ? ? ? ? data->queued_calls++;
>
> - ? ? ? e_book_query_unref(query);
> + ? ? ? ? ? ? ? ebook = ebook->next;
> + ? ? ? }
> +
> + ? ? ? if (data->queued_calls == 0)
> + ? ? ? ? ? ? ? return -ENOENT;
>
> ? ? ? ?return 0;
> ?}
> @@ -485,22 +556,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 +588,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
>
> --

Btw, are we still using libebook? I though this breaks the integration
with gdbus, doesn't it?



--
Luiz Augusto von Dentz

2011-07-04 21:51:38

by Bartosz Szatkowski

[permalink] [raw]
Subject: [PATCH obexd 2/5] 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 f223965..dc78d17 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -513,6 +513,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


2011-07-04 21:51:41

by Bartosz Szatkowski

[permalink] [raw]
Subject: [PATCH obexd 5/5] 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 395c54a..e4fcbe0 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -501,9 +501,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-04 21:51:40

by Bartosz Szatkowski

[permalink] [raw]
Subject: [PATCH obexd 4/5] 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 54b764b..395c54a 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -600,6 +600,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)
@@ -618,6 +625,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-04 21:51:39

by Bartosz Szatkowski

[permalink] [raw]
Subject: [PATCH obexd 3/5] 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 dc78d17..54b764b 100644
--- a/plugins/phonebook-ebook.c
+++ b/plugins/phonebook-ebook.c
@@ -545,10 +545,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;
}
@@ -575,10 +577,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;
}
@@ -616,10 +620,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