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