a2c97995d77ebe1c05bde07680ac14779c389347
[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                 ERR("cal_vcalendar_make_get_data() Fail");
64                 return CALENDAR_ERROR_OUT_OF_MEMORY;
65         }
66
67         if (!*ical) {
68                 ERR("No ical data");
69                 free(ical);
70                 return CALENDAR_ERROR_NO_DATA;
71         }
72
73         *vcalendar_stream = ical;
74
75         return CALENDAR_ERROR_NONE;
76 }
77
78 static const char* __calendar_vcalendar_get_vcalendar_object(const char *original, char **pvcalendar_object)
79 {
80         int len = 0;
81         const char *vcal_start = original;
82         const char *vcal_cursor = NULL;
83         bool new_line = false;
84         char *vcalendar_object = NULL;
85
86         RETV_IF(NULL == pvcalendar_object, original);
87         *pvcalendar_object = NULL;
88
89         while ('\n' == *vcal_start || '\r' == *vcal_start)
90                 vcal_start++;
91
92         if (strncmp(vcal_start, "BEGIN:VCALENDAR", strlen("BEGIN:VCALENDAR")))
93                 return vcal_start;
94
95         vcal_start += strlen("BEGIN:VCALENDAR");
96         while ('\n' == *vcal_start || '\r' == *vcal_start)
97                 vcal_start++;
98         vcal_cursor = vcal_start;
99
100         while (*vcal_cursor) {
101                 if (new_line) {
102                         if (CAL_STRING_EQUAL == strncmp(vcal_cursor, "END:VCALENDAR", strlen("END:VCALENDAR"))) {
103                                 vcal_cursor += strlen("END:VCALENDAR");
104                                 while ('\r' == *vcal_cursor || '\n' == *vcal_cursor) {
105                                         new_line = true;
106                                         vcal_cursor++;
107                                 }
108
109                                 len = (int)((long)vcal_cursor - (long)vcal_start);
110                                 vcalendar_object = calloc(len + 1, sizeof(char));
111                                 if (NULL == vcalendar_object) {
112                                         ERR("calloc() Fail");
113                                         return NULL;
114                                 }
115                                 memcpy(vcalendar_object, vcal_start, len);
116                                 *pvcalendar_object = vcalendar_object;
117                                 return vcal_cursor;
118                         }
119                         new_line = false;
120                 }
121                 vcal_cursor++;
122                 while ('\r' == *vcal_cursor || '\n' == *vcal_cursor) {
123                         new_line = true;
124                         vcal_cursor++;
125                 }
126         }
127         return vcal_cursor;
128 }
129
130 /*
131  * parse from here
132  */
133 API int calendar_vcalendar_parse_to_calendar(const char* vcalendar_stream, calendar_list_h *out_list)
134 {
135         int count = 0;
136         const char *cursor = NULL;
137         char *vcalendar_object = NULL;
138         calendar_error_e err;
139         calendar_list_h list = NULL;
140
141         RETV_IF(NULL == vcalendar_stream, CALENDAR_ERROR_INVALID_PARAMETER);
142         RETV_IF(NULL == out_list, CALENDAR_ERROR_INVALID_PARAMETER);
143
144         /* get vcalendar object */
145         cursor = vcalendar_stream;
146
147         int ret = 0;
148         ret = calendar_list_create(&list);
149         RETVM_IF(CALENDAR_ERROR_NONE != ret, ret, "calendar_list_create() Fail(%d)", ret);
150
151         cal_time_init();
152
153         while (NULL != (cursor = __calendar_vcalendar_get_vcalendar_object(cursor, &vcalendar_object))) {
154                 if (NULL == vcalendar_object)
155                         break;
156
157                 err = cal_vcalendar_parse_vcalendar_object(vcalendar_object, list, NULL);
158                 if (CALENDAR_ERROR_NONE != err) {
159                         ERR("cal_vcalendar_parse_vcalendar_object() failed(%d)", err);
160                         calendar_list_destroy(list, true);
161                         free(vcalendar_object);
162                         cal_time_fini();
163                         return err;
164                 }
165                 free(vcalendar_object);
166         }
167         calendar_list_get_count(list, &count);
168         if (count <= 0) {
169                 calendar_list_destroy(list, true);
170                 cal_time_fini();
171                 return CALENDAR_ERROR_INVALID_PARAMETER;
172         }
173         calendar_list_first(list);
174         *out_list = list;
175         cal_time_fini();
176         return CALENDAR_ERROR_NONE;
177 }
178
179 API int calendar_vcalendar_parse_to_calendar_foreach(const char *vcalendar_file_path, calendar_vcalendar_parse_cb callback, void *user_data)
180 {
181         FILE *file;
182         int buf_size, len;
183         char *stream;
184         char buf[CAL_STR_MIDDLE_LEN];
185         vcalendar_foreach_s *foreach_data = NULL;
186
187         RETV_IF(NULL == vcalendar_file_path, CALENDAR_ERROR_INVALID_PARAMETER);
188         RETV_IF(NULL == callback, CALENDAR_ERROR_INVALID_PARAMETER);
189
190         int ret = 0;
191         calendar_list_h list = NULL;
192         ret = calendar_list_create(&list);
193         RETVM_IF(CALENDAR_ERROR_NONE != ret, ret, "calendar_list_create() Fail(%d)", ret);
194
195         file = fopen(vcalendar_file_path, "r");
196         if (NULL == file) {
197                 ERR("Invalid argument: no file");
198                 calendar_list_destroy(list, true);
199                 return CALENDAR_ERROR_INVALID_PARAMETER;
200         }
201
202         len = 0;
203         buf_size = ICALENAR_BUFFER_MAX;
204         stream = calloc(ICALENAR_BUFFER_MAX, sizeof(char));
205         if (NULL == stream) {
206                 ERR("calloc() Fail");
207                 fclose(file);
208                 calendar_list_destroy(list, true);
209                 return CALENDAR_ERROR_OUT_OF_MEMORY;
210         }
211
212         foreach_data = calloc(1, sizeof(vcalendar_foreach_s));
213         if (NULL == foreach_data) {
214                 ERR("calloc() Fail");
215                 free(stream);
216                 fclose(file);
217                 calendar_list_destroy(list, true);
218                 return CALENDAR_ERROR_OUT_OF_MEMORY;
219         }
220         foreach_data->callback = callback;
221         foreach_data->user_data = user_data;
222         foreach_data->ret = true;
223
224         while (fgets(buf, sizeof(buf), file)) {
225                 if (len + sizeof(buf) < buf_size) {
226                         len += snprintf(stream + len, strlen(buf) +1, "%s", buf);
227                 } else {
228                         char *new_stream;
229                         buf_size *= 2;
230                         new_stream = realloc(stream, buf_size);
231                         if (new_stream) {
232                                 stream = new_stream;
233                         } else {
234                                 free(stream);
235                                 fclose(file);
236                                 free(foreach_data);
237                                 calendar_list_destroy(list, true);
238                                 ERR("out of memory");
239                                 return CALENDAR_ERROR_OUT_OF_MEMORY;
240                         }
241                         len += snprintf(stream + len, strlen(buf) +1, "%s", buf);
242                 }
243
244                 if (CAL_STRING_EQUAL == strncmp(buf, "END:VCALENDAR", strlen("END:VCALENDAR"))) {
245                         DBG("end vcalendar");
246                         int err;
247                         char *vcalendar_object = NULL;
248                         __calendar_vcalendar_get_vcalendar_object(stream, &vcalendar_object);
249                         err = cal_vcalendar_parse_vcalendar_object(vcalendar_object, list, foreach_data);
250                         if (CALENDAR_ERROR_NONE != err || false == foreach_data->ret) {
251                                 ERR("cal_vcalendar_parse_vcalendar_object() failed(%d)", err);
252                                 calendar_list_destroy(list, true);
253                                 free(vcalendar_object);
254                                 free(stream);
255                                 free(foreach_data);
256                                 fclose(file);
257                                 return err;
258                         }
259                         free(vcalendar_object);
260                         len = 0;
261                 }
262         }
263
264         calendar_list_destroy(list, true);
265         free(stream);
266         free(foreach_data);
267         fclose(file);
268
269         return CALENDAR_ERROR_NONE;
270 }