Add contact feature
[platform/core/pim/contacts-service.git] / common / ctsvc_list.c
1 /*
2  * Contacts Service
3  *
4  * Copyright (c) 2010 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19 #include <glib.h>
20
21 #include "contacts.h"
22 #include "ctsvc_internal.h"
23 #include "ctsvc_list.h"
24 #include "ctsvc_record.h"
25
26 EXPORT_API int contacts_list_create(contacts_list_h *out_list)
27 {
28         CHECK_CONTACT_SUPPORTED(CONTACT_FEATURE);
29         ctsvc_list_s *list_s;
30
31         RETV_IF(NULL == out_list, CONTACTS_ERROR_INVALID_PARAMETER);
32         *out_list = NULL;
33
34         list_s = calloc(1, sizeof(ctsvc_list_s));
35         RETVM_IF(NULL == list_s, CONTACTS_ERROR_OUT_OF_MEMORY, "calloc() Fail");
36
37         list_s->l_type = -1;
38         *out_list = (contacts_list_h)list_s;
39         return CONTACTS_ERROR_NONE;
40 }
41
42 EXPORT_API int contacts_list_get_count(contacts_list_h list, int *count)
43 {
44         CHECK_CONTACT_SUPPORTED(CONTACT_FEATURE);
45         ctsvc_list_s *list_s;
46
47         RETV_IF(NULL == count, CONTACTS_ERROR_INVALID_PARAMETER);
48         *count = 0;
49
50         RETV_IF(NULL == list, CONTACTS_ERROR_INVALID_PARAMETER);
51         list_s = (ctsvc_list_s*)list;
52
53         *count = list_s->count;
54         return CONTACTS_ERROR_NONE;
55 }
56
57 int ctsvc_list_add_child(contacts_list_h list, contacts_record_h child_record)
58 {
59         ctsvc_list_s *s_list;
60         ctsvc_record_s *s_record;
61
62         RETV_IF(NULL == list || NULL == child_record, CONTACTS_ERROR_INVALID_PARAMETER);
63         s_list = (ctsvc_list_s*)list;
64         s_record = (ctsvc_record_s*)child_record;
65
66         if (-1 == s_list->l_type)
67                 s_list->l_type = s_record->r_type;
68         else if (s_list->l_type != s_record->r_type)
69                 return CONTACTS_ERROR_INVALID_PARAMETER;
70
71         s_list->records = g_list_append(s_list->records, child_record);
72
73         if (s_list->count == 0)
74                 s_list->cursor = s_list->records;
75
76         s_list->count++;
77         return CONTACTS_ERROR_NONE;
78 }
79
80 EXPORT_API int contacts_list_add(contacts_list_h list, contacts_record_h child_record)
81 {
82         CHECK_CONTACT_SUPPORTED(CONTACT_FEATURE);
83         ctsvc_list_s *s_list;
84         ctsvc_record_s *s_record;
85
86         RETV_IF(NULL == list || NULL == child_record, CONTACTS_ERROR_INVALID_PARAMETER);
87         s_list = (ctsvc_list_s*)list;
88         s_record = (ctsvc_record_s*)child_record;
89
90         if (-1 == s_list->l_type)
91                 s_list->l_type = s_record->r_type;
92         else if (s_list->l_type != s_record->r_type)
93                 return CONTACTS_ERROR_INVALID_PARAMETER;
94
95         s_list->records = g_list_append(s_list->records, child_record);
96
97         if (s_list->count == 0)
98                 s_list->cursor = s_list->records;
99
100         s_list->count++;
101         return CONTACTS_ERROR_NONE;
102 }
103
104 int ctsvc_list_prepend(contacts_list_h list, contacts_record_h child_record)
105 {
106         ctsvc_list_s *s_list;
107         ctsvc_record_s *s_record;
108
109         RETV_IF(NULL == list || NULL == child_record, CONTACTS_ERROR_INVALID_PARAMETER);
110         s_list = (ctsvc_list_s*)list;
111         s_record = (ctsvc_record_s*)child_record;
112
113         if (-1 == s_list->l_type)
114                 s_list->l_type = s_record->r_type;
115         else if (s_list->l_type != s_record->r_type)
116                 return CONTACTS_ERROR_INVALID_PARAMETER;
117
118         s_list->records = g_list_prepend(s_list->records, child_record);
119
120         if (s_list->count == 0)
121                 s_list->cursor = s_list->records;
122
123         s_list->count++;
124         return CONTACTS_ERROR_NONE;
125 }
126
127 int ctsvc_list_reverse(contacts_list_h list)
128 {
129         ctsvc_list_s *s_list;
130
131         RETV_IF(NULL == list, CONTACTS_ERROR_INVALID_PARAMETER);
132         s_list = (ctsvc_list_s*)list;
133
134         if (s_list->count != 0)
135                 s_list->records =  g_list_reverse(s_list->records);
136
137         return CONTACTS_ERROR_NONE;
138 }
139
140 int ctsvc_list_remove_child(contacts_list_h list, contacts_record_h record,
141                 bool insert_delete_list)
142 {
143         GList *cursor = NULL;
144         ctsvc_list_s *s_list;
145         ctsvc_record_s *s_record;
146         contacts_record_h delete_record;
147         contacts_error_e err = CONTACTS_ERROR_NONE;
148
149         RETV_IF(NULL == list || NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
150         s_list = (ctsvc_list_s*)list;
151         s_record = (ctsvc_record_s*)record;
152
153         if (s_list->l_type != s_record->r_type)
154                 return CONTACTS_ERROR_INVALID_PARAMETER;
155
156         for (cursor = s_list->records; cursor; cursor = cursor->next) {
157                 ctsvc_record_s *data = cursor->data;
158                 if (data == s_record) {
159                         s_list->count--;
160                         if (s_list->cursor == cursor)
161                                 s_list->cursor = cursor->next;
162
163                         s_list->records = g_list_remove(s_list->records, s_record);
164                         if (insert_delete_list) {
165                                 err = contacts_record_clone(record, &delete_record);
166                                 if (CONTACTS_ERROR_NONE != err) {
167                                         /* LCOV_EXCL_START */
168                                         ERR("contacts_record_clone() Fail(%d)", err);
169                                         return err;
170                                         /* LCOV_EXCL_STOP */
171                                 }
172
173                                 s_list->deleted_records = g_list_append(s_list->deleted_records, delete_record);
174                         }
175                         return CONTACTS_ERROR_NONE;
176                 }
177         }
178
179         return CONTACTS_ERROR_NO_DATA;
180 }
181
182 EXPORT_API int contacts_list_remove(contacts_list_h list, contacts_record_h record)
183 {
184         CHECK_CONTACT_SUPPORTED(CONTACT_FEATURE);
185         GList *cursor = NULL;
186         ctsvc_list_s *s_list;
187         ctsvc_record_s *s_record;
188
189         RETV_IF(NULL == list || NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
190         s_list = (ctsvc_list_s*)list;
191         s_record = (ctsvc_record_s*)record;
192
193         if (s_list->l_type != s_record->r_type)
194                 return CONTACTS_ERROR_INVALID_PARAMETER;
195
196         for (cursor = s_list->records; cursor; cursor = cursor->next) {
197                 ctsvc_record_s *data = cursor->data;
198                 if (data == s_record) {
199                         s_list->count--;
200                         if (s_list->cursor == cursor)
201                                 s_list->cursor = cursor->next;
202                         s_list->records = g_list_remove(s_list->records, s_record);
203                         return CONTACTS_ERROR_NONE;
204                 }
205         }
206
207         return CONTACTS_ERROR_NO_DATA;
208 }
209
210 EXPORT_API int contacts_list_get_current_record_p(contacts_list_h list, contacts_record_h *record)
211 {
212         CHECK_CONTACT_SUPPORTED(CONTACT_FEATURE);
213         ctsvc_list_s *list_s;
214
215         RETV_IF(NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
216         *record = NULL;
217
218         RETV_IF(NULL == list || NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
219         list_s = (ctsvc_list_s*)list;
220
221         if (NULL == list_s->cursor) {
222                 *record = NULL;
223                 return CONTACTS_ERROR_NO_DATA;
224         }
225
226         *record = list_s->cursor->data;
227
228         return CONTACTS_ERROR_NONE;
229 }
230
231 int ctsvc_list_get_nth_record_p(contacts_list_h list, int index, contacts_record_h *record)
232 {
233         GList *cursor = NULL;
234         ctsvc_list_s *list_s;
235         int i, j;
236
237         RETV_IF(NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
238         *record = NULL;
239
240         RETV_IF(NULL == list || NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
241         list_s = (ctsvc_list_s*)list;
242
243         for (i = 0, j = 0, cursor = list_s->records; cursor; cursor = cursor->next, i++) {
244                 if (j == index) {
245                         *record = cursor->data;
246                         return CONTACTS_ERROR_NONE;
247                 }
248                 j++;
249         }
250         *record = NULL;
251         return CONTACTS_ERROR_NO_DATA;
252 }
253
254 static int __ctsvc_list_move_cursor(contacts_list_h list, bool next)
255 {
256         ctsvc_list_s *list_s;
257
258         RETV_IF(NULL == list, CONTACTS_ERROR_INVALID_PARAMETER);
259         list_s = (ctsvc_list_s*)list;
260
261         if (NULL == list_s->cursor)
262                 return CONTACTS_ERROR_NO_DATA;
263
264         list_s->cursor = next ? list_s->cursor->next : list_s->cursor->prev ;
265
266         if (NULL == list_s->cursor)
267                 return CONTACTS_ERROR_NO_DATA;
268
269         return CONTACTS_ERROR_NONE;
270 }
271
272 EXPORT_API int contacts_list_prev(contacts_list_h list)
273 {
274         CHECK_CONTACT_SUPPORTED(CONTACT_FEATURE);
275         return __ctsvc_list_move_cursor(list, false);
276 }
277
278 EXPORT_API int contacts_list_next(contacts_list_h list)
279 {
280         CHECK_CONTACT_SUPPORTED(CONTACT_FEATURE);
281         return __ctsvc_list_move_cursor(list, true);
282 }
283
284
285
286 EXPORT_API int contacts_list_first(contacts_list_h list)
287 {
288         CHECK_CONTACT_SUPPORTED(CONTACT_FEATURE);
289         ctsvc_list_s *list_s;
290
291         RETV_IF(NULL == list, CONTACTS_ERROR_INVALID_PARAMETER);
292         list_s = (ctsvc_list_s*)list;
293
294         list_s->cursor = list_s->records;
295         if (NULL == list_s->cursor)
296                 return CONTACTS_ERROR_NO_DATA;
297
298         return CONTACTS_ERROR_NONE;
299 }
300
301 EXPORT_API int contacts_list_last(contacts_list_h list)
302 {
303         CHECK_CONTACT_SUPPORTED(CONTACT_FEATURE);
304         ctsvc_list_s *list_s;
305
306         RETV_IF(NULL == list, CONTACTS_ERROR_INVALID_PARAMETER);
307         list_s = (ctsvc_list_s*)list;
308
309         list_s->cursor = g_list_last(list_s->records);
310         if (NULL == list_s->cursor)
311                 return CONTACTS_ERROR_NO_DATA;
312
313         return CONTACTS_ERROR_NONE;
314 }
315
316 EXPORT_API int contacts_list_destroy(contacts_list_h list, bool delete_child)
317 {
318         CHECK_CONTACT_SUPPORTED(CONTACT_FEATURE);
319         ctsvc_list_s *s_list;
320         GList *cursor = NULL;
321
322         RETV_IF(NULL == list, CONTACTS_ERROR_INVALID_PARAMETER);
323
324         s_list = (ctsvc_list_s*)list;
325
326         if (delete_child) {
327                 for (cursor = s_list->records; cursor; cursor = cursor->next)
328                         contacts_record_destroy((contacts_record_h)(cursor->data), true);
329         }
330         g_list_free(s_list->records);
331
332         for (cursor = s_list->deleted_records; cursor; cursor = cursor->next)
333                 contacts_record_destroy((contacts_record_h)(cursor->data), true);
334         g_list_free(s_list->deleted_records);
335
336         free(s_list);
337         return CONTACTS_ERROR_NONE;
338 }
339
340 int ctsvc_list_clone(contacts_list_h list, contacts_list_h *out_list)
341 {
342         ctsvc_list_s *list_s;
343         contacts_record_h new_record;
344         contacts_list_h new_list;
345         GList *cursor = NULL;
346         contacts_error_e err = CONTACTS_ERROR_NONE;
347
348         RETV_IF(NULL == list, CONTACTS_ERROR_INVALID_PARAMETER);
349
350         list_s = (ctsvc_list_s*)list;
351
352         contacts_list_create(&new_list);
353         for (cursor = list_s->records; cursor; cursor = cursor->next) {
354                 err = contacts_record_clone(cursor->data, &new_record);
355                 if (CONTACTS_ERROR_NONE != err) {
356                         /* LCOV_EXCL_START */
357                         ERR("contacts_record_clone() Fail(%d)", err);
358                         contacts_list_destroy(new_list, true);
359                         return err;
360                         /* LCOV_EXCL_STOP */
361                 }
362                 ctsvc_list_prepend(new_list, new_record);
363         }
364         ctsvc_list_reverse(new_list);
365
366         for (cursor = list_s->deleted_records; cursor; cursor = cursor->next) {
367                 err = contacts_record_clone(cursor->data, &new_record);
368                 if (CONTACTS_ERROR_NONE != err) {
369                         /* LCOV_EXCL_START */
370                         ERR("contacts_record_clone() Fail(%d)", err);
371                         contacts_list_destroy(new_list, true);
372                         return err;
373                         /* LCOV_EXCL_STOP */
374                 }
375                 ((ctsvc_list_s*)new_list)->deleted_records
376                         = g_list_prepend(((ctsvc_list_s*)new_list)->deleted_records, new_record);
377         }
378         if (((ctsvc_list_s*)new_list)->deleted_records) {
379                 ((ctsvc_list_s*)new_list)->deleted_records
380                         = g_list_reverse(((ctsvc_list_s*)new_list)->deleted_records);
381         }
382
383         *out_list = new_list;
384
385         return CONTACTS_ERROR_NONE;
386 }
387
388
389 int ctsvc_list_get_deleted_count(contacts_list_h list, unsigned int *count)
390 {
391         ctsvc_list_s *list_s;
392
393         RETV_IF(NULL == count, CONTACTS_ERROR_INVALID_PARAMETER);
394         *count = 0;
395
396         RETV_IF(NULL == list, CONTACTS_ERROR_INVALID_PARAMETER);
397         list_s = (ctsvc_list_s*)list;
398
399         if (NULL == list_s->deleted_records)
400                 return CONTACTS_ERROR_NONE;
401
402         *count = g_list_length(list_s->deleted_records);
403
404         return CONTACTS_ERROR_NONE;
405 }
406
407 int ctsvc_list_get_deleted_nth_record_p(contacts_list_h list, int index,
408                 contacts_record_h *record)
409 {
410         ctsvc_list_s *list_s;
411
412         RETV_IF(NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
413         *record = NULL;
414
415         RETV_IF(NULL == list || NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
416         list_s = (ctsvc_list_s*)list;
417
418         RETV_IF(NULL == list_s->deleted_records, CONTACTS_ERROR_NO_DATA);
419
420         *record = (contacts_record_h)g_list_nth_data(list_s->deleted_records, index);
421
422         return CONTACTS_ERROR_NONE;
423 }
424
425 int ctsvc_list_append_deleted_record(contacts_list_h list, contacts_record_h record)
426 {
427         ctsvc_list_s *list_s;
428
429         RETV_IF(NULL == list || NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
430
431         list_s = (ctsvc_list_s*)list;
432
433         list_s->deleted_records = g_list_append(list_s->deleted_records, record);
434
435         return CONTACTS_ERROR_NONE;
436 }