Fix coding rule
[platform/core/api/context.git] / src / trigger / ContextItem.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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 <map>
18 #include <vector>
19 #include <algorithm>
20 #include <json/json.h>
21 #include <SharedUtil.h>
22 #include <job_scheduler_internal.h>
23 #include <job_scheduler_types_internal.h>
24 #include <context_trigger.h>
25 #include "PrivilegeChecker.h"
26 #include "ContextItem.h"
27
28 #define CTX_SCHED_URI_ALARM                     CTX_SCHED_URI_PREFIX "event/time"
29 #define CTX_SCHED_URI_CALL                      CTX_SCHED_URI_PREFIX "state/email"
30 #define CTX_SCHED_URI_EMAIL                     CTX_SCHED_URI_PREFIX "event/email"
31 #define CTX_SCHED_URI_MESSAGE           CTX_SCHED_URI_PREFIX "event/message"
32 #define CTX_SCHED_URI_APP_FREQ          CTX_SCHED_URI_PREFIX "stats/app"
33 #define CTX_SCHED_URI_COMM_FREQ         CTX_SCHED_URI_PREFIX "stats/comm"
34 #define CTX_SCHED_URI_MUSIC_FREQ        CTX_SCHED_URI_PREFIX "stats/music"
35 #define CTX_SCHED_URI_VIDEO_FREQ        CTX_SCHED_URI_PREFIX "stats/video"
36
37 #define URI(x)      CTX_SCHED_URI_##x
38 #define NAME(x)     CTX_SCHED_ATTR_NAME_##x
39
40 ContextItem::ContextItem(int cx) :
41         __context(cx),
42         __uri(NULL)
43 {
44 }
45
46 bool ContextItem::allowed()
47 {
48         return PrivilegeChecker::hasPrivilege(__getPrivilege());
49 }
50
51 bool ContextItem::isValid(ctx_sched_job_context_h jobContext)
52 {
53         IF_FAIL_RETURN(jobContext, false);
54
55         struct MandatoryEntry {
56                 const char* uri;
57                 std::vector<const char*> attributes;
58         };
59
60         static std::vector<MandatoryEntry> mandatories = {
61                 { URI(ALARM),           {NAME(TIME_OF_DAY)} },
62                 { URI(GEOFENCE),        {NAME(PLACE_ID)} },
63                 { URI(APP_FREQ),        {CONTEXT_TRIGGER_APP_ID} }
64                 //TODO
65         };
66
67         const char* serialized = ctx_sched_job_context_serialize(jobContext);
68         IF_FAIL_RETURN(serialized, false);
69
70         Json::Value jCtx;
71
72         try {
73                 Json::Reader reader;
74                 if (!reader.parse(serialized, jCtx)) {
75                         _E("Parsing failed");
76                         return false;
77                 }
78         } catch (const Json::Exception& e) {
79                 _E("Exception: %s", e.what());
80                 return false;
81         }
82
83         IF_FAIL_RETURN(jCtx.isMember("Attribute"), false);
84
85         Json::Value& attributes = jCtx["Attribute"];
86
87         for (auto& entry : mandatories) {
88                 if (!STR_EQ(entry.uri, getUri()))
89                         continue;
90
91                 for (auto& mandatoryAttr : entry.attributes) {
92                         // The mandatory attribute should be exist
93                         if (!attributes.isMember(mandatoryAttr))
94                                 return false;
95
96                         // If exist, at least one target value needs to be designated
97                         if (attributes[mandatoryAttr]["Target"].size() == 0)
98                                 return false;
99                 }
100
101                 return true;
102         }
103
104         return true;
105 }
106
107 bool ContextItem::isValidData(const char* attribute)
108 {
109         return (isValidData(attribute, 1) || isValidData(attribute, static_cast<const char*>(NULL)));
110 }
111
112 bool ContextItem::isValidData(const char* attribute, int value)
113 {
114         static std::vector<IntAttributeRange> attributeRanges = {
115                 { URI(ALARM),           NAME(TIME_OF_DAY),      0,      1439 },
116                 { URI(TIME),            NAME(TIME_OF_DAY),      0,      1439 },
117                 { URI(TIME),            NAME(DAY_OF_MONTH),     1,      31 },
118                 { URI(BATTERY),         NAME(IS_CHARGING),      0,      1 },
119                 { URI(CHARGER),         NAME(IS_CONNECTED),     0,      1 },
120                 { URI(EARJACK),         NAME(IS_CONNECTED),     0,      1 },
121                 { URI(USB),                     NAME(IS_CONNECTED),     0,      1 },
122                 { URI(POWERSAVE),       NAME(IS_ENABLED),       0,      1 }
123                 //TODO: unsupported items
124         };
125
126         _D("Verify %s, %d", attribute, value);
127
128         return __isValid(attributeRanges, attribute, value);
129 }
130
131 bool ContextItem::isValidData(const char* attribute, const char* value)
132 {
133         static std::vector<StrAttributeValues> attributeValues = {
134                 { URI(ALARM),           NAME(DAY_OF_WEEK),      {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Weekday", "Weekend"} },
135                 { URI(TIME),            NAME(DAY_OF_WEEK),      {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Weekday", "Weekend"} },
136                 { URI(BATTERY),         NAME(LEVEL),    {"Empty", "Critical", "Low", "Normal", "High", "Full"} },
137                 { URI(GEOFENCE),        NAME(EVENT),    {"In", "Out"} },
138                 { URI(GPS),                     NAME(STATE),    {"Disabled", "Searching", "Connected"} },
139                 { URI(EARJACK),         NAME(TYPE),             {"Normal", "Headset", "Bluetooth"} },
140                 { URI(WIFI),            NAME(STATE),    {"Disabled", "Unconnected", "Connected"} },
141                 { URI(WIFI),            NAME(BSSID),    {} },
142                 { URI(STATIONARY),      NAME(EVENT),    {"Detected"} },
143                 { URI(WALKING),         NAME(EVENT),    {"Detected"} },
144                 { URI(RUNNING),         NAME(EVENT),    {"Detected"} },
145                 { URI(IN_VEHICLE),      NAME(EVENT),    {"Detected"} },
146                 { URI(CONTACTS_DB),     NAME(EVENT),    {"Changed"} },
147                 { URI(CONTACTS_DB),     NAME(TYPE),             {"MyProfile", "Person"} }
148                 //TODO: unsupported items
149         };
150
151         _D("Verify %s, %s", attribute, value);
152
153         return __isValid(attributeValues, attribute, value);
154 }
155
156 bool ContextItem::isValidOption(const char* attribute)
157 {
158         return (isValidOption(attribute, 1) || isValidOption(attribute, static_cast<const char*>(NULL)));
159 }
160
161 bool ContextItem::isValidOption(const char* attribute, int value)
162 {
163         static std::vector<IntAttributeRange> attributeRanges = {
164                 { URI(GEOFENCE),        NAME(PLACE_ID), 1,      INT_MAX }
165                 //TODO: unsupported items
166         };
167
168         _D("Verify %s, %d", attribute, value);
169
170         return __isValid(attributeRanges, attribute, value);
171 }
172
173 bool ContextItem::isValidOption(const char* attribute, const char* value)
174 {
175         static std::vector<StrAttributeValues> attributeValues = {
176                 { URI(STATIONARY),      NAME(ACCURACY), {"Low", "Normal", "High"} },
177                 { URI(WALKING),         NAME(ACCURACY), {"Low", "Normal", "High"} },
178                 { URI(RUNNING),         NAME(ACCURACY), {"Low", "Normal", "High"} },
179                 { URI(IN_VEHICLE),      NAME(ACCURACY), {"Low", "Normal", "High"} }
180                 //TODO: unsupported items
181         };
182
183         _D("Verify %s, %s", attribute, value);
184
185         return __isValid(attributeValues, attribute, value);
186 }
187
188 bool ContextItem::__isValid(const std::vector<IntAttributeRange>& attributeRanges, const char* attribute, int value)
189 {
190         for (auto& range : attributeRanges) {
191                 if (!STR_EQ(range.uri, getUri()))
192                         continue;
193
194                 if (!STR_EQ(range.attribute, attribute))
195                         continue;
196
197                 if (value < range.min || value > range.max)
198                         return false;
199
200                 return true;
201         }
202
203         return false;
204 }
205
206 bool ContextItem::__isValid(const std::vector<StrAttributeValues>& attributeValues, const char* attribute, const char* value)
207 {
208         for (auto& values : attributeValues) {
209                 if (!STR_EQ(values.uri, getUri()))
210                         continue;
211
212                 if (!STR_EQ(values.attribute, attribute))
213                         continue;
214
215                 // NULL value is a wildcard
216                 if (!value)
217                         return true;
218
219                 // Accept any strings
220                 if (values.values.empty())
221                         return true;
222
223                 auto it = std::find_if(values.values.begin(), values.values.end(),
224                                 [&value](const char* validValue)->bool {
225                                         return STR_EQ(value, validValue);
226                                 });
227
228                 if (it == values.values.end())
229                         return false;
230
231                 return true;
232         }
233
234         return false;
235 }
236
237 EventItem::EventItem(int event) :
238         ContextItem(event)
239 {
240 }
241
242 bool EventItem::deprecated()
243 {
244         switch (__context) {
245         case CONTEXT_TRIGGER_EVENT_TIME:
246         case CONTEXT_TRIGGER_EVENT_POWER_SAVING_MODE:
247         case CONTEXT_TRIGGER_EVENT_CALL:
248         case CONTEXT_TRIGGER_EVENT_EMAIL:
249         case CONTEXT_TRIGGER_EVENT_MESSAGE:
250                 return true;
251         default:
252                 return false;
253         }
254 }
255
256 const char* EventItem::getUri()
257 {
258         static const std::map<int, const char*> uriMap = {
259                 {CONTEXT_TRIGGER_EVENT_TIME,                            URI(ALARM)},
260                 {CONTEXT_TRIGGER_EVENT_BATTERY,             URI(BATTERY)},
261                 {CONTEXT_TRIGGER_EVENT_CHARGER,             URI(CHARGER)},
262                 {CONTEXT_TRIGGER_EVENT_GPS,                 URI(GPS)},
263                 {CONTEXT_TRIGGER_EVENT_HEADPHONE,           URI(EARJACK)},
264                 {CONTEXT_TRIGGER_EVENT_POWER_SAVING_MODE,   URI(POWERSAVE)},
265                 {CONTEXT_TRIGGER_EVENT_USB,                 URI(USB)},
266                 {CONTEXT_TRIGGER_EVENT_WIFI,                URI(WIFI)},
267                 {CONTEXT_TRIGGER_EVENT_CALL,                            URI(CALL)},
268                 {CONTEXT_TRIGGER_EVENT_EMAIL,                           URI(EMAIL)},
269                 {CONTEXT_TRIGGER_EVENT_MESSAGE,                         URI(MESSAGE)},
270                 {CONTEXT_TRIGGER_EVENT_CONTACTS,            URI(CONTACTS_DB)},
271                 {CONTEXT_TRIGGER_EVENT_ACTIVITY_STATIONARY, URI(STATIONARY)},
272                 {CONTEXT_TRIGGER_EVENT_ACTIVITY_WALKING,    URI(WALKING)},
273                 {CONTEXT_TRIGGER_EVENT_ACTIVITY_RUNNING,    URI(RUNNING)},
274                 {CONTEXT_TRIGGER_EVENT_ACTIVITY_IN_VEHICLE, URI(IN_VEHICLE)},
275                 {CONTEXT_TRIGGER_EVENT_PLACE,               URI(GEOFENCE)}
276         };
277
278         if (__uri) return __uri;
279
280         auto it = uriMap.find(__context);
281
282         if (it == uriMap.end())
283                 return NULL;
284
285         return (__uri = it->second);
286 }
287
288 const char* EventItem::__getPrivilege()
289 {
290         if (CONTEXT_TRIGGER_EVENT_TIME == __context)
291                 return "http://tizen.org/privilege/alarm.set";
292
293         if (CONTEXT_TRIGGER_EVENT_WIFI == __context)
294                 return "http://tizen.org/privilege/network.get";
295
296         if (CONTEXT_TRIGGER_EVENT_CALL == __context)
297                 return "http://tizen.org/privilege/telephony";
298
299         if (CONTEXT_TRIGGER_EVENT_MESSAGE == __context)
300                 return "http://tizen.org/privilege/message.read";
301
302         if (CONTEXT_TRIGGER_EVENT_CONTACTS == __context)
303                 return "http://tizen.org/privilege/contact.read";
304
305         if (CONTEXT_TRIGGER_EVENT_PLACE == __context)
306                 return "http://tizen.org/privilege/location";
307
308         return NULL;
309 }
310
311 ConditionItem::ConditionItem(int cond) :
312         ContextItem(cond)
313 {
314 }
315
316 bool ConditionItem::deprecated()
317 {
318         switch (__context) {
319         case CONTEXT_TRIGGER_CONDITION_POWER_SAVING_MODE:
320         case CONTEXT_TRIGGER_CONDITION_CALL:
321         case CONTEXT_TRIGGER_CONDITION_APP_USE_FREQUENCY:
322         case CONTEXT_TRIGGER_CONDITION_COMMUNICATION_FREQUENCY:
323         case CONTEXT_TRIGGER_CONDITION_MUSIC_PLAYBACK_FREQUENCY:
324         case CONTEXT_TRIGGER_CONDITION_VIDEO_PLAYBACK_FREQUENCY:
325                 return true;
326         default:
327                 return false;
328         }
329 }
330
331 const char* ConditionItem::getUri()
332 {
333         static const std::map<int, const char*> uriMap = {
334                 {CONTEXT_TRIGGER_CONDITION_TIME,              URI(TIME)},
335                 {CONTEXT_TRIGGER_CONDITION_BATTERY,           URI(BATTERY)},
336                 {CONTEXT_TRIGGER_CONDITION_CHARGER,           URI(CHARGER)},
337                 {CONTEXT_TRIGGER_CONDITION_GPS,               URI(GPS)},
338                 {CONTEXT_TRIGGER_CONDITION_HEADPHONE,         URI(EARJACK)},
339                 {CONTEXT_TRIGGER_CONDITION_POWER_SAVING_MODE, URI(POWERSAVE)},
340                 {CONTEXT_TRIGGER_CONDITION_USB,               URI(USB)},
341                 {CONTEXT_TRIGGER_CONDITION_WIFI,              URI(WIFI)},
342                 {CONTEXT_TRIGGER_CONDITION_CALL,                     URI(CALL)},
343                 {CONTEXT_TRIGGER_CONDITION_APP_USE_FREQUENCY,        URI(APP_FREQ)},
344                 {CONTEXT_TRIGGER_CONDITION_COMMUNICATION_FREQUENCY,  URI(COMM_FREQ)},
345                 {CONTEXT_TRIGGER_CONDITION_MUSIC_PLAYBACK_FREQUENCY, URI(MUSIC_FREQ)},
346                 {CONTEXT_TRIGGER_CONDITION_VIDEO_PLAYBACK_FREQUENCY, URI(VIDEO_FREQ)}
347         };
348
349         if (__uri) return __uri;
350
351         auto it = uriMap.find(__context);
352
353         if (it == uriMap.end())
354                 return NULL;
355
356         return (__uri = it->second);
357 }
358
359 const char* ConditionItem::__getPrivilege()
360 {
361         if (CONTEXT_TRIGGER_CONDITION_WIFI == __context)
362                 return "http://tizen.org/privilege/network.get";
363
364         if (CONTEXT_TRIGGER_CONDITION_CALL == __context)
365                 return "http://tizen.org/privilege/telephony";
366
367         if (CONTEXT_TRIGGER_CONDITION_APP_USE_FREQUENCY == __context)
368                 return "http://tizen.org/privilege/apphistory.read";
369
370         if (CONTEXT_TRIGGER_CONDITION_COMMUNICATION_FREQUENCY == __context)
371                 return "http://tizen.org/privilege/callhistory.read";
372
373         if (CONTEXT_TRIGGER_CONDITION_MUSIC_PLAYBACK_FREQUENCY == __context)
374                 return "http://tizen.org/privilege/mediahistory.read";
375
376         if (CONTEXT_TRIGGER_CONDITION_VIDEO_PLAYBACK_FREQUENCY == __context)
377                 return "http://tizen.org/privilege/mediahistory.read";
378
379         return NULL;
380 }