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