Migrate from 2.4 code repo
[platform/core/context/context-service.git] / src / context_trigger / rule_manager.cpp
1 /*
2  * context-service
3  *
4  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <sstream>
21 #include <app.h>
22 #include <glib.h>
23 #include <types_internal.h>
24 #include <json.h>
25 #include <stdlib.h>
26 #include <bundle.h>
27 #include <app_control.h>
28 #include <appsvc.h>
29 #include <app_control_internal.h>
30 #include <notification.h>
31 #include <notification_internal.h>
32 #include <context_trigger_types_internal.h>
33 #include <context_trigger.h>
34 #include <db_mgr.h>
35 #include <zone_util.h>
36 #include "../access_control/privilege.h"
37 #include "rule_manager.h"
38 #include "script_generator.h"
39 #include "trigger.h"
40
41 #define RULE_TABLE "context_trigger_rule"
42 #define EVENT_TABLE "context_trigger_event"
43 #define CONDITION_TABLE "context_trigger_condition"
44 #define TEMPLATE_TABLE "context_trigger_template"
45
46 #define RULE_TABLE_COLUMNS "enabled INTEGER DEFAULT 0 NOT NULL, creator TEXT DEFAULT '' NOT NULL, description TEXT DEFAULT '', details TEXT DEFAULT '' NOT NULL, zone TEXT DEFAULT '' NOT NULL"
47 #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 '', zone TEXT DEFAULT '' NOT NULL"
48 #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 '', zone TEXT DEFAULT '' NOT NULL"
49 #define CREATE_TEMPLATE_TABLE "CREATE TABLE IF NOT EXISTS context_trigger_template (name TEXT DEFAULT '' NOT NULL PRIMARY KEY, j_template TEXT DEFAULT '' NOT NULL)"
50 #define QUERY_TEMPLATE_TABLE "SELECT j_template FROM context_trigger_template"
51 #define FOREIGN_KEYS_ON "PRAGMA foreign_keys = ON"
52 #define DELETE_RULE_STATEMENT "DELETE FROM 'context_trigger_rule' where row_id = "
53 #define UPDATE_RULE_ENABLED_STATEMENT "UPDATE context_trigger_rule SET enabled = 1 WHERE row_id = "
54 #define UPDATE_RULE_DISABLED_STATEMENT "UPDATE context_trigger_rule SET enabled = 0 WHERE row_id = "
55 #define QUERY_NAME_INSTANCE_NAME_AND_TEMPLATE_BY_RULE_ID_STATEMENT "SELECT context_trigger_condition.name, instance_name, j_template as templates FROM context_trigger_condition JOIN context_trigger_template ON (context_trigger_condition.name = context_trigger_template.name) WHERE rule_id = "
56 #define QUERY_CONDITION_TEMPLATES_OF_INVOKED_EVENT_STATEMENT "SELECT DISTINCT context_trigger_condition.name, instance_name, option, j_template 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 = '"
57 #define QUERY_RULE_AND_ZONE_BY_RULE_ID "SELECT details, zone FROM context_trigger_rule WHERE row_id = "
58 #define QUERY_EVENT_TEMPLATE_BY_RULE_ID "SELECT j_template FROM context_trigger_template WHERE name IN (SELECT name FROM context_trigger_event WHERE rule_id = "
59 #define QUERY_CONDITION_BY_RULE_ID "SELECT name, option FROM context_trigger_condition WHERE rule_id = "
60
61 #define INSTANCE_NAME_DELIMITER "/"
62 #define EVENT_KEY_PREFIX "?"
63
64 static ctx::context_trigger* trigger = NULL;
65
66 static int string_to_int(std::string str)
67 {
68         int i;
69         std::istringstream convert(str);
70
71         if (!(convert >> i))
72                 i = 0;
73
74         return i;
75 }
76
77 static std::string int_to_string(int i)
78 {
79         std::ostringstream convert;
80         convert << i;
81         std::string str = convert.str();
82         return str;
83 }
84
85 ctx::rule_manager::rule_manager()
86 {
87 }
88
89 ctx::rule_manager::~rule_manager()
90 {
91 }
92
93 bool ctx::rule_manager::init(ctx::context_trigger* tr, ctx::fact_reader* fr)
94 {
95         int error;
96         bool ret;
97
98         trigger = tr;
99
100         ret = clips_h.init(this);
101         IF_FAIL_RETURN_TAG(ret, false, _E, "CLIPS handler initialization failed");
102
103         ret = c_monitor.init(fr, tr);
104
105         // Create tables into db (rule, event, condition, action, template)
106         ret = db_manager::create_table(1, RULE_TABLE, RULE_TABLE_COLUMNS, NULL, NULL);
107         IF_FAIL_RETURN_TAG(ret, false, _E, "Create rule table failed");
108
109         ret = db_manager::create_table(2, EVENT_TABLE, EVENT_TABLE_COLUMNS, NULL, NULL);
110         IF_FAIL_RETURN_TAG(ret, false, _E, "Create event table failed");
111
112         ret = db_manager::create_table(3, CONDITION_TABLE, CONDITION_TABLE_COLUMNS, NULL, NULL);
113         IF_FAIL_RETURN_TAG(ret, false, _E, "Create condition table failed");
114
115         ret = db_manager::execute(4, CREATE_TEMPLATE_TABLE, NULL);
116         IF_FAIL_RETURN_TAG(ret, false, _E, "Create template table failed");
117
118         // Load all templates from DB
119         std::vector<json> record;
120         ret = db_manager::execute_sync(QUERY_TEMPLATE_TABLE, &record);
121         IF_FAIL_RETURN_TAG(ret, false, _E, "Query template table failed");
122
123         // Make scripts for deftemplate, defclass, make-instance and load them to clips
124         std::vector<json>::iterator vec_end = record.end();
125         for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
126                 ctx::json elem = *vec_pos;
127                 std::string tmpl_str;
128                 elem.get(NULL, "j_template", &tmpl_str);
129                 ctx::json tmpl = tmpl_str;
130
131                 std::string deftemplate_str = script_generator::generate_deftemplate(&tmpl);
132                 error = clips_h.define_template(deftemplate_str);
133                 IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Deftemplate failed");
134
135                 std::string defclass_str = script_generator::generate_defclass(&tmpl);
136                 error = clips_h.define_class(defclass_str);
137                 IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Defclass failed");
138
139                 std::string makeinstance_str = script_generator::generate_makeinstance(&tmpl);
140                 error = clips_h.make_instance(makeinstance_str);
141                 IF_FAIL_RETURN_TAG(error == ERR_NONE, false, _E, "Makeinstance failed");
142         }
143
144         // Foreign keys on
145         ret = db_manager::execute_sync(FOREIGN_KEYS_ON, &record);
146         IF_FAIL_RETURN_TAG(ret, false, _E, "Foreign keys on failed");
147
148         ret = reenable_rule();
149
150         return ret;
151 }
152
153 bool ctx::rule_manager::reenable_rule(void)
154 {
155         int error;
156         std::string q = "SELECT row_id FROM context_trigger_rule where enabled = 1";
157
158         std::vector<json> record;
159         bool ret = db_manager::execute_sync(q.c_str(), &record);
160         IF_FAIL_RETURN_TAG(ret, false, _E, "Query row_ids of enabled rules failed");
161
162         std::vector<json>::iterator vec_end = record.end();
163         for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
164                 ctx::json elem = *vec_pos;
165                 int row_id;
166                 elem.get(NULL, "row_id", &row_id);
167
168                 error = enable_rule(row_id);
169                 if (error != ERR_NONE) {
170                         _E("Re-enable rule%d failed(%d)", row_id, error);
171                 } else {
172                         _E("Re-enable rule%d succeeded", row_id);
173                 }
174         }
175
176         return true;
177 }
178
179 bool ctx::rule_manager::rule_data_arr_elem_equals(ctx::json& lelem, ctx::json& relem)
180 {
181         std::string lkey, rkey;
182         lelem.get(NULL, CT_RULE_DATA_KEY, &lkey);
183         relem.get(NULL, CT_RULE_DATA_KEY, &rkey);
184         if (lkey.compare(rkey))
185                 return false;
186
187         int lvc, rvc, lvoc, rvoc;
188         lvc = lelem.array_get_size(NULL, CT_RULE_DATA_VALUE_ARR);
189         rvc = relem.array_get_size(NULL, CT_RULE_DATA_VALUE_ARR);
190         lvoc = lelem.array_get_size(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR);
191         rvoc = relem.array_get_size(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR);
192         if (!((lvc == rvc) && (lvc == lvoc) && (lvc && rvoc)))
193                 return false;
194
195         if (lvc > 1) {
196                 std::string lop, rop;
197                 lelem.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &lop);
198                 relem.get(NULL, CT_RULE_DATA_KEY_OPERATOR, &rop);
199                 if (lop.compare(rop))
200                         return false;
201         }
202
203         for (int i = 0; i < lvc; i++) {
204                 bool found = false;
205                 std::string lv, lvo;
206                 lelem.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, i, &lv);
207                 lelem.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, i, &lvo);
208
209                 for (int j = 0; j < lvc; j++) {
210                         std::string rv, rvo;
211                         relem.get_array_elem(NULL, CT_RULE_DATA_VALUE_ARR, j, &rv);
212                         relem.get_array_elem(NULL, CT_RULE_DATA_VALUE_OPERATOR_ARR, j, &rvo);
213
214                         if (!lv.compare(rv) && !lvo.compare(rvo)) {
215                                 found = true;
216                                 break;
217                         }
218                 }
219                 if (!found)
220                         return false;
221         }
222
223         return true;
224 }
225
226 bool ctx::rule_manager::rule_item_equals(ctx::json& litem, ctx::json& ritem)
227 {
228         // Compare item name
229         std::string lei, rei;
230         litem.get(NULL, CT_RULE_EVENT_ITEM, &lei);
231         ritem.get(NULL, CT_RULE_EVENT_ITEM, &rei);
232         if (lei.compare(rei))
233                 return false;
234
235         // Compare option
236         ctx::json loption, roption;
237         std::string linst, rinst;
238         litem.get(NULL, CT_RULE_EVENT_OPTION, &loption);
239         ritem.get(NULL, CT_RULE_EVENT_OPTION, &roption);
240         linst = get_instance_name(lei, loption);
241         rinst = get_instance_name(rei, roption);
242         if (linst.compare(rinst))
243                 return false;
244
245         int ledac, redac;
246         ledac = litem.array_get_size(NULL, CT_RULE_DATA_ARR);
247         redac = ritem.array_get_size(NULL, CT_RULE_DATA_ARR);
248         if (ledac != redac)
249                 return false;
250
251         // Compare item operator;
252         if (ledac > 1 ) {
253                 std::string leop, reop;
254                 litem.get(NULL, CT_RULE_EVENT_OPERATOR, &leop);
255                 ritem.get(NULL, CT_RULE_EVENT_OPERATOR, &reop);
256                 if (leop.compare(reop))
257                         return false;
258         }
259
260         for (int i = 0; i < ledac; i++) {
261                 bool found = false;
262                 ctx::json lelem;
263                 litem.get_array_elem(NULL, CT_RULE_DATA_ARR, i, &lelem);
264
265                 for (int j = 0; j < ledac; j++) {
266                         ctx::json relem;
267                         ritem.get_array_elem(NULL, CT_RULE_DATA_ARR, j, &relem);
268
269                         if (rule_data_arr_elem_equals(lelem, relem)) {
270                                 found = true;
271                                 break;
272                         }
273                 }
274                 if (!found)
275                         return false;
276         }
277
278         return true;
279 }
280
281 bool ctx::rule_manager::rule_equals(ctx::json& lrule, ctx::json& rrule)
282 {
283         // Compare event
284         ctx::json le, re;
285         lrule.get(NULL, CT_RULE_EVENT, &le);
286         rrule.get(NULL, CT_RULE_EVENT, &re);
287         if (!rule_item_equals(le, re))
288                 return false;
289
290         // Compare conditions
291         int lcc, rcc;
292         lcc = lrule.array_get_size(NULL, CT_RULE_CONDITION);
293         rcc = rrule.array_get_size(NULL, CT_RULE_CONDITION);
294         if (lcc != rcc)
295                 return false;
296
297         if (lcc > 1) {
298                 std::string lop, rop;
299                 lrule.get(NULL, CT_RULE_OPERATOR, &lop);
300                 rrule.get(NULL, CT_RULE_OPERATOR, &rop);
301                 if (lop.compare(rop))
302                         return false;
303         }
304
305         for (int i = 0; i < lcc; i++) {
306                 bool found = false;
307                 ctx::json lc;
308                 lrule.get_array_elem(NULL, CT_RULE_CONDITION, i, &lc);
309
310                 for (int j = 0; j < lcc; j++) {
311                         ctx::json rc;
312                         rrule.get_array_elem(NULL, CT_RULE_CONDITION, j, &rc);
313
314                         if (rule_item_equals(lc, rc)) {
315                                 found = true;
316                                 break;
317                         }
318                 }
319                 if (!found)
320                         return false;
321         }
322
323         // Compare action
324         std::string laction, raction;
325         lrule.get(NULL, CT_RULE_ACTION, &laction);
326         rrule.get(NULL, CT_RULE_ACTION, &raction);
327         if (laction.compare(raction))
328                 return false;
329
330         return true;
331 }
332
333 int64_t ctx::rule_manager::get_duplicated_rule(std::string creator, std::string zone, ctx::json& rule)
334 {
335         std::string q = "SELECT row_id, details FROM context_trigger_rule WHERE creator = '";
336         q += creator;
337         q += "' AND zone ='";
338         q += zone;
339         q += "'";
340
341         std::vector<json> record;
342         bool ret = db_manager::execute_sync(q.c_str(), &record);
343         IF_FAIL_RETURN_TAG(ret, false, _E, "Query row_id, details by creator failed");
344
345         ctx::json r_details;
346         rule.get(NULL, CT_RULE_DETAILS, &r_details);
347         std::vector<json>::iterator vec_end = record.end();
348
349         for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
350                 ctx::json elem = *vec_pos;
351                 std::string details;
352                 ctx::json d_details;
353
354                 elem.get(NULL, "details", &details);
355                 d_details = details;
356
357                 if (rule_equals(r_details, d_details)) {
358                         int64_t row_id;
359                         elem.get(NULL, "row_id", &row_id);
360                         return row_id;
361                 }
362         }
363
364         return -1;
365 }
366
367 int ctx::rule_manager::verify_rule(ctx::json& rule, const char* app_id, const char* zone)
368 {
369         ctx::json details;
370         rule.get(NULL, CT_RULE_DETAILS, &details);
371
372         std::string e_name;
373         rule.get(CT_RULE_DETAILS "." CT_RULE_EVENT, CT_RULE_EVENT_ITEM, &e_name);
374
375         IF_FAIL_RETURN_TAG(c_monitor.is_supported(e_name, zone), ERR_NOT_SUPPORTED, _I, "Event(%s) is not supported", e_name.c_str());
376
377         if (app_id) {
378                 if (!ctx::privilege_manager::is_allowed(app_id, e_name.c_str())) {
379                         _W("Permission denied for '%s'", e_name.c_str());
380                         return ERR_PERMISSION_DENIED;
381                 }
382         }
383
384         ctx::json it;
385         for (int i = 0; rule.get_array_elem(CT_RULE_DETAILS, CT_RULE_CONDITION, i, &it); i++){
386                 std::string c_name;
387                 it.get(NULL, CT_RULE_CONDITION_ITEM, &c_name);
388
389                 IF_FAIL_RETURN_TAG(c_monitor.is_supported(c_name, zone), ERR_NOT_SUPPORTED, _I, "Condition(%s) is not supported", c_name.c_str());
390
391                 if (!ctx::privilege_manager::is_allowed(app_id, c_name.c_str())) {
392                         _W("Permission denied for '%s'", c_name.c_str());
393                         return ERR_PERMISSION_DENIED;
394                 }
395         }
396
397         return ERR_NONE;
398 }
399
400 int ctx::rule_manager::add_rule(std::string creator, ctx::json rule, std::string zone, ctx::json* rule_id)
401 {
402         // * Insert rule to DB
403         bool ret;
404         int64_t rid;
405
406         // Check if all items are supported && allowed to access
407         int err = verify_rule(rule, creator.c_str(), zone.c_str());
408         IF_FAIL_RETURN(err==ERR_NONE, err);
409
410         // Check if duplicated rule exits
411         if ((rid = get_duplicated_rule(creator, zone, rule)) > 0) {
412                 // Save rule id
413                 rule_id->set(NULL, CT_RULE_ID, rid);
414                 return ERR_NONE;
415         }
416
417         // Insert rule to rule table, get rule id and save it to json parameter
418         ctx::json r_record;
419         std::string description;
420         ctx::json details;
421         rule.get(NULL, CT_RULE_DESCRIPTION, &description);
422         rule.get(NULL, CT_RULE_DETAILS, &details);
423         r_record.set(NULL, "creator", creator);
424         r_record.set(NULL, "description", description);
425         r_record.set(NULL, "details", details.str());
426         r_record.set(NULL, "zone", zone);
427         ret = db_manager::insert_sync(RULE_TABLE, r_record, &rid);
428         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert rule to db failed");
429
430         // Save rule id
431         rule_id->set(NULL, CT_RULE_ID, rid);
432
433         // Insert event & conditions of a rule into each table
434         ctx::json e_record;
435         std::string e_name;
436         ctx::json e_option_j;
437         std::string e_inst;
438
439         rule.get(CT_RULE_DETAILS "." CT_RULE_EVENT, CT_RULE_EVENT_ITEM, &e_name);
440         rule.get(CT_RULE_DETAILS "." CT_RULE_EVENT, CT_RULE_EVENT_OPTION, &e_option_j);
441         e_inst = get_instance_name(e_name, e_option_j);
442
443         e_record.set(NULL, "rule_id", rid);
444         e_record.set(NULL, "name", e_name);
445         e_record.set(NULL, "instance_name", e_inst);
446         e_record.set(NULL, "zone", zone);
447         ret = db_manager::insert(1, EVENT_TABLE, e_record, NULL);
448         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert event to db failed");
449
450         ctx::json it;
451         for (int i = 0; rule.get_array_elem(CT_RULE_DETAILS, CT_RULE_CONDITION, i, &it); i++){
452                 ctx::json c_record;
453                 std::string c_name;
454                 ctx::json c_option;
455                 char* c_option_str;
456                 ctx::json tmp_option;
457                 std::string c_inst;
458
459                 it.get(NULL, CT_RULE_CONDITION_ITEM, &c_name);
460                 it.get(NULL, CT_RULE_CONDITION_OPTION, &tmp_option);
461                 c_inst = get_instance_name(c_name, tmp_option);
462                 c_option.set(NULL, CT_RULE_CONDITION_OPTION, tmp_option);
463                 c_option_str = c_option.dup_cstr();
464
465                 c_record.set(NULL, "rule_id", rid);
466                 c_record.set(NULL, "name", c_name);
467                 c_record.set(NULL, "option", (c_option_str)? c_option_str : "");
468                 c_record.set(NULL, "instance_name", c_inst);
469                 c_record.set(NULL, "zone", zone);
470
471                 ret = db_manager::insert(2, CONDITION_TABLE, c_record, NULL);
472                 IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Insert conditions to db failed");
473
474                 free(c_option_str);
475         }
476
477         _D("Add rule%d succeeded", (int)rid);
478         return ERR_NONE;
479 }
480
481
482 int ctx::rule_manager::remove_rule(int rule_id)
483 {
484         // Delete rule from DB
485         bool ret;
486
487         std::string query = DELETE_RULE_STATEMENT;
488         query += int_to_string(rule_id);
489         std::vector<json> record;
490         ret = db_manager::execute_sync(query.c_str(), &record);
491         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Remove rule from db failed");
492
493         return ERR_NONE;
494 }
495
496
497 int ctx::rule_manager::enable_rule(int rule_id)
498 {
499         // Subscribe event
500         bool ret;
501         int error;
502         std::string id_str = int_to_string(rule_id);
503
504         // Get rule json by rule id;
505         std::string q1 = QUERY_RULE_AND_ZONE_BY_RULE_ID;
506         q1 += int_to_string(rule_id);
507         std::vector<json> rule_record;
508         ret = db_manager::execute_sync(q1.c_str(), &rule_record);
509         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query rule by rule id failed");
510         std::string r1;
511         std::string zone;
512         rule_record[0].get(NULL, "details", &r1);
513         rule_record[0].get(NULL, "zone", &zone);
514         ctx::json rule = r1;
515         ctx::json event;
516         rule.get(NULL, CT_RULE_EVENT, &event);
517
518         // Get event template by rule id
519         std::string q2 = QUERY_EVENT_TEMPLATE_BY_RULE_ID;
520         q2 += int_to_string(rule_id);
521         q2 += ")";
522         std::vector<json> etemplate_record;
523         ret = db_manager::execute_sync(q2.c_str(), &etemplate_record);
524         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query event template by rule id failed");
525         std::string r2;
526         etemplate_record[0].get(NULL, "j_template", &r2);
527         ctx::json etemplate = r2;
528
529         // Query name, instance name & template for conditions of the rule
530         std::string q3 = QUERY_NAME_INSTANCE_NAME_AND_TEMPLATE_BY_RULE_ID_STATEMENT;
531         q3 += id_str;
532         std::vector<json> cond_record;
533         ret = db_manager::execute_sync(q3.c_str(), &cond_record);
534         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query condition's names, instance names, templates by rule id failed");
535
536         ctx::json inst_names;
537         std::vector<json>::iterator vec_end = cond_record.end();
538         for (std::vector<json>::iterator vec_pos = cond_record.begin(); vec_pos != vec_end; ++vec_pos) {
539                 ctx::json elem = *vec_pos;
540
541                 std::string cname;
542                 std::string ciname;
543                 std::string temp;
544                 elem.get(NULL, "name", &cname);
545                 elem.get(NULL, "instance_name", &ciname);
546                 elem.get(NULL, "templates", &temp);
547                 ctx::json ctemplate = temp;
548                 ctemplate.set(NULL, "instance_name", ciname);
549                 // TODO ctemplate (name, instance_name, attributes) now - it is based on form using when templates are inserted into db when rebooting
550
551                 // For defrule script generation
552                 inst_names.set(NULL, cname.c_str(), ciname);
553
554                 if (cname.compare(ciname) != 0) {
555                         if (!clips_h.find_instance(ciname)) {
556                                 std::string makeinst_script = script_generator::generate_makeinstance(&ctemplate);
557                                 error = clips_h.make_instance(makeinst_script);
558                                 IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Add condition instance([%s]) failed", ciname.c_str());
559
560                                 cond_cnt_map[ciname] = 1;
561                         } else {
562                                 cond_cnt_map[ciname]++;
563                         }
564                 }
565         }
566
567         // Subscribe event
568         std::string ename;
569         etemplate.get(NULL, "name", &ename);
570
571         //TODO: set the proper zone
572         error = c_monitor.subscribe(rule_id, ename, event, zone.c_str());
573         IF_FAIL_RETURN(error == ERR_NONE, ERR_OPERATION_FAILED);
574
575         // Generate defrule script and execute it
576         std::string script = script_generator::generate_defrule(id_str, etemplate, rule, &inst_names, zone);
577         error = clips_h.define_rule(script);
578         IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Defrule failed");
579
580         // Update db to set 'enabled'
581         std::string q4 = UPDATE_RULE_ENABLED_STATEMENT;
582         q4 += id_str;
583         std::vector<json> record;
584         ret = db_manager::execute_sync(q4.c_str(), &record);
585         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Update db failed");
586
587         _D(YELLOW("Enable Rule%d succeeded"), rule_id);
588
589         return ERR_NONE;
590 }
591
592 std::string ctx::rule_manager::get_instance_name(std::string name, ctx::json& option)
593 {
594         std::string inst_name = name;
595
596         // Get template for the option
597         std::string q = "SELECT j_template FROM context_trigger_template WHERE name = '";
598         q += name;
599         q += "'";
600         std::vector<json> template_record;
601         db_manager::execute_sync(q.c_str(), &template_record);
602
603         std::string ct_str;
604         template_record[0].get(NULL, "j_template", &ct_str);
605         ctx::json j_template = ct_str;
606
607         std::string option_key;
608         for (int i = 0; j_template.get_array_elem(NULL, "option", i, &option_key); i++) {
609                 std::string val_str;
610                 int val;
611                 if (option.get(NULL, option_key.c_str(), &val_str)) {
612                         inst_name += INSTANCE_NAME_DELIMITER;
613                         inst_name += val_str;
614                 } else if (option.get(NULL, option_key.c_str(), &val)) {
615                         inst_name += INSTANCE_NAME_DELIMITER;
616                         inst_name += int_to_string(val);
617                 } else {
618                         inst_name += INSTANCE_NAME_DELIMITER;
619                 }
620         }
621
622         return inst_name;
623 }
624
625 int ctx::rule_manager::disable_rule(int rule_id)
626 {
627         int error;
628         bool ret;
629
630         // For event with options
631         // Get rule json by rule id;
632         std::string q1 = QUERY_RULE_AND_ZONE_BY_RULE_ID;
633         q1 += int_to_string(rule_id);
634         std::vector<json> rule_record;
635         ret = db_manager::execute_sync(q1.c_str(), &rule_record);
636         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query rule by rule id failed");
637         std::string r1;
638         std::string zone;
639         rule_record[0].get(NULL, "details", &r1);
640         rule_record[0].get(NULL, "zone", &zone);
641         ctx::json rule = r1;
642         ctx::json event;
643         rule.get(NULL, CT_RULE_EVENT, &event);
644         std::string ename;
645         event.get(NULL, CT_RULE_EVENT_ITEM, &ename);
646
647         // Unsubscribe event
648         error = c_monitor.unsubscribe(rule_id, ename, event, zone.c_str());
649         IF_FAIL_RETURN(error == ERR_NONE, ERR_OPERATION_FAILED);
650
651         // Undef rule in clips
652         std::string id_str = int_to_string(rule_id);
653         std::string script = script_generator::generate_undefrule(id_str);
654         error = clips_h.route_string_command(script);
655         IF_FAIL_RETURN_TAG(error == ERR_NONE, ERR_OPERATION_FAILED, _E, "Undefrule failed");
656
657         // Update db to set 'disabled'
658         std::string q2 = UPDATE_RULE_DISABLED_STATEMENT;
659         q2 += id_str;
660         std::vector<json> record;
661         ret = db_manager::execute_sync(q2.c_str(), &record);
662         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Update db failed");
663
664         // Remove condition instances TODO
665         std::string q3 = "SELECT name, instance_name FROM context_trigger_condition WHERE rule_id = ";
666         q3 += id_str;
667         std::vector<json> name_record;
668         ret = db_manager::execute_sync(q3.c_str(), &name_record);
669         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query condition's name, instance names by rule id failed");
670
671         std::vector<json>::iterator vec_end = name_record.end();
672         for (std::vector<json>::iterator vec_pos = name_record.begin(); vec_pos != vec_end; ++vec_pos) {
673                 ctx::json elem = *vec_pos;
674
675                 std::string cname;
676                 std::string ciname;
677                 elem.get(NULL, "name", &cname);
678                 elem.get(NULL, "instance_name", &ciname);
679
680                 if (cname.compare(ciname) != 0) {
681                         cond_cnt_map[ciname]--;
682
683                         if (cond_cnt_map[ciname] == 0) {
684                                 error = clips_h.unmake_instance(ciname);
685                                 IF_FAIL_RETURN(error == ERR_NONE, error);
686
687                                 cond_cnt_map.erase(ciname);
688                         }
689                 }
690         }
691
692         return ERR_NONE;
693 }
694
695 void ctx::rule_manager::make_condition_option_based_on_event_data(ctx::json& ctemplate, ctx::json& edata, ctx::json* coption)
696 {
697         std::string option_key;
698         for (int i = 0; ctemplate.get_array_elem(NULL, "option", i, &option_key); i++) {
699                 std::string coption_valstr;
700                 if (coption->get(NULL, option_key.c_str(), &coption_valstr)) {
701                         if (coption_valstr.find(EVENT_KEY_PREFIX) == 0) {
702                                 std::string event_key = coption_valstr.substr(1, coption_valstr.length() - 1);
703
704                                 std::string e_valstr;
705                                 int e_val;
706                                 if (edata.get(NULL, event_key.c_str(), &e_valstr)) {
707                                         coption->set(NULL, option_key.c_str(), e_valstr);
708                                 } else if (edata.get(NULL, event_key.c_str(), &e_val)) {
709                                         coption->set(NULL, option_key.c_str(), e_val);
710                                 }
711                         }
712                 }
713         }
714 }
715
716 void ctx::rule_manager::on_event_received(std::string item, ctx::json option, ctx::json data, std::string zone)
717 {
718         _D(YELLOW("Event(%s(%s) - %s) is invoked."), item.c_str(), option.str().c_str(), data.str().c_str());
719         // TODO: Check permission of an event(item), if permission denied, return
720
721         int err;
722         bool ret;
723         // Set the zone
724         ret = clips_h.set_global_variable_string("zone", zone);
725         if (!ret) {
726                 _E("Set clips zone to %s failed", zone.c_str());
727                 return;
728         }
729
730         // Generate event fact script
731         std::string q1 = "SELECT j_template FROM context_trigger_template WHERE name = '";
732         q1 += item;
733         q1 += "'";
734         std::vector<json> etemplate_record;
735         db_manager::execute_sync(q1.c_str(), &etemplate_record);
736         std::string r1;
737         etemplate_record[0].get(NULL, "j_template", &r1);
738         ctx::json etemplate = r1;
739
740         std::string eventfact_str = script_generator::generate_fact(item, etemplate, option, data);
741
742         // Get Conditions template of invoked event (db query)
743         std::string e_inst = get_instance_name(item, option);
744         std::string query = QUERY_CONDITION_TEMPLATES_OF_INVOKED_EVENT_STATEMENT;
745         query += e_inst;
746         query += "' AND zone = '";
747         query += zone;
748         query += "'))";
749         std::vector<json> conds;
750         ret = db_manager::execute_sync(query.c_str(), &conds);
751         IF_FAIL_VOID_TAG(ret, _E, "Query condition templates of invoked event failed");
752
753         int cond_num = conds.size();
754         for (int i = 0; i < cond_num; i++) {
755                 std::string temp;
756                 conds[i].get(NULL, "j_template", &temp);
757                 ctx::json ctemplate = temp;
758
759                 std::string cname;
760                 conds[i].get(NULL, "name", &cname);
761
762                 std::string ciname;
763                 conds[i].get(NULL, "instance_name", &ciname);
764
765                 std::string coption_str;
766                 conds[i].get(NULL, "option", &coption_str);
767                 ctx::json coption = NULL;
768                 if (!coption_str.empty()) {
769                         ctx::json coption_tmp = coption_str;
770                         coption_tmp.get(NULL, CT_RULE_CONDITION_OPTION, &coption);
771                 }
772
773                 // Check if the condition uses event data key as an option
774                 if (ciname.find(EVENT_KEY_PREFIX) != std::string::npos) {
775                         make_condition_option_based_on_event_data(ctemplate, data, &coption);
776                 }
777
778                 // TODO: Check permission of a condition(cname), if permission granted, read condition data. (or, condition data should be empty json)
779
780                 //      Get Context Data and Set the proper zone.
781                 ctx::json condition_data;
782                 err = c_monitor.read(cname, coption, zone.c_str(), &condition_data);
783                 if (err != ERR_NONE)
784                         return;
785                 _D(YELLOW("Condition(%s(%s) - %s)."), cname.c_str(), coption.str().c_str(), condition_data.str().c_str());
786
787                 // Generate ModifyInstance script
788                 std::string modifyinst_script = script_generator::generate_modifyinstance(ciname, ctemplate, condition_data);
789
790                 err = clips_h.route_string_command(modifyinst_script);
791                 IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Modify condition instance failed");
792         }
793
794         // Add fact and Run environment
795         err = clips_h.add_fact(eventfact_str);
796         IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Assert event fact failed");
797
798         err = clips_h.run_environment();
799         IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Run environment failed");
800
801         // Retract event fact
802         std::string retract_command = "(retract *)";
803         err = clips_h.route_string_command(retract_command);
804         IF_FAIL_VOID_TAG(err == ERR_NONE, _E, "Retract event fact failed");
805 }
806
807 static void trigger_action_app_control(ctx::json& action, std::string zone)
808 {
809         int error;
810         std::string appctl_str;
811         action.get(NULL, CT_RULE_ACTION_APP_CONTROL, &appctl_str);
812
813         char* str = static_cast<char*>(malloc(appctl_str.length()));
814         if (str == NULL) {
815                 _E("Memory allocation failed");
816                 return;
817         }
818         appctl_str.copy(str, appctl_str.length(), 0);
819         bundle_raw* encoded = reinterpret_cast<unsigned char*>(str);
820         bundle* appctl_bundle = bundle_decode(encoded, appctl_str.length());
821
822         app_control_h app = NULL;
823         app_control_create(&app);
824         app_control_import_from_bundle(app, appctl_bundle);
825
826         char* op;
827         app_control_get_operation(app, &op);
828         app_control_set_operation(app, APP_SVC_OPERATION_JUMP);
829         app_control_add_extra_data(app, APP_SVC_K_JUMP_ZONE_NAME, zone.c_str());
830         if (op != NULL) {
831                 app_control_add_extra_data(app, APP_SVC_K_JUMP_ORIGIN_OPERATION, op);
832         }
833
834         error = app_control_send_launch_request(app, NULL, NULL);
835         if (error != APP_CONTROL_ERROR_NONE) {
836                 _E("Launch request failed(%d)", error);
837         } else {
838                 _D("Launch request succeeded");
839         }
840         bundle_free(appctl_bundle);
841         free(str);
842         app_control_destroy(app);
843 }
844
845 static void trigger_action_notification(ctx::json& action, std::string creator, std::string zone)
846 {
847         int error;
848         notification_h notification = notification_create(NOTIFICATION_TYPE_NOTI);
849         std::string title;
850         if (action.get(NULL, CT_RULE_ACTION_NOTI_TITLE, &title)) {
851                 error = notification_set_text(notification, NOTIFICATION_TEXT_TYPE_TITLE, title.c_str(), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
852                 if (error != NOTIFICATION_ERROR_NONE) {
853                         _E("Set notification title failed(%d)", error);
854                 }
855         }
856
857         std::string content;
858         if (action.get(NULL, CT_RULE_ACTION_NOTI_CONTENT, &content)) {
859                 error = notification_set_text(notification, NOTIFICATION_TEXT_TYPE_CONTENT, content.c_str(), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
860                 if (error != NOTIFICATION_ERROR_NONE) {
861                         _E("Set notification contents failed(%d)", error);
862                 }
863         }
864
865         std::string image_path;
866         if (action.get(NULL, CT_RULE_ACTION_NOTI_ICON_PATH, &image_path)) {
867                 error = notification_set_image(notification, NOTIFICATION_IMAGE_TYPE_ICON, image_path.c_str());
868                 if (error != NOTIFICATION_ERROR_NONE) {
869                         _E("Set notification icon image failed(%d)", error);
870                 }
871         }
872
873         std::string appctl_str;
874         char* str = NULL;
875         bundle_raw* encoded = NULL;
876         bundle* appctl_bundle = NULL;
877         app_control_h app = NULL;
878         if (action.get(NULL, CT_RULE_ACTION_APP_CONTROL, &appctl_str)) {
879                 str = static_cast<char*>(malloc(appctl_str.length()));
880                 if (str == NULL) {
881                         _E("Memory allocation failed");
882                         notification_free(notification);
883                         return;
884                 }
885                 appctl_str.copy(str, appctl_str.length(), 0);
886                 encoded = reinterpret_cast<unsigned char*>(str);
887                 appctl_bundle = bundle_decode(encoded, appctl_str.length());
888
889                 app_control_create(&app);
890                 app_control_import_from_bundle(app, appctl_bundle);
891
892                 error = notification_set_launch_option(notification, NOTIFICATION_LAUNCH_OPTION_APP_CONTROL, app);
893                 if (error != NOTIFICATION_ERROR_NONE) {
894                         _E("Set launch option failed(%d)", error);
895                 }
896         }
897
898         error = notification_set_pkgname(notification, creator.c_str());
899         if (error != NOTIFICATION_ERROR_NONE) {
900                 _E("Set pkgname(%s) failed(%d)", creator.c_str(), error);
901         }
902
903         ctx::scope_zone_joiner sz(zone.c_str());
904
905         error = notification_post(notification);
906         if (error != NOTIFICATION_ERROR_NONE) {
907                 _E("Post notification failed(%d)", error);
908         } else {
909                 _D("Post notification succeeded");
910         }
911
912         bundle_free(appctl_bundle);
913         free(str);
914         notification_free(notification);
915         if (app) {
916                 app_control_destroy(app);
917         }
918 }
919
920 void ctx::rule_manager::on_rule_triggered(int rule_id)
921 {
922         _D(YELLOW("Rule%d is triggered"), rule_id);
923
924         std::string q = "SELECT details, creator, zone FROM context_trigger_rule WHERE row_id =";
925         q += int_to_string(rule_id);
926
927         std::vector<json> record;
928         db_manager::execute_sync(q.c_str(), &record);
929
930         std::string details_str;
931         record[0].get(NULL, "details", &details_str);
932         ctx::json details = details_str;
933         ctx::json action;
934         details.get(NULL, CT_RULE_ACTION, &action);
935         std::string zone;
936         record[0].get(NULL, "zone", &zone);
937
938         std::string type;
939         if (action.get(NULL, CT_RULE_ACTION_TYPE, &type)) {
940                 if (type.compare(CT_RULE_ACTION_TYPE_APP_CONTROL) == 0) {
941                         trigger_action_app_control(action, zone);
942                 } else if (type.compare(CT_RULE_ACTION_TYPE_NOTIFICATION) == 0) {
943                         std::string creator;
944                         record[0].get(NULL, "creator", &creator);
945                         trigger_action_notification(action, creator, zone);
946                 }
947         }
948 }
949
950 int ctx::rule_manager::check_rule(std::string creator, int rule_id)
951 {
952         // Get creator app id
953         std::string q = "SELECT creator FROM context_trigger_rule WHERE row_id =";
954         q += int_to_string(rule_id);
955
956         std::vector<json> record;
957         bool ret = db_manager::execute_sync(q.c_str(), &record);
958         IF_FAIL_RETURN_TAG(ret, false, _E, "Query creator by rule id failed");
959
960         if (record.size() == 0) {
961                 return ERR_NO_DATA;
962         }
963
964         std::string c;
965         record[0].get(NULL, "creator", &c);
966
967         if (c.compare(creator) == 0){
968                 return ERR_NONE;
969         }
970
971         return ERR_NO_DATA;
972 }
973
974 bool ctx::rule_manager::is_rule_enabled(int rule_id)
975 {
976         std::string q = "SELECT enabled FROM context_trigger_rule WHERE row_id =";
977         q += int_to_string(rule_id);
978
979         std::vector<json> record;
980         bool ret = db_manager::execute_sync(q.c_str(), &record);
981         IF_FAIL_RETURN_TAG(ret, false, _E, "Query enabled by rule id failed");
982
983         int enabled;
984         record[0].get(NULL, "enabled", &enabled);
985
986         if (enabled == 1)
987                 return true;
988         else
989                 return false;
990 }
991
992 int ctx::rule_manager::get_rule_by_id(std::string creator, int rule_id, ctx::json* request_result)
993 {
994 //      std::string q = "SELECT description, details FROM context_trigger_rule WHERE (creator = '";
995         std::string q = "SELECT description FROM context_trigger_rule WHERE (creator = '";
996         q += creator;
997         q += "') and (row_id = ";
998         q += int_to_string(rule_id);
999         q += ")";
1000
1001         std::vector<json> record;
1002         bool ret = db_manager::execute_sync(q.c_str(), &record);
1003         IF_FAIL_RETURN_TAG(ret, false, _E, "Query rule by rule id failed");
1004
1005         if (record.size() == 0) {
1006                 return ERR_NO_DATA;
1007         } else if (record.size() != 1) {
1008                 return ERR_OPERATION_FAILED;
1009         }
1010
1011         std::string description;
1012 //      std::string details;
1013         record[0].get(NULL, "description", &description);
1014 //      record[0].get(NULL, "details", &details);
1015
1016         (*request_result).set(NULL, CT_RULE_ID, rule_id);
1017         (*request_result).set(NULL, CT_RULE_DESCRIPTION, description);
1018 //      (*request_result).set(NULL, CT_RULE_DETAILS, details);
1019
1020         return ERR_NONE;
1021 }
1022
1023 int ctx::rule_manager::get_rule_ids(std::string creator, ctx::json* request_result)
1024 {
1025         (*request_result) = "{ \"" CT_RULE_ARRAY_ENABLED "\" : [ ] , \"" CT_RULE_ARRAY_DISABLED "\" : [ ] }";
1026
1027         std::string q = "SELECT row_id, enabled FROM context_trigger_rule WHERE (creator = '";
1028         q += creator;
1029         q += "')";
1030
1031         std::vector<json> record;
1032         bool ret = db_manager::execute_sync(q.c_str(), &record);
1033         IF_FAIL_RETURN_TAG(ret, ERR_OPERATION_FAILED, _E, "Query rules failed");
1034
1035         std::vector<json>::iterator vec_end = record.end();
1036         for (std::vector<json>::iterator vec_pos = record.begin(); vec_pos != vec_end; ++vec_pos) {
1037                 ctx::json elem = *vec_pos;
1038                 std::string id;
1039                 int enabled;
1040
1041                 elem.get(NULL, "row_id", &id);
1042                 elem.get(NULL, "enabled", &enabled);
1043
1044                 if (enabled == 1) {
1045                         (*request_result).array_append(NULL, CT_RULE_ARRAY_ENABLED, string_to_int(id));
1046                 } else if (enabled == 0) {
1047                         (*request_result).array_append(NULL, CT_RULE_ARRAY_DISABLED, string_to_int(id));
1048                 }
1049         }
1050
1051         return ERR_NONE;
1052 }