[Alarm] Don't raise an error when an alarm without TYPE is found
[platform/core/api/webapi-plugins.git] / src / alarm / alarm_manager.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include "alarm_manager.h"
18
19 #include <alarm.h>
20 #include <app.h>
21 #include <app_alarm.h>
22 #include <app_control_internal.h>
23
24 #if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
25 #include <notification_internal.h>
26 #endif
27
28 #include "common/converter.h"
29 #include "common/logger.h"
30 #include "common/scope_exit.h"
31 #include "common/tools.h"
32
33 #include "alarm_instance.h"
34 #include "alarm_utils.h"
35
36 #include "notification/common_notification.h"
37 #include "notification/status_notification.h"
38 #include "notification/user_notification.h"
39
40 using namespace common;
41 using namespace common::tools;
42
43 namespace extension {
44 namespace alarm {
45
46 namespace {
47 const int kDateSize = 22;  //"yyy mm dd hh mm ss dd" e.g 115 11 28 11 25 50 -1
48 const std::string kPrivilegeAlarm = "http://tizen.org/privilege/alarm";
49 const std::string kPrivilegeNotification = "http://tizen.org/privilege/notification";
50
51 const std::string kAlarmRelative = "AlarmRelative";
52 const std::string kAlarmAbsolute = "AlarmAbsolute";
53
54 const char* kAlarmAbsoluteRecurrenceTypeKey = "RECURRENCE";
55 const char* kAlarmAbsoluteReccurrenceTypeInterval = "INTERVAL";
56 const char* kAlarmAbsoluteReccurrenceTypeByDayValue = "BYDAYVALUE";
57 const char* kAlarmAbsoluteRecurrenceTypeNone = "NONE";
58 const char* kAlarmAbsoluteDateKey = "DATE";
59
60 const char* kAlarmKeyType = "TYPE";
61
62 const char* kAlarmTypeValueAbsolute = "ABSOLUTE";
63 const char* kAlarmTypeValueRelative = "RELATIVE";
64
65 const char* kAlarmRelativeDelayKey = "RELATIVE_DELAY";
66 }  // namespace
67
68 AlarmManager::AlarmManager() {
69   ScopeLogger();
70 }
71
72 AlarmManager::~AlarmManager() {
73   ScopeLogger();
74 }
75
76 void AlarmManager::Add(const picojson::value& args, picojson::object& out) {
77   ScopeLogger();
78   CHECK_PRIVILEGE_ACCESS(kPrivilegeAlarm, &out);
79
80   if (!args.contains("alarm")) {
81     LogAndReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."),
82                       &out);
83     return;
84   }
85   const picojson::object& alarm = args.get("alarm").get<picojson::object>();
86
87   std::string alarm_type;
88   if (args.contains("type")) {
89     alarm_type = args.get("type").get<std::string>();
90   }
91
92   std::string app_id;
93   if (args.contains("applicationId")) {
94     app_id = args.get("applicationId").get<std::string>();
95   }
96
97   app_control_h app_control = nullptr;
98   SCOPE_EXIT {
99     app_control_destroy(app_control);
100   };
101
102   if (args.contains("appControl") && args.get("appControl").is<picojson::object>()) {
103     PlatformResult result =
104         util::AppControlToService(args.get("appControl").get<picojson::object>(), &app_control);
105     if (!result) {
106       LogAndReportError(result, &out, ("Failed: util::AppControlToService"));
107       return;
108     }
109   } else {
110     app_control_create(&app_control);
111     app_control_set_operation(app_control, APP_CONTROL_OPERATION_DEFAULT);
112   }
113
114   app_control_set_app_id(app_control, app_id.c_str());
115
116   int alarm_id = 0;
117   int period = 0;
118
119   // result object
120   picojson::value result = picojson::value(picojson::object());
121   picojson::object& result_obj = result.get<picojson::object>();
122
123   if (kAlarmRelative == alarm_type) {
124     app_control_add_extra_data(app_control, kAlarmKeyType, kAlarmTypeValueRelative);
125
126     const auto it_delay = alarm.find("delay");
127     const auto it_period = alarm.find("period");
128
129     if (alarm.end() == it_delay || alarm.end() == it_period || !it_delay->second.is<double>()) {
130       LogAndReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."),
131                         &out);
132       return;
133     }
134     int delay = static_cast<int>(it_delay->second.get<double>());
135
136     if (it_period->second.is<double>()) {
137       period = static_cast<int>(it_period->second.get<double>());
138     }
139
140     bool isPeriodSet = false;
141     if (args.contains("isPeriodSet")) {
142       isPeriodSet = args.get("isPeriodSet").get<bool>();
143     }
144
145     std::string delay_str = std::to_string(delay);
146     int ret_app =
147         app_control_add_extra_data(app_control, kAlarmRelativeDelayKey, delay_str.c_str());
148     if (APP_CONTROL_ERROR_NONE != ret_app) {
149       LogAndReportError(
150           PlatformResult(ErrorCode::UNKNOWN_ERR, "Fail to add data from app_control."), &out,
151           ("Fail to add data from app_control: %d (%s)", ret_app, get_error_message(ret_app)));
152       return;
153     }
154
155     int ret = ALARM_ERROR_NONE;
156     if (!isPeriodSet) {
157       ret = alarm_schedule_once_after_delay(app_control, delay, &alarm_id);
158     } else {
159       ret = alarm_schedule_after_delay(app_control, delay, period, &alarm_id);
160     }
161     if (ALARM_ERROR_NONE != ret) {
162       LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Error while add alarm to server."),
163                         &out,
164                         ("Error while add alarm to server: %d (%s)", ret, get_error_message(ret)));
165       return;
166     }
167
168     ret = alarm_get_scheduled_period(alarm_id, &period);
169     if (ALARM_ERROR_NONE != ret) {
170       LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred."), &out,
171                         ("Unknown error occurred: %d (%s)", ret, get_error_message(ret)));
172       return;
173     }
174     if (period != 0) {
175       result_obj.insert(std::make_pair("period", picojson::value(std::to_string(period))));
176     }
177   } else {
178     app_control_add_extra_data(app_control, kAlarmKeyType, kAlarmTypeValueAbsolute);
179
180     const auto it_period = alarm.find("period");
181     const auto it_daysOfTheWeek = alarm.find("daysOfTheWeek");
182
183     long long int seconds = 0;
184     if (args.contains("seconds")) {
185       seconds = atoll(args.get("seconds").get<std::string>().c_str());
186     }
187
188     time_t second = seconds / 1000;
189     struct tm start_date = {0};
190
191     tzset();
192     if (nullptr == localtime_r(&second, &start_date)) {
193       LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Invalid date."), &out);
194       return;
195     }
196
197     mktime(&start_date);
198
199     char str_date[kDateSize];
200
201     snprintf(str_date, sizeof(str_date), "%d %d %d %d %d %d %d", start_date.tm_year,
202              start_date.tm_mon, start_date.tm_mday, start_date.tm_hour, start_date.tm_min,
203              start_date.tm_sec, start_date.tm_isdst);
204
205     app_control_add_extra_data(app_control, kAlarmAbsoluteDateKey, str_date);
206
207     int ret = 0;
208     if (alarm.end() != it_period && it_period->second.is<double>()) {
209       app_control_add_extra_data(app_control, kAlarmAbsoluteRecurrenceTypeKey,
210                                  kAlarmAbsoluteReccurrenceTypeInterval);
211       period = static_cast<int>(it_period->second.get<double>());
212       ret = alarm_schedule_at_date(app_control, &start_date, period, &alarm_id);
213       if (ALARM_ERROR_NONE != ret) {
214         LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Adding alarm to server failed."),
215                           &out,
216                           ("Adding alarm to server failed: %d (%s)", ret, get_error_message(ret)));
217         return;
218       }
219
220       ret = alarm_get_scheduled_period(alarm_id, &period);
221       result_obj.insert(std::make_pair("period", picojson::value(std::to_string(period))));
222     } else if (alarm.end() != it_daysOfTheWeek && it_daysOfTheWeek->second.is<picojson::array>() &&
223                !(it_daysOfTheWeek->second.get<picojson::array>()).empty()) {
224       app_control_add_extra_data(app_control, kAlarmAbsoluteRecurrenceTypeKey,
225                                  kAlarmAbsoluteReccurrenceTypeByDayValue);
226       const picojson::array& days_of_the_week = it_daysOfTheWeek->second.get<picojson::array>();
227       int repeat_value = 0;
228       PlatformResult result = util::ArrayDaysToMask(days_of_the_week, &repeat_value);
229       if (!result) {
230         LogAndReportError(PlatformResult(result.error_code(), result.message()), &out);
231         return;
232       }
233       ret = alarm_schedule_with_recurrence_week_flag(app_control, &start_date, repeat_value,
234                                                      &alarm_id);
235     } else {
236       app_control_add_extra_data(app_control, kAlarmAbsoluteRecurrenceTypeKey,
237                                  kAlarmAbsoluteRecurrenceTypeNone);
238       ret = alarm_schedule_at_date(app_control, &start_date, 0, &alarm_id);
239     }
240
241     if (ALARM_ERROR_NONE != ret) {
242       LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Adding alarm to server failed."),
243                         &out,
244                         ("Adding alarm to server failed: %d (%s)", ret, get_error_message(ret)));
245       return;
246     }
247   }
248
249   result_obj.insert(std::make_pair("id", picojson::value(std::to_string(alarm_id))));
250   ReportSuccess(result, out);
251 }
252
253 #if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
254 void AlarmManager::AddAlarmNotification(const picojson::value& args, picojson::object& out) {
255   using namespace extension::notification;
256   ScopeLogger();
257   CHECK_PRIVILEGE_ACCESS(kPrivilegeAlarm, &out);
258   CHECK_PRIVILEGE_ACCESS(kPrivilegeNotification, &out);
259
260   if (!args.contains("alarm") || !args.contains("notification")) {
261     LogAndReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."),
262                       &out);
263     return;
264   }
265
266   const picojson::object& alarm = args.get("alarm").get<picojson::object>();
267
268   std::string alarm_type;
269   if (args.contains("type")) {
270     alarm_type = args.get("type").get<std::string>();
271   }
272
273   notification_h notification_handle = nullptr;
274   app_control_h app_control = nullptr;
275
276   SCOPE_EXIT {
277     notification_free(notification_handle);
278     app_control_destroy(app_control);
279   };
280
281   using namespace std::placeholders;
282   GetHandleFromJsonFun impl{};
283   if (args.contains("newImpl") && args.get("newImpl").is<bool>() &&
284       args.get("newImpl").get<bool>()) {
285     LoggerD("New implementation");
286     impl = std::bind(&UserNotification::GetNotiHandleFromJson, _1, _2, _3);
287   } else {
288     LoggerW("Deprecated object used");
289     impl = std::bind(&StatusNotification::GetNotiHandleFromJson, _1, _2, _3);
290   }
291
292   PlatformResult platform_result = impl(args.get("notification"), false, &notification_handle);
293   if (!platform_result) {
294     LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, platform_result.message().c_str()),
295                       &out);
296   }
297   platform_result = CommonNotification::GetAppControl(notification_handle, &app_control);
298
299   if (!platform_result) {
300     LogAndReportError(
301         PlatformResult(platform_result.error_code(), platform_result.message().c_str()), &out);
302   }
303
304   int alarm_id = 0;
305   int ret = 0;
306
307   if (kAlarmRelative == alarm_type) {
308     ret = app_control_add_extra_data(app_control, kAlarmKeyType, kAlarmTypeValueRelative);
309     if (ret != APP_CONTROL_ERROR_NONE) {
310       LogAndReportError(
311           PlatformResult(ErrorCode::ABORT_ERR, "Fail to add data from app_control."), &out,
312           ("Fail to add data from app_control: %d (%s)", ret, get_error_message(ret)));
313       return;
314     }
315
316     const auto it_period = alarm.find("period");
317     const auto it_delay = alarm.find("delay");
318
319     if (alarm.end() == it_delay || alarm.end() == it_period || !it_delay->second.is<double>()) {
320       LogAndReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid parameter passed."),
321                         &out);
322       return;
323     }
324
325     int delay = static_cast<int>(it_delay->second.get<double>());
326
327     std::string delay_str = std::to_string(delay);
328     ret = app_control_add_extra_data(app_control, kAlarmRelativeDelayKey, delay_str.c_str());
329     if (APP_CONTROL_ERROR_NONE != ret) {
330       LogAndReportError(
331           PlatformResult(ErrorCode::ABORT_ERR, "Fail to add data from app_control."), &out,
332           ("Fail to add data from app_control: %d (%s)", ret, get_error_message(ret)));
333       return;
334     }
335
336     platform_result = CommonNotification::SetAppControl(notification_handle, app_control);
337
338     if (!platform_result) {
339       LogAndReportError(
340           PlatformResult(platform_result.error_code(), platform_result.message().c_str()), &out);
341     }
342
343     int period = 0;
344     if (it_period->second.is<double>()) {
345       period = static_cast<int>(it_period->second.get<double>());
346     }
347
348     bool isPeriodSet = false;
349     if (args.contains("isPeriodSet")) {
350       isPeriodSet = args.get("isPeriodSet").get<bool>();
351     }
352
353     if (!isPeriodSet) {
354       ret = alarm_schedule_noti_once_after_delay(notification_handle, delay, &alarm_id);
355     } else {
356       ret = alarm_schedule_noti_after_delay(notification_handle, delay, period, &alarm_id);
357     }
358   } else {
359     if (alarm.find("period")->second.is<double>()) {
360       LogAndReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR,
361                                        "AlarmAbsolute constructed by deprecated constructor."),
362                         &out);
363       return;
364     }
365
366     ret = app_control_add_extra_data(app_control, kAlarmKeyType, kAlarmTypeValueAbsolute);
367     if (APP_CONTROL_ERROR_NONE != ret) {
368       LogAndReportError(
369           PlatformResult(ErrorCode::ABORT_ERR, "Fail to add data from app_control."), &out,
370           ("Fail to add data from app_control: %d (%s)", ret, get_error_message(ret)));
371       return;
372     }
373
374     const auto it_daysOfTheWeek = alarm.find("daysOfTheWeek");
375     long long int milliseconds = 0;
376
377     if (args.contains("milliseconds")) {
378       milliseconds = strtoll(args.get("milliseconds").get<std::string>().c_str(), nullptr, 10);
379     }
380
381     time_t second = milliseconds / 1000;
382     struct tm start_date = {0};
383
384     tzset();
385     if (nullptr == localtime_r(&second, &start_date)) {
386       LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Invalid date."), &out);
387       return;
388     }
389
390     mktime(&start_date);
391
392     char str_date[kDateSize];
393
394     snprintf(str_date, sizeof(str_date), "%d %d %d %d %d %d %d", start_date.tm_year,
395              start_date.tm_mon, start_date.tm_mday, start_date.tm_hour, start_date.tm_min,
396              start_date.tm_sec, start_date.tm_isdst);
397
398     ret = app_control_add_extra_data(app_control, kAlarmAbsoluteDateKey, str_date);
399     if (APP_CONTROL_ERROR_NONE != ret) {
400       LogAndReportError(
401           PlatformResult(ErrorCode::ABORT_ERR, "Fail to add data from app_control."), &out,
402           ("Fail to add data from app_control: %d (%s)", ret, get_error_message(ret)));
403       return;
404     }
405
406     if (alarm.end() != it_daysOfTheWeek && it_daysOfTheWeek->second.is<picojson::array>() &&
407         !(it_daysOfTheWeek->second.get<picojson::array>()).empty()) {
408       app_control_add_extra_data(app_control, kAlarmAbsoluteRecurrenceTypeKey,
409                                  kAlarmAbsoluteReccurrenceTypeByDayValue);
410
411       const picojson::array& days_of_the_week = it_daysOfTheWeek->second.get<picojson::array>();
412       int repeat_value = 0;
413       util::ArrayDaysToMask(days_of_the_week, &repeat_value);
414
415       platform_result = CommonNotification::SetAppControl(notification_handle, app_control);
416       if (!platform_result) {
417         LogAndReportError(
418             PlatformResult(platform_result.error_code(), platform_result.message().c_str()), &out);
419       }
420
421       ret = alarm_schedule_noti_with_recurrence_week_flag(notification_handle, &start_date,
422                                                           repeat_value, &alarm_id);
423     } else {
424       ret = app_control_add_extra_data(app_control, kAlarmAbsoluteRecurrenceTypeKey,
425                                        kAlarmAbsoluteRecurrenceTypeNone);
426       if (APP_CONTROL_ERROR_NONE != ret) {
427         LogAndReportError(
428             PlatformResult(ErrorCode::ABORT_ERR, "Fail to add data from app_control."), &out,
429             ("Fail to add data from app_control: %d (%s)", ret, get_error_message(ret)));
430         return;
431       }
432
433       platform_result = CommonNotification::SetAppControl(notification_handle, app_control);
434       if (!platform_result) {
435         LogAndReportError(
436             PlatformResult(platform_result.error_code(), platform_result.message().c_str()), &out);
437       }
438
439       ret = alarm_schedule_noti_once_at_date(notification_handle, &start_date, &alarm_id);
440     }
441   }
442
443   if (ALARM_ERROR_NONE != ret) {
444     if (ALARM_ERROR_INVALID_TIME == ret || ALARM_ERROR_INVALID_DATE == ret ||
445         ALARM_ERROR_INVALID_PARAMETER == ret) {
446       platform_result = PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid data.");
447     } else {
448       platform_result = PlatformResult(ErrorCode::ABORT_ERR, "Error while adding alarm to server.");
449     }
450
451     LogAndReportError(platform_result, &out,
452                       ("Error while add alarm to server: %d (%s)", ret, get_error_message(ret)));
453     return;
454   }
455
456   picojson::value result = picojson::value(picojson::object());
457   picojson::object& result_obj = result.get<picojson::object>();
458
459   if (alarm_type == kAlarmRelative) {
460     int period = 0;
461     ret = alarm_get_scheduled_period(alarm_id, &period);
462     if (ALARM_ERROR_NONE != ret) {
463       LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred."), &out,
464                         ("Unknown error occurred: %d (%s)", ret, get_error_message(ret)));
465       return;
466     }
467     if (0 != period) {
468       result_obj.insert(std::make_pair("period", picojson::value(std::to_string(period))));
469     }
470   }
471
472   result_obj.insert(std::make_pair("id", picojson::value(std::to_string(alarm_id))));
473   ReportSuccess(result, out);
474 }
475 #endif
476
477 void AlarmManager::Remove(const picojson::value& args, picojson::object& out) {
478   ScopeLogger();
479   CHECK_PRIVILEGE_ACCESS(kPrivilegeAlarm, &out);
480
481   int id = 0;
482
483   if (args.contains("id") && args.get("id").is<double>()) {
484     id = static_cast<int>(args.get("id").get<double>());
485   }
486
487   if (id <= 0) {
488     LogAndReportError(PlatformResult(ErrorCode::INVALID_VALUES_ERR, "Invalid id."), &out,
489                       ("id is wrong: %d", id));
490     return;
491   }
492
493   int ret = alarm_cancel(id);
494   if (ALARM_ERROR_NONE == ret) {
495     ReportSuccess(out);
496   } else if (ALARM_ERROR_INVALID_PARAMETER == ret) {
497     LogAndReportError(PlatformResult(ErrorCode::NOT_FOUND_ERR, "Alarm not found."), &out);
498   } else {
499     LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Platform unknown error."), &out,
500                       ("Platform unknown error: %d (%s)", ret, get_error_message(ret)));
501   }
502 }
503
504 void AlarmManager::RemoveAll(const picojson::value& args, picojson::object& out) {
505   ScopeLogger();
506   CHECK_PRIVILEGE_ACCESS(kPrivilegeAlarm, &out);
507
508   int ret = alarm_cancel_all();
509   if (ALARM_ERROR_NONE != ret) {
510     LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Platform unknown error."), &out,
511                       ("Platform unknown error: %d (%s)", ret, get_error_message(ret)));
512     return;
513   }
514
515   ReportSuccess(out);
516 }
517
518 PlatformResult AlarmManager::GetAlarm(int id, picojson::object& obj) {
519   ScopeLogger();
520
521   if (id <= 0) {
522     return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Invalid id.",
523                               ("id is wrong: %d", id));
524   }
525
526   int ret = ALARM_ERROR_NONE;
527   app_control_h app_control = nullptr;
528   char* alarm_type = nullptr;
529   char* date_string = nullptr;
530   char* delay_string = nullptr;
531   notification_h notification_handle = nullptr;
532
533   SCOPE_EXIT {
534     app_control_destroy(app_control);
535     free(alarm_type);
536     free(date_string);
537     free(delay_string);
538     notification_free(notification_handle);
539   };
540
541   if (ALARM_ERROR_NONE != alarm_get_app_control(id, &app_control)) {
542     if (ALARM_ERROR_NONE != alarm_get_notification(id, &notification_handle)) {
543       return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Alarm not found.",
544                                 ("Alarm not found: %d (%s)", ret, get_error_message(ret)));
545     } else {
546       PlatformResult platform_result = extension::notification::CommonNotification::GetAppControl(
547           notification_handle, &app_control);
548       if (!platform_result) {
549         return LogAndCreateResult(
550             platform_result.error_code(), platform_result.message().c_str(),
551             ("Failed to get AppControl: %d (%s)", static_cast<int>(platform_result.error_code()),
552              platform_result.message().c_str()));
553       }
554     }
555   }
556
557   obj.insert(std::make_pair("id", picojson::value(std::to_string(id))));
558
559   ret = app_control_get_extra_data(app_control, kAlarmKeyType, &alarm_type);
560   if (APP_CONTROL_ERROR_NONE != ret) {
561     // This is not always an error.
562     // Sometimes an application adds an alarm without alarm type set in appcontrol's extra data
563     // (possibly, when the alarm is set by a C service app, which doesn't set this value in extra
564     // data). In such cases, we return the alarm as an "Alarm" JS object, having only ID
565     LoggerW("Getting extra data (%s) failed: [%d](%s)", kAlarmKeyType, ret, get_error_message(ret));
566     return PlatformResult(ErrorCode::NO_ERROR);
567   }
568
569   if (!strcmp(alarm_type, kAlarmTypeValueAbsolute)) {
570     struct tm date;
571     memset(&date, 0, sizeof(tm));
572
573     ret = app_control_get_extra_data(app_control, kAlarmAbsoluteDateKey, &date_string);
574
575     if (APP_CONTROL_ERROR_NONE != ret) {
576       return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Failed to get data.",
577                                 ("Failed to get data: %d (%s)", ret, get_error_message(ret)));
578     }
579
580     sscanf(date_string, "%5d %5d %5d %5d %5d %5d %5d", &date.tm_year, &date.tm_mon, &date.tm_mday,
581            &date.tm_hour, &date.tm_min, &date.tm_sec, &date.tm_isdst);
582     mktime(&date);
583
584     obj.insert(std::make_pair("year", picojson::value(std::to_string(date.tm_year + 1900))));
585     obj.insert(std::make_pair("month", picojson::value(std::to_string(date.tm_mon))));
586     obj.insert(std::make_pair("day", picojson::value(std::to_string(date.tm_mday))));
587     obj.insert(std::make_pair("hour", picojson::value(std::to_string(date.tm_hour))));
588     obj.insert(std::make_pair("min", picojson::value(std::to_string(date.tm_min))));
589     obj.insert(std::make_pair("sec", picojson::value(std::to_string(date.tm_sec))));
590
591     int interval = 0;
592
593     ret = app_control_get_extra_data(app_control, kAlarmAbsoluteRecurrenceTypeKey, &alarm_type);
594     if (APP_CONTROL_ERROR_NONE != ret) {
595       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.",
596                                 ("Getting data failed: %d (%s)", ret, get_error_message(ret)));
597     }
598
599     if (!strcmp(alarm_type, kAlarmAbsoluteReccurrenceTypeInterval)) {
600       ret = alarm_get_scheduled_period(id, &interval);
601       if (ALARM_ERROR_NONE != ret) {
602         return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.",
603                                   ("Unknown error occurred: %d (%s)", ret, get_error_message(ret)));
604       }
605
606       obj.insert(std::make_pair("second", picojson::value(std::to_string(interval))));
607     } else if (!strcmp(alarm_type, kAlarmAbsoluteReccurrenceTypeByDayValue)) {
608       int byDayValue = 0;
609
610       ret = alarm_get_scheduled_recurrence_week_flag(id, &byDayValue);
611       if (ALARM_ERROR_NONE != ret) {
612         return LogAndCreateResult(ErrorCode::NOT_FOUND_ERR, "Failed to get data.",
613                                   ("Failed to get data: %d (%s)", ret, get_error_message(ret)));
614       }
615
616       picojson::array& array =
617           obj.insert(std::make_pair("second", picojson::value(picojson::array())))
618               .first->second.get<picojson::array>();
619
620       using namespace util;
621       if (byDayValue & ALARM_WEEK_FLAG_SUNDAY) array.push_back(picojson::value(kSundayShort));
622       if (byDayValue & ALARM_WEEK_FLAG_MONDAY) array.push_back(picojson::value(kMondayShort));
623       if (byDayValue & ALARM_WEEK_FLAG_TUESDAY) array.push_back(picojson::value(kTuesdayShort));
624       if (byDayValue & ALARM_WEEK_FLAG_WEDNESDAY) array.push_back(picojson::value(kWednesdayShort));
625       if (byDayValue & ALARM_WEEK_FLAG_THURSDAY) array.push_back(picojson::value(kThuesdayShort));
626       if (byDayValue & ALARM_WEEK_FLAG_FRIDAY) array.push_back(picojson::value(kFridayShort));
627       if (byDayValue & ALARM_WEEK_FLAG_SATURDAY) array.push_back(picojson::value(kSaturdayShort));
628     }
629
630     obj.insert(std::make_pair("type", picojson::value(kAlarmAbsolute)));
631
632   } else if (!strcmp(alarm_type, kAlarmTypeValueRelative)) {
633     int interval = 0;
634
635     ret = alarm_get_scheduled_period(id, &interval);
636     if (ALARM_ERROR_NONE != ret) {
637       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.",
638                                 ("Unknown error occurred: %d (%s)", ret, get_error_message(ret)));
639     }
640
641     int ret_app = app_control_get_extra_data(app_control, kAlarmRelativeDelayKey, &delay_string);
642     if (APP_CONTROL_ERROR_NONE != ret_app) {
643       return LogAndCreateResult(
644           ErrorCode::NOT_FOUND_ERR, "Failed to get data.",
645           ("Failed to get data: %d (%s)", ret_app, get_error_message(ret_app)));
646     }
647
648     obj.insert(std::make_pair("type", picojson::value(kAlarmRelative)));
649     obj.insert(std::make_pair("delay", picojson::value(delay_string)));
650     if (interval != 0) {
651       // according to documentation interval will not be lower than 600,
652       // thus 0 from native means period wasn't set by user
653       obj.insert(std::make_pair("period", picojson::value(std::to_string(interval))));
654     }
655   } else {
656     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.");
657   }
658
659   return PlatformResult(ErrorCode::NO_ERROR);
660 }
661
662 void AlarmManager::Get(const picojson::value& args, picojson::object& out) {
663   ScopeLogger();
664
665   int id = 0;
666
667   if (args.contains("id") && args.get("id").is<double>()) {
668     id = static_cast<int>(args.get("id").get<double>());
669   }
670
671   picojson::value result = picojson::value(picojson::object());
672   picojson::object& result_obj = result.get<picojson::object>();
673
674   PlatformResult platform_result = GetAlarm(id, result_obj);
675
676   if (!platform_result) {
677     LogAndReportError(platform_result, &out);
678   } else {
679     ReportSuccess(result, out);
680   }
681 }
682
683 #if defined(TIZEN_MOBILE) || defined(TIZEN_WEARABLE)
684 void AlarmManager::GetAlarmNotification(const picojson::value& args, picojson::object& out) {
685   using namespace extension::notification;
686   ScopeLogger();
687
688   int alarm_id = 0;
689   int ret = ALARM_ERROR_NONE;
690   notification_h notification_handle = nullptr;
691   PlatformResult platform_result = PlatformResult(ErrorCode::NO_ERROR);
692
693   SCOPE_EXIT {
694     notification_free(notification_handle);
695   };
696
697   if (args.contains("id") && args.get("id").is<double>()) {
698     alarm_id = static_cast<int>(args.get("id").get<double>());
699   }
700
701   ret = alarm_get_notification(alarm_id, &notification_handle);
702
703   if (ALARM_ERROR_NONE != ret) {
704     if (ALARM_ERROR_INVALID_PARAMETER == ret) {
705       platform_result =
706           PlatformResult(ErrorCode::NOT_FOUND_ERR, "Alarm with given ID was not found.");
707     } else {
708       platform_result = PlatformResult(ErrorCode::ABORT_ERR, "Failed to get notification.");
709     }
710     LogAndReportError(platform_result, &out);
711   }
712
713   app_control_h app_control = nullptr;
714   platform_result = CommonNotification::GetAppControl(notification_handle, &app_control);
715
716   if (!platform_result) {
717     LogAndReportError(platform_result, &out);
718   }
719
720   picojson::value result = picojson::value(picojson::object());
721   picojson::object& result_obj = result.get<picojson::object>();
722
723   platform_result = UserNotification::ToJson(-1, notification_handle, app_control, &result_obj);
724
725   if (ALARM_ERROR_NONE != ret) {
726     LogAndReportError(PlatformResult(ErrorCode::ABORT_ERR, "Failed ToJson()."), &out);
727   }
728
729   ReportSuccess(result, out);
730 }
731 #endif
732 static bool AlarmIterateCB(int alarm_id, void* user_data) {
733   ScopeLogger();
734
735   std::vector<int>* alarm_ids = reinterpret_cast<std::vector<int>*>(user_data);
736
737   alarm_ids->push_back(alarm_id);
738   return true;
739 }
740 #include <stdio.h>
741
742 void AlarmManager::GetAll(const picojson::value& args, picojson::object& out) {
743   ScopeLogger();
744   std::vector<int> alarm_ids;
745   int ret = alarm_foreach_registered_alarm(AlarmIterateCB, &alarm_ids);
746
747   if (ALARM_ERROR_NONE != ret) {
748     LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Platform unknown error."), &out,
749                       ("Platform unknown error: %d (%s)", ret, get_error_message(ret)));
750     return;
751   }
752
753   picojson::value result_array = picojson::value(picojson::array());
754   picojson::array& array_obj = result_array.get<picojson::array>();
755
756   for (size_t i = 0; i < alarm_ids.size(); i++) {
757     picojson::value result = picojson::value(picojson::object());
758     picojson::object& obj = result.get<picojson::object>();
759
760     PlatformResult platform_result = GetAlarm(alarm_ids.at(i), obj);
761     if (!platform_result) {
762       LogAndReportError(platform_result, &out, ("Failed GetAlarm()"));
763       return;
764     }
765     array_obj.push_back(result);
766   }
767
768   ReportSuccess(result_array, out);
769 }
770
771 void AlarmManager::GetRemainingSeconds(const picojson::value& args, picojson::object& out) {
772   ScopeLogger();
773
774   struct tm date;
775   struct tm current;
776   time_t current_time;
777   time_t next_time;
778
779   int id = 0;
780
781   if (args.contains("id") && args.get("id").is<double>()) {
782     id = static_cast<int>(args.get("id").get<double>());
783   }
784
785   picojson::value result = picojson::value(picojson::object());
786   picojson::object& result_obj = result.get<picojson::object>();
787
788   int ret = alarm_get_scheduled_date(id, &date);
789   if (ALARM_ERROR_NONE != ret) {
790     LoggerI("alarm_get_scheduled_date error: %d (%s)", ret, get_error_message(ret));
791     if (ALARM_ERROR_INVALID_PARAMETER == ret || ALARM_ERROR_CONNECTION_FAIL == ret) {
792       result_obj.insert(std::make_pair("seconds", picojson::value()));
793       ReportSuccess(result, out);
794       return;
795     } else {
796       LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Platform unknown error."), &out);
797       return;
798     }
799   }
800
801   alarm_get_current_time(&current);
802   next_time = mktime(&date);
803   current_time = mktime(&current);
804
805   long seconds = next_time - current_time;
806
807   result_obj.insert(std::make_pair("seconds", picojson::value(std::to_string(seconds))));
808   ReportSuccess(result, out);
809 }
810
811 void AlarmManager::GetNextScheduledDate(const picojson::value& args, picojson::object& out) {
812   ScopeLogger();
813   int id = 0;
814
815   if (args.contains("id") && args.get("id").is<double>()) {
816     id = static_cast<int>(args.get("id").get<double>());
817   }
818
819   struct tm date;
820   int ret = alarm_get_scheduled_date(id, &date);
821
822   picojson::value result = picojson::value(picojson::object());
823   picojson::object& result_obj = result.get<picojson::object>();
824
825   if (ALARM_ERROR_NONE != ret) {
826     result_obj.insert(std::make_pair("year", picojson::value()));
827     ReportSuccess(result, out);
828     return;
829   }
830
831   struct tm curr_date;
832   ret = alarm_get_current_time(&curr_date);
833   if (ALARM_ERROR_NONE != ret || mktime(&date) < mktime(&curr_date)) {
834     result_obj.insert(std::make_pair("year", picojson::value()));
835     ReportSuccess(result, out);
836     return;
837   }
838
839   // tm struct contains years since 1900
840   // there is added 1900 to tm_year to return proper date
841   result_obj.insert(std::make_pair("year", picojson::value(std::to_string(date.tm_year + 1900))));
842   result_obj.insert(std::make_pair("month", picojson::value(std::to_string(date.tm_mon))));
843   result_obj.insert(std::make_pair("day", picojson::value(std::to_string(date.tm_mday))));
844   result_obj.insert(std::make_pair("hour", picojson::value(std::to_string(date.tm_hour))));
845   result_obj.insert(std::make_pair("min", picojson::value(std::to_string(date.tm_min))));
846   result_obj.insert(std::make_pair("sec", picojson::value(std::to_string(date.tm_sec))));
847
848   ReportSuccess(result, out);
849 }
850
851 }  // namespace alarm
852 }  // namespace extension