add comment LCOV_EXCL
[platform/core/pim/calendar-service.git] / server / db / cal_db_plugin_event_helper.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 "cal_internal.h"
23 #include "cal_typedef.h"
24 #include "cal_view.h"
25 #include "cal_record.h"
26 #include "cal_time.h"
27 #include "cal_access_control.h"
28 #include "cal_db_query.h"
29 #include "cal_db_rrule.h"
30 #include "cal_db_query.h"
31 #include "cal_db_plugin_alarm_helper.h"
32 #include "cal_db_instance.h"
33 #include "cal_db_plugin_attendee_helper.h"
34 #include "cal_db_plugin_extended_helper.h"
35 #include "cal_db_plugin_event_helper.h"
36 #include "cal_db_plugin_timezone_helper.h"
37 #include "cal_db.h"
38 #include "cal_db_util.h"
39 #include "cal_utils.h"
40
41 enum {
42         CAL_RECURRENCE_ID_RANGE_NONE,
43         CAL_RECURRENCE_ID_RANGE_THISANDFUTURE,
44         CAL_RECURRENCE_ID_RANGE_THISANDPRIOR,
45         CAL_RECURRENCE_ID_RANGE_MAX,
46 };
47
48 #define DEBUG_DATETIME(x) DBG("%04d-%02d-%02dT%02d:%02d:%02d",\
49                 x->time.date.year,\
50                 x->time.date.month,\
51                 x->time.date.mday,\
52                 x->time.date.hour,\
53                 x->time.date.minute,\
54                 x->time.date.second)
55
56 int cal_db_event_update_original_event_version(int original_event_id, int version)
57 {
58         int ret = 0;
59         char query[CAL_DB_SQL_MAX_LEN] = {0};
60
61         DBG("original_event(%d) changed_ver updated", original_event_id);
62         if (0 < original_event_id) {
63                 snprintf(query, sizeof(query), "UPDATE %s SET changed_ver=%d, has_exception = 1 WHERE id=%d ",
64                                 CAL_TABLE_SCHEDULE, version, original_event_id);
65
66                 ret = cal_db_util_query_exec(query);
67                 if (CALENDAR_ERROR_NONE != ret) {
68                         /* LCOV_EXCL_START */
69                         ERR("cal_db_util_query_exec() Fail(%d)", ret);
70                         SECURE("[%s]", query);
71                         return ret;
72                         /* LCOV_EXCL_STOP */
73                 }
74         }
75         return CALENDAR_ERROR_NONE;
76 }
77
78 int cal_db_event_check_value_validation(cal_event_s *event)
79 {
80         long long int slli = 0;
81         long long int elli = 0;
82
83         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
84
85         if (event->start.type != event->end.type) {
86                 /* LCOV_EXCL_START */
87                 ERR("normal end(%lld) < start(%lld)",
88                                 event->end.time.utime, event->start.time.utime);
89                 return CALENDAR_ERROR_INVALID_PARAMETER;
90                 /* LCOV_EXCL_STOP */
91         }
92
93         switch (event->start.type) {
94         case CALENDAR_TIME_UTIME:
95                 if (event->end.time.utime < event->start.time.utime) {
96                         /* LCOV_EXCL_START */
97                         ERR("normal end(%lld) < start(%lld) so set same", event->end.time.utime, event->start.time.utime);
98                         event->end.time.utime =  event->start.time.utime;
99                         return CALENDAR_ERROR_INVALID_PARAMETER;
100                         /* LCOV_EXCL_STOP */
101                 }
102                 break;
103
104         case CALENDAR_TIME_LOCALTIME:
105                 /* check invalid value */
106                 if (event->start.time.date.month < 1 || 12 < event->start.time.date.month) {
107                         /* LCOV_EXCL_START */
108                         ERR("Error check start month(input:%d)", event->start.time.date.month);
109                         return CALENDAR_ERROR_INVALID_PARAMETER;
110                         /* LCOV_EXCL_STOP */
111                 } else if (event->start.time.date.mday < 1 || 31 < event->start.time.date.mday) {
112                         /* LCOV_EXCL_START */
113                         ERR("Error check start mday(input:%d)", event->start.time.date.mday);
114                         return CALENDAR_ERROR_INVALID_PARAMETER;
115                         /* LCOV_EXCL_STOP */
116                 } else if (event->end.time.date.month < 1 || 12 < event->end.time.date.month) {
117                         /* LCOV_EXCL_START */
118                         ERR("Error check end month(input:%d)", event->end.time.date.month);
119                         return CALENDAR_ERROR_INVALID_PARAMETER;
120                         /* LCOV_EXCL_STOP */
121                 } else if (event->end.time.date.mday < 1 || 31 < event->end.time.date.mday) {
122                         /* LCOV_EXCL_START */
123                         ERR("Error check end mday(input:%d)", event->end.time.date.mday);
124                         return CALENDAR_ERROR_INVALID_PARAMETER;
125                         /* LCOV_EXCL_STOP */
126                 } else {
127                         /* handle hour, minute, second */
128                         if (event->start.time.date.hour < 0 || 24 < event->start.time.date.hour)
129                                 event->start.time.date.hour = 0;
130                         if (event->start.time.date.minute < 0 || 60 < event->start.time.date.minute)
131                                 event->start.time.date.minute = 0;
132                         if (event->start.time.date.second < 0 || 60 < event->start.time.date.second)
133                                 event->start.time.date.second = 0;
134                         if (event->end.time.date.hour < 0 || 24 < event->end.time.date.hour)
135                                 event->end.time.date.hour = 0;
136                         if (event->end.time.date.minute < 0 || 60 < event->end.time.date.minute)
137                                 event->end.time.date.minute = 0;
138                         if (event->end.time.date.second < 0 || 60 < event->end.time.date.second)
139                                 event->end.time.date.second = 0;
140                 }
141
142                 /* check end < start; convert long long int */
143                 slli = cal_time_convert_itol(NULL,
144                                 event->start.time.date.year, event->start.time.date.month, event->start.time.date.mday,
145                                 event->start.time.date.hour, event->start.time.date.minute, event->start.time.date.second);
146                 elli = cal_time_convert_itol(NULL,
147                                 event->end.time.date.year, event->end.time.date.month, event->end.time.date.mday,
148                                 event->end.time.date.hour, event->end.time.date.minute, event->end.time.date.second);
149
150                 if (1 < slli - elli) {
151                         /* 1 is to ignore milliseconds */
152                         /* LCOV_EXCL_START */
153                         ERR("allday end(%lld) < start(%lld) so set same", elli, slli);
154                         return CALENDAR_ERROR_INVALID_PARAMETER;
155                         /* LCOV_EXCL_STOP */
156                 }
157                 break;
158         }
159
160         return CALENDAR_ERROR_NONE;
161 }
162
163 GList* cal_db_event_get_list_with_uid(char *uid, int parent_id)
164 {
165         int ret = 0;
166         RETV_IF(NULL == uid, NULL);
167         RETV_IF('\0' == *uid, NULL);
168
169         char query[CAL_DB_SQL_MAX_LEN] = {0};
170         snprintf(query, sizeof(query), "SELECT id FROM %s WHERE original_event_id=-1 AND uid LIKE '%s' AND id!=%d",
171                         CAL_TABLE_SCHEDULE, uid, parent_id);
172
173         sqlite3_stmt *stmt = NULL;
174         ret = cal_db_util_query_prepare(query, &stmt);
175         if (CALENDAR_ERROR_NONE != ret) {
176                 /* LCOV_EXCL_START */
177                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
178                 SECURE("query[%s]", query);
179                 return NULL;
180                 /* LCOV_EXCL_STOP */
181         }
182
183         GList *l = NULL;
184         while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
185                 int id = sqlite3_column_int(stmt, 0);
186                 l = g_list_append(l, GINT_TO_POINTER(id));
187         }
188         sqlite3_finalize(stmt);
189         return l;
190 }
191
192 void cal_db_event_update_child_origina_event_id(int child_id, int parent_id)
193 {
194         CAL_FN_CALL();
195
196         int ret = 0;
197         char query[CAL_DB_SQL_MAX_LEN] = {0};
198         snprintf(query, sizeof(query), "UPDATE %s SET original_event_id=%d WHERE id=%d",
199                         CAL_TABLE_SCHEDULE, parent_id, child_id);
200         ret = cal_db_util_query_exec(query);
201         if (CALENDAR_ERROR_NONE != ret) {
202                 /* LCOV_EXCL_START */
203                 ERR("cal_db_util_query_exec() Fail(%d)", ret);
204                 SECURE("[%s]", query);
205                 /* LCOV_EXCL_STOP */
206         }
207 }
208
209 char* cal_db_event_get_recurrence_id_from_exception(int child_id)
210 {
211         int ret = 0;
212         char query[CAL_DB_SQL_MAX_LEN] = {0};
213         snprintf(query, sizeof(query), "SELECT recurrence_id FROM %s WHERE id=%d",
214                         CAL_TABLE_SCHEDULE, child_id);
215
216         sqlite3_stmt *stmt = NULL;
217         ret = cal_db_util_query_prepare(query, &stmt);
218         if (CALENDAR_ERROR_NONE != ret) {
219                 /* LCOV_EXCL_START */
220                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
221                 SECURE("query[%s]", query);
222                 return NULL;
223                 /* LCOV_EXCL_STOP */
224         }
225
226         char *recurrence_id = NULL;
227         if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt))
228                 recurrence_id = cal_strdup((const char*)sqlite3_column_text(stmt, 0));
229
230         sqlite3_finalize(stmt);
231         return recurrence_id;
232 }
233
234 static void __get_tzid_and_range(char *p, char **out_tzid, int *out_range)
235 {
236         RET_IF(NULL == p);
237         RET_IF('\0' == *p);
238         RET_IF(NULL == out_tzid);
239         RET_IF(NULL == out_range);
240
241         char **s = NULL;
242         s = g_strsplit(p, ";", -1);
243         RETM_IF(NULL == s, "g_strsplit() Fail");
244
245         int count = g_strv_length(s);
246         int i;
247         char *tzid = NULL;
248         int range = CAL_RECURRENCE_ID_RANGE_NONE;
249         for (i = 0; i < count; i++) {
250                 if (NULL == s[i] || '\0' == *s[i])
251                         continue;
252
253                 if (CAL_STRING_EQUAL == strncmp(s[i], "TZID=", strlen("TZID="))) {
254                         if (tzid)
255                                 continue;
256                         tzid = strdup(s[i] + strlen("TZID="));
257                         DBG("tzid [%s]", tzid);
258                 } else if (CAL_STRING_EQUAL == strncmp(s[i], "RANGE=", strlen("RANGE="))) {
259                         char *param = s[i] + strlen("RANGE=");
260                         if (CAL_STRING_EQUAL == strncmp(param, "THISANDFUTURE", strlen("THISANDFUTURE")))
261                                 range = CAL_RECURRENCE_ID_RANGE_THISANDFUTURE;
262                         else if (CAL_STRING_EQUAL == strncmp(param, "THISANDPRIOR", strlen("THISANDPRIOR")))
263                                 range = CAL_RECURRENCE_ID_RANGE_THISANDPRIOR;
264                         else
265                                 WARN("Invalid param[%s]", s[i]);
266                 } else {
267                         WARN("Invalid param[%s]", s[i]);
268                 }
269         }
270         *out_tzid = tzid;
271         *out_range = range;
272         g_strfreev(s);
273 }
274
275 static void cal_db_event_apply_recurrence_id_child(int child_id, cal_event_s *event, calendar_time_s until, bool is_prior)
276 {
277         int ret = 0;
278         calendar_record_h record = NULL;
279         ret = cal_db_get_record(_calendar_event._uri, child_id, &record);
280         RETM_IF(CALENDAR_ERROR_NONE != ret, "cal_db_get_record() Fail(%d)", ret);
281
282         if (true == is_prior) {
283                 cal_record_set_caltime(record, _calendar_event.start_time, event->start);
284                 cal_record_set_caltime(record, _calendar_event.end_time, event->end);
285                 switch (event->start.type) {
286                 case CALENDAR_TIME_UTIME:
287                         DBG("dtstart(%lld) dtend(%lld)", event->start.time.utime, event->end.time.utime);
288                         break;
289                 case CALENDAR_TIME_LOCALTIME:
290                         DBG("dtstart(%04d-%02d-%02dT%02d:%02d:%02d) dtend(%04d-%02d-%02dT%02d:%02d:%02d)",
291                                         event->start.time.date.year, event->start.time.date.month, event->start.time.date.mday,
292                                         event->start.time.date.hour, event->start.time.date.minute, event->start.time.date.second,
293                                         event->end.time.date.year, event->end.time.date.month, event->end.time.date.mday,
294                                         event->end.time.date.hour, event->end.time.date.minute, event->end.time.date.second);
295                         break;
296                 }
297         }
298
299         cal_record_set_int(record, _calendar_event.freq, event->freq);
300         cal_record_set_int(record, _calendar_event.interval, event->interval);
301         cal_record_set_int(record, _calendar_event.wkst, event->wkst);
302         if (event->byyearday && *event->byyearday)
303                 cal_record_set_str(record, _calendar_event.byyearday, event->byyearday);
304         if (event->byweekno && *event->byweekno)
305                 cal_record_set_str(record, _calendar_event.byweekno, event->byweekno);
306         if (event->bymonth && *event->bymonth)
307                 cal_record_set_str(record, _calendar_event.bymonth, event->bymonth);
308         if (event->bymonthday && *event->bymonthday)
309                 cal_record_set_str(record, _calendar_event.bymonthday, event->bymonthday);
310         if (event->byday && *event->byday)
311                 cal_record_set_str(record, _calendar_event.byday, event->byday);
312         if (event->bysetpos && *event->bysetpos)
313                 cal_record_set_str(record, _calendar_event.bysetpos, event->bysetpos);
314
315         /* until */
316         cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_UNTIL);
317         cal_record_set_caltime(record, _calendar_event.until_time, until);
318
319         /* reset */
320         cal_record_set_str(record, _calendar_event.uid, "");
321         cal_record_set_int(record, _calendar_event.original_event_id, -1);
322
323         cal_db_update_record(record);
324         calendar_record_destroy(record, true);
325 }
326 static void __get_next_instance_caltime(int parent_id, calendar_time_s *caltime, calendar_time_s *dtstart, calendar_time_s *dtend)
327 {
328         int ret = 0;
329         char query[CAL_DB_SQL_MAX_LEN] = {0};
330         sqlite3_stmt *stmt = NULL;
331
332         switch (caltime->type) {
333         case CALENDAR_TIME_UTIME:
334                 snprintf(query, sizeof(query), "SELECT dtstart_utime, dtend_utime FROM %s WHERE event_id=%d AND dtstart_utime>%lld "
335                                 "ORDER BY dtstart_utime ASC LIMIT 1",
336                                 CAL_TABLE_NORMAL_INSTANCE, parent_id, caltime->time.utime);
337
338                 ret = cal_db_util_query_prepare(query, &stmt);
339                 if (CALENDAR_ERROR_NONE != ret) {
340                         /* LCOV_EXCL_START */
341                         ERR("cal_db_util_query_prepare() Fail(%d)", ret);
342                         SECURE("query[%s]", query);
343                         return;
344                         /* LCOV_EXCL_STOP */
345                 }
346
347                 while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
348                         dtstart->type = CALENDAR_TIME_UTIME;
349                         dtstart->time.utime = sqlite3_column_int64(stmt, 0);
350                         dtend->type = CALENDAR_TIME_UTIME;
351                         dtend->time.utime = sqlite3_column_int64(stmt, 0);
352                         break;
353                 }
354                 break;
355         case CALENDAR_TIME_LOCALTIME:
356                 snprintf(query, sizeof(query), "SELECT dtstart_datetime, dtend_datetime FROM %s "
357                                 "WHERE event_id=%d AND dtstart_datetime>'%04d-%02d-%02dT%02d:%02d:%02d' "
358                                 "ORDER BY dtstart_datetime ASC LIMIT 1",
359                                 CAL_TABLE_ALLDAY_INSTANCE, parent_id,
360                                 caltime->time.date.year, caltime->time.date.month, caltime->time.date.mday,
361                                 caltime->time.date.hour, caltime->time.date.minute, caltime->time.date.second);
362
363                 ret = cal_db_util_query_prepare(query, &stmt);
364                 if (CALENDAR_ERROR_NONE != ret) {
365                         /* LCOV_EXCL_START */
366                         ERR("cal_db_util_query_prepare() Fail(%d)", ret);
367                         SECURE("query[%s]", query);
368                         return;
369                         /* LCOV_EXCL_STOP */
370                 }
371
372                 if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
373                         char *temp = NULL;
374                         dtstart->type = CALENDAR_TIME_LOCALTIME;
375                         temp = (char *)sqlite3_column_text(stmt, 0);
376                         if (temp && *temp) {
377                                 sscanf(temp, CAL_FORMAT_LOCAL_DATETIME,
378                                                 &(dtstart->time.date.year), &(dtstart->time.date.month), &(dtstart->time.date.mday),
379                                                 &(dtstart->time.date.hour), &(dtstart->time.date.minute), &(dtstart->time.date.second));
380                         }
381                         dtend->type = CALENDAR_TIME_LOCALTIME;
382                         temp = (char *)sqlite3_column_text(stmt, 1);
383                         if (temp && *temp) {
384                                 sscanf(temp, CAL_FORMAT_LOCAL_DATETIME,
385                                                 &(dtend->time.date.year), &(dtend->time.date.month), &(dtend->time.date.mday),
386                                                 &(dtend->time.date.hour), &(dtend->time.date.minute), &(dtend->time.date.second));
387                         }
388                 }
389                 break;
390         }
391         sqlite3_finalize(stmt);
392 }
393 static void __get_last_instance_caltime(int parent_id, int type, calendar_time_s *dtstart)
394 {
395         int ret = 0;
396         char query[CAL_DB_SQL_MAX_LEN] = {0};
397         sqlite3_stmt *stmt = NULL;
398
399         switch (type) {
400         case CALENDAR_TIME_UTIME:
401                 snprintf(query, sizeof(query), "SELECT dtstart_utime FROM %s WHERE event_id=%d "
402                                 "ORDER BY dtstart_utime DESC LIMIT 1",
403                                 CAL_TABLE_NORMAL_INSTANCE, parent_id);
404                 ret = cal_db_util_query_prepare(query, &stmt);
405                 if (CALENDAR_ERROR_NONE != ret) {
406                         /* LCOV_EXCL_START */
407                         ERR("cal_db_util_query_prepare() Fail(%d)", ret);
408                         SECURE("query[%s]", query);
409                         return;
410                         /* LCOV_EXCL_STOP */
411                 }
412                 while (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
413                         dtstart->type = CALENDAR_TIME_UTIME;
414                         dtstart->time.utime = sqlite3_column_int64(stmt, 0);
415                         break;
416                 }
417                 break;
418         case CALENDAR_TIME_LOCALTIME:
419                 snprintf(query, sizeof(query), "SELECT dtstart_datetime FROM %s WHERE event_id=%d "
420                                 "ORDER BY dtstart_datetime DESC LIMIT 1",
421                                 CAL_TABLE_ALLDAY_INSTANCE, parent_id);
422                 ret = cal_db_util_query_prepare(query, &stmt);
423                 if (CALENDAR_ERROR_NONE != ret) {
424                         /* LCOV_EXCL_START */
425                         ERR("cal_db_util_query_prepare() Fail(%d)", ret);
426                         SECURE("query[%s]", query);
427                         return;
428                         /* LCOV_EXCL_STOP */
429                 }
430                 if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt)) {
431                         char *temp = NULL;
432                         dtstart->type = CALENDAR_TIME_LOCALTIME;
433                         temp = (char *)sqlite3_column_text(stmt, 0);
434                         if (temp && *temp) {
435                                 sscanf(temp, CAL_FORMAT_LOCAL_DATETIME,
436                                                 &(dtstart->time.date.year), &(dtstart->time.date.month), &(dtstart->time.date.mday),
437                                                 &(dtstart->time.date.hour), &(dtstart->time.date.minute), &(dtstart->time.date.second));
438                         } else {
439                                 WARN("datetime is NULL");
440                         }
441                 }
442                 break;
443         }
444         sqlite3_finalize(stmt);
445 }
446
447 static void __del_recurence_id_instance(calendar_time_s *rectime, int parent_id)
448 {
449         int ret = 0;
450         char query[CAL_DB_SQL_MAX_LEN] = {0};
451         switch (rectime->type) {
452         case CALENDAR_TIME_UTIME:
453                 snprintf(query, sizeof(query), "DELETE FROM %s WHERE dtstart_utime=%lld AND event_id=%d",
454                                 CAL_TABLE_NORMAL_INSTANCE, rectime->time.utime, parent_id);
455                 break;
456         case CALENDAR_TIME_LOCALTIME:
457                 snprintf(query, sizeof(query), "DELETE FROM %s WHERE dtstart_datetime='%04d-%02d-%02dT%02d:%02d:%02d' AND event_id=%d",
458                                 CAL_TABLE_ALLDAY_INSTANCE, rectime->time.date.year, rectime->time.date.month, rectime->time.date.mday,
459                                 rectime->time.date.hour, rectime->time.date.minute, rectime->time.date.second, parent_id);
460                 break;
461         }
462         ret = cal_db_util_query_exec(query);
463         if (CALENDAR_ERROR_NONE != ret) {
464                 /* LCOV_EXCL_START */
465                 ERR("cal_db_util_query_exec() Fail(%d)", ret);
466                 SECURE("[%s]", query);
467                 return;
468                 /* LCOV_EXCL_STOP */
469         }
470
471         int y = 0, m = 0, d = 0;
472         int h = 0, n = 0, s = 0;
473         switch (rectime->type) {
474         case CALENDAR_TIME_UTIME:
475                 cal_time_get_datetime(rectime->time.utime, &y, &m, &d, &h, &n, &s);
476                 DBG("[DELETED] %04d-%02d-%02dT%02d:%02d:%02d (utime)", y, m, d, h, n, s);
477                 break;
478         case CALENDAR_TIME_LOCALTIME:
479                 DBG("[DELETED] %04d-%02d-%02dT%02d:%02d:%02d (local)",
480                                 rectime->time.date.year, rectime->time.date.month, rectime->time.date.mday,
481                                 rectime->time.date.hour, rectime->time.date.minute, rectime->time.date.second);
482                 break;
483         }
484 }
485
486 static void __set_original_event_id_in_child(int child_id, int parent_id)
487 {
488         int ret = 0;
489         char query[CAL_DB_SQL_MAX_LEN] = {0};
490         snprintf(query, sizeof(query), "UPDATE %s SET original_event_id=%d WHERE id=%d",
491                         CAL_TABLE_SCHEDULE, parent_id, child_id);
492
493         ret = cal_db_util_query_exec(query);
494         if (CALENDAR_ERROR_NONE != ret) {
495                 /* LCOV_EXCL_START */
496                 ERR("cal_db_util_query_exec() Fail(%d)", ret);
497                 SECURE("[%s]", query);
498                 /* LCOV_EXCL_STOP */
499         }
500 }
501
502 /*
503  * RECURRENCE-ID;VALUE=DATE:19960401
504  * RECURRENCE-ID;RANGE=THISANDFUTURE:19960120T120000Z
505  * RECURRENCE-ID;RANGE=THISANDPRIOR:19980401T133000Z
506  * RECURRENCE-ID;TZID=Asia/Seoul:20150106T090000
507  */
508 void cal_db_event_apply_recurrence_id(int parent_id, cal_event_s *event, char *recurrence_id, int child_id)
509 {
510         CAL_FN_CALL();
511
512         RET_IF(NULL == recurrence_id);
513         RET_IF('\0' == *recurrence_id);
514
515         char **t = NULL;
516         t =  g_strsplit(recurrence_id, ":", -1);
517         RETM_IF(NULL == t, "g_strsplit() Fail");
518
519         if ('\0' == *t[0]) { /* no param */
520                 g_strfreev(t);
521                 return;
522         }
523         int count = g_strv_length(t);
524         int len_param = strlen(t[count -1]);
525         *(recurrence_id + strlen(recurrence_id) - len_param -1) = '\0';
526         g_strfreev(t);
527
528         char *datetime = recurrence_id + strlen(recurrence_id) +1;
529         int len_datetime = strlen(datetime);
530         DBG("datetime[%s]", datetime);
531
532         char *tzid = NULL;
533         int range = CAL_RECURRENCE_ID_RANGE_NONE;
534         __get_tzid_and_range(recurrence_id, &tzid, &range);
535
536         int y = 0, m = 0, d = 0;
537         int h = 0, n = 0, s = 0;
538         char dtstart_datetime[CAL_STR_SHORT_LEN32] = {0};
539         long long int dtstart_utime = 0;
540         calendar_time_s rectime = {0};
541         switch (len_datetime) {
542         case 8:
543                 sscanf(datetime, CAL_DATETIME_FORMAT_YYYYMMDD, &y, &m, &d);
544                 snprintf(dtstart_datetime, sizeof(dtstart_datetime), CAL_FORMAT_LOCAL_DATETIME, y, m, d, 0, 0, 0);
545                 rectime.type = CALENDAR_TIME_LOCALTIME;
546                 rectime.time.date.year = y;
547                 rectime.time.date.month = m;
548                 rectime.time.date.mday = d;
549                 rectime.time.date.hour = 0;
550                 rectime.time.date.minute = 0;
551                 rectime.time.date.second = 0;
552                 break;
553         case 15:
554                 sscanf(datetime, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSS, &y, &m, &d, &h, &n, &s);
555                 if (tzid && *tzid) {
556                         dtstart_utime = cal_time_convert_itol(tzid, y, m, d, h, n, s);
557                         rectime.type = CALENDAR_TIME_UTIME;
558                         rectime.time.utime = dtstart_utime;
559                 } else {
560                         snprintf(dtstart_datetime, sizeof(dtstart_datetime), CAL_FORMAT_LOCAL_DATETIME, y, m, d, h, n, s);
561                         rectime.type = CALENDAR_TIME_LOCALTIME;
562                         rectime.time.date.year = y;
563                         rectime.time.date.month = m;
564                         rectime.time.date.mday = d;
565                         rectime.time.date.hour = h;
566                         rectime.time.date.minute = n;
567                         rectime.time.date.second = s;
568                 }
569                 break;
570         case 16:
571                 sscanf(datetime, CAL_DATETIME_FORMAT_YYYYMMDDTHHMMSSZ, &y, &m, &d, &h, &n, &s);
572                 dtstart_utime = cal_time_convert_itol(tzid, y, m, d, h, n, s);
573                 rectime.type = CALENDAR_TIME_UTIME;
574                 rectime.time.utime = dtstart_utime;
575                 break;
576         }
577         free(tzid);
578
579         calendar_time_s until = {0};
580         calendar_time_s dtstart = {0};
581         calendar_time_s dtend = {0};
582         calendar_record_h record = (calendar_record_h)event;
583         switch (range) {
584         case CAL_RECURRENCE_ID_RANGE_THISANDFUTURE:
585                 DBG("update child");
586                 switch (event->range_type) {
587                 case CALENDAR_RANGE_UNTIL:
588                 case CALENDAR_RANGE_NONE:
589                         until = event->start;
590                         break;
591                 case CALENDAR_RANGE_COUNT:
592                         __get_last_instance_caltime(parent_id, rectime.type, &until);
593                         break;
594                 }
595                 cal_db_event_apply_recurrence_id_child(child_id, event, until, false);
596
597                 DBG("update parent");
598                 until = rectime;
599                 cal_time_modify_caltime(&until, -1);
600                 cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_UNTIL);
601                 cal_record_set_caltime(record, _calendar_event.until_time, until);
602                 cal_record_set_str(record, _calendar_event.recurrence_id, "");
603                 cal_record_set_str(record, _calendar_event.uid, "");
604                 cal_db_update_record(record);
605                 break;
606         case CAL_RECURRENCE_ID_RANGE_THISANDPRIOR:
607                 DBG("update child");
608                 until = rectime;
609                 cal_db_event_apply_recurrence_id_child(child_id, event, until, true);
610
611                 DBG("update parent");
612                 __get_next_instance_caltime(parent_id, &until, &dtstart, &dtend);
613                 cal_record_set_caltime(record, _calendar_event.start_time, dtstart);
614                 cal_record_set_caltime(record, _calendar_event.end_time, dtend);
615                 switch (event->range_type) {
616                 case CALENDAR_RANGE_UNTIL:
617                 case CALENDAR_RANGE_NONE:
618                         break;
619                 case CALENDAR_RANGE_COUNT:
620                         __get_last_instance_caltime(parent_id, rectime.type, &until);
621                         cal_record_set_int(record, _calendar_event.range_type, CALENDAR_RANGE_UNTIL);
622                         cal_record_set_caltime(record, _calendar_event.until_time, until);
623                         DBG(CAL_FORMAT_LOCAL_DATETIME,
624                                         until.time.date.year, until.time.date.month, until.time.date.mday,
625                                         until.time.date.hour, until.time.date.minute, until.time.date.second);
626                         break;
627                 }
628                 cal_record_set_str(record, _calendar_event.recurrence_id, "");
629                 cal_db_update_record(record);
630                 break;
631         default:
632                 __del_recurence_id_instance(&rectime, parent_id);
633                 __set_original_event_id_in_child(child_id, parent_id);
634                 break;
635         }
636 }
637 static int __get_parent_id_with_uid(char *uid, int child_id)
638 {
639         int ret = 0;
640         char query[CAL_DB_SQL_MAX_LEN] = {0};
641         int parent_id = -1;
642         snprintf(query, sizeof(query), "SELECT id FROM %s WHERE original_event_id=-1 AND id!=%d AND uid='%s'",
643                         CAL_TABLE_SCHEDULE, child_id, uid);
644
645         sqlite3_stmt *stmt = NULL;
646         ret = cal_db_util_query_prepare(query, &stmt);
647         if (CALENDAR_ERROR_NONE != ret) {
648                 /* LCOV_EXCL_START */
649                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
650                 SECURE("query[%s]", query);
651                 return ret;
652                 /* LCOV_EXCL_STOP */
653         }
654         if (CAL_SQLITE_ROW == cal_db_util_stmt_step(stmt))
655                 parent_id = sqlite3_column_int64(stmt, 0);
656
657         sqlite3_finalize(stmt);
658         DBG("found parent_id(%d)", parent_id);
659         return parent_id;
660 }
661
662 int cal_db_event_insert_record(calendar_record_h record, int original_event_id, int *id)
663 {
664         int ret = -1;
665         int event_id = -1;
666         int index;
667         int input_ver;
668         char query[CAL_DB_SQL_MAX_LEN] = {0};
669         char dtstart_datetime[CAL_STR_SHORT_LEN32] = {0};
670         char dtend_datetime[CAL_STR_SHORT_LEN32] = {0};
671         sqlite3_stmt *stmt = NULL;
672         cal_event_s* event =  (cal_event_s*)(record);
673         cal_rrule_s *rrule = NULL;
674         int tmp = 0;
675         int calendar_book_id = 0;
676         calendar_record_h record_calendar = NULL;
677         int has_alarm = 0;
678         int timezone_id = 0;
679
680         RETV_IF(NULL == event, CALENDAR_ERROR_INVALID_PARAMETER);
681
682         ret = cal_db_event_check_value_validation(event);
683         if (CALENDAR_ERROR_NONE != ret) {
684                 /* LCOV_EXCL_START */
685                 ERR("cal_db_event_check_value_validation() Fail(%d)", ret);
686                 return ret;
687                 /* LCOV_EXCL_STOP */
688         }
689
690         /* access control */
691         if (cal_access_control_have_write_permission(event->calendar_id) == false) {
692                 /* LCOV_EXCL_START */
693                 ERR("cal_access_control_have_write_permission() Fail");
694                 return CALENDAR_ERROR_PERMISSION_DENIED;
695                 /* LCOV_EXCL_STOP */
696         }
697
698         ret = calendar_record_get_int(record, _calendar_event.calendar_book_id, &calendar_book_id);
699         DBG("calendar_book_id(%d)", calendar_book_id);
700
701         ret = cal_db_get_record(_calendar_book._uri, calendar_book_id, &record_calendar);
702         RETVM_IF(CALENDAR_ERROR_NONE != ret, CALENDAR_ERROR_INVALID_PARAMETER, "cal_db_get_record() Fail(%d)", ret);
703
704         calendar_record_destroy(record_calendar, true);
705
706         has_alarm = cal_db_alarm_has_alarm(event->alarm_list);
707         cal_db_timezone_search_with_tzid(event->calendar_id, event->start_tzid, &timezone_id);
708         input_ver = cal_db_util_get_next_ver();
709
710         int is_allday = 0;
711         if (CALENDAR_TIME_LOCALTIME == event->start.type
712                         && (0 == event->start.time.date.hour)
713                         && (0 == event->start.time.date.minute)
714                         && (0 == event->start.time.date.second)
715                         && (0 == event->end.time.date.hour)
716                         && (0 == event->end.time.date.minute)
717                         && (0 == event->end.time.date.second)) {
718                 is_allday = 1;
719         }
720
721         snprintf(query, sizeof(query), "INSERT INTO %s ("
722                         "type, "
723                         "created_ver, changed_ver, "
724                         "summary, description, location, categories, exdate, "
725                         "task_status, priority, "
726                         "timezone, "
727                         "contact_id, busy_status, sensitivity, uid, "
728                         "organizer_name, organizer_email, meeting_status, "
729                         "calendar_id, "
730                         "original_event_id, "
731                         "latitude, longitude, "
732                         "email_id, "
733                         "created_time, completed_time, progress, "
734                         "dtstart_type, dtstart_utime, dtstart_datetime, dtstart_tzid, "
735                         "dtend_type, dtend_utime, dtend_datetime, dtend_tzid, "
736                         "last_mod, rrule_id, "
737                         "recurrence_id, rdate, has_attendee, "
738                         "has_alarm, system_type, updated, "
739                         "sync_data1, sync_data2, sync_data3, sync_data4,"
740                         "has_exception, has_extended, freq, is_allday "
741                         ") VALUES ("
742                         "%d, "
743                         "%d, %d, "
744                         "?, ?, ?, ?, ?, "
745                         "%d, %d, "
746                         "%d, "
747                         "%d, %d, %d, ?, "
748                         "?, ?, %d, "
749                         "%d, "
750                         "%d, "
751                         "%lf, %lf, "
752                         "%d, "
753                         "strftime('%%s', 'now'), %lld, %d, "
754                         "%d, %lld, ?, ?, "
755                         "%d, %lld, ?, ?, "
756                         "strftime('%%s', 'now'), %d, "
757                         "?, ?, %d, %d, %d, %d, "
758                         "?, ?, ?, ?, "
759                         "%d, %d, %d, %d) ",
760                 CAL_TABLE_SCHEDULE,
761                 CAL_SCH_TYPE_EVENT, /*event->cal_type,*/
762                 input_ver, input_ver,
763                 event->event_status, event->priority,
764                 event->timezone ? event->timezone : timezone_id,
765                 event->contact_id, event->busy_status, event->sensitivity,
766                 event->meeting_status,
767                 event->calendar_id,
768                 original_event_id,
769                 event->latitude, event->longitude,
770                 event->email_id,
771                 (long long int)0, 0, /* event->completed_time, event->progress */
772                 event->start.type, event->start.type == CALENDAR_TIME_UTIME ? event->start.time.utime : 0,
773                 event->end.type, event->end.type == CALENDAR_TIME_UTIME ? event->end.time.utime : 0,
774                 0 < event->freq ? 1 : 0,
775                 (0 < event->attendee_list->count) ? 1 : 0,
776                 has_alarm,
777                 event->system_type,
778                 event->updated,
779                 (0 < event->exception_list->count) ? 1 : 0,
780                 (0 < event->extended_list->count) ? 1 : 0,
781                 event->freq, is_allday);
782
783         ret = cal_db_util_query_prepare(query, &stmt);
784         if (CALENDAR_ERROR_NONE != ret) {
785                 /* LCOV_EXCL_START */
786                 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
787                 SECURE("query[%s]", query);
788                 return ret;
789                 /* LCOV_EXCL_STOP */
790         }
791
792         index = 1;
793
794         if (event->summary)
795                 cal_db_util_stmt_bind_text(stmt, index, event->summary);
796         index++;
797
798         if (event->description)
799                 cal_db_util_stmt_bind_text(stmt, index, event->description);
800         index++;
801
802         if (event->location)
803                 cal_db_util_stmt_bind_text(stmt, index, event->location);
804         index++;
805
806         if (event->categories)
807                 cal_db_util_stmt_bind_text(stmt, index, event->categories);
808         index++;
809
810         if (event->exdate)
811                 cal_db_util_stmt_bind_text(stmt, index, event->exdate);
812         index++;
813
814         if (event->uid)
815                 cal_db_util_stmt_bind_text(stmt, index, event->uid);
816         index++;
817
818         if (event->organizer_name)
819                 cal_db_util_stmt_bind_text(stmt, index, event->organizer_name);
820         index++;
821
822         if (event->organizer_email)
823                 cal_db_util_stmt_bind_text(stmt, index, event->organizer_email);
824         index++;
825
826         if (CALENDAR_TIME_LOCALTIME == event->start.type) {
827                 snprintf(dtstart_datetime, sizeof(dtstart_datetime), CAL_FORMAT_LOCAL_DATETIME,
828                                 event->start.time.date.year,
829                                 event->start.time.date.month,
830                                 event->start.time.date.mday,
831                                 event->start.time.date.hour,
832                                 event->start.time.date.minute,
833                                 event->start.time.date.second);
834                 cal_db_util_stmt_bind_text(stmt, index, dtstart_datetime);
835         }
836         index++;
837
838         if (event->start_tzid)
839                 cal_db_util_stmt_bind_text(stmt, index, event->start_tzid);
840         index++;
841
842         if (CALENDAR_TIME_LOCALTIME == event->end.type) {
843                 snprintf(dtend_datetime, sizeof(dtend_datetime), CAL_FORMAT_LOCAL_DATETIME,
844                                 event->end.time.date.year,
845                                 event->end.time.date.month,
846                                 event->end.time.date.mday,
847                                 event->end.time.date.hour,
848                                 event->end.time.date.minute,
849                                 event->end.time.date.second);
850                 cal_db_util_stmt_bind_text(stmt, index, dtend_datetime);
851         }
852         index++;
853
854         if (event->end_tzid)
855                 cal_db_util_stmt_bind_text(stmt, index, event->end_tzid);
856         index++;
857
858         if (event->recurrence_id)
859                 cal_db_util_stmt_bind_text(stmt, index, event->recurrence_id);
860         index++;
861
862         if (event->rdate)
863                 cal_db_util_stmt_bind_text(stmt, index, event->rdate);
864         index++;
865
866         if (event->sync_data1)
867                 cal_db_util_stmt_bind_text(stmt, index, event->sync_data1);
868         index++;
869
870         if (event->sync_data2)
871                 cal_db_util_stmt_bind_text(stmt, index, event->sync_data2);
872         index++;
873
874         if (event->sync_data3)
875                 cal_db_util_stmt_bind_text(stmt, index, event->sync_data3);
876         index++;
877
878         if (event->sync_data4)
879                 cal_db_util_stmt_bind_text(stmt, index, event->sync_data4);
880         index++;
881
882         ret = cal_db_util_stmt_step(stmt);
883         sqlite3_finalize(stmt);
884         if (CALENDAR_ERROR_NONE != ret) {
885                 /* LCOV_EXCL_START */
886                 ERR("cal_db_util_stmt_step() Fail(%d)", ret);
887                 return ret;
888                 /* LCOV_EXCL_STOP */
889         }
890         event_id = cal_db_util_last_insert_id();
891
892         /*
893          * update parent event changed ver in case this event is exception mod
894          * which is original_event_id > 0
895          */
896         cal_db_event_update_original_event_version(original_event_id, input_ver);
897
898         calendar_record_get_int(record, _calendar_event.id, &tmp);
899         cal_record_set_int(record, _calendar_event.id, event_id);
900         if (id)
901                 *id = event_id;
902
903         cal_db_rrule_get_rrule_from_record(record, &rrule);
904         if (rrule) {
905                 cal_db_rrule_insert_record(event_id, rrule);
906                 CAL_FREE(rrule);
907         }
908
909         if (0 < original_event_id)
910                 cal_record_set_int(record, _calendar_event.original_event_id, original_event_id);
911
912         cal_db_instance_publish_record(record);
913
914         while (event->uid && *event->uid) {
915                 if (NULL == event->recurrence_id || '\0' == *event->recurrence_id) {
916                         DBG("this is parent");
917                         /*
918                          * parent exception event is inserted in case child exception existed already.
919                          * find child exceptions and link(one exception) or devide(this and future/prior)
920                          */
921
922                         GList *list = NULL;
923                         list = cal_db_event_get_list_with_uid(event->uid, event_id);
924                         if (NULL == list)
925                                 break;
926                         GList *l = g_list_first(list);
927                         if (l) {
928                                 int child_id = GPOINTER_TO_INT(l->data);
929                                 /* update children original_event_id */
930                                 cal_db_event_update_child_origina_event_id(child_id, event_id);
931                                 char *recurrence_id = NULL;
932                                 recurrence_id = cal_db_event_get_recurrence_id_from_exception(child_id);
933                                 if (NULL == recurrence_id || '\0' == *recurrence_id) {
934                                         if (recurrence_id) free(recurrence_id);
935                                         l = g_list_next(l);
936                                         continue;
937                                 }
938                                 /* remove parent instance */
939                                 cal_db_event_apply_recurrence_id(event_id, event, recurrence_id, child_id);
940                                 free(recurrence_id);
941                                 l = g_list_next(l);
942                         }
943                         g_list_free(list);
944                 } else {
945                         DBG("this is child");
946                         /* get parent with uid and update original_event_id */
947                         int parent_id = 0;
948                         parent_id = __get_parent_id_with_uid(event->uid, event_id);
949                         if (parent_id < 0) {
950                                 /* LCOV_EXCL_START */
951                                 ERR("__get_parent_id_with_uid() Fail");
952                                 break;
953                                 /* LCOV_EXCL_STOP */
954                         }
955                         calendar_record_h parent = NULL;
956                         cal_db_get_record(_calendar_event._uri, parent_id, &parent);
957                         cal_db_event_apply_recurrence_id(parent_id, (cal_event_s *)parent, event->recurrence_id, event_id);
958                         calendar_record_destroy(parent, true);
959                 }
960                 break;
961         }
962
963         if (event->alarm_list->count)   {
964                 DBG("insert alarm");
965                 ret = cal_db_alarm_insert_records(event->alarm_list, event_id);
966                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_db_alarm_insert_records() Fail(%d)", ret);
967         } else {
968                 DBG("No alarm");
969         }
970
971         if (0 < event->attendee_list->count) {
972                 DBG("insert attendee");
973                 ret = cal_db_attendee_insert_records(event->attendee_list, event_id);
974                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_db_attendee_insert_records() Fail(%d)", ret);
975         } else {
976                 DBG("No attendee");
977         }
978
979         if (original_event_id <= 0 && 0 < event->exception_list->count) {
980                 DBG("insert exception");
981                 ret = cal_db_event_insert_records(event->exception_list, event_id);
982                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_db_event_insert_records() Fail(%d)", ret);
983         } else {
984                 DBG("No exception");
985         }
986
987         if (0 < event->extended_list->count) {
988                 DBG("insert extended");
989                 ret = cal_db_extended_insert_records(event->extended_list, event_id, CALENDAR_RECORD_TYPE_EVENT);
990                 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_db_extended_insert_records() Fail(%d)", ret);
991         } else {
992                 DBG("No extended");
993         }
994
995         cal_db_util_notify(CAL_NOTI_TYPE_EVENT);
996
997         cal_record_set_int(record, _calendar_event.id, tmp);
998         return CALENDAR_ERROR_NONE;
999 }
1000
1001 int cal_db_event_insert_records(cal_list_s *list_s, int original_event_id)
1002 {
1003         int ret;
1004         int count = 0;
1005         calendar_record_h record = NULL;
1006         calendar_list_h list = (calendar_list_h)list_s;
1007
1008         RETV_IF(NULL == list, CALENDAR_ERROR_INVALID_PARAMETER);
1009
1010         calendar_list_get_count(list, &count);
1011         if (0 == count)
1012                 return CALENDAR_ERROR_NONE;
1013
1014         calendar_list_first(list);
1015         while (CALENDAR_ERROR_NONE == calendar_list_get_current_record_p(list, &record)) {
1016                 ret = cal_db_event_insert_record(record, original_event_id, NULL);
1017                 RETVM_IF(CALENDAR_ERROR_NONE != ret, ret, "cal_db_extended_insert_record() Fail(%d)", ret);
1018                 calendar_list_next(list);
1019         }
1020         return CALENDAR_ERROR_NONE;
1021 }