4 #include <Elementary.h>
8 #include <contacts-ug.h>
14 #include "contacts-ofono-efl.h"
17 typedef struct _Contacts {
19 Eina_Bool contacts_on;
20 Ecore_Timer *reconnect;
21 struct ui_gadget *ug_all;
22 Eina_Hash *numbers, *hash_ids;
24 * hash_ids is a pair (tizen_db_id, Contact_Info)
25 * So we won't create a duplicated Contact_Info when dealing
30 typedef struct _Contact_Number {
32 unsigned int numberlen;
37 typedef struct _Contact_Name_Search {
40 } Contact_Name_Search;
42 typedef struct _Contact_Number_Entry {
45 } Contact_Number_Entry;
47 struct _Contact_Info {
49 const char *first_name;
50 const char *last_name;
51 const char *full_name;
55 Eina_Inlist *on_del_cbs;
58 Eina_Inlist *listeners;
64 typedef struct _Contact_Info_On_Del_Ctx {
66 void (*cb)(void *, const Contact_Info *);
68 } Contact_Info_On_Del_Ctx;
70 typedef struct _Contact_Info_On_Changed_Ctx {
72 void (*cb)(void *, Contact_Info *);
75 } Contact_Info_On_Changed_Ctx;
77 struct _Contact_Partial_Match
79 const Contact_Info *info;
81 Eina_Bool name_match : 1;
84 typedef struct _Partial_Match_Search
87 const Contacts *contacts;
88 } Partial_Match_Search;
91 static void _contact_number_entry_add(const char *number, Contact_Info *c_info);
93 static const char *phone_type_get(contact_number_h number);
94 static void _contact_info_free(Contact_Info *c_info);
96 static void _contact_number_add(char *number,
98 contact_number_h number_h);
100 const char *contact_info_number_check(const Contact_Info *c,
103 static void _partial_match_add(Eina_List **p_list, const char *type,
104 const Contact_Info *c_info,
105 Eina_Bool name_match)
107 Contact_Partial_Match *pm = malloc(sizeof(Contact_Partial_Match));
108 EINA_SAFETY_ON_NULL_RETURN(pm);
111 pm->name_match = name_match;
112 *p_list = eina_list_append(*p_list, pm);
115 static void _partial_number_match_add(Eina_List **p_list, const char *type,
116 const Contact_Info *c_info)
118 _partial_match_add(p_list, type, c_info, EINA_FALSE);
121 static bool _number_partial_search(contact_query_number_s *query, void *data)
123 Partial_Match_Search *pm_search = data;
124 const Contacts *contacts = pm_search->contacts;
128 contact_number_iterator_h it;
129 contact_number_h number_h;
130 Contact_Info *c_info;
133 c_info = eina_hash_find(contacts->hash_ids, &query->contact_db_id);
138 c_info = calloc(1, sizeof(Contact_Info));
139 EINA_SAFETY_ON_NULL_RETURN_VAL(c_info, true);
140 c_info->first_name = eina_stringshare_add(query->first_name);
141 c_info->last_name = eina_stringshare_add(query->last_name);
142 c_info->picture = eina_stringshare_add(query->contact_image_path);
143 c_info->id = query->contact_db_id;
144 if (contact_get_from_db(c_info->id, &tizen_c) != CONTACTS_ERROR_NONE)
147 if (contact_get_number_iterator(tizen_c, &it) !=
151 while (contact_number_iterator_has_next(it)) {
152 if (contact_number_iterator_next(&it, &number_h) !=
155 if (contact_number_get_number(number_h, &n) !=
158 _contact_number_add(n, c_info, number_h);
161 contact_destroy(tizen_c);
164 c_info->contacts = (Contacts *)contacts;
165 eina_hash_add(contacts->hash_ids, &c_info->id, c_info);
166 EINA_INLIST_FOREACH(c_info->numbers, cn)
167 _contact_number_entry_add(cn->number, c_info);
170 type = contact_info_number_check(c_info, query->phone_number);
171 _partial_number_match_add(&pm_search->matches, type,
177 static bool _name_partial_search(contact_query_name_s *query, void *data)
179 Partial_Match_Search *pm_search = data;
180 const Contacts *contacts = pm_search->contacts;
183 contact_number_iterator_h it;
184 contact_number_h number_h;
185 Contact_Info *c_info;
187 Eina_Bool c_info_new = EINA_FALSE;
190 c_info = eina_hash_find(contacts->hash_ids, &query->contact_db_id);
195 c_info = calloc(1, sizeof(Contact_Info));
196 EINA_SAFETY_ON_NULL_RETURN_VAL(c_info, true);
197 c_info->first_name = eina_stringshare_add(query->first_name);
198 c_info->last_name = eina_stringshare_add(query->last_name);
199 c_info->picture = eina_stringshare_add(query->contact_image_path);
200 c_info->id = query->contact_db_id;
201 if (contact_get_from_db(c_info->id, &tizen_c) != CONTACTS_ERROR_NONE)
204 if (contact_get_number_iterator(tizen_c, &it) !=
208 while (contact_number_iterator_has_next(it)) {
209 if (contact_number_iterator_next(&it, &number_h) !=
212 if (contact_number_get_number(number_h, &n) !=
215 _contact_number_add(n, c_info, number_h);
218 contact_destroy(tizen_c);
221 c_info->contacts = (Contacts *)contacts;
222 eina_hash_add(contacts->hash_ids, &c_info->id, c_info);
223 c_info_new = EINA_TRUE;
225 EINA_INLIST_FOREACH(c_info->numbers, cn) {
227 _contact_number_entry_add(cn->number, c_info);
228 _partial_match_add(&pm_search->matches, cn->type, c_info,
234 Eina_List *contact_partial_match_search(Evas_Object *obj, const char *query)
237 const Contacts *contacts;
239 Eina_Bool name_search = EINA_FALSE;
241 Partial_Match_Search pm_search;
243 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
244 EINA_SAFETY_ON_NULL_RETURN_VAL(query, NULL);
245 contacts = evas_object_data_get(obj, "contacts.ctx");
246 EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, NULL);
248 if (!contacts->contacts_on)
251 /* Check if it is numeric */
252 query_number = alloca(strlen(query) + 1);
253 EINA_SAFETY_ON_NULL_RETURN_VAL(query_number, NULL);
254 for (i = 0, j = 0; query[i] != '\0'; i++) {
255 if (isalpha(query[i])) {
256 name_search = EINA_TRUE;
258 } else if (isdigit(query[i]))
259 query_number[j++] = query[i];
262 pm_search.contacts = contacts;
263 pm_search.matches = NULL;
266 if (contact_query_contact_by_name(_name_partial_search, query,
268 ERR("Could not search in contacts DB the name: %s",
273 query_number[j] = '\0';
274 if (contact_query_contact_by_number(_number_partial_search,
277 ERR("Could not search in contacts DB the number: %s",
283 return pm_search.matches;
286 void contact_partial_match_search_free(Eina_List *results)
288 Contact_Partial_Match *pm;
289 EINA_LIST_FREE(results, pm)
293 const char *contact_partial_match_type_get(const Contact_Partial_Match *pm)
295 EINA_SAFETY_ON_NULL_RETURN_VAL(pm, NULL);
299 const Contact_Info *contact_partial_match_info_get(const Contact_Partial_Match *pm)
301 EINA_SAFETY_ON_NULL_RETURN_VAL(pm, NULL);
305 Eina_Bool contact_partial_match_name_match_get(const Contact_Partial_Match *pm)
307 EINA_SAFETY_ON_NULL_RETURN_VAL(pm, EINA_FALSE);
308 return pm->name_match;
311 Eina_List *contact_info_all_numbers_get(const Contact_Info *c)
316 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
318 EINA_INLIST_FOREACH(c->numbers, cn)
319 l = eina_list_append(l, cn->number);
324 static void _contact_number_entry_add(const char *number,
325 Contact_Info *c_info)
327 Contact_Number_Entry *e = eina_hash_find(c_info->contacts->numbers,
330 size_t numberlen = strlen(number);
331 e = calloc(1, sizeof(Contact_Number_Entry) + numberlen + 1);
332 EINA_SAFETY_ON_NULL_RETURN(e);
333 memcpy(e->number, number, numberlen + 1);
334 eina_hash_direct_add(c_info->contacts->numbers, e->number, e);
336 e->contacts = eina_list_append(e->contacts, c_info);
339 static void _contact_number_entry_del(const char *number,
340 Contact_Info *c_info)
342 Eina_Hash *numbers = c_info->contacts->numbers;
343 Contact_Number_Entry *e = eina_hash_find(numbers, number);
344 EINA_SAFETY_ON_NULL_RETURN(e);
345 e->contacts = eina_list_remove(e->contacts, c_info);
348 eina_hash_del_by_key(numbers, e->number);
349 /* hash's free callback will free "e" for me */
352 static Eina_Bool _is_alias(Contact_Number *cn, const char *alias)
354 unsigned int aliaslen = strlen(alias);
355 unsigned int suffix = cn->numberlen - aliaslen;
356 if (cn->numberlen < aliaslen)
359 return memcmp(cn->number + suffix, alias, aliaslen) == 0;
362 static Eina_Bool _contact_number_is_equal(Contact_Number *cn,
365 unsigned int numberlen = strlen(number);
366 if (cn->numberlen == numberlen &&
367 memcmp(cn->number, number, numberlen) == 0)
373 static void _alias_delete(Contact_Number *cn, Contact_Info *c_info)
375 Contact_Number *alias;
376 Eina_List *deleted_list = NULL;
378 EINA_INLIST_FOREACH(c_info->alias, alias) {
379 if (_is_alias(cn, alias->number))
380 deleted_list = eina_list_append(deleted_list, alias);
383 EINA_LIST_FREE(deleted_list, alias) {
384 c_info->alias = eina_inlist_remove(c_info->alias,
385 EINA_INLIST_GET(alias));
386 _contact_number_entry_del(alias->number, c_info);
391 static Eina_Bool _contact_phone_changed(Contact_Info *c_info,
395 Eina_Bool ret = EINA_FALSE;
396 Eina_List *deleted_list = NULL;
398 /* Looking for deleted phones */
399 EINA_INLIST_FOREACH(c_info->numbers, cn) {
400 Eina_Bool deleted = EINA_TRUE;
401 contact_number_iterator_h it;
402 contact_number_h number_h;
404 if (contact_get_number_iterator(contact, &it) !=
407 while (contact_number_iterator_has_next(it)) {
408 if (contact_number_iterator_next(&it, &number_h) !=
411 if (contact_number_get_number(number_h, &number) !=
414 Eina_Bool equal = _contact_number_is_equal(cn, number);
417 deleted = EINA_FALSE;
423 _contact_number_entry_del(cn->number, c_info);
424 deleted_list = eina_list_append(deleted_list, cn);
428 contact_number_iterator_h it;
429 if (contact_get_number_iterator(contact, &it) != CONTACTS_ERROR_NONE)
432 /* Looking for new phones */
433 while (contact_number_iterator_has_next(it)) {
434 Eina_Bool added = EINA_TRUE;
435 contact_number_h number_h;
437 if (contact_number_iterator_next(&it, &number_h) !=
440 if (contact_number_get_number(number_h, &number) !=
443 EINA_INLIST_FOREACH(c_info->numbers, cn) {
444 if (_contact_number_is_equal(cn, number)) {
450 _contact_number_add(number, c_info, number_h);
454 EINA_LIST_FREE(deleted_list, cn) {
455 c_info->numbers = eina_inlist_remove(c_info->numbers,
456 EINA_INLIST_GET(cn));
457 _alias_delete(cn, c_info);
464 static void _contact_info_on_del_dispatch(Contact_Info *c)
466 Eina_Inlist *lst = c->on_del_cbs;
467 c->on_del_cbs = NULL; /* avoid contact_info_on_del_callback_del() */
469 Contact_Info_On_Del_Ctx *ctx = EINA_INLIST_CONTAINER_GET
470 (lst, Contact_Info_On_Del_Ctx);
472 lst = eina_inlist_remove(lst, lst);
474 ctx->cb((void *)ctx->data, c);
479 static void _contact_info_on_changed_dispatch(Contact_Info *c)
481 Contact_Info_On_Changed_Ctx *ctx;
483 c->on_changed_cbs.walking++;
484 EINA_INLIST_FOREACH(c->on_changed_cbs.listeners, ctx) {
487 ctx->cb((void *)ctx->data, c);
489 c->on_changed_cbs.walking--;
491 if (c->on_changed_cbs.walking <= 0) {
492 EINA_LIST_FREE(c->on_changed_cbs.deleted, ctx) {
493 c->on_changed_cbs.listeners = eina_inlist_remove(
494 c->on_changed_cbs.listeners,
495 EINA_INLIST_GET(ctx));
501 static Eina_Bool _hash_foreach(const Eina_Hash *hash __UNUSED__,
502 const void *key __UNUSED__, void *data,
505 Eina_List **deleted = fdata;
506 Eina_Bool disp = EINA_FALSE;
507 Contact_Info *c_info = data;
508 contact_h contact = NULL;
509 contact_name_h name_h = NULL;
510 char *f_name = NULL, *l_name = NULL, *img = NULL;
512 contact_get_from_db(c_info->id, &contact);
513 /* Contact no longer exists. */
516 contact_get_name(contact, &name_h);
517 EINA_SAFETY_ON_NULL_GOTO(name_h, err_contact);
519 contact_name_get_detail(name_h, CONTACT_NAME_DETAIL_FIRST, &f_name);
520 contact_name_get_detail(name_h, CONTACT_NAME_DETAIL_LAST, &l_name);
521 contact_get_image(contact, &img);
523 if (eina_stringshare_replace(&c_info->first_name, f_name)) {
525 eina_stringshare_del(c_info->full_name);
526 c_info->full_name = NULL;
529 if (eina_stringshare_replace(&c_info->last_name, l_name)) {
531 eina_stringshare_del(c_info->full_name);
532 c_info->full_name = NULL;
535 disp |= eina_stringshare_replace(&c_info->picture, img);
537 disp |= _contact_phone_changed(c_info, contact);
540 _contact_info_on_changed_dispatch(c_info);
546 contact_destroy(contact);
550 *deleted = eina_list_append(*deleted, c_info);
554 static void _contact_db_changed(void *data)
556 Contacts *contacts = data;
557 Contact_Info *c_info;
558 Eina_List *deleted = NULL;
560 EINA_SAFETY_ON_NULL_RETURN(contacts);
561 eina_hash_foreach(contacts->hash_ids, _hash_foreach, &deleted);
563 EINA_LIST_FREE(deleted, c_info) {
565 /* _contact_info_free() will free the lists for me */
566 EINA_INLIST_FOREACH(c_info->alias, cn)
567 _contact_number_entry_del(cn->number, c_info);
568 EINA_INLIST_FOREACH(c_info->numbers, cn)
569 _contact_number_entry_del(cn->number, c_info);
570 eina_hash_del_by_key(contacts->hash_ids, &c_info->id);
574 static void _contact_number_add(char *number,
575 Contact_Info *c_info,
576 contact_number_h number_h)
578 unsigned int numberlen = strlen(number);
579 Contact_Number *cn = malloc(sizeof(Contact_Number) + numberlen + 1);
580 EINA_SAFETY_ON_NULL_RETURN(cn);
581 memcpy(cn->number, number, numberlen);
582 cn->numberlen = numberlen;
583 cn->number[numberlen] = '\0';
584 cn->type = phone_type_get(number_h);
585 c_info->numbers = eina_inlist_append(c_info->numbers,
586 EINA_INLIST_GET(cn));
589 bool _search_cb(contact_query_number_s *query, void *data)
591 Contact_Info **c_info = data;
594 contact_number_iterator_h it;
595 contact_number_h number_h;
597 *c_info = calloc(1, sizeof(Contact_Info));
598 EINA_SAFETY_ON_NULL_RETURN_VAL((*c_info), false);
599 (*c_info)->first_name = eina_stringshare_add(query->first_name);
600 (*c_info)->last_name = eina_stringshare_add(query->last_name);
601 (*c_info)->picture = eina_stringshare_add(query->contact_image_path);
602 (*c_info)->id = query->contact_db_id;
603 if (contact_get_from_db((*c_info)->id, &tizen_c) != CONTACTS_ERROR_NONE)
606 if (contact_get_number_iterator(tizen_c, &it) !=
610 while (contact_number_iterator_has_next(it)) {
611 if (contact_number_iterator_next(&it, &number_h) !=
614 if (contact_number_get_number(number_h, &n) !=
617 _contact_number_add(n, (*c_info), number_h);
620 contact_destroy(tizen_c);
624 static const char *phone_type_get(contact_number_h number)
626 contact_number_type_e type_e;
628 if (contact_number_get_type(number, &type_e) < 0)
632 case CONTACT_NUMBER_TYPE_NONE:
634 case CONTACT_NUMBER_TYPE_HOME:
636 case CONTACT_NUMBER_TYPE_WORK:
638 case CONTACT_NUMBER_TYPE_VOICE:
640 case CONTACT_NUMBER_TYPE_FAX:
642 case CONTACT_NUMBER_TYPE_MSG:
644 case CONTACT_NUMBER_TYPE_CELL:
646 case CONTACT_NUMBER_TYPE_PAGER:
648 case CONTACT_NUMBER_TYPE_BBS:
649 return "Bulletin board";
650 case CONTACT_NUMBER_TYPE_MODEM:
652 case CONTACT_NUMBER_TYPE_CAR:
654 case CONTACT_NUMBER_TYPE_ISDN:
656 case CONTACT_NUMBER_TYPE_VIDEO:
657 return "Video conference";
658 case CONTACT_NUMBER_TYPE_PCS:
659 return "Personal communicatior";
660 case CONTACT_NUMBER_TYPE_ASSISTANT:
661 return "Assistant telephone";
662 case CONTACT_NUMBER_TYPE_CUSTOM:
669 static const char *_alias_phone_type_match(Contact_Info *c_info,
673 EINA_INLIST_FOREACH(c_info->numbers, cn) {
674 if (_is_alias(cn, alias))
680 static Eina_Bool _alias_create(Contact_Info *c_info, const char *number)
682 unsigned int numberlen = strlen(number);
683 Contact_Number *cn = malloc(sizeof(Contact_Number) + numberlen + 1);
684 EINA_SAFETY_ON_NULL_RETURN_VAL(cn, EINA_FALSE);
685 memcpy(cn->number, number, numberlen);
686 cn->numberlen = numberlen;
687 cn->number[numberlen] = '\0';
688 cn->type = _alias_phone_type_match(c_info, number);
689 c_info->alias = eina_inlist_append(
690 c_info->alias, EINA_INLIST_GET(cn));
691 _contact_number_entry_add(cn->number, c_info);
695 Contact_Info *contact_search(Evas_Object *obj, const char *number,
698 Contact_Info *c_info = NULL, *found;
700 Contact_Number_Entry *entry;
702 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
703 EINA_SAFETY_ON_NULL_RETURN_VAL(number, NULL);
704 contacts = evas_object_data_get(obj, "contacts.ctx");
705 EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, NULL);
707 if (!contacts->contacts_on)
710 entry = eina_hash_find(contacts->numbers, number);
713 c_info = eina_list_data_get(entry->contacts);
714 EINA_SAFETY_ON_NULL_RETURN_VAL(c_info, NULL);
718 if (contact_query_contact_by_number(_search_cb, number, &c_info) < 0) {
719 ERR("Could not fetch phone number: %s from DB", number);
726 /* Do we have this contact already ? */
727 found = eina_hash_find(contacts->hash_ids, &c_info->id);
730 _contact_info_free(c_info);
732 /* The user enterer an alias */
734 r = _alias_create(c_info, number);
735 EINA_SAFETY_ON_FALSE_RETURN_VAL(r, NULL);
738 c_info->contacts = contacts;
739 eina_hash_add(contacts->hash_ids, &c_info->id, c_info);
741 EINA_INLIST_FOREACH(c_info->numbers, cn)
742 _contact_number_entry_add(cn->number, c_info);
747 *type = contact_info_number_check(c_info, number);
751 const char *contact_info_picture_get(const Contact_Info *c)
753 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
757 const char *contact_info_full_name_get(const Contact_Info *c)
760 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
762 c2 = (Contact_Info *)c;
763 c2->full_name = eina_stringshare_printf("%s %s", c->first_name,
769 const char *contact_info_first_name_get(const Contact_Info *c)
771 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
772 return c->first_name;
775 const char *contact_info_last_name_get(const Contact_Info *c)
777 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
781 const char *contact_info_detail_get(const Contact_Info *c,
784 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
785 EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL);
787 /* Do not check in the alias list. Because here we want in fact a
790 EINA_INLIST_FOREACH(c->numbers, cn) {
791 if (strcmp(cn->type, type) == 0)
797 const char *contact_info_number_check(const Contact_Info *c,
800 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
801 EINA_SAFETY_ON_NULL_RETURN_VAL(number, NULL);
804 EINA_INLIST_FOREACH(c->numbers, cn) {
805 if (_contact_number_is_equal(cn, number))
808 /* It could be an alias */
809 EINA_INLIST_FOREACH(c->alias, cn) {
810 if (_contact_number_is_equal(cn, number))
816 Eina_Bool contact_info_picture_set(Contact_Info *c __UNUSED__,
817 const char *filename __UNUSED__)
823 Eina_Bool contact_info_first_name_set(Contact_Info *c __UNUSED__,
824 const char *name __UNUSED__)
830 Eina_Bool contact_info_last_name_set(Contact_Info *c __UNUSED__,
831 const char *name __UNUSED__)
837 Eina_Bool contact_info_detail_set(Contact_Info *c __UNUSED__,
838 const char *type __UNUSED__,
839 const char *number __UNUSED__)
845 void contact_info_on_changed_callback_add(Contact_Info *c,
846 void (*cb)(void *data, Contact_Info *c),
849 Contact_Info_On_Changed_Ctx *ctx;
851 EINA_SAFETY_ON_NULL_RETURN(c);
852 EINA_SAFETY_ON_NULL_RETURN(cb);
854 ctx = calloc(1, sizeof(Contact_Info_On_Changed_Ctx));
855 EINA_SAFETY_ON_NULL_RETURN(ctx);
859 c->on_changed_cbs.listeners = eina_inlist_append(
860 c->on_changed_cbs.listeners, EINA_INLIST_GET(ctx));
863 void contact_info_on_changed_callback_del(Contact_Info *c,
864 void (*cb)(void *data, Contact_Info *c),
868 Contact_Info_On_Changed_Ctx *ctx, *found = NULL;
869 EINA_SAFETY_ON_NULL_RETURN(c);
870 EINA_SAFETY_ON_NULL_RETURN(cb);
872 EINA_INLIST_FOREACH(c->on_changed_cbs.listeners, ctx) {
873 if (ctx->cb == cb && ctx->data == data) {
882 if (c->on_changed_cbs.walking > 0) {
883 found->deleted = EINA_TRUE;
884 c->on_changed_cbs.deleted = eina_list_append(
885 c->on_changed_cbs.deleted, found);
889 c->on_changed_cbs.listeners = eina_inlist_remove(
890 c->on_changed_cbs.listeners, EINA_INLIST_GET(found));
894 void contact_info_on_del_callback_add(Contact_Info *c,
895 void (*cb)(void *data, const Contact_Info *c),
899 Contact_Info_On_Del_Ctx *ctx;
901 EINA_SAFETY_ON_NULL_RETURN(c);
902 EINA_SAFETY_ON_NULL_RETURN(cb);
904 ctx = calloc(1, sizeof(Contact_Info_On_Del_Ctx));
905 EINA_SAFETY_ON_NULL_RETURN(ctx);
909 c->on_del_cbs = eina_inlist_append(c->on_del_cbs, EINA_INLIST_GET(ctx));
912 void contact_info_on_del_callback_del(Contact_Info *c,
913 void (*cb)(void *data, const Contact_Info *c),
917 Contact_Info_On_Del_Ctx *ctx, *found = NULL;
918 EINA_SAFETY_ON_NULL_RETURN(c);
919 EINA_SAFETY_ON_NULL_RETURN(cb);
921 EINA_INLIST_FOREACH(c->on_del_cbs, ctx) {
922 if (ctx->cb == cb && ctx->data == data) {
931 c->on_del_cbs = eina_inlist_remove(c->on_del_cbs,
932 EINA_INLIST_GET(found));
937 void contact_info_del(Contact_Info *c_info __UNUSED__)
942 static void _contacts_ug_layout_create(struct ui_gadget *ug,
943 enum ug_mode mode __UNUSED__,
946 Contacts *contacts = priv;
947 EINA_SAFETY_ON_NULL_RETURN(ug);
948 elm_object_part_content_set(contacts->self, "elm.swallow.genlist",
952 static void _contact_info_free(Contact_Info *c_info)
955 _contact_info_on_del_dispatch(c_info);
956 EINA_SAFETY_ON_FALSE_RETURN(c_info->on_changed_cbs.walking == 0);
958 if (c_info->on_changed_cbs.deleted) {
959 ERR("contact still have changed deleted listeners: %p %s %s",
960 c_info, c_info->first_name, c_info->last_name);
961 eina_list_free(c_info->on_changed_cbs.deleted);
964 if (c_info->on_changed_cbs.listeners) {
965 while (c_info->on_changed_cbs.listeners) {
966 Contact_Info_On_Changed_Ctx *ctx;
968 ctx = EINA_INLIST_CONTAINER_GET(
969 c_info->on_changed_cbs.listeners,
970 Contact_Info_On_Changed_Ctx);
971 c_info->on_changed_cbs.listeners = eina_inlist_remove
972 (c_info->on_changed_cbs.listeners,
973 c_info->on_changed_cbs.listeners);
978 while (c_info->numbers) {
979 cn = EINA_INLIST_CONTAINER_GET(c_info->numbers,
981 c_info->numbers = eina_inlist_remove(c_info->numbers,
986 while (c_info->alias) {
987 cn = EINA_INLIST_CONTAINER_GET(c_info->alias,
989 c_info->alias = eina_inlist_remove(c_info->alias,
994 eina_stringshare_del(c_info->first_name);
995 eina_stringshare_del(c_info->last_name);
996 eina_stringshare_del(c_info->full_name);
997 eina_stringshare_del(c_info->picture);
1001 void _hash_elements_free(void *data)
1003 Contact_Info *c = data;
1004 _contact_info_free(c);
1007 void _numbers_hash_elements_free(void *data)
1009 Contact_Number_Entry *e = data;
1010 /*Contact_Info will be deleted by hash_ids */
1011 eina_list_free(e->contacts);
1015 static void _on_del(void *data, Evas *e __UNUSED__,
1016 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
1018 Contacts *contacts = data;
1019 eina_hash_free(contacts->hash_ids);
1020 eina_hash_free(contacts->numbers);
1021 ug_destroy(contacts->ug_all);
1022 if (contacts->reconnect)
1023 ecore_timer_del(contacts->reconnect);
1025 contacts_disconnect();
1028 static void _create_contacts_ug(Contacts *contacts)
1032 struct ui_gadget *ug;
1035 cbs.priv = contacts;
1036 cbs.layout_cb = _contacts_ug_layout_create;
1037 cbs.result_cb = NULL;
1038 cbs.destroy_cb = NULL;
1040 bd = bundle_create();
1041 EINA_SAFETY_ON_NULL_RETURN(bd);
1043 snprintf(buf, sizeof(buf), "%d", CT_UG_REQUEST_DETAIL);
1044 bundle_add(bd, CT_UG_BUNDLE_TYPE, buf);
1045 snprintf(buf, sizeof(buf), "%d", 1);
1046 bundle_add(bd, CT_UG_BUNDLE_ID, buf);
1048 ug = ug_create(NULL, UG_CONTACTS_LIST, UG_MODE_FRAMEVIEW, bd, &cbs);
1049 EINA_SAFETY_ON_NULL_GOTO(ug, err_ug);
1051 contacts->ug_all = ug;
1052 evas_object_data_set(contacts->self, "contacts.ctx", contacts);
1058 static Eina_Bool _contacts_reconnect(void *data)
1060 Contacts *contacts = data;
1062 if (contacts_connect() != CONTACTS_ERROR_NONE)
1063 return ECORE_CALLBACK_RENEW;
1065 contacts->contacts_on = EINA_TRUE;
1066 contacts->reconnect = NULL;
1067 contacts_add_contact_db_changed_cb(_contact_db_changed, contacts);
1068 _create_contacts_ug(contacts);
1069 return ECORE_CALLBACK_DONE;
1072 Evas_Object *contacts_add(Evas_Object *parent)
1076 contacts = calloc(1, sizeof(Contacts));
1077 EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, NULL);
1078 contacts->self = layout_add(parent, "contacts_bg");
1079 EINA_SAFETY_ON_NULL_GOTO(contacts->self, err_layout);
1080 evas_object_event_callback_add(contacts->self, EVAS_CALLBACK_DEL,
1083 if (contacts_connect() != CONTACTS_ERROR_NONE) {
1084 WRN("Could not connect to the contacts DB");
1085 contacts->contacts_on = EINA_FALSE;
1086 contacts->reconnect = ecore_timer_add(1.0, _contacts_reconnect,
1089 contacts_add_contact_db_changed_cb(_contact_db_changed,
1091 contacts->contacts_on = EINA_TRUE;
1092 _create_contacts_ug(contacts);
1095 contacts->numbers = eina_hash_string_superfast_new(
1096 _numbers_hash_elements_free);
1097 EINA_SAFETY_ON_NULL_GOTO(contacts->numbers, err_hash);
1099 contacts->hash_ids = eina_hash_int32_new(_hash_elements_free);
1100 EINA_SAFETY_ON_NULL_GOTO(contacts->hash_ids, err_hash_id);
1102 return contacts->self;
1105 eina_hash_free(contacts->numbers);
1107 evas_object_del(contacts->self);
1108 if (contacts->reconnect)
1109 ecore_timer_del(contacts->reconnect);