add comment LCOV_EXCL
[platform/core/pim/calendar-service.git] / common / cal_vcalendar.c
1 /*
2  * Calendar Service
3  *
4  * Copyright (c) 2012 - 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
20 #include <stdlib.h>
21
22 #include "calendar_vcalendar.h"
23 #include "cal_internal.h"
24 #include "cal_typedef.h"
25 #include "cal_record.h"
26 #include "cal_view.h"
27 #include "cal_time.h"
28 #include "cal_list.h"
29 #include "cal_vcalendar.h"
30 #include "cal_vcalendar_make.h"
31 #include "cal_vcalendar_parse.h"
32
33 #define ICALENAR_BUFFER_MAX (1024*1024)
34
35 /*
36  * vcalendar should not have multi version: ver1.0 or 2.0 only.
37  * could have multi timezone events: MULTI BEGIN:VCALENDAR.
38  */
39 API int calendar_vcalendar_make_from_records(calendar_list_h list, char **vcalendar_stream)
40 {
41         int ret;
42         cal_make_s *b;
43         char *ical = NULL;
44
45         RETV_IF(NULL == list, CALENDAR_ERROR_INVALID_PARAMETER);
46         RETV_IF(NULL == vcalendar_stream, CALENDAR_ERROR_INVALID_PARAMETER);
47
48         b = cal_vcalendar_make_new();
49         RETVM_IF(!b, CALENDAR_ERROR_OUT_OF_MEMORY,
50                         "cal_vcalendar_make_new() Fail");
51
52         ret = cal_vcalendar_make_vcalendar(b, list);
53
54         if (ret < 0) {
55                 cal_vcalendar_make_free(&b);
56                 return ret;
57         }
58
59         ical = cal_vcalendar_make_get_data(b);
60         cal_vcalendar_make_free(&b);
61
62         if (!ical) {
63                 /* LCOV_EXCL_START */
64                 ERR("cal_vcalendar_make_get_data() Fail");
65                 return CALENDAR_ERROR_OUT_OF_MEMORY;
66                 /* LCOV_EXCL_STOP */
67         }
68
69         if (!*ical) {
70                 /* LCOV_EXCL_START */
71                 ERR("No ical data");
72                 free(ical);
73                 return CALENDAR_ERROR_NO_DATA;
74                 /* LCOV_EXCL_STOP */
75         }
76
77         *vcalendar_stream = ical;
78
79         return CALENDAR_ERROR_NONE;
80 }
81
82 static const char* __calendar_vcalendar_get_vcalendar_object(const char *original, char **pvcalendar_object)
83 {
84         int len = 0;
85         const char *vcal_start = original;
86         const char *vcal_cursor = NULL;
87         bool new_line = false;
88         char *vcalendar_object = NULL;
89
90         RETV_IF(NULL == pvcalendar_object, original);
91         *pvcalendar_object = NULL;
92
93         while ('\n' == *vcal_start || '\r' == *vcal_start)
94                 vcal_start++;
95
96         if (strncmp(vcal_start, "BEGIN:VCALENDAR", strlen("BEGIN:VCALENDAR")))
97                 return vcal_start;
98
99         vcal_start += strlen("BEGIN:VCALENDAR");
100         while ('\n' == *vcal_start || '\r' == *vcal_start)
101                 vcal_start++;
102         vcal_cursor = vcal_start;
103
104         while (*vcal_cursor) {
105                 if (new_line) {
106                         if (CAL_STRING_EQUAL == strncmp(vcal_cursor, "END:VCALENDAR", strlen("END:VCALENDAR"))) {
107                                 vcal_cursor += strlen("END:VCALENDAR");
108                                 while ('\r' == *vcal_cursor || '\n' == *vcal_cursor) {
109                                         new_line = true;
110                                         vcal_cursor++;
111                                 }
112
113                                 len = (int)((long)vcal_cursor - (long)vcal_start);
114                                 vcalendar_object = calloc(len + 1, sizeof(char));
115                                 if (NULL == vcalendar_object) {
116                                         /* LCOV_EXCL_START */
117                                         ERR("calloc() Fail");
118                                         return NULL;
119                                         /* LCOV_EXCL_STOP */
120                                 }
121                                 memcpy(vcalendar_object, vcal_start, len);
122                                 *pvcalendar_object = vcalendar_object;
123                                 return vcal_cursor;
124                         }
125                         new_line = false;
126                 }
127                 vcal_cursor++;
128                 while ('\r' == *vcal_cursor || '\n' == *vcal_cursor) {
129                         new_line = true;
130                         vcal_cursor++;
131                 }
132         }
133         return vcal_cursor;
134 }
135
136 /*
137  * parse from here
138  */
139 API int calendar_vcalendar_parse_to_calendar(const char* vcalendar_stream, calendar_list_h *out_list)
140 {
141         int count = 0;
142         const char *cursor = NULL;
143         char *vcalendar_object = NULL;
144         calendar_error_e err;
145         calendar_list_h list = NULL;
146
147         RETV_IF(NULL == vcalendar_stream, CALENDAR_ERROR_INVALID_PARAMETER);
148         RETV_IF(NULL == out_list, CALENDAR_ERROR_INVALID_PARAMETER);
149
150         /* get vcalendar object */
151         cursor = vcalendar_stream;
152
153         int ret = 0;
154         ret = calendar_list_create(&list);
155         RETVM_IF(CALENDAR_ERROR_NONE != ret, ret, "calendar_list_create() Fail(%d)", ret);
156
157         cal_time_init();
158
159         while (NULL != (cursor = __calendar_vcalendar_get_vcalendar_object(cursor, &vcalendar_object))) {
160                 if (NULL == vcalendar_object)
161                         break;
162
163                 err = cal_vcalendar_parse_vcalendar_object(vcalendar_object, list, NULL);
164                 if (CALENDAR_ERROR_NONE != err) {
165                         /* LCOV_EXCL_START */
166                         ERR("cal_vcalendar_parse_vcalendar_object() failed(%d)", err);
167                         calendar_list_destroy(list, true);
168                         free(vcalendar_object);
169                         cal_time_fini();
170                         return err;
171                         /* LCOV_EXCL_STOP */
172                 }
173                 free(vcalendar_object);
174         }
175         calendar_list_get_count(list, &count);
176         if (count <= 0) {
177                 calendar_list_destroy(list, true);
178                 cal_time_fini();
179                 return CALENDAR_ERROR_INVALID_PARAMETER;
180         }
181         calendar_list_first(list);
182         *out_list = list;
183         cal_time_fini();
184         return CALENDAR_ERROR_NONE;
185 }
186
187 API int calendar_vcalendar_parse_to_calendar_foreach(const char *vcalendar_file_path, calendar_vcalendar_parse_cb callback, void *user_data)
188 {
189         FILE *file;
190         int buf_size, len;
191         char *stream;
192         char buf[CAL_STR_MIDDLE_LEN];
193         vcalendar_foreach_s *foreach_data = NULL;
194
195         RETV_IF(NULL == vcalendar_file_path, CALENDAR_ERROR_INVALID_PARAMETER);
196         RETV_IF(NULL == callback, CALENDAR_ERROR_INVALID_PARAMETER);
197
198         int ret = 0;
199         calendar_list_h list = NULL;
200         ret = calendar_list_create(&list);
201         RETVM_IF(CALENDAR_ERROR_NONE != ret, ret, "calendar_list_create() Fail(%d)", ret);
202
203         file = fopen(vcalendar_file_path, "r");
204         if (NULL == file) {
205                 /* LCOV_EXCL_START */
206                 ERR("Invalid argument: no file");
207                 calendar_list_destroy(list, true);
208                 return CALENDAR_ERROR_INVALID_PARAMETER;
209                 /* LCOV_EXCL_STOP */
210         }
211
212         len = 0;
213         buf_size = ICALENAR_BUFFER_MAX;
214         stream = calloc(ICALENAR_BUFFER_MAX, sizeof(char));
215         if (NULL == stream) {
216                 /* LCOV_EXCL_START */
217                 ERR("calloc() Fail");
218                 fclose(file);
219                 calendar_list_destroy(list, true);
220                 return CALENDAR_ERROR_OUT_OF_MEMORY;
221                 /* LCOV_EXCL_STOP */
222         }
223
224         foreach_data = calloc(1, sizeof(vcalendar_foreach_s));
225         if (NULL == foreach_data) {
226                 /* LCOV_EXCL_START */
227                 ERR("calloc() Fail");
228                 free(stream);
229                 fclose(file);
230                 calendar_list_destroy(list, true);
231                 return CALENDAR_ERROR_OUT_OF_MEMORY;
232                 /* LCOV_EXCL_STOP */
233         }
234         foreach_data->callback = callback;
235         foreach_data->user_data = user_data;
236         foreach_data->ret = true;
237
238         while (fgets(buf, sizeof(buf), file)) {
239                 if (len + sizeof(buf) < buf_size) {
240                         len += snprintf(stream + len, strlen(buf) +1, "%s", buf);
241                 } else {
242                         char *new_stream;
243                         buf_size *= 2;
244                         new_stream = realloc(stream, buf_size);
245                         if (new_stream) {
246                                 stream = new_stream;
247                         } else {
248                                 /* LCOV_EXCL_START */
249                                 ERR("out of memory");
250                                 free(stream);
251                                 fclose(file);
252                                 free(foreach_data);
253                                 calendar_list_destroy(list, true);
254                                 return CALENDAR_ERROR_OUT_OF_MEMORY;
255                                 /* LCOV_EXCL_STOP */
256                         }
257                         len += snprintf(stream + len, strlen(buf) +1, "%s", buf);
258                 }
259
260                 if (CAL_STRING_EQUAL == strncmp(buf, "END:VCALENDAR", strlen("END:VCALENDAR"))) {
261                         DBG("end vcalendar");
262                         int err;
263                         char *vcalendar_object = NULL;
264                         __calendar_vcalendar_get_vcalendar_object(stream, &vcalendar_object);
265                         err = cal_vcalendar_parse_vcalendar_object(vcalendar_object, list, foreach_data);
266                         if (CALENDAR_ERROR_NONE != err || false == foreach_data->ret) {
267                                 /* LCOV_EXCL_START */
268                                 ERR("cal_vcalendar_parse_vcalendar_object() failed(%d)", err);
269                                 calendar_list_destroy(list, true);
270                                 free(vcalendar_object);
271                                 free(stream);
272                                 free(foreach_data);
273                                 fclose(file);
274                                 return err;
275                                 /* LCOV_EXCL_STOP */
276                         }
277                         free(vcalendar_object);
278                         len = 0;
279                 }
280         }
281
282         calendar_list_destroy(list, true);
283         free(stream);
284         free(foreach_data);
285         fclose(file);
286
287         return CALENDAR_ERROR_NONE;
288 }