set rtc time when time is changed externally
[framework/appfw/alarm-manager.git] / alarm-manager-schedule.c
1 /*
2  *  alarm-manager
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Venkatesha Sarpangala <sarpangala.v@samsung.com>, Jayoun Lee <airjany@samsung.com>,
7  * Sewook Park <sewook7.park@samsung.com>, Jaeho Lee <jaeho81.lee@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23
24
25
26 #define _BSD_SOURCE             /*localtime_r requires */
27 #include<stdio.h>
28 #include<stdlib.h>
29 #include<time.h>
30 #include<signal.h>
31 #include<string.h>
32 #include<sys/types.h>
33
34 #include<dbus/dbus.h>
35 #include<glib.h>
36
37 #include"alarm.h"
38 #include"alarm-internal.h"
39 #define WAKEUP_ALARM_APP_ID "org.tizen.alarm.ALARM"     /*alarm ui
40                                                            application's alarm's dbus_service name instead of 21 value */
41
42 extern __alarm_server_context_t alarm_context;
43 extern GSList *g_scheduled_alarm_list;
44
45 #ifdef __ALARM_BOOT
46 extern bool enable_power_on_alarm;
47 #endif
48
49 static void __free_scheduled_alarm(gpointer data, gpointer user_data);
50 static time_t __alarm_next_duetime_once(__alarm_info_t *__alarm_info);
51 static time_t __alarm_next_duetime_repeat(__alarm_info_t *__alarm_info);
52 static time_t __alarm_next_duetime_annually(__alarm_info_t *__alarm_info);
53 static time_t __alarm_next_duetime_monthly(__alarm_info_t *__alarm_info);
54 static time_t __alarm_next_duetime_weekly(__alarm_info_t *__alarm_info);
55 static bool __find_next_alarm_to_be_scheduled(time_t *min_due_time);
56 #ifdef __ALARM_BOOT
57 /*alarm boot*/
58 static bool __find_next_alarm_to_be_scheduled_power_on(time_t *min_due_time);
59 bool _alarm_find_mintime_power_on(time_t *min_time);
60 #endif
61 bool _alarm_schedule(void);
62
63 static void __free_scheduled_alarm(gpointer data, gpointer user_data)
64 {
65         if (data != NULL) {
66                 g_free(data);
67         }
68 }
69
70 bool _clear_scheduled_alarm_list()
71 {
72
73         g_slist_foreach(g_scheduled_alarm_list, __free_scheduled_alarm, NULL);
74         g_slist_free(g_scheduled_alarm_list);
75
76         g_scheduled_alarm_list = NULL;
77
78         return true;
79 }
80
81 bool _init_scheduled_alarm_list()
82 {
83         _clear_scheduled_alarm_list();
84
85         return true;
86 }
87
88 bool _add_to_scheduled_alarm_list(__alarm_info_t *__alarm_info)
89 {
90 /*
91  *      20080328. Sewook Park(sewook7.park@samsung.com)
92  *      When multiple alarms are expired at same time, dbus rpc call for alarm
93  *      ui should be invoked first.(Ui conflicting manager cannot manage the 
94  *      different kinds of alarm popups(wake up alarm/org alarm) correctly, 
95  *      when they are displayed at same time)So when arranging the schedule 
96  *      alarm list, wake up alarm element is located ahead.
97  */
98
99         bool prior = false;
100         gint count = 0;
101         GSList *iter = NULL;
102         __scheduled_alarm_t *alarm = NULL;
103         __scheduled_alarm_t *entry = NULL;
104
105         alarm = g_malloc(sizeof(__scheduled_alarm_t));
106         if (alarm == NULL) {
107                 return false;
108         }
109
110         alarm->used = true;
111         alarm->alarm_id = __alarm_info->alarm_id;
112         alarm->pid = __alarm_info->pid;
113         alarm->__alarm_info = __alarm_info;
114
115         ALARM_MGR_LOG_PRINT("%s :alarm->pid =%d, app_service_name=%s(%u)\n",
116                             __FUNCTION__, alarm->pid,
117                         g_quark_to_string(alarm->
118                         __alarm_info->quark_app_service_name),
119                             alarm->__alarm_info->quark_app_service_name);
120
121         if (alarm->__alarm_info->quark_app_service_name !=
122             g_quark_from_string(WAKEUP_ALARM_APP_ID)) {
123                 g_scheduled_alarm_list =
124                     g_slist_append(g_scheduled_alarm_list, alarm);
125                 return true;
126         } else {
127                 for (iter = g_scheduled_alarm_list; iter != NULL;
128                      iter = g_slist_next(iter)) {
129                         count++;
130                         entry = iter->data;
131                         if (entry->__alarm_info->quark_app_service_name !=
132                             g_quark_from_string(WAKEUP_ALARM_APP_ID)) {
133                                 prior = true;
134                                 break;
135                         }
136                 }
137
138                 if (!prior) {
139                         g_scheduled_alarm_list =
140                             g_slist_append(g_scheduled_alarm_list, alarm);
141                         ALARM_MGR_LOG_PRINT(
142                             "appended : prior is %d\tcount is %d\n", prior,
143                              count);
144                 } else {
145                         g_scheduled_alarm_list =
146                             g_slist_insert(g_scheduled_alarm_list, alarm,
147                                            count - 1);
148                         ALARM_MGR_LOG_PRINT(
149                             "appended : prior is %d\tcount is %d\n", prior,
150                              count);
151                 }
152         }
153
154         return true;
155 }
156
157 bool _remove_from_scheduled_alarm_list(int pid, alarm_id_t alarm_id)
158 {
159         bool result = false;
160         GSList *iter = NULL;
161         __scheduled_alarm_t *alarm = NULL;
162
163         for (iter = g_scheduled_alarm_list; iter != NULL;
164              iter = g_slist_next(iter)) {
165                 alarm = iter->data;
166                 if (alarm->alarm_id == alarm_id) {
167                         g_scheduled_alarm_list =
168                             g_slist_remove(g_scheduled_alarm_list, iter->data);
169                         /*g_free(iter->data); */
170                         result = true;
171                         break;
172                 }
173
174         }
175
176         if (g_slist_length(g_scheduled_alarm_list) == 0) {
177                 alarm_context.c_due_time = -1;
178         }
179
180         return result;
181 }
182
183 static time_t __alarm_next_duetime_once(__alarm_info_t *__alarm_info)
184 {
185         time_t due_time = 0;
186         time_t current_time = 0;
187         struct tm duetime_tm;
188         int wday;
189
190         alarm_info_t *alarm_info = &__alarm_info->alarm_info;
191         alarm_date_t *start = &alarm_info->start;
192
193         time(&current_time);
194         localtime_r(&current_time, &duetime_tm);
195         wday = duetime_tm.tm_wday;
196         duetime_tm.tm_hour = start->hour;
197         duetime_tm.tm_min = start->min;
198         duetime_tm.tm_sec = start->sec;
199
200         if (start->year == 0 && start->month == 0 && start->day == 0)
201                 /*any date */  {
202                 due_time = mktime(&duetime_tm);
203                 if (!(due_time > current_time)) {
204                         due_time = due_time + 60 * 60 * 24;
205                 }
206         } else  /*specific date*/ {
207                 duetime_tm.tm_year = start->year - 1900;
208                 duetime_tm.tm_mon = start->month - 1;
209                 duetime_tm.tm_mday = start->day;
210                 due_time = mktime(&duetime_tm);
211         }
212
213         return due_time;
214
215 }
216
217 static time_t __alarm_next_duetime_repeat(__alarm_info_t *__alarm_info)
218 {
219         time_t due_time = 0;
220         time_t current_time = 0;
221         struct tm duetime_tm;
222
223         alarm_info_t *alarm_info = &__alarm_info->alarm_info;
224         alarm_date_t *start = &alarm_info->start;
225
226         time(&current_time);
227         /*localtime_r(&current_time, &duetime_tm); */
228
229         duetime_tm.tm_hour = start->hour;
230         duetime_tm.tm_min = start->min;
231         duetime_tm.tm_sec = start->sec;
232
233         duetime_tm.tm_year = start->year - 1900;
234         duetime_tm.tm_mon = start->month - 1;
235         duetime_tm.tm_mday = start->day;
236
237         due_time = mktime(&duetime_tm);
238
239         while (__alarm_info->start > due_time || current_time >= due_time) {
240                 due_time += alarm_info->mode.u_interval.interval;
241
242                 /* due_time = mktime(&duetime_tm); */
243         }
244         localtime_r(&due_time, &duetime_tm);
245
246         start->year = duetime_tm.tm_year + 1900;
247         start->month = duetime_tm.tm_mon + 1;
248         start->day = duetime_tm.tm_mday;
249         start->hour = duetime_tm.tm_hour;
250         start->min = duetime_tm.tm_min;
251         start->sec = duetime_tm.tm_sec;
252
253         return due_time;
254
255 }
256
257 static time_t __alarm_next_duetime_annually(__alarm_info_t *__alarm_info)
258 {
259         time_t due_time = 0;
260         time_t current_time = 0;
261         struct tm duetime_tm;
262         int wday;
263
264         alarm_info_t *alarm_info = &__alarm_info->alarm_info;
265         alarm_date_t *start = &alarm_info->start;
266
267         time(&current_time);
268         localtime_r(&current_time, &duetime_tm);
269         wday = duetime_tm.tm_wday;
270         duetime_tm.tm_hour = start->hour;
271         duetime_tm.tm_min = start->min;
272         duetime_tm.tm_sec = start->sec;
273
274         if (start->year != 0) {
275                 duetime_tm.tm_year = start->year - 1900;
276         }
277
278         duetime_tm.tm_mon = start->month - 1;
279         duetime_tm.tm_mday = start->day;
280
281         due_time = mktime(&duetime_tm);
282
283         while (__alarm_info->start > due_time || current_time > due_time) {
284                 duetime_tm.tm_year += 1;
285                 due_time = mktime(&duetime_tm);
286         }
287
288         return due_time;
289
290 }
291
292 static time_t __alarm_next_duetime_monthly(__alarm_info_t *__alarm_info)
293 {
294         time_t due_time = 0;
295         time_t current_time = 0;
296         struct tm duetime_tm;
297         int wday;
298
299         alarm_info_t *alarm_info = &__alarm_info->alarm_info;
300         alarm_date_t *start = &alarm_info->start;
301
302         time(&current_time);
303         localtime_r(&current_time, &duetime_tm);
304         wday = duetime_tm.tm_wday;
305         duetime_tm.tm_hour = start->hour;
306         duetime_tm.tm_min = start->min;
307         duetime_tm.tm_sec = start->sec;
308
309         if (start->year != 0) {
310                 duetime_tm.tm_year = start->year - 1900;
311         }
312
313         if (start->month != 0) {
314
315                 duetime_tm.tm_mon = start->month - 1;
316         }
317
318         duetime_tm.tm_mday = start->day;
319
320         due_time = mktime(&duetime_tm);
321
322         while (__alarm_info->start > due_time || current_time > due_time) {
323                 duetime_tm.tm_mon += 1;
324                 if (duetime_tm.tm_mon == 12) {
325                         duetime_tm.tm_mon = 0;
326                         duetime_tm.tm_year += 1;
327                 }
328                 due_time = mktime(&duetime_tm);
329         }
330
331         return due_time;
332
333 }
334
335 static time_t __alarm_next_duetime_weekly(__alarm_info_t *__alarm_info)
336 {
337         time_t due_time = 0;
338         time_t current_time = 0;
339         struct tm duetime_tm;
340         int wday;
341
342         alarm_info_t *alarm_info = &__alarm_info->alarm_info;
343         alarm_date_t *start = &alarm_info->start;
344
345         alarm_mode_t *mode = &alarm_info->mode;
346
347         time(&current_time);
348         localtime_r(&current_time, &duetime_tm);
349         wday = duetime_tm.tm_wday;
350         duetime_tm.tm_hour = start->hour;
351         duetime_tm.tm_min = start->min;
352         duetime_tm.tm_sec = start->sec;
353
354         if (__alarm_info->start != 0) {
355
356                 if (__alarm_info->start >= current_time)        /*case 1*/ {
357                         duetime_tm.tm_year = start->year - 1900;
358                         duetime_tm.tm_mon = start->month - 1;
359                         duetime_tm.tm_mday = start->day;
360                 } else  /*case 3*/ {
361                         /*don't need to be set */
362                 }
363         }
364         /*case 4 */
365
366         due_time = mktime(&duetime_tm);
367         wday = duetime_tm.tm_wday;
368
369         /* CQ defect(72810) : only one time alarm function is not working 
370            under all recurrence_disabled. */
371         if (due_time > current_time && mode->u_interval.day_of_week == 0)
372                 return due_time;
373
374         if (current_time >= due_time
375             || !(mode->u_interval.day_of_week & 1 << wday)) {
376                 int day = wday + 1;
377                 int next_week = 0;
378                 int interval = 1;
379                 /*this week */
380
381                 if (day == 7) {
382                         day = 0;
383                         next_week = 1;
384                 }
385
386                 while (!(mode->u_interval.day_of_week & 1 << day)
387                        && interval < 8) {
388                         day += 1;
389                         interval += 1;
390
391                         if (day == 7) {
392                                 day = 0;
393                                 next_week = 1;
394                         }
395
396                 }
397                 ALARM_MGR_LOG_PRINT("interval : %d\n", interval);
398                 due_time += 60 * 60 * 24 * interval;
399         }
400
401         return due_time;
402
403 }
404
405 time_t _alarm_next_duetime(__alarm_info_t *__alarm_info)
406 {
407
408         time_t current_time = 0;
409         time_t due_time = 0;
410
411         alarm_info_t *alarm_info = &__alarm_info->alarm_info;
412         alarm_mode_t *mode = &alarm_info->mode;
413
414         time(&current_time);
415
416         ALARM_MGR_LOG_PRINT("mode->repeat is %d\n", mode->repeat);
417
418         if (mode->repeat == ALARM_REPEAT_MODE_ONCE) {
419                 due_time = __alarm_next_duetime_once(__alarm_info);
420         } else if (mode->repeat == ALARM_REPEAT_MODE_REPEAT) {
421                 due_time = __alarm_next_duetime_repeat(__alarm_info);
422         } else if (mode->repeat == ALARM_REPEAT_MODE_ANNUALLY) {
423                 due_time = __alarm_next_duetime_annually(__alarm_info);
424         } else if (mode->repeat == ALARM_REPEAT_MODE_MONTHLY) {
425                 due_time = __alarm_next_duetime_monthly(__alarm_info);
426         } else if (mode->repeat == ALARM_REPEAT_MODE_WEEKLY) {
427                 due_time = __alarm_next_duetime_weekly(__alarm_info);
428         } else {
429                 ALARM_MGR_EXCEPTION_PRINT("repeat mode(%d) is wrong\n",
430                                           mode->repeat);
431                 return 0;
432         }
433
434         ALARM_MGR_LOG_PRINT("due_time %d\n", due_time);
435
436         if (__alarm_info->end != 0 && __alarm_info->end < due_time) {
437                 ALARM_MGR_LOG_PRINT("due time > end time");
438                 __alarm_info->due_time = 0;
439                 return 0;
440         }
441         __alarm_info->due_time = due_time;
442
443         return due_time;
444
445 }
446
447 static bool __find_next_alarm_to_be_scheduled(time_t *min_due_time)
448 {
449         time_t current_time;
450         time_t min_time = -1;
451         time_t due_time;
452         GSList *iter = NULL;
453         __alarm_info_t *entry = NULL;
454
455         time(&current_time);
456
457         for (iter = alarm_context.alarms; iter != NULL;
458              iter = g_slist_next(iter)) {
459                 entry = iter->data;
460                 due_time = entry->due_time;
461
462                 double interval = 0;
463
464                 ALARM_MGR_LOG_PRINT("alarm[%d] with duetime(%u) at "
465                                     "current(%u) pid: (%d)\n",
466                      entry->alarm_id, due_time, current_time, entry->pid);
467                 if (due_time == 0)      /*0 means this alarm 
468                         has been disabled*/ {
469                         continue;
470                 }
471
472                 interval = difftime(due_time, current_time);
473
474                 if (interval <= 0)      /*2008.08.06 when the alarm expires, 
475                         it may makes an error.*/ {
476                         ALARM_MGR_LOG_PRINT("this may be error.. alarm[%d]\n",
477                                             entry->alarm_id);
478                         continue;
479                 }
480
481                 interval = difftime(due_time, min_time);
482
483                 if ((interval < 0) || min_time == -1) {
484                         min_time = due_time;
485                 }
486
487         }
488
489         *min_due_time = min_time;
490         return true;
491 }
492
493 #ifdef __ALARM_BOOT
494 /*alarm boot*/
495 static bool __find_next_alarm_to_be_scheduled_power_on(time_t *min_due_time)
496 {
497         time_t current_time;
498         time_t min_time = -1;
499         time_t due_time;
500         struct tm duetime_tm;
501         __alarm_info_t *entry = NULL;
502         struct tm *temp_info;
503         GSList *iter = NULL;
504
505         time(&current_time);
506
507         tzset();                /*for portability tzset() need to be called
508                                 before locatime_r,refer manpage localtime_r*/
509         temp_info = localtime_r(&current_time, &duetime_tm);
510
511         if (temp_info != NULL)
512                 ALARM_MGR_LOG_PRINT
513                     ("__find_next_alarm_to_be_scheduled_power_on "
514                      ": %d %d %d %d %d\n", temp_info->tm_year,
515                      temp_info->tm_mon, temp_info->tm_mday, temp_info->tm_hour,
516                      temp_info->tm_min);
517
518         for (iter = alarm_context.alarms; iter != NULL;
519              iter = g_slist_next(iter)) {
520                 entry = iter->data;
521                 due_time = entry->due_time;
522
523                 double interval = 0;
524
525                 ALARM_MGR_LOG_PRINT("%s\n", g_quark_to_string(
526                         entry->quark_dst_service_name));
527
528                 /*if(entry->quark_dst_service_name  != g_quark_from_string
529                    (WAKEUP_ALARM_APP_ID)) continue; */
530
531                 if (strcmp
532                     (g_quark_to_string(entry->quark_dst_service_name),
533                      WAKEUP_ALARM_APP_ID) != 0)
534                         continue;
535
536                 ALARM_MGR_LOG_PRINT(
537                     "alarm[%d] with duetime(%u) at current(%u)\n",
538                      entry->alarm_id, due_time, current_time);
539                 if (due_time == 0)      /* 0 means this alarm has 
540                         been disabled*/ {
541                         continue;
542                 }
543
544                 interval = difftime(due_time, current_time);
545
546                 if (interval <= 0)      /*2008.08.06 when the alarm expires, 
547                 it may makes an error.*/ {
548                         ALARM_MGR_LOG_PRINT("this may be error.. alarm[%d]\n",
549                                             entry->alarm_id);
550                         continue;
551                 }
552
553                 interval = difftime(due_time, min_time);
554
555                 if ((interval < 0) || min_time == -1) {
556                         min_time = due_time;
557                 }
558
559         }
560
561         *min_due_time = min_time;
562         return true;
563 }
564 #endif
565
566 bool _alarm_schedule()
567 {
568         time_t current_time;
569         time_t due_time;
570         time_t min_time;
571         GSList *iter;
572         __alarm_info_t *entry = NULL;
573
574         int min = -1;
575
576         time(&current_time);
577
578         min_time = 0;
579
580         __find_next_alarm_to_be_scheduled(&min_time);
581
582         if (min_time == -1) {
583                 ALARM_MGR_LOG_PRINT("[alarm-server][schedule]: There is no "
584                                     "alarm to be scheduled..\n");
585         } else {
586                 for (iter = alarm_context.alarms; iter != NULL;
587                      iter = g_slist_next(iter)) {
588                         entry = iter->data;
589                         due_time = entry->due_time;
590
591                         if (due_time == min_time) {
592                                 _add_to_scheduled_alarm_list(entry);
593                         }
594
595         }
596
597                 _alarm_set_timer(&alarm_context, alarm_context.timer, min_time,
598                                  min);
599
600         }
601
602         return true;
603 }
604
605 #ifdef __ALARM_BOOT
606 /*alarm boot*/
607 bool _alarm_find_mintime_power_on(time_t *min_time)
608 {
609
610         __find_next_alarm_to_be_scheduled_power_on(min_time);
611
612         if ((*min_time) == -1) {
613                 ALARM_MGR_LOG_PRINT("[alarm-server][schedule]: There is no "
614                                     "alarm boot to be scheduled..\n");
615                 return false;
616         }
617
618         return true;
619 }
620 #endif