4 #include <Elementary.h>
9 #include <contacts-ug.h>
16 #include "contacts-ofono-efl.h"
19 typedef struct _Contacts {
21 Eina_Bool contacts_on;
22 Ecore_Timer *reconnect;
23 struct ui_gadget *ug_all;
24 Eina_Hash *numbers, *hash_ids;
26 * hash_ids is a pair (tizen_db_id, Contact_Info)
27 * So we won't create a duplicated Contact_Info when dealing
32 typedef struct _Contact_Number {
34 unsigned int numberlen;
39 typedef struct _Contact_Name_Search {
42 } Contact_Name_Search;
44 typedef struct _Contact_Number_Entry {
47 } Contact_Number_Entry;
49 struct _Contact_Info {
51 const char *first_name;
52 const char *last_name;
53 const char *full_name;
57 Eina_Inlist *on_del_cbs;
60 Eina_Inlist *listeners;
66 typedef struct _Contact_Info_On_Del_Ctx {
68 void (*cb)(void *, const Contact_Info *);
70 } Contact_Info_On_Del_Ctx;
72 typedef struct _Contact_Info_On_Changed_Ctx {
74 void (*cb)(void *, Contact_Info *);
77 } Contact_Info_On_Changed_Ctx;
79 struct _Contact_Partial_Match
81 const Contact_Info *info;
83 Eina_Bool name_match : 1;
86 typedef struct _Partial_Match_Search
89 const Contacts *contacts;
90 } Partial_Match_Search;
93 static void _contact_number_entry_add(const char *number, Contact_Info *c_info);
95 static const char *_contact_number_type_get(contacts_record_h contact_number_h);
96 static void _contact_info_free(Contact_Info *c_info);
98 static void _contact_number_add(char *number,
100 contacts_record_h contact_number_h);
102 const char *contact_info_number_check(const Contact_Info *c,
105 static void _partial_match_add(Eina_List **p_list, const char *type,
106 const Contact_Info *c_info,
107 Eina_Bool name_match)
109 Contact_Partial_Match *pm = malloc(sizeof(Contact_Partial_Match));
110 EINA_SAFETY_ON_NULL_RETURN(pm);
113 pm->name_match = name_match;
114 *p_list = eina_list_append(*p_list, pm);
117 static void _partial_number_match_add(Eina_List **p_list, const char *type,
118 const Contact_Info *c_info)
120 _partial_match_add(p_list, type, c_info, EINA_FALSE);
123 static int _db_query_partial_search(const char *name_or_number,
124 Partial_Match_Search *pm_search,
125 Eina_Bool name_match)
127 const Contacts *contacts = pm_search->contacts;
128 Contact_Info *c_info;
129 contacts_error_e err = CONTACTS_ERROR_NONE;
130 contacts_list_h list = NULL;
131 contacts_query_h query = NULL;
132 contacts_filter_h filter = NULL;
133 unsigned int contact_count = 0;
134 contacts_record_h contact_h = NULL;
135 contacts_record_h contact_name_h = NULL;
136 contacts_record_h contact_number_h = NULL;
138 char *f_name = NULL, *l_name = NULL, *img = NULL;
143 err = contacts_query_create(_contacts_number._uri, &query);
146 if (CONTACTS_ERROR_NONE != (err = contacts_filter_create(_contacts_name._uri, &filter)))
148 if (CONTACTS_ERROR_NONE != (err = contacts_filter_add_str(filter, _contacts_name.first, CONTACTS_MATCH_EXACTLY, name_or_number)))
150 if (CONTACTS_ERROR_NONE != (err = contacts_filter_add_operator( filter, CONTACTS_FILTER_OPERATOR_OR)))
152 if (CONTACTS_ERROR_NONE != (err = contacts_filter_add_str(filter, _contacts_name.last, CONTACTS_MATCH_EXACTLY, name_or_number)))
154 if (CONTACTS_ERROR_NONE != (err = contacts_query_set_filter(query, filter)))
156 if (CONTACTS_ERROR_NONE != (err = contacts_db_get_records_with_query(query, 0, 0, &list)))
161 err = contacts_query_create(_contacts_number._uri, &query);
164 if (CONTACTS_ERROR_NONE != (err = contacts_filter_create(_contacts_number._uri, &filter)))
166 if (CONTACTS_ERROR_NONE != (err = contacts_filter_add_str(filter, _contacts_number.number, CONTACTS_MATCH_EXACTLY, name_or_number)))
168 if (CONTACTS_ERROR_NONE != (err = contacts_query_set_filter(query, filter)))
170 if (CONTACTS_ERROR_NONE != (err = contacts_db_get_records_with_query(query, 0, 0, &list)))
175 if (CONTACTS_ERROR_NONE != err) {
176 ERR("contacts_query_create() Failed(%d)", err);
179 contacts_filter_destroy(filter);
180 contacts_query_destroy(query);
182 contacts_list_get_count(list, &contact_count);
183 if (contact_count == 0)
186 while (CONTACTS_ERROR_NONE == err) {
187 c_info = calloc(1, sizeof(Contact_Info));
188 EINA_SAFETY_ON_NULL_RETURN_VAL(c_info, -1);
189 err = contacts_list_get_current_record_p(list, &contact_number_h);
190 if (CONTACTS_ERROR_NONE != err) {
191 ERR("contacts_list_get_current_record_p() Failed(%d)", err);
195 contacts_record_get_int(contact_number_h, _contacts_number.contact_id, &contact_id);
196 err = contacts_db_get_record(_contacts_contact._uri, contact_id, &contact_h);
197 if (CONTACTS_ERROR_NONE != err) {
198 ERR("contacts_db_get_record() Failed(%d)", err);
202 err = contacts_record_get_child_record_at_p(contact_h, _contacts_contact.name, 0, &contact_name_h);
203 if (CONTACTS_ERROR_NONE != err) {
204 ERR("contacts_record_get_child_record_at_p() Failed(%d)", err);
208 contacts_record_get_str(contact_h, _contacts_contact.image_thumbnail_path, &img);
209 contacts_record_get_str(contact_name_h, _contacts_name.first, &f_name);
210 contacts_record_get_str(contact_name_h, _contacts_name.last, &l_name);
212 c_info->id = contact_id;
213 c_info->picture = eina_stringshare_add(img);
214 c_info->first_name = eina_stringshare_add(f_name);
215 c_info->last_name = eina_stringshare_add(l_name);
218 while (CONTACTS_ERROR_NONE == contacts_record_get_child_record_at_p(contact_h,
219 _contacts_contact.number,
221 &contact_number_h)) {
223 contacts_record_get_str(contact_number_h, _contacts_number.number, &number);
224 _contact_number_add(number, c_info, contact_number_h);
226 Contact_Info *c_info_found;
227 c_info_found = eina_hash_find(contacts->hash_ids, &c_info->id);
229 /* Destroy and use old contact info */
230 _contact_info_free(c_info);
231 c_info = c_info_found;
234 /* New contact info */
235 eina_hash_add(contacts->hash_ids, &c_info->id, c_info);
238 type = contact_info_number_check(c_info, number);
240 _partial_match_add(&pm_search->matches, type, c_info, EINA_TRUE);
243 _partial_number_match_add(&pm_search->matches, type, c_info);
248 contacts_record_destroy(contact_h, true);
253 err = contacts_list_next(list);
256 if (CONTACTS_ERROR_NONE != err) {
257 ERR("contacts_list_next() Failed(%d)", err);
264 Eina_List *contact_partial_match_search(Evas_Object *obj, const char *query)
267 const Contacts *contacts;
269 Eina_Bool name_search = EINA_FALSE;
271 Partial_Match_Search pm_search;
273 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
274 EINA_SAFETY_ON_NULL_RETURN_VAL(query, NULL);
275 contacts = evas_object_data_get(obj, "contacts.ctx");
276 EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, NULL);
278 if (!contacts->contacts_on)
281 /* Check if it is numeric */
282 query_number = alloca(strlen(query) + 1);
283 EINA_SAFETY_ON_NULL_RETURN_VAL(query_number, NULL);
284 for (i = 0, j = 0; query[i] != '\0'; i++) {
285 if (isalpha(query[i])) {
286 name_search = EINA_TRUE;
288 } else if (isdigit(query[i]))
289 query_number[j++] = query[i];
292 pm_search.contacts = contacts;
293 pm_search.matches = NULL;
296 if (_db_query_partial_search(query, &pm_search, name_search) < 0) {
297 ERR("Could not search in contacts DB the name: %s",
302 query_number[j] = '\0';
303 if (_db_query_partial_search(query, &pm_search, name_search) < 0) {
304 ERR("Could not search in contacts DB the number: %s",
310 return pm_search.matches;
313 void contact_partial_match_search_free(Eina_List *results)
315 Contact_Partial_Match *pm;
316 EINA_LIST_FREE(results, pm)
320 const char *contact_partial_match_type_get(const Contact_Partial_Match *pm)
322 EINA_SAFETY_ON_NULL_RETURN_VAL(pm, NULL);
326 const Contact_Info *contact_partial_match_info_get(const Contact_Partial_Match *pm)
328 EINA_SAFETY_ON_NULL_RETURN_VAL(pm, NULL);
332 Eina_Bool contact_partial_match_name_match_get(const Contact_Partial_Match *pm)
334 EINA_SAFETY_ON_NULL_RETURN_VAL(pm, EINA_FALSE);
335 return pm->name_match;
338 Eina_List *contact_info_all_numbers_get(const Contact_Info *c)
343 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
345 EINA_INLIST_FOREACH(c->numbers, cn)
346 l = eina_list_append(l, cn->number);
351 static void _contact_number_entry_add(const char *number,
352 Contact_Info *c_info)
354 Contact_Number_Entry *e = eina_hash_find(c_info->contacts->numbers,
357 size_t numberlen = strlen(number);
358 e = calloc(1, sizeof(Contact_Number_Entry) + numberlen + 1);
359 EINA_SAFETY_ON_NULL_RETURN(e);
360 memcpy(e->number, number, numberlen + 1);
361 eina_hash_direct_add(c_info->contacts->numbers, e->number, e);
363 e->contacts = eina_list_append(e->contacts, c_info);
366 static void _contact_number_entry_del(const char *number,
367 Contact_Info *c_info)
369 Eina_Hash *numbers = c_info->contacts->numbers;
370 Contact_Number_Entry *e = eina_hash_find(numbers, number);
371 EINA_SAFETY_ON_NULL_RETURN(e);
372 e->contacts = eina_list_remove(e->contacts, c_info);
375 eina_hash_del_by_key(numbers, e->number);
376 /* hash's free callback will free "e" for me */
379 static Eina_Bool _is_alias(Contact_Number *cn, const char *alias)
381 unsigned int aliaslen = strlen(alias);
382 unsigned int suffix = cn->numberlen - aliaslen;
383 if (cn->numberlen < aliaslen)
386 return memcmp(cn->number + suffix, alias, aliaslen) == 0;
389 static Eina_Bool _contact_number_is_equal(Contact_Number *cn,
392 unsigned int numberlen = strlen(number);
393 if (cn->numberlen == numberlen &&
394 memcmp(cn->number, number, numberlen) == 0)
400 static void _alias_delete(Contact_Number *cn, Contact_Info *c_info)
402 Contact_Number *alias;
403 Eina_List *deleted_list = NULL;
405 EINA_INLIST_FOREACH(c_info->alias, alias) {
406 if (_is_alias(cn, alias->number))
407 deleted_list = eina_list_append(deleted_list, alias);
410 EINA_LIST_FREE(deleted_list, alias) {
411 c_info->alias = eina_inlist_remove(c_info->alias,
412 EINA_INLIST_GET(alias));
413 _contact_number_entry_del(alias->number, c_info);
418 static Eina_Bool _contact_phone_changed(Contact_Info *c_info,
419 contacts_record_h contact_h)
422 Eina_Bool ret = EINA_FALSE;
423 Eina_List *deleted_list = NULL;
426 /* Looking for deleted phones */
427 EINA_INLIST_FOREACH(c_info->numbers, cn) {
428 Eina_Bool deleted = EINA_TRUE;
430 contacts_record_h contact_number_h;
431 while (CONTACTS_ERROR_NONE == contacts_record_get_child_record_at_p(contact_h,
432 _contacts_contact.number,
434 &contact_number_h)) {
436 if (contacts_record_get_str_p(contact_number_h, _contacts_number.number, &number) !=
439 Eina_Bool equal = _contact_number_is_equal(cn, number);
441 deleted = EINA_FALSE;
447 _contact_number_entry_del(cn->number, c_info);
448 deleted_list = eina_list_append(deleted_list, cn);
453 contacts_record_h contact_number_h;
454 if (contacts_record_get_child_record_at_p(contact_h, _contacts_contact.number, 0, &contact_number_h) !=
458 /* Looking for new phones */
459 while (CONTACTS_ERROR_NONE == contacts_record_get_child_record_at_p(contact_h,
460 _contacts_contact.number,
462 &contact_number_h)) {
463 Eina_Bool added = EINA_TRUE;
465 if (contacts_record_get_str(contact_number_h, _contacts_number.number, &number) !=
468 EINA_INLIST_FOREACH(c_info->numbers, cn) {
469 if (_contact_number_is_equal(cn, number)) {
475 _contact_number_add(number, c_info, contact_number_h);
479 EINA_LIST_FREE(deleted_list, cn) {
480 c_info->numbers = eina_inlist_remove(c_info->numbers,
481 EINA_INLIST_GET(cn));
482 _alias_delete(cn, c_info);
489 static void _contact_info_on_del_dispatch(Contact_Info *c)
491 Eina_Inlist *lst = c->on_del_cbs;
492 c->on_del_cbs = NULL; /* avoid contact_info_on_del_callback_del() */
494 Contact_Info_On_Del_Ctx *ctx = EINA_INLIST_CONTAINER_GET
495 (lst, Contact_Info_On_Del_Ctx);
497 lst = eina_inlist_remove(lst, lst);
499 ctx->cb((void *)ctx->data, c);
504 static void _contact_info_on_changed_dispatch(Contact_Info *c)
506 Contact_Info_On_Changed_Ctx *ctx;
508 c->on_changed_cbs.walking++;
509 EINA_INLIST_FOREACH(c->on_changed_cbs.listeners, ctx) {
512 ctx->cb((void *)ctx->data, c);
514 c->on_changed_cbs.walking--;
516 if (c->on_changed_cbs.walking <= 0) {
517 EINA_LIST_FREE(c->on_changed_cbs.deleted, ctx) {
518 c->on_changed_cbs.listeners = eina_inlist_remove(
519 c->on_changed_cbs.listeners,
520 EINA_INLIST_GET(ctx));
526 static Eina_Bool _hash_foreach(const Eina_Hash *hash __UNUSED__,
527 const void *key __UNUSED__, void *data,
530 contacts_error_e err = CONTACTS_ERROR_NONE;
531 Eina_List **deleted = fdata;
532 Eina_Bool disp = EINA_FALSE;
533 Contact_Info *c_info = data;
534 contacts_record_h contact_h = NULL;
535 contacts_record_h contact_name_h = NULL;
536 char *f_name = NULL, *l_name = NULL, *img = NULL;
538 err = contacts_db_get_record( _contacts_contact._uri, c_info->id, &contact_h);
539 if (CONTACTS_ERROR_NONE != err) {
540 ERR("contacts_db_get_record() Failed(%d)", err);
544 /* Contact no longer exists. */
547 err = contacts_record_get_child_record_at_p(contact_h, _contacts_contact.name, 0, &contact_name_h);
548 if (CONTACTS_ERROR_NONE != err) {
549 ERR("contacts_record_get_child_record_at_p(%d)", err);
552 EINA_SAFETY_ON_NULL_GOTO(contact_name_h, err_contact);
554 contacts_record_get_str(contact_name_h, _contacts_name.first, &f_name);
555 contacts_record_get_str(contact_name_h, _contacts_name.last, &l_name);
556 contacts_record_get_str(contact_h, _contacts_contact.image_thumbnail_path, &img);
558 if (eina_stringshare_replace(&c_info->first_name, f_name)) {
560 eina_stringshare_del(c_info->full_name);
561 c_info->full_name = NULL;
564 if (eina_stringshare_replace(&c_info->last_name, l_name)) {
566 eina_stringshare_del(c_info->full_name);
567 c_info->full_name = NULL;
570 disp |= eina_stringshare_replace(&c_info->picture, img);
572 disp |= _contact_phone_changed(c_info, contact_h);
575 _contact_info_on_changed_dispatch(c_info);
577 contacts_record_destroy(contact_name_h, true);
582 contacts_record_destroy(contact_h, true);
586 *deleted = eina_list_append(*deleted, c_info);
590 static void _contact_db_changed(const char *view_uri __UNUSED__, void *data)
592 Contacts *contacts = data;
593 Contact_Info *c_info;
594 Eina_List *deleted = NULL;
596 EINA_SAFETY_ON_NULL_RETURN(contacts);
597 eina_hash_foreach(contacts->hash_ids, _hash_foreach, &deleted);
599 EINA_LIST_FREE(deleted, c_info) {
601 /* _contact_info_free() will free the lists for me */
602 EINA_INLIST_FOREACH(c_info->alias, cn)
603 _contact_number_entry_del(cn->number, c_info);
604 EINA_INLIST_FOREACH(c_info->numbers, cn)
605 _contact_number_entry_del(cn->number, c_info);
606 eina_hash_del_by_key(contacts->hash_ids, &c_info->id);
610 static void _contact_number_add(char *number,
611 Contact_Info *c_info,
612 contacts_record_h contact_number_h)
614 unsigned int numberlen = strlen(number);
615 Contact_Number *cn = malloc(sizeof(Contact_Number) + numberlen + 1);
616 EINA_SAFETY_ON_NULL_RETURN(cn);
617 memcpy(cn->number, number, numberlen);
618 cn->numberlen = numberlen;
619 cn->number[numberlen] = '\0';
620 cn->type = _contact_number_type_get(contact_number_h);
621 c_info->numbers = eina_inlist_append(c_info->numbers,
622 EINA_INLIST_GET(cn));
625 static int _db_query_search_number(const char *number, Contact_Info **c_info)
627 contacts_error_e err = CONTACTS_ERROR_NONE;
628 contacts_list_h list = NULL;
629 contacts_query_h query = NULL;
630 contacts_filter_h filter = NULL;
631 unsigned int contact_count = 0;
632 contacts_record_h contact_h = NULL;
633 contacts_record_h contact_name_h = NULL;
634 contacts_record_h contact_number_h = NULL;
636 char *f_name = NULL, *l_name = NULL, *img = NULL;
639 *c_info = calloc(1, sizeof(Contact_Info));
640 EINA_SAFETY_ON_NULL_RETURN_VAL((*c_info), -1);
642 err = contacts_query_create(_contacts_number._uri, &query);
645 if (CONTACTS_ERROR_NONE != (err = contacts_filter_create(_contacts_number._uri, &filter)))
647 if (CONTACTS_ERROR_NONE != (err = contacts_filter_add_str(filter, _contacts_number.number, CONTACTS_MATCH_EXACTLY, number)))
649 if (CONTACTS_ERROR_NONE != (err = contacts_query_set_filter(query, filter)))
651 if (CONTACTS_ERROR_NONE != (err = contacts_db_get_records_with_query(query, 0, 0, &list)))
655 if (CONTACTS_ERROR_NONE != err) {
656 ERR("contacts_query_create() Failed(%d)", err);
659 contacts_filter_destroy(filter);
660 contacts_query_destroy(query);
662 contacts_list_get_count(list, &contact_count);
663 if (contact_count == 0) {
669 err = contacts_list_get_current_record_p(list, &contact_number_h);
670 if (CONTACTS_ERROR_NONE != err) {
671 ERR("contacts_list_get_current_record_p() Failed(%d)", err);
677 contacts_record_get_int(contact_number_h, _contacts_number.contact_id, &contact_id);
678 err = contacts_db_get_record(_contacts_contact._uri, contact_id, &contact_h);
679 if (CONTACTS_ERROR_NONE != err) {
680 ERR("contacts_db_get_record() Failed(%d)", err);
686 err = contacts_record_get_child_record_at_p(contact_h, _contacts_contact.name, 0, &contact_name_h);
687 if (CONTACTS_ERROR_NONE != err) {
688 ERR("contacts_record_get_child_record_at_p() Failed(%d)", err);
694 contacts_record_get_str(contact_h, _contacts_contact.image_thumbnail_path, &img);
695 contacts_record_get_str(contact_name_h, _contacts_name.first, &f_name);
696 contacts_record_get_str(contact_name_h, _contacts_name.last, &l_name);
698 (*c_info)->id = contact_id;
699 (*c_info)->picture = eina_stringshare_add(img);
700 (*c_info)->first_name = eina_stringshare_add(f_name);
701 (*c_info)->last_name = eina_stringshare_add(l_name);
704 while (CONTACTS_ERROR_NONE == contacts_record_get_child_record_at_p(contact_h,
705 _contacts_contact.number,
707 &contact_number_h)) {
709 contacts_record_get_str(contact_number_h, _contacts_number.number, &number_str);
710 _contact_number_add(number_str, (*c_info), contact_number_h);
714 contacts_record_destroy(contact_h, true);
721 static const char *_contact_number_type_get(contacts_record_h contact_number_h)
725 if (contacts_record_get_int(contact_number_h, _contacts_number.type, &number_type) < 0)
728 if (number_type & CONTACTS_NUMBER_TYPE_OTHER) {
731 else if (number_type & CONTACTS_NUMBER_TYPE_HOME) {
734 else if (number_type & CONTACTS_NUMBER_TYPE_WORK) {
737 else if (number_type & CONTACTS_NUMBER_TYPE_VOICE) {
740 else if (number_type & CONTACTS_NUMBER_TYPE_FAX) {
743 else if (number_type & CONTACTS_NUMBER_TYPE_MSG) {
746 else if (number_type & CONTACTS_NUMBER_TYPE_CELL) {
749 else if (number_type & CONTACTS_NUMBER_TYPE_PAGER) {
752 else if (number_type & CONTACTS_NUMBER_TYPE_BBS) {
753 return _("Bulletin board");
755 else if (number_type & CONTACTS_NUMBER_TYPE_MODEM) {
758 else if (number_type & CONTACTS_NUMBER_TYPE_CAR) {
759 return _("Car phone");
761 else if (number_type & CONTACTS_NUMBER_TYPE_ISDN) {
764 else if (number_type & CONTACTS_NUMBER_TYPE_VIDEO) {
765 return _("Video conference");
767 else if (number_type & CONTACTS_NUMBER_TYPE_PCS) {
768 return _("Personal communicatior");
770 else if (number_type & CONTACTS_NUMBER_TYPE_ASSISTANT) {
771 return _("Assistant telephone");
773 else if (number_type & CONTACTS_NUMBER_TYPE_CUSTOM) {
781 static const char *_alias_phone_type_match(Contact_Info *c_info,
785 EINA_INLIST_FOREACH(c_info->numbers, cn) {
786 if (_is_alias(cn, alias))
792 static Eina_Bool _alias_create(Contact_Info *c_info, const char *number)
794 unsigned int numberlen = strlen(number);
795 Contact_Number *cn = malloc(sizeof(Contact_Number) + numberlen + 1);
796 EINA_SAFETY_ON_NULL_RETURN_VAL(cn, EINA_FALSE);
797 memcpy(cn->number, number, numberlen);
798 cn->numberlen = numberlen;
799 cn->number[numberlen] = '\0';
800 cn->type = _alias_phone_type_match(c_info, number);
801 c_info->alias = eina_inlist_append(
802 c_info->alias, EINA_INLIST_GET(cn));
803 _contact_number_entry_add(cn->number, c_info);
807 Contact_Info *contact_search(Evas_Object *obj, const char *number,
810 Contact_Info *c_info = NULL, *found;
812 Contact_Number_Entry *entry;
814 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
815 EINA_SAFETY_ON_NULL_RETURN_VAL(number, NULL);
816 contacts = evas_object_data_get(obj, "contacts.ctx");
817 EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, NULL);
819 if (!contacts->contacts_on)
822 entry = eina_hash_find(contacts->numbers, number);
825 c_info = eina_list_data_get(entry->contacts);
826 EINA_SAFETY_ON_NULL_RETURN_VAL(c_info, NULL);
830 if (_db_query_search_number(number, &c_info) < 0) {
831 ERR("Could not fetch phone number: %s from DB", number);
838 /* Do we have this contact already ? */
839 found = eina_hash_find(contacts->hash_ids, &c_info->id);
842 _contact_info_free(c_info);
844 /* The user enterer an alias */
846 r = _alias_create(c_info, number);
847 EINA_SAFETY_ON_FALSE_RETURN_VAL(r, NULL);
850 c_info->contacts = contacts;
851 eina_hash_add(contacts->hash_ids, &c_info->id, c_info);
853 EINA_INLIST_FOREACH(c_info->numbers, cn)
854 _contact_number_entry_add(cn->number, c_info);
859 *type = contact_info_number_check(c_info, number);
863 const char *contact_info_picture_get(const Contact_Info *c)
865 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
869 const char *contact_info_full_name_get(const Contact_Info *c)
872 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
874 c2 = (Contact_Info *)c;
875 c2->full_name = eina_stringshare_printf("%s %s", c->first_name,
881 const char *contact_info_first_name_get(const Contact_Info *c)
883 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
884 return c->first_name;
887 const char *contact_info_last_name_get(const Contact_Info *c)
889 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
893 const char *contact_info_detail_get(const Contact_Info *c,
896 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
897 EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL);
899 /* Do not check in the alias list. Because here we want in fact a
902 EINA_INLIST_FOREACH(c->numbers, cn) {
903 if (strcmp(cn->type, type) == 0)
909 const char *contact_info_number_check(const Contact_Info *c,
912 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
913 EINA_SAFETY_ON_NULL_RETURN_VAL(number, NULL);
916 EINA_INLIST_FOREACH(c->numbers, cn) {
917 if (_contact_number_is_equal(cn, number))
920 /* It could be an alias */
921 EINA_INLIST_FOREACH(c->alias, cn) {
922 if (_contact_number_is_equal(cn, number))
928 Eina_Bool contact_info_picture_set(Contact_Info *c __UNUSED__,
929 const char *filename __UNUSED__)
935 Eina_Bool contact_info_first_name_set(Contact_Info *c __UNUSED__,
936 const char *name __UNUSED__)
942 Eina_Bool contact_info_last_name_set(Contact_Info *c __UNUSED__,
943 const char *name __UNUSED__)
949 Eina_Bool contact_info_detail_set(Contact_Info *c __UNUSED__,
950 const char *type __UNUSED__,
951 const char *number __UNUSED__)
957 void contact_info_on_changed_callback_add(Contact_Info *c,
958 void (*cb)(void *data, Contact_Info *c),
961 Contact_Info_On_Changed_Ctx *ctx;
963 EINA_SAFETY_ON_NULL_RETURN(c);
964 EINA_SAFETY_ON_NULL_RETURN(cb);
966 ctx = calloc(1, sizeof(Contact_Info_On_Changed_Ctx));
967 EINA_SAFETY_ON_NULL_RETURN(ctx);
971 c->on_changed_cbs.listeners = eina_inlist_append(
972 c->on_changed_cbs.listeners, EINA_INLIST_GET(ctx));
975 void contact_info_on_changed_callback_del(Contact_Info *c,
976 void (*cb)(void *data, Contact_Info *c),
980 Contact_Info_On_Changed_Ctx *ctx, *found = NULL;
981 EINA_SAFETY_ON_NULL_RETURN(c);
982 EINA_SAFETY_ON_NULL_RETURN(cb);
984 EINA_INLIST_FOREACH(c->on_changed_cbs.listeners, ctx) {
985 if (ctx->cb == cb && ctx->data == data) {
994 if (c->on_changed_cbs.walking > 0) {
995 found->deleted = EINA_TRUE;
996 c->on_changed_cbs.deleted = eina_list_append(
997 c->on_changed_cbs.deleted, found);
1001 c->on_changed_cbs.listeners = eina_inlist_remove(
1002 c->on_changed_cbs.listeners, EINA_INLIST_GET(found));
1006 void contact_info_on_del_callback_add(Contact_Info *c,
1007 void (*cb)(void *data, const Contact_Info *c),
1011 Contact_Info_On_Del_Ctx *ctx;
1013 EINA_SAFETY_ON_NULL_RETURN(c);
1014 EINA_SAFETY_ON_NULL_RETURN(cb);
1016 ctx = calloc(1, sizeof(Contact_Info_On_Del_Ctx));
1017 EINA_SAFETY_ON_NULL_RETURN(ctx);
1021 c->on_del_cbs = eina_inlist_append(c->on_del_cbs, EINA_INLIST_GET(ctx));
1024 void contact_info_on_del_callback_del(Contact_Info *c,
1025 void (*cb)(void *data, const Contact_Info *c),
1029 Contact_Info_On_Del_Ctx *ctx, *found = NULL;
1030 EINA_SAFETY_ON_NULL_RETURN(c);
1031 EINA_SAFETY_ON_NULL_RETURN(cb);
1033 EINA_INLIST_FOREACH(c->on_del_cbs, ctx) {
1034 if (ctx->cb == cb && ctx->data == data) {
1043 c->on_del_cbs = eina_inlist_remove(c->on_del_cbs,
1044 EINA_INLIST_GET(found));
1049 void contact_info_del(Contact_Info *c_info __UNUSED__)
1054 #ifdef HAVE_UI_GADGET
1055 static void _contacts_ug_layout_create(struct ui_gadget *ug,
1056 enum ug_mode mode __UNUSED__,
1059 Contacts *contacts = priv;
1060 EINA_SAFETY_ON_NULL_RETURN(ug);
1061 elm_object_part_content_set(contacts->self, "elm.swallow.genlist",
1066 static void _contact_info_free(Contact_Info *c_info)
1069 _contact_info_on_del_dispatch(c_info);
1070 EINA_SAFETY_ON_FALSE_RETURN(c_info->on_changed_cbs.walking == 0);
1072 if (c_info->on_changed_cbs.deleted) {
1073 ERR("contact still have changed deleted listeners: %p %s %s",
1074 c_info, c_info->first_name, c_info->last_name);
1075 eina_list_free(c_info->on_changed_cbs.deleted);
1078 if (c_info->on_changed_cbs.listeners) {
1079 while (c_info->on_changed_cbs.listeners) {
1080 Contact_Info_On_Changed_Ctx *ctx;
1082 ctx = EINA_INLIST_CONTAINER_GET(
1083 c_info->on_changed_cbs.listeners,
1084 Contact_Info_On_Changed_Ctx);
1085 c_info->on_changed_cbs.listeners = eina_inlist_remove
1086 (c_info->on_changed_cbs.listeners,
1087 c_info->on_changed_cbs.listeners);
1092 while (c_info->numbers) {
1093 cn = EINA_INLIST_CONTAINER_GET(c_info->numbers,
1095 c_info->numbers = eina_inlist_remove(c_info->numbers,
1100 while (c_info->alias) {
1101 cn = EINA_INLIST_CONTAINER_GET(c_info->alias,
1103 c_info->alias = eina_inlist_remove(c_info->alias,
1108 eina_stringshare_del(c_info->first_name);
1109 eina_stringshare_del(c_info->last_name);
1110 eina_stringshare_del(c_info->full_name);
1111 eina_stringshare_del(c_info->picture);
1115 void _hash_elements_free(void *data)
1117 Contact_Info *c = data;
1118 _contact_info_free(c);
1121 void _numbers_hash_elements_free(void *data)
1123 Contact_Number_Entry *e = data;
1124 /*Contact_Info will be deleted by hash_ids */
1125 eina_list_free(e->contacts);
1129 static void _on_del(void *data, Evas *e __UNUSED__,
1130 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
1132 Contacts *contacts = data;
1133 eina_hash_free(contacts->hash_ids);
1134 eina_hash_free(contacts->numbers);
1135 #ifdef HAVE_UI_GADGET
1136 ug_destroy(contacts->ug_all);
1138 if (contacts->reconnect)
1139 ecore_timer_del(contacts->reconnect);
1141 contacts_disconnect2();
1144 #ifdef HAVE_UI_GADGET
1145 static void _create_contacts_ug(Contacts *contacts)
1149 struct ui_gadget *ug;
1152 cbs.priv = contacts;
1153 cbs.layout_cb = _contacts_ug_layout_create;
1154 cbs.result_cb = NULL;
1155 cbs.destroy_cb = NULL;
1157 bd = bundle_create();
1158 EINA_SAFETY_ON_NULL_RETURN(bd);
1160 snprintf(buf, sizeof(buf), "%d", CT_UG_REQUEST_DETAIL);
1161 bundle_add(bd, CT_UG_BUNDLE_TYPE, buf);
1162 snprintf(buf, sizeof(buf), "%d", 1);
1163 bundle_add(bd, CT_UG_BUNDLE_ID, buf);
1165 ug = ug_create(NULL, UG_CONTACTS_LIST, UG_MODE_FRAMEVIEW, bd, &cbs);
1166 EINA_SAFETY_ON_NULL_GOTO(ug, err_ug);
1168 contacts->ug_all = ug;
1169 evas_object_data_set(contacts->self, "contacts.ctx", contacts);
1176 static Eina_Bool _contacts_reconnect(void *data)
1178 Contacts *contacts = data;
1180 if (contacts_connect2() != CONTACTS_ERROR_NONE)
1181 return ECORE_CALLBACK_RENEW;
1183 contacts->contacts_on = EINA_TRUE;
1184 contacts->reconnect = NULL;
1185 contacts_db_add_changed_cb(_contacts_contact._uri, _contact_db_changed, contacts);
1186 #ifdef HAVE_UI_GADGET
1187 _create_contacts_ug(contacts);
1189 return ECORE_CALLBACK_DONE;
1192 Evas_Object *contacts_add(Evas_Object *parent)
1196 contacts = calloc(1, sizeof(Contacts));
1197 EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, NULL);
1198 contacts->self = layout_add(parent, "contacts_bg");
1199 EINA_SAFETY_ON_NULL_GOTO(contacts->self, err_layout);
1200 evas_object_event_callback_add(contacts->self, EVAS_CALLBACK_DEL,
1203 if (contacts_connect2() != CONTACTS_ERROR_NONE) {
1204 WRN("Could not connect to the contacts DB");
1205 contacts->contacts_on = EINA_FALSE;
1206 contacts->reconnect = ecore_timer_add(1.0, _contacts_reconnect,
1209 contacts_db_add_changed_cb(_contacts_contact._uri, _contact_db_changed, contacts);
1210 contacts->contacts_on = EINA_TRUE;
1211 #ifdef HAVE_UI_GADGET
1212 _create_contacts_ug(contacts);
1216 contacts->numbers = eina_hash_string_superfast_new(
1217 _numbers_hash_elements_free);
1218 EINA_SAFETY_ON_NULL_GOTO(contacts->numbers, err_hash);
1220 contacts->hash_ids = eina_hash_int32_new(_hash_elements_free);
1221 EINA_SAFETY_ON_NULL_GOTO(contacts->hash_ids, err_hash_id);
1223 return contacts->self;
1226 eina_hash_free(contacts->numbers);
1228 evas_object_del(contacts->self);
1229 if (contacts->reconnect)
1230 ecore_timer_del(contacts->reconnect);