tizen 2.4 release
[framework/context/context-service.git] / src / context_trigger / rule_manager.cpp
1 /*
2  * Copyright (c) 2015 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 <sstream>
18 #include <app.h>
19 #include <glib.h>
20 #include <types_internal.h>
21 #include <json.h>
22 #include <stdlib.h>
23 #include <bundle.h>
24 #include <app_control.h>
25 #include <appsvc.h>
26 #include <app_control_internal.h>
27 #include <device/display.h>
28 #include <notification.h>
29 #include <notification_internal.h>
30 #include <runtime_info.h>
31 #include <system_settings.h>
32 #include <context_trigger_types_internal.h>
33 #include <context_trigger.h>
34 #include <db_mgr.h>
35 #include "../dbus_server_impl.h"
36 #include <app_manager.h>
37 #include "fact_reader.h"
38 #include "rule_manager.h"
39 #include "script_generator.h"
40 #include "trigger.h"
41
42 #define RULE_TABLE "context_trigger_rule"
43 #define EVENT_TABLE "context_trigger_event"
44 #define CONDITION_TABLE "context_trigger_condition"
45 #define TEMPLATE_TABLE "context_trigger_template"
46
47 #define RULE_TABLE_COLUMNS "enabled INTEGER DEFAULT 0 NOT NULL, creator TEXT DEFAULT '' NOT NULL, creator_app_id TEXT DEFAULT '' NOT NULL, description TEXT DEFAULT '', details TEXT DEFAULT '' NOT NULL"
48 #define EVENT_TABLE_COLUMNS "rule_id INTEGER references context_trigger_rule(row_id) ON DELETE CASCADE NOT NULL, name TEXT DEFAULT '' NOT NULL, instance_name TEXT DEFAULT ''"
49 #define CONDITION_TABLE_COLUMNS "rule_id INTEGER references context_trigger_rule(row_id) ON DELETE CASCADE NOT NULL, name TEXT DEFAULT '' NOT NULL, option TEXT DEFAULT '', instance_name TEXT DEFAULT ''"
50 #define CREATE_TEMPLATE_TABLE "CREATE TABLE IF NOT EXISTS context_trigger_template (name TEXT DEFAULT '' NOT NULL PRIMARY KEY, operation INTEGER DEFAULT 3 NOT NULL, attributes TEXT DEFAULT '' NOT NULL, options TEXT DEFAULT '' NOT NULL)"
51 #define QUERY_TEMPLATE_TABLE "SELECT name, operation, attributes, options FROM context_trigger_template"
52 #define FOREIGN_KEYS_ON "PRAGMA foreign_keys = ON"
53 #define DELETE_RULE_STATEMENT "DELETE FROM 'context_trigger_rule' where row_id = "
54 #define UPDATE_RULE_ENABLED_STATEMENT "UPDATE context_trigger_rule SET enabled = 1 WHERE row_id = "
55 #define UPDATE_RULE_DISABLED_STATEMENT "UPDATE context_trigger_rule SET enabled = 0 WHERE row_id = "
56 #define QUERY_NAME_INSTANCE_NAME_AND_ATTRIBUTES_BY_RULE_ID_STATEMENT "SELECT context_trigger_condition.name, instance_name, attributes FROM context_trigger_condition JOIN context_trigger_template ON (context_trigger_condition.name = context_trigger_template.name) WHERE rule_id = "
57 #define QUERY_CONDITION_TEMPLATES_OF_INVOKED_EVENT_STATEMENT "SELECT DISTINCT context_trigger_condition.name, instance_name, option, attributes, options FROM context_trigger_condition JOIN context_trigger_template ON (context_trigger_condition.name = context_trigger_template.name) WHERE rule_id IN (SELECT row_id FROM context_trigger_rule WHERE enabled = 1 AND row_id IN (SELECT rule_id FROM context_trigger_event WHERE context_trigger_event.instance_name = '"
58 #define QUERY_RULE_BY_RULE_ID "SELECT details FROM context_trigger_rule WHERE row_id = "
59 #define QUERY_EVENT_TEMPLATE_BY_RULE_ID "SELECT name, attributes, options FROM context_trigger_template WHERE name IN (SELECT name FROM context_trigger_event WHERE rule_id = "
60 #define QUERY_CONDITION_BY_RULE_ID "SELECT name, option FROM context_trigger_condition WHERE rule_id = "
61
62 #define INSTANCE_NAME_DELIMITER "/"
63 #define EVENT_KEY_PREFIX "?"
64
65 static ctx::context_trigger* trigger = NULL;
66 static int enb_rule_cnt = 0;
67
68 static int string_to_int(std::string str)
69 {
70         int i;
71         std::istringstream convert(str);
72
73         if (!(convert >> i))
74                 i = 0;
75
76         return i;
77 }
78
79 static std::string int_to_string(int i)
80 {
81         std::ostringstream convert;
82         convert << i;
83         std::string str = convert.str();
84         return str;
85 }
86
87 static bool convert_str_to_json(ctx::json* val, const char* path, const char* key)
88 {
89         // TODO:
90         IF_FAIL_RETURN(val, false);
91
92         std::string buf;
93         IF_FAIL_RETURN(val->get(path, key, &buf), false);
94
95         ctx::json temp = buf;
96         IF_FAIL_RETURN(val->set(path, key, temp), false);
97
98         return true;
99 }
100
101 ctx::rule_manager::rule_manager()
102 {
103 }
104
105 ctx::rule_manager::~rule_manager()
106 {
107         destroy_clips();
108 }
109
110 bool ctx::rule_manager::init(ctx::context_trigger* tr, ctx::fact_reader* fr)
111 {
112         bool ret;
113         int error;
114
115         clips_h = NULL;
116         trigger = tr;
117         ret = c_monitor.init(fr, tr);
118         IF_FAIL_RETURN_TAG(ret, false, _E, "Context monitor initialization failed");
119
120         // Create tables into db (rule, event, condition, action, template)
121         ret = db_manager::create_table(1, RULE_TABLE, RULE_TABLE_COLUMNS, NULL, NULL);
122         IF_FAIL_RETURN_TAG(ret, false, _E, "Create rule table failed");
123
124         ret = db_manager::create_table(2, EVENT_TABLE, EVENT_TABLE_COLUMNS, NULL, NULL);
125         IF_FAIL_RETURN_TAG(ret, false, _E, "Create event table failed");
126
127         ret = db_manager::create_table(3, CONDITION_TABLE, CONDITION_TABLE_COLUMNS, NULL, NULL);
128         IF_FAIL_RETURN_TAG(ret, false, _E, "Create condition table failed");
129
130         ret = db_manager::execute(4, CREATE_TEMPLATE_TABLE, NULL);
131         IF_FAIL_RETURN_TAG(ret, false, _E, "Create template table failed");
132
133         // Foreign keys on
134         std::vector<json> record;
135         ret = db_manager::execute_sync(FOREIGN_KEYS_ON, &record);
136         IF_FAIL_RETURN_TAG(ret, false, _E, "Foreign keys on failed");
137
138         apply_templates(fr);
139
140         if (get_uninstalled_app() > 0) {
141                 error = clear_rule_of_uninstalled_app(true);
142                 IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Failed to remove uninstalled apps' rules while initialization");
143         }
144         ret = reenable_rule();
145
146         return ret;
147 }
148
149 void ctx::rule_manager::apply_templates(ctx::fact_reader *fr)
150 {
151         std::string subject;
152         int operation;
153         ctx::json attributes;
154         ctx::json options;
155         std::string q_update;
156         std::string q_insert = "INSERT OR IGNORE INTO context_trigger_template (name, operation, attributes, options) VALUES";
157
158         while (fr->get_fact_definition(subject, operation, attributes, options)) {
159                 _D("Subject: %s, Ops: %d", subject.c_str(), operation);
160                 _J("Attr", attributes);
161                 _J("Opt", options);
162
163                 q_update += "UPDATE context_trigger_template SET operation=" + int_to_string(operation)
164                         + ", attributes='" + attributes.str() + "', options='" + options.str() + "' WHERE name='" + subject + "';";
165
166                 q_insert += " ('" + subject + "', " + int_to_string(operation) + ", '" + attributes.str() + "', '" + options.str() + "'),";
167         }
168
169         q_insert.erase(q_insert.end() - 1, q_insert.end());
170         q_insert += ";";
171
172         bool ret = db_manager::execute(5, q_update.c_str(), NULL);
173         if (!ret)
174                 _E("Update item definition failed");
175
176         ret = db_manager::execute(6, q_insert.c_str(), NULL);
177         IF_FAIL_VOID_TAG(ret, _E, "Insert item definition failed");
178 }
179
180 int ctx::rule_manager::get_uninstalled_app(void)
181 {
182         // Return number of uninstalled apps
183         std::string q1 = "SELECT DISTINCT creator_app_id FROM context_trigger_rule";
184
185         std::vector<json> record;
186         bool ret = db_manager::execute_sync(q1.c_str(), &record);
187         IF_FAIL_RETURN_TAG(ret, -1, _E, "Query creators of registered rules failed");
188
189         std::vector<json>::iterator vec_end = record.end();
190         for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
191                 ctx::json elem = *vec_pos;
192                 std::string app_id;
193                 elem.get(NULL, "creator_app_id", &app_id);
194
195                 if (is_uninstalled_package(app_id)) {
196                         uninstalled_apps.insert(app_id);
197                 }
198         }
199
200         return uninstalled_apps.size();
201 }
202
203 bool ctx::rule_manager::is_uninstalled_package(std::string app_id)
204 {
205         IF_FAIL_RETURN_TAG(!app_id.empty(), false, _D, "Empty app id");
206
207         app_info_h app_info;
208         int     error = app_manager_get_app_info(app_id.c_str(), &app_info);
209
210         if (error == APP_MANAGER_ERROR_NONE) {
211                 app_info_destroy(app_info);
212         } else if (error == APP_MANAGER_ERROR_NO_SUCH_APP) {
213                 // Uninstalled app found
214                 _D("Uninstalled app found: %s", app_id.c_str());
215                 return true;
216         } else {
217                 _E("Get app info(%s) failed: %d", app_id.c_str(), error);
218         }
219
220         return false;
221 }
222
223 int ctx::rule_manager::clear_rule_of_uninstalled_app(bool is_init)
224 {
225         if (uninstalled_apps.size() <= 0) {
226                 return ERR_NONE;
227         }
228
229         int error;
230         bool ret;
231
232         _D("Clear uninstalled apps' rule started");
233         // creator list
234         std::string creator_list = "(";
235         std::set<std::string>::iterator it = uninstalled_apps.begin();
236         creator_list += "creator_app_id = '" + *it + "'";
237         it++;
238         for (; it != uninstalled_apps.end(); ++it) {
239                 creator_list += " OR creator_app_id = '" + *it + "'";
240         }
241         creator_list += ")";
242
243         // After event received, disable all the enabled rules of uninstalled apps
244         if (!is_init) {
245                 std::string q1 = "SELECT row_id, details FROM context_trigger_rule WHERE enabled = 1 and (";
246                 q1 += creator_list;
247                 q1 += ")";
248
249                 std::vector<json> record;
250                 ret = db_manager::execute_sync(q1.c_str(), &record);
251                 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query enabled rules of uninstalled apps failed");
252
253                 std::vector<json>::iterator vec_end = record.end();
254                 for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
255                         ctx::json elem = *vec_pos;
256                         error = disable_uninstalled_rule(elem);
257                         IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to disable rules" );
258                 }
259                 _D("Uninstalled apps' rules are disabled");
260         }
261
262         // Delete rules of uninstalled apps from DB
263         std::string q2 = "DELETE FROM context_trigger_rule WHERE " + creator_list;
264         std::vector<json> dummy;
265         ret = db_manager::execute_sync(q2.c_str(), &dummy);
266         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Remove rule from db failed");
267         _D("Uninstalled apps's rule are deleted from db");
268
269         uninstalled_apps.clear();
270
271         return ERR_NONE;
272 }
273
274 int ctx::rule_manager::disable_uninstalled_rule(ctx::json& rule_info)
275 {
276         int error;
277         bool ret;
278
279         int rule_id;
280         rule_info.get(NULL, "row_id", &rule_id);
281
282         // For event with options
283         std::string r1;
284         rule_info.get(NULL, "details", &r1);
285         ctx::json rule = r1;
286         ctx::json event;
287         rule.get(NULL, CT_RULE_EVENT, &event);
288         std::string ename;
289         event.get(NULL, CT_RULE_EVENT_ITEM, &ename);
290
291         // Unsubscribe event
292         error = c_monitor.unsubscribe(rule_id, ename, event);
293         IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Failed to unsubscribe %s of rule%d: %d", ename.c_str(), rule_id, error);
294
295         // Undef rule in clips
296         std::string id_str = int_to_string(rule_id);
297         std::string script = script_generator::generate_undefrule(id_str);
298         error = clips_h->route_string_command(script);
299         IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Failed to undefine rule%d: %d", rule_id, error);
300
301         // Remove condition instances
302         std::string q3 = "SELECT name, instance_name FROM context_trigger_condition WHERE rule_id = ";
303         q3 += id_str;
304         std::vector<json> name_record;
305         ret = db_manager::execute_sync(q3.c_str(), &name_record);
306         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Failed to query condition table of rule%d failed: %d", rule_id, error);
307
308         std::vector<json>::iterator vec_end = name_record.end();
309         for (std::vector<json>::iterator vec_pos = name_record.begin(); vec_pos != vec_end; ++vec_pos) {
310                 ctx::json elem = *vec_pos;
311
312                 std::string cname;
313                 std::string ciname;
314                 elem.get(NULL, "name", &cname);
315                 elem.get(NULL, "instance_name", &ciname);
316
317                 if (cname.compare(ciname) != 0) {
318                         cond_cnt_map[ciname]--;
319
320                         if (cond_cnt_map[ciname] == 0) {
321                                 error = clips_h->unmake_instance(ciname);
322                                 IF_FAIL_RETURN_TAG(error == ERR_NONE, error, _E, "Failed to unmake instance %s of rule%d: %d", ciname.c_str(), rule_id, error);
323
324                                 cond_cnt_map.erase(ciname);
325                         }
326                 }
327         }
328
329         if (--enb_rule_cnt <= 0) {
330                 enb_rule_cnt = 0;
331                 destroy_clips();
332         }
333         return ERR_NONE;
334 }
335
336 bool ctx::rule_manager::initialize_clips(void)
337 {
338         if (clips_h) {
339                 _D("CLIPS handler already initialized");
340                 return true;
341         }
342
343         clips_h = new(std::nothrow) clips_handler(this);
344         IF_FAIL_RETURN_TAG(clips_h, false, _E, "CLIPS handler initialization failed");
345
346         // Load all templates from DB
347         std::vector<json> record;
348         bool ret = db_manager::execute_sync(QUERY_TEMPLATE_TABLE, &record);
349         IF_FAIL_RETURN_TAG(ret, false, _E, "Query template table failed");
350
351         // Make scripts for deftemplate, defclass, make-instance and load them to clips
352         std::vector<json>::iterator vec_end = record.end();
353         for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
354                 ctx::json tmpl = *vec_pos;
355                 convert_str_to_json(&tmpl, NULL, "attributes");
356                 convert_str_to_json(&tmpl, NULL, "options");
357
358                 std::string deftemplate_str = script_generator::generate_deftemplate(tmpl);
359                 int error = clips_h->define_template(deftemplate_str);
360                 IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Deftemplate failed");
361
362                 std::string defclass_str = script_generator::generate_defclass(tmpl);
363                 error = clips_h->define_class(defclass_str);
364                 IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Defclass failed");
365
366                 std::string makeinstance_str = script_generator::generate_makeinstance(tmpl);
367                 error = clips_h->make_instance(makeinstance_str);
368                 IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Makeinstance failed");
369         }
370
371         _D(YELLOW("Deftemplate, Defclass, Make-instance completed"));
372         return true;
373 }
374
375 void ctx::rule_manager::destroy_clips(void)
376 {
377         delete clips_h;
378         clips_h = NULL;
379 }
380
381 bool ctx::rule_manager::reenable_rule(void)
382 {
383         int error;
384         std::string q = "SELECT row_id FROM context_trigger_rule where enabled = 1";
385
386         std::vector<json> record;
387         bool ret = db_manager::execute_sync(q.c_str(), &record);
388         IF_FAIL_RETURN_TAG(ret, false, _E, "Query row_ids of enabled rules failed");
389
390         std::vector<json>::iterator vec_end = record.end();
391         for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
392                 ctx::json elem = *vec_pos;
393                 int row_id;
394                 elem.get(NULL, "row_id", &row_id);
395
396                 error = enable_rule(row_id);
397                 if (error != ERR_NONE) {
398                         _E("Re-enable rule%d failed(%d)", row_id, error);
399                 } else {
400                         _D("Re-enable rule%d succeeded", row_id);
401                 }
402         }
403
404         return true;
405 }
406
407 bool ctx::rule_manager::rule_data_arr_elem_equals(ctx::json& lelem, ctx::json& relem)
408 {
409         std::string lkey, rkey;
410         lelem.get(NULL, CT_RULE_DATA_KEY, &lkey);
411         relem.get(NULL, CT_RULE_DATA_KEY, &rkey);
412         if (lkey.compare(rkey))
413                 return false;
414
415         int lvc, rvc, lvoc, rvoc;
416         lvc = lelem.array_get_size(NULL, CT_RULE_DATA_VALUE_ARR);
417         rvc = relem.array_get_size(NULL, CT_RULE_DATA_VALUE_ARR);
418         lvoc = lelem.array_get_size(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR);
419         rvoc = relem.array_get_size(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR);
420         if (!((lvc == rvc) && (lvc == lvoc) && (lvc && rvoc)))
421                 return false;
422
423         if (lvc > 1) {
424                 std::string lop, rop;
425                 lelem.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &lop);
426                 relem.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &rop);
427                 if (lop.compare(rop))
428                         return false;
429         }
430
431         for (int i = 0; i < lvc; i++) {
432                 bool found = false;
433                 std::string lv, lvo;
434                 lelem.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, i, &lv);
435                 lelem.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, i, &lvo);
436
437                 for (int j = 0; j < lvc; j++) {
438                         std::string rv, rvo;
439                         relem.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, j, &rv);
440                         relem.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, j, &rvo);
441
442                         if (!lv.compare(rv) && !lvo.compare(rvo)) {
443                                 found = true;
444                                 break;
445                         }
446                 }
447                 if (!found)
448                         return false;
449         }
450
451         return true;
452 }
453
454 bool ctx::rule_manager::rule_item_equals(ctx::json& litem, ctx::json& ritem)
455 {
456         // Compare item name
457         std::string lei, rei;
458         litem.get(NULL, CT_RULE_EVENT_ITEM, &lei);
459         ritem.get(NULL, CT_RULE_EVENT_ITEM, &rei);
460         if (lei.compare(rei))
461                 return false;
462
463         // Compare option
464         ctx::json loption, roption;
465         std::string linst, rinst;
466         litem.get(NULL, CT_RULE_EVENT_OPTION, &loption);
467         ritem.get(NULL, CT_RULE_EVENT_OPTION, &roption);
468         linst = get_instance_name(lei, loption);
469         rinst = get_instance_name(rei, roption);
470         if (linst.compare(rinst))
471                 return false;
472
473         int ledac, redac;
474         ledac = litem.array_get_size(NULL, CT_RULE_DATA_ARR);
475         redac = ritem.array_get_size(NULL, CT_RULE_DATA_ARR);
476         if (ledac != redac)
477                 return false;
478
479         // Compare item operator;
480         if (ledac > 1 ) {
481                 std::string leop, reop;
482                 litem.get(NULL, CT_RULE_EVENT_OPERATOR, &leop);
483                 ritem.get(NULL, CT_RULE_EVENT_OPERATOR, &reop);
484                 if (leop.compare(reop))
485                         return false;
486         }
487
488         for (int i = 0; i < ledac; i++) {
489                 bool found = false;
490                 ctx::json lelem;
491                 litem.get_array_elem(NULL, CT_RULE_DATA_ARR, i, &lelem);
492
493                 for (int j = 0; j < ledac; j++) {
494                         ctx::json relem;
495                         ritem.get_array_elem(NULL, CT_RULE_DATA_ARR, j, &relem);
496
497                         if (rule_data_arr_elem_equals(lelem, relem)) {
498                                 found = true;
499                                 break;
500                         }
501                 }
502                 if (!found)
503                         return false;
504         }
505
506         return true;
507 }
508
509 bool ctx::rule_manager::rule_equals(ctx::json& lrule, ctx::json& rrule)
510 {
511         // Compare event
512         ctx::json le, re;
513         lrule.get(NULL, CT_RULE_EVENT, &le);
514         rrule.get(NULL, CT_RULE_EVENT, &re);
515         if (!rule_item_equals(le, re))
516                 return false;
517
518         // Compare conditions
519         int lcc, rcc;
520         lcc = lrule.array_get_size(NULL, CT_RULE_CONDITION);
521         rcc = rrule.array_get_size(NULL, CT_RULE_CONDITION);
522         if (lcc != rcc)
523                 return false;
524
525         if (lcc > 1) {
526                 std::string lop, rop;
527                 lrule.get(NULL, CT_RULE_OPERATOR, &lop);
528                 rrule.get(NULL, CT_RULE_OPERATOR, &rop);
529                 if (lop.compare(rop))
530                         return false;
531         }
532
533         for (int i = 0; i < lcc; i++) {
534                 bool found = false;
535                 ctx::json lc;
536                 lrule.get_array_elem(NULL, CT_RULE_CONDITION, i, &lc);
537
538                 for (int j = 0; j < lcc; j++) {
539                         ctx::json rc;
540                         rrule.get_array_elem(NULL, CT_RULE_CONDITION, j, &rc);
541
542                         if (rule_item_equals(lc, rc)) {
543                                 found = true;
544                                 break;
545                         }
546                 }
547                 if (!found)
548                         return false;
549         }
550
551         // Compare action
552         ctx::json laction, raction;
553         lrule.get(NULL, CT_RULE_ACTION, &laction);
554         rrule.get(NULL, CT_RULE_ACTION, &raction);
555         if (laction != raction)
556                 return false;
557
558         return true;
559 }
560
561 int64_t ctx::rule_manager::get_duplicated_rule_id(std::string creator, ctx::json& rule)
562 {
563         std::string q = "SELECT row_id, description, details FROM context_trigger_rule WHERE creator = '";
564         q += creator;
565         q += "'";
566
567         std::vector<json> d_record;
568         bool ret = db_manager::execute_sync(q.c_str(), &d_record);
569         IF_FAIL_RETURN_TAG(ret, false, _E, "Query row_id, details by creator failed");
570
571         ctx::json r_details;
572         rule.get(NULL, CT_RULE_DETAILS, &r_details);
573         std::string r_desc;
574         rule.get(NULL, CT_RULE_DESCRIPTION, &r_desc);
575         std::vector<json>::iterator vec_end = d_record.end();
576
577         for (std::vector<json>::iterator vec_pos = d_record.begin(); vec_pos != vec_end; ++vec_pos) {
578                 ctx::json elem = *vec_pos;
579                 std::string details;
580                 ctx::json d_details;
581
582                 elem.get(NULL, "details", &details);
583                 d_details = details;
584
585                 if (rule_equals(r_details, d_details)) {
586                         int64_t row_id;
587                         elem.get(NULL, "row_id", &row_id);
588
589                         // Description comparison
590                         std::string d_desc;
591                         elem.get(NULL, "description", &d_desc);
592                         if (r_desc.compare(d_desc)) {
593                                 // Only description is changed
594                                 std::string q_update = "UPDATE context_trigger_rule SET description='" + r_desc + "' WHERE row_id = " + int_to_string(row_id);
595
596                                 std::vector<json> record;
597                                 ret = db_manager::execute_sync(q_update.c_str(), &record);
598                                 if (ret) {
599                                         _D("Rule%lld description is updated", row_id);
600                                 } else {
601                                         _W("Failed to update description of rule%lld", row_id);
602                                 }
603                         }
604
605                         return row_id;
606                 }
607         }
608
609         return -1;
610 }
611
612 int ctx::rule_manager::verify_rule(ctx::json& rule, const char* creator)
613 {
614         ctx::json details;
615         rule.get(NULL, CT_RULE_DETAILS, &details);
616
617         std::string e_name;
618         rule.get(CT_RULE_DETAILS "." CT_RULE_EVENT, CT_RULE_EVENT_ITEM, &e_name);
619
620         IF_FAIL_RETURN_TAG(c_monitor.is_supported(e_name), ERR_NOT_SUPPORTED, _I, "Event(%s) is not supported", e_name.c_str());
621
622         if (creator) {
623                 if (!c_monitor.is_allowed(creator, e_name.c_str())) {
624                         _W("Permission denied for '%s'", e_name.c_str());
625                         return ERR_PERMISSION_DENIED;
626                 }
627         }
628
629         ctx::json it;
630         for (int i = 0; rule.get_array_elem(CT_RULE_DETAILS, CT_RULE_CONDITION, i, &it); i++){
631                 std::string c_name;
632                 it.get(NULL, CT_RULE_CONDITION_ITEM, &c_name);
633
634                 IF_FAIL_RETURN_TAG(c_monitor.is_supported(c_name), ERR_NOT_SUPPORTED, _I, "Condition(%s) is not supported", c_name.c_str());
635
636                 if (!c_monitor.is_allowed(creator, c_name.c_str())) {
637                         _W("Permission denied for '%s'", c_name.c_str());
638                         return ERR_PERMISSION_DENIED;
639                 }
640         }
641
642         return ERR_NONE;
643 }
644
645 int ctx::rule_manager::add_rule(std::string creator, const char* app_id, ctx::json rule, ctx::json* rule_id)
646 {
647         // * Insert rule to DB
648         bool ret;
649         int64_t rid;
650
651         // Check if all items are supported && allowed to access
652         int err = verify_rule(rule, creator.c_str());
653         IF_FAIL_RETURN(err==ERR_NONE, err);
654
655         // Check if duplicated rule exits
656         if ((rid = get_duplicated_rule_id(creator, rule)) > 0) {
657                 // Save rule id
658                 rule_id->set(NULL, CT_RULE_ID, rid);
659                 _D("Duplicated rule found");
660                 return ERR_NONE;
661         }
662
663         // Insert rule to rule table, get rule id and save it to json parameter
664         ctx::json r_record;
665         std::string description;
666         ctx::json details;
667         rule.get(NULL, CT_RULE_DESCRIPTION, &description);
668         rule.get(NULL, CT_RULE_DETAILS, &details);
669         r_record.set(NULL, "creator", creator);
670         if (app_id) {
671                 r_record.set(NULL, "creator_app_id", app_id);
672         }
673         r_record.set(NULL, "description", description);
674         r_record.set(NULL, "details", details.str());
675         ret = db_manager::insert_sync(RULE_TABLE, r_record, &rid);
676         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert rule to db failed");
677
678         // Save rule id
679         rule_id->set(NULL, CT_RULE_ID, rid);
680
681         // Insert event & conditions of a rule into each table
682         ctx::json e_record;
683         std::string e_name;
684         ctx::json e_option_j;
685         std::string e_inst;
686
687         rule.get(CT_RULE_DETAILS "." CT_RULE_EVENT, CT_RULE_EVENT_ITEM, &e_name);
688         rule.get(CT_RULE_DETAILS "." CT_RULE_EVENT, CT_RULE_EVENT_OPTION, &e_option_j);
689         e_inst = get_instance_name(e_name, e_option_j);
690
691         e_record.set(NULL, "rule_id", rid);
692         e_record.set(NULL, "name", e_name);
693         e_record.set(NULL, "instance_name", e_inst);
694         ret = db_manager::insert(1, EVENT_TABLE, e_record, NULL);
695         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert event to db failed");
696
697         ctx::json it;
698         for (int i = 0; rule.get_array_elem(CT_RULE_DETAILS, CT_RULE_CONDITION, i, &it); i++){
699                 ctx::json c_record;
700                 std::string c_name;
701                 ctx::json c_option;
702                 char* c_option_str;
703                 ctx::json tmp_option;
704                 std::string c_inst;
705
706                 it.get(NULL, CT_RULE_CONDITION_ITEM, &c_name);
707                 it.get(NULL, CT_RULE_CONDITION_OPTION, &tmp_option);
708                 c_inst = get_instance_name(c_name, tmp_option);
709                 c_option.set(NULL, CT_RULE_CONDITION_OPTION, tmp_option);
710                 c_option_str = c_option.dup_cstr();
711
712                 c_record.set(NULL, "rule_id", rid);
713                 c_record.set(NULL, "name", c_name);
714                 c_record.set(NULL, "option", (c_option_str)? c_option_str : "");
715                 c_record.set(NULL, "instance_name", c_inst);
716
717                 ret = db_manager::insert(2, CONDITION_TABLE, c_record, NULL);
718                 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert conditions to db failed");
719
720                 free(c_option_str);
721         }
722
723         _D("Add rule%d succeeded", (int)rid);
724         return ERR_NONE;
725 }
726
727
728 int ctx::rule_manager::remove_rule(int rule_id)
729 {
730         // Delete rule from DB
731         bool ret;
732
733         std::string query = DELETE_RULE_STATEMENT;
734         query += int_to_string(rule_id);
735         std::vector<json> record;
736         ret = db_manager::execute_sync(query.c_str(), &record);
737         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Remove rule from db failed");
738
739         return ERR_NONE;
740 }
741
742 int ctx::rule_manager::enable_rule(int rule_id)
743 {
744         if (enb_rule_cnt == 0) {
745                 IF_FAIL_RETURN_TAG(initialize_clips(), ERR_OPERATION_FAILED, _E, "Failed to init clips");
746         }
747
748         // Subscribe event
749         int error;
750         std::string query;
751         std::string ename;
752         std::string script;
753         std::string tmp;
754
755         ctx::json jrule;
756         ctx::json jetemplate;
757         ctx::json jevent;
758         ctx::json inst_names;
759
760         std::vector<json> rule_record;
761         std::vector<json> etmpl_record;
762         std::vector<json> cond_record;
763         std::vector<json> record;
764         std::vector<json>::iterator vec_end;
765
766         std::string id_str = int_to_string(rule_id);
767
768         // Get rule json by rule id;
769         query = QUERY_RULE_BY_RULE_ID;
770         query += int_to_string(rule_id);
771         error = (db_manager::execute_sync(query.c_str(), &rule_record))? ERR_NONE : ERR_OPERATION_FAILED;
772         IF_FAIL_CATCH_TAG(error == ERR_NONE, _E, "Query rule by rule id failed");
773
774         rule_record[0].get(NULL, "details", &tmp);
775         jrule = tmp;
776         jrule.get(NULL, CT_RULE_EVENT, &jevent);
777
778         // Get event template by rule id
779         query = QUERY_EVENT_TEMPLATE_BY_RULE_ID;
780         query += int_to_string(rule_id);
781         query += ")";
782         error = (db_manager::execute_sync(query.c_str(), &etmpl_record))? ERR_NONE : ERR_OPERATION_FAILED;
783         IF_FAIL_CATCH_TAG(error == ERR_NONE, _E, "Query event template by rule id failed");
784
785         jetemplate = etmpl_record[0].str();
786         convert_str_to_json(&jetemplate, NULL, "attributes");
787         convert_str_to_json(&jetemplate, NULL, "options");
788
789         // Query name, instance name & attributes for conditions of the rule
790         query = QUERY_NAME_INSTANCE_NAME_AND_ATTRIBUTES_BY_RULE_ID_STATEMENT;
791         query += id_str;
792         error = (db_manager::execute_sync(query.c_str(), &cond_record))? ERR_NONE : ERR_OPERATION_FAILED;
793         IF_FAIL_CATCH_TAG(error == ERR_NONE, _E, "Query condition's names, instance names, attributes by rule id failed");
794
795         vec_end = cond_record.end();
796         for (std::vector<json>::iterator vec_pos = cond_record.begin(); vec_pos != vec_end; ++vec_pos) {
797                 ctx::json elem = *vec_pos;
798
799                 std::string cname;
800                 std::string ciname;
801                 elem.get(NULL, "name", &cname);
802                 elem.get(NULL, "instance_name", &ciname);
803                 convert_str_to_json(&elem, NULL, "attributes");
804
805                 // For defrule script generation
806                 inst_names.set(NULL, cname.c_str(), ciname);
807
808                 if (cname.compare(ciname) != 0) {
809                         if (!clips_h->find_instance(ciname)) {
810                                 std::string makeinst_script = script_generator::generate_makeinstance(elem);
811                                 error = (makeinst_script.length() > 0)? ERR_NONE : ERR_OPERATION_FAILED;
812                                 IF_FAIL_CATCH_TAG(error == ERR_NONE, _E, "Make instance script generation failed");
813                                 error = clips_h->make_instance(makeinst_script);
814                                 IF_FAIL_CATCH_TAG(error == ERR_NONE, _E, "Add condition instance([%s]) failed", ciname.c_str());
815
816                                 cond_cnt_map[ciname] = 1;
817                         } else {
818                                 cond_cnt_map[ciname]++;
819                         }
820                 }
821         }
822
823         // Subscribe event
824         jetemplate.get(NULL, "name", &ename);
825         error = c_monitor.subscribe(rule_id, ename, jevent);
826         IF_FAIL_CATCH(error == ERR_NONE);
827
828         // Generate defrule script and execute it
829         script = script_generator::generate_defrule(id_str, jetemplate, jrule, inst_names);
830         error = clips_h->define_rule(script);
831         IF_FAIL_CATCH_TAG(error == ERR_NONE, _E, "Defrule failed");
832
833         // Update db to set 'enabled'
834         query = UPDATE_RULE_ENABLED_STATEMENT;
835         query += id_str;
836         error = (db_manager::execute_sync(query.c_str(), &record))? ERR_NONE : ERR_OPERATION_FAILED;
837         IF_FAIL_CATCH_TAG(error == ERR_NONE, _E, "Update db failed");
838
839         enb_rule_cnt++;
840         _D(YELLOW("Enable Rule%d succeeded"), rule_id);
841
842         return ERR_NONE;
843
844 CATCH:
845         if (enb_rule_cnt <= 0) {
846                 enb_rule_cnt = 0;
847                 destroy_clips();
848         }
849
850         return error;
851 }
852
853 std::string ctx::rule_manager::get_instance_name(std::string name, ctx::json& option)
854 {
855         std::string inst_name = name;
856         std::vector<json> record_tmpl;
857         ctx::json tmpl_c;
858         std::list<std::string> option_keys;
859
860         // Get template for the option
861         std::string q = "SELECT options FROM context_trigger_template WHERE name = '";
862         q += name;
863         q += "'";
864         db_manager::execute_sync(q.c_str(), &record_tmpl);
865
866         convert_str_to_json(&record_tmpl[0], NULL, "options");
867         record_tmpl[0].get(NULL, "options", &tmpl_c);
868
869         tmpl_c.get_keys(&option_keys);
870
871         for (std::list<std::string>::iterator it = option_keys.begin(); it != option_keys.end(); ++it) {
872                 std::string key = (*it);
873                 std::string val_str;
874                 int val;
875
876                 if (option.get(NULL, key.c_str(), &val_str)) {
877                         inst_name += INSTANCE_NAME_DELIMITER;
878                         inst_name += val_str;
879                 } else if (option.get(NULL, key.c_str(), &val)) {
880                         inst_name += INSTANCE_NAME_DELIMITER;
881                         inst_name += int_to_string(val);
882                 } else {
883                         inst_name += INSTANCE_NAME_DELIMITER;
884                 }
885         }
886
887         return inst_name;
888 }
889
890 int ctx::rule_manager::disable_rule(int rule_id)
891 {
892         int error;
893         bool ret;
894
895         // For event with options
896         // Get rule json by rule id;
897         std::string q1 = QUERY_RULE_BY_RULE_ID;
898         q1 += int_to_string(rule_id);
899         std::vector<json> rule_record;
900         ret = db_manager::execute_sync(q1.c_str(), &rule_record);
901         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query rule by rule id failed");
902         std::string r1;
903         rule_record[0].get(NULL, "details", &r1);
904         ctx::json rule = r1;
905         ctx::json event;
906         rule.get(NULL, CT_RULE_EVENT, &event);
907         std::string ename;
908         event.get(NULL, CT_RULE_EVENT_ITEM, &ename);
909
910         // Unsubscribe event
911         error = c_monitor.unsubscribe(rule_id, ename, event);
912         IF_FAIL_RETURN(error == ERR_NONE, ERR_OPERATION_FAILED);
913
914         // Undef rule in clips
915         std::string id_str = int_to_string(rule_id);
916         std::string script = script_generator::generate_undefrule(id_str);
917         error = clips_h->route_string_command(script);
918         IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Undefrule failed");
919
920         // Update db to set 'disabled'
921         std::string q2 = UPDATE_RULE_DISABLED_STATEMENT;
922         q2 += id_str;
923         std::vector<json> record;
924         ret = db_manager::execute_sync(q2.c_str(), &record);
925         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Update db failed");
926
927         // Remove condition instances
928         std::string q3 = "SELECT name, instance_name FROM context_trigger_condition WHERE rule_id = ";
929         q3 += id_str;
930         std::vector<json> name_record;
931         ret = db_manager::execute_sync(q3.c_str(), &name_record);
932         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query condition's name, instance names by rule id failed");
933
934         std::vector<json>::iterator vec_end = name_record.end();
935         for (std::vector<json>::iterator vec_pos = name_record.begin(); vec_pos != vec_end; ++vec_pos) {
936                 ctx::json elem = *vec_pos;
937
938                 std::string cname;
939                 std::string ciname;
940                 elem.get(NULL, "name", &cname);
941                 elem.get(NULL, "instance_name", &ciname);
942
943                 if (cname.compare(ciname) != 0) {
944                         cond_cnt_map[ciname]--;
945
946                         if (cond_cnt_map[ciname] == 0) {
947                                 error = clips_h->unmake_instance(ciname);
948                                 IF_FAIL_RETURN(error == ERR_NONE, error);
949
950                                 cond_cnt_map.erase(ciname);
951                         }
952                 }
953         }
954
955         if (--enb_rule_cnt <= 0) {
956                 enb_rule_cnt = 0;
957                 destroy_clips();
958         }
959         return ERR_NONE;
960 }
961
962 void ctx::rule_manager::make_condition_option_based_on_event_data(ctx::json& ctemplate, ctx::json& edata, ctx::json* coption)
963 {
964         std::list<std::string> option_keys;
965         ctemplate.get_keys(&option_keys);
966
967         for (std::list<std::string>::iterator it = option_keys.begin(); it != option_keys.end(); ++it) {
968                 std::string key = (*it);
969
970                 std::string coption_valstr;
971                 if (coption->get(NULL, key.c_str(), &coption_valstr)) {
972                         if (coption_valstr.find(EVENT_KEY_PREFIX) == 0) {
973                                 std::string event_key = coption_valstr.substr(1, coption_valstr.length() - 1);
974
975                                 std::string e_valstr;
976                                 int e_val;
977                                 if (edata.get(NULL, event_key.c_str(), &e_valstr)) {
978                                         coption->set(NULL, key.c_str(), e_valstr);
979                                 } else if (edata.get(NULL, event_key.c_str(), &e_val)) {
980                                         coption->set(NULL, key.c_str(), e_val);
981                                 }
982                         }
983                 }
984         }
985 }
986
987 void ctx::rule_manager::on_event_received(std::string item, ctx::json option, ctx::json data)
988 {
989         _D(YELLOW("Event(%s(%s) - %s) is invoked."), item.c_str(), option.str().c_str(), data.str().c_str());
990         // TODO: Check permission of an event(item), if permission denied, return
991
992         int err;
993         bool ret;
994
995         // Generate event fact script
996         std::string q1 = "SELECT attributes, options FROM context_trigger_template WHERE name = '";
997         q1 += item;
998         q1 += "'";
999         std::vector<json> etemplate_record;
1000         db_manager::execute_sync(q1.c_str(), &etemplate_record);
1001
1002         ctx::json etemplate = etemplate_record[0];
1003         convert_str_to_json(&etemplate, NULL, "attributes");
1004         convert_str_to_json(&etemplate, NULL, "options");
1005
1006         std::string eventfact_str = script_generator::generate_fact(item, etemplate, option, data);
1007
1008         // Get Conditions template of invoked event (db query)
1009         std::string e_inst = get_instance_name(item, option);
1010         std::string query = QUERY_CONDITION_TEMPLATES_OF_INVOKED_EVENT_STATEMENT;
1011         query += e_inst;
1012         query += "'))";
1013         std::vector<json> conds;
1014         ret = db_manager::execute_sync(query.c_str(), &conds);
1015         IF_FAIL_VOID_TAG(ret, _E, "Query condition templates of invoked event failed");
1016
1017         int cond_num = conds.size();
1018         for (int i = 0; i < cond_num; i++) {
1019                 convert_str_to_json(&conds[i], NULL, "options");
1020                 convert_str_to_json(&conds[i], NULL, "attributes");
1021
1022                 std::string cname;
1023                 conds[i].get(NULL, "name", &cname);
1024
1025                 std::string ciname;
1026                 conds[i].get(NULL, "instance_name", &ciname);
1027
1028                 std::string coption_str;
1029                 conds[i].get(NULL, "option", &coption_str);
1030                 ctx::json coption = NULL;
1031                 if (!coption_str.empty()) {
1032                         ctx::json coption_tmp = coption_str;
1033                         coption_tmp.get(NULL, CT_RULE_CONDITION_OPTION, &coption);
1034                 }
1035
1036                 // Check if the condition uses event data key as an option
1037                 if (ciname.find(EVENT_KEY_PREFIX) != std::string::npos) {
1038                         make_condition_option_based_on_event_data(conds[i], data, &coption);    //TODO: conds[i] -> "options"
1039                 }
1040
1041                 // TODO: Check permission of a condition(cname), if permission granted, read condition data. (or, condition data should be empty json)
1042
1043                 //      Get Context Data
1044                 ctx::json condition_data;
1045                 err = c_monitor.read(cname, coption, &condition_data);
1046                 if (err != ERR_NONE)
1047                         return;
1048                 _D(YELLOW("Condition(%s(%s) - %s)."), cname.c_str(), coption.str().c_str(), condition_data.str().c_str());
1049
1050                 // Generate ModifyInstance script       // TODO: conds[i] => "attributes"
1051                 std::string modifyinst_script = script_generator::generate_modifyinstance(ciname, conds[i], condition_data);
1052
1053                 err = clips_h->route_string_command(modifyinst_script);
1054                 IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Modify condition instance failed");
1055         }
1056
1057         // Add fact and Run environment
1058         err = clips_h->add_fact(eventfact_str);
1059         IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Assert event fact failed");
1060
1061         err = clips_h->run_environment();
1062         IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Run environment failed");
1063
1064         // Retract event fact
1065         std::string retract_command = "(retract *)";
1066         err = clips_h->route_string_command(retract_command);
1067         IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Retract event fact failed");
1068
1069         // Clear uninstalled apps' rules if triggered
1070         if (uninstalled_apps.size() > 0) {
1071                 err = clear_rule_of_uninstalled_app();
1072                 IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Failed to clear uninstalled apps' rules");
1073         }
1074 }
1075
1076 static void trigger_action_app_control(ctx::json& action)
1077 {
1078         int error;
1079         std::string appctl_str;
1080         action.get(NULL, CT_RULE_ACTION_APP_CONTROL, &appctl_str);
1081
1082         char* str = static_cast<char*>(malloc(appctl_str.length()));
1083         if (str == NULL) {
1084                 _E("Memory allocation failed");
1085                 return;
1086         }
1087         appctl_str.copy(str, appctl_str.length(), 0);
1088         bundle_raw* encoded = reinterpret_cast<unsigned char*>(str);
1089         bundle* appctl_bundle = bundle_decode(encoded, appctl_str.length());
1090
1091         app_control_h app = NULL;
1092         app_control_create(&app);
1093         app_control_import_from_bundle(app, appctl_bundle);
1094
1095         error = app_control_send_launch_request(app, NULL, NULL);
1096         if (error != APP_CONTROL_ERROR_NONE) {
1097                 _E("Launch request failed(%d)", error);
1098         } else {
1099                 _D("Launch request succeeded");
1100         }
1101         bundle_free(appctl_bundle);
1102         free(str);
1103         app_control_destroy(app);
1104
1105         error = device_display_change_state(DISPLAY_STATE_NORMAL);
1106         if (error != DEVICE_ERROR_NONE) {
1107                 _E("Change display state failed(%d)", error);
1108         }
1109 }
1110
1111 static void trigger_action_notification(ctx::json& action, std::string app_id)
1112 {
1113         int error;
1114         notification_h notification = notification_create(NOTIFICATION_TYPE_NOTI);
1115         std::string title;
1116         if (action.get(NULL, CT_RULE_ACTION_NOTI_TITLE, &title)) {
1117                 error = notification_set_text(notification, NOTIFICATION_TEXT_TYPE_TITLE, title.c_str(), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
1118                 if (error != NOTIFICATION_ERROR_NONE) {
1119                         _E("Set notification title failed(%d)", error);
1120                 }
1121         }
1122
1123         std::string content;
1124         if (action.get(NULL, CT_RULE_ACTION_NOTI_CONTENT, &content)) {
1125                 error = notification_set_text(notification, NOTIFICATION_TEXT_TYPE_CONTENT, content.c_str(), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
1126                 if (error != NOTIFICATION_ERROR_NONE) {
1127                         _E("Set notification contents failed(%d)", error);
1128                 }
1129         }
1130
1131         std::string image_path;
1132         if (action.get(NULL, CT_RULE_ACTION_NOTI_ICON_PATH, &image_path)) {
1133                 error = notification_set_image(notification, NOTIFICATION_IMAGE_TYPE_ICON, image_path.c_str());
1134                 if (error != NOTIFICATION_ERROR_NONE) {
1135                         _E("Set notification icon image failed(%d)", error);
1136                 }
1137         }
1138
1139         std::string appctl_str;
1140         char* str = NULL;
1141         bundle_raw* encoded = NULL;
1142         bundle* appctl_bundle = NULL;
1143         app_control_h app = NULL;
1144         if (action.get(NULL, CT_RULE_ACTION_APP_CONTROL, &appctl_str)) {
1145                 str = static_cast<char*>(malloc(appctl_str.length()));
1146                 if (str == NULL) {
1147                         _E("Memory allocation failed");
1148                         notification_free(notification);
1149                         return;
1150                 }
1151                 appctl_str.copy(str, appctl_str.length(), 0);
1152                 encoded = reinterpret_cast<unsigned char*>(str);
1153                 appctl_bundle = bundle_decode(encoded, appctl_str.length());
1154
1155                 app_control_create(&app);
1156                 app_control_import_from_bundle(app, appctl_bundle);
1157
1158                 error = notification_set_launch_option(notification, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL, app);
1159                 if (error != NOTIFICATION_ERROR_NONE) {
1160                         _E("Set launch option failed(%d)", error);
1161                 }
1162         }
1163
1164         if (!app_id.empty()) {
1165                 error = notification_set_pkgname(notification, app_id.c_str());
1166                 if (error != NOTIFICATION_ERROR_NONE) {
1167                         _E("Set pkgname(%s) failed(%d)", app_id.c_str(), error);
1168                 }
1169         }
1170
1171         bool silent = true;
1172         error = system_settings_get_value_bool(SYSTEM_SETTINGS_KEY_SOUND_SILENT_MODE, &silent);
1173         if (error != SYSTEM_SETTINGS_ERROR_NONE) {
1174                 _E("Get system setting(silent mode) failed(%d)", error);
1175         }
1176
1177         bool vibration = true;
1178         error = runtime_info_get_value_bool(RUNTIME_INFO_KEY_VIBRATION_ENABLED, &vibration);
1179         if (error != RUNTIME_INFO_ERROR_NONE) {
1180                 _E("Get runtime info(vibration) failed(%d)", error);
1181         }
1182
1183         if (!silent) {
1184             error = notification_set_sound(notification, NOTIFICATION_SOUND_TYPE_DEFAULT, NULL);
1185                 if (error != NOTIFICATION_ERROR_NONE) {
1186                         _E("Set notification sound failed(%d)", error);
1187                 }
1188
1189                 if (vibration) {
1190                         error = notification_set_vibration(notification, NOTIFICATION_VIBRATION_TYPE_DEFAULT, NULL);
1191                         if (error != NOTIFICATION_ERROR_NONE) {
1192                                 _E("Set notification vibration failed(%d)", error);
1193                         }
1194                 }
1195         }
1196
1197         error = notification_post(notification);
1198         if (error != NOTIFICATION_ERROR_NONE) {
1199                 _E("Post notification failed(%d)", error);
1200         } else {
1201                 _D("Post notification succeeded");
1202         }
1203
1204         bundle_free(appctl_bundle);
1205         free(str);
1206         notification_free(notification);
1207         if (app) {
1208                 app_control_destroy(app);
1209         }
1210
1211         error = device_display_change_state(DISPLAY_STATE_NORMAL);
1212         if (error != DEVICE_ERROR_NONE) {
1213                 _E("Change display state failed(%d)", error);
1214         }
1215 }
1216
1217 static void trigger_action_dbus_call(ctx::json& action)
1218 {
1219         std::string bus_name, object, iface, method;
1220         GVariant *param = NULL;
1221
1222         action.get(NULL, CT_RULE_ACTION_DBUS_NAME, &bus_name);
1223         IF_FAIL_VOID_TAG(!bus_name.empty(), _E, "No target bus name");
1224
1225         action.get(NULL, CT_RULE_ACTION_DBUS_OBJECT, &object);
1226         IF_FAIL_VOID_TAG(!object.empty(), _E, "No object path");
1227
1228         action.get(NULL, CT_RULE_ACTION_DBUS_INTERFACE, &iface);
1229         IF_FAIL_VOID_TAG(!iface.empty(), _E, "No interface name");
1230
1231         action.get(NULL, CT_RULE_ACTION_DBUS_METHOD, &method);
1232         IF_FAIL_VOID_TAG(!method.empty(), _E, "No method name");
1233
1234         action.get(NULL, CT_RULE_ACTION_DBUS_PARAMETER, &param);
1235
1236         ctx::dbus_server::call(bus_name.c_str(), object.c_str(), iface.c_str(), method.c_str(), param);
1237 }
1238
1239 void ctx::rule_manager::on_rule_triggered(int rule_id)
1240 {
1241         std::string q = "SELECT details, creator_app_id FROM context_trigger_rule WHERE row_id =";
1242         q += int_to_string(rule_id);
1243         std::vector<json> record;
1244         db_manager::execute_sync(q.c_str(), &record);
1245         if (record.empty()) {
1246                 _E("Rule%d not exist", rule_id);
1247                 return;
1248         }
1249
1250         // If rule's creator is uninstalled, skip action
1251         std::string app_id;
1252         record[0].get(NULL, "creator_app_id", &app_id);
1253         if (is_uninstalled_package(app_id)) {
1254                 _D(YELLOW("Rule%d's creator(%s) is uninstalled. Skip action."), rule_id, app_id.c_str());
1255                 uninstalled_apps.insert(app_id);
1256                 return;
1257         }
1258
1259         _D(YELLOW("Rule%d is triggered"), rule_id);
1260
1261         // Do action
1262         std::string details_str;
1263         record[0].get(NULL, "details", &details_str);
1264         ctx::json details = details_str;
1265         ctx::json action;
1266         details.get(NULL, CT_RULE_ACTION, &action);
1267
1268         std::string type;
1269         if (action.get(NULL, CT_RULE_ACTION_TYPE, &type)) {
1270                 if (type.compare(CT_RULE_ACTION_TYPE_APP_CONTROL) == 0) {
1271                         trigger_action_app_control(action);
1272                 } else if (type.compare(CT_RULE_ACTION_TYPE_NOTIFICATION) == 0) {
1273                         trigger_action_notification(action, app_id);
1274                 } else if (type.compare(CT_RULE_ACTION_TYPE_DBUS_CALL) == 0) {
1275                         trigger_action_dbus_call(action);
1276                 }
1277         }
1278 }
1279
1280 int ctx::rule_manager::check_rule(std::string creator, int rule_id)
1281 {
1282         // Get creator app id
1283         std::string q = "SELECT creator FROM context_trigger_rule WHERE row_id =";
1284         q += int_to_string(rule_id);
1285
1286         std::vector<json> record;
1287         bool ret = db_manager::execute_sync(q.c_str(), &record);
1288         IF_FAIL_RETURN_TAG(ret, false, _E, "Query creator by rule id failed");
1289
1290         if (record.size() == 0) {
1291                 return ERR_NO_DATA;
1292         }
1293
1294         std::string c;
1295         record[0].get(NULL, "creator", &c);
1296
1297         if (c.compare(creator) == 0){
1298                 return ERR_NONE;
1299         }
1300
1301         return ERR_NO_DATA;
1302 }
1303
1304 bool ctx::rule_manager::is_rule_enabled(int rule_id)
1305 {
1306         std::string q = "SELECT enabled FROM context_trigger_rule WHERE row_id =";
1307         q += int_to_string(rule_id);
1308
1309         std::vector<json> record;
1310         bool ret = db_manager::execute_sync(q.c_str(), &record);
1311         IF_FAIL_RETURN_TAG(ret, false, _E, "Query enabled by rule id failed");
1312
1313         int enabled;
1314         record[0].get(NULL, "enabled", &enabled);
1315
1316         if (enabled == 1)
1317                 return true;
1318         else
1319                 return false;
1320 }
1321
1322 int ctx::rule_manager::get_rule_by_id(std::string creator, int rule_id, ctx::json* request_result)
1323 {
1324         std::string q = "SELECT description FROM context_trigger_rule WHERE (creator = '";
1325         q += creator;
1326         q += "') and (row_id = ";
1327         q += int_to_string(rule_id);
1328         q += ")";
1329
1330         std::vector<json> record;
1331         bool ret = db_manager::execute_sync(q.c_str(), &record);
1332         IF_FAIL_RETURN_TAG(ret, false, _E, "Query rule by rule id failed");
1333
1334         if (record.size() == 0) {
1335                 return ERR_NO_DATA;
1336         } else if (record.size() != 1) {
1337                 return ERR_OPERATION_FAILED;
1338         }
1339
1340         std::string description;
1341         record[0].get(NULL, "description", &description);
1342
1343         (*request_result).set(NULL, CT_RULE_ID, rule_id);
1344         (*request_result).set(NULL, CT_RULE_DESCRIPTION, description);
1345
1346         return ERR_NONE;
1347 }
1348
1349 int ctx::rule_manager::get_rule_ids(std::string creator, ctx::json* request_result)
1350 {
1351         (*request_result) = "{ \"" CT_RULE_ARRAY_ENABLED "\" : [ ] , \"" CT_RULE_ARRAY_DISABLED "\" : [ ] }";
1352
1353         std::string q = "SELECT row_id, enabled FROM context_trigger_rule WHERE (creator = '";
1354         q += creator;
1355         q += "')";
1356
1357         std::vector<json> record;
1358         bool ret = db_manager::execute_sync(q.c_str(), &record);
1359         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query rules failed");
1360
1361         std::vector<json>::iterator vec_end = record.end();
1362         for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
1363                 ctx::json elem = *vec_pos;
1364                 std::string id;
1365                 int enabled;
1366
1367                 elem.get(NULL, "row_id", &id);
1368                 elem.get(NULL, "enabled", &enabled);
1369
1370                 if (enabled == 1) {
1371                         (*request_result).array_append(NULL, CT_RULE_ARRAY_ENABLED, string_to_int(id));
1372                 } else if (enabled == 0) {
1373                         (*request_result).array_append(NULL, CT_RULE_ARRAY_DISABLED, string_to_int(id));
1374                 }
1375         }
1376
1377         return ERR_NONE;
1378 }