Fix defects detected by static analysis tool
[platform/core/uifw/multi-assistant-service.git] / src / service_config.cpp
1 /*
2  * Copyright 2020 Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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 <libxml/parser.h>
18 #include <sys/types.h>
19 #include <dirent.h>
20 #include <unistd.h>
21
22 #include <app_preference.h>
23
24 #include "service_config.h"
25 #include "service_common.h"
26
27 int CServiceConfig::parse_assistant_info(service_config_assistant_info_cb callback,
28         const char *path, void* user_data)
29 {
30         xmlDocPtr doc = NULL;
31         xmlNodePtr cur = NULL;
32         xmlChar *key;
33
34         int loop;
35         int retry_count = 0;
36
37         while (NULL == doc) {
38                 doc = xmlParseFile(path);
39                 if (NULL != doc) {
40                         break;
41                 }
42
43                 if (MA_RETRY_COUNT == retry_count++) {
44                         MAS_LOGE("[ERROR] Fail to parse file error : %s", path);
45                         xmlCleanupParser();
46                         return -1;
47                 }
48                 usleep(10000);
49         }
50
51         cur = xmlDocGetRootElement(doc);
52         if (cur == NULL) {
53                 MAS_LOGE("[ERROR] Empty document");
54                 xmlFreeDoc(doc);
55                 return -1;
56         }
57
58         if (xmlStrcmp(cur->name, (const xmlChar *) MA_TAG_ASSISTANT_BASE)) {
59                 MAS_LOGE("[ERROR] The wrong type, root node is NOT %s", MA_TAG_ASSISTANT_BASE);
60                 xmlFreeDoc(doc);
61                 return -1;
62         }
63
64         cur = cur->xmlChildrenNode;
65         if (cur == NULL) {
66                 MAS_LOGE("[ERROR] Empty document");
67                 xmlFreeDoc(doc);
68                 return -1;
69         }
70
71         /* alloc assistant info */
72         ma_assistant_info_s temp;
73
74         while (cur != NULL) {
75                 if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar *)MA_TAG_ASSISTANT_LANGUAGE_SET)) {
76                         xmlNodePtr child_node = cur->xmlChildrenNode;
77                         while (child_node != NULL) {
78                                 if (child_node->name && 0 == xmlStrcmp(child_node->name, (const xmlChar*)MA_TAG_ASSISTANT_LANGUAGE)) {
79                                         key = xmlNodeGetContent(child_node);
80                                         if (key) {
81                                                 temp.supported_lang[temp.cnt_lang++] = strdup((const char*)key);
82                                                 MAS_LOGD("Language : %s", key);
83                                                 xmlFree(key);
84                                         }
85                                 }
86
87                                 child_node = child_node->next;
88                         }
89                 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar *)MA_TAG_ASSISTANT_WAKEUP_WORD_SET)) {
90                         xmlNodePtr child_node = cur->xmlChildrenNode;
91                         while (child_node != NULL) {
92                                 if (child_node->name && 0 == xmlStrcmp(child_node->name, (const xmlChar*)MA_TAG_ASSISTANT_WAKEUP_WORD)) {
93                                         key = xmlNodeGetContent(child_node);
94                                         if (key) {
95                                                 temp.wakeup_list[temp.cnt_wakeup] = strdup((const char*)key);
96                                                 MAS_LOGD("Wakeup Word : %s", key);
97                                                 xmlFree(key);
98                                         }
99                                         xmlChar* prop = xmlNodeGetLang(child_node);
100                                         if (prop) {
101                                                 temp.wakeup_language[temp.cnt_wakeup] = strdup((const char*)prop);
102                                                 MAS_LOGD("Wakeup Language for %s : %s", temp.wakeup_list[temp.cnt_wakeup], prop);
103                                                 xmlFree(prop);
104                                         }
105                                         temp.cnt_wakeup++;
106                                 }
107
108                                 child_node = child_node->next;
109                         }
110                 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_NAME)) {
111                         key = xmlNodeGetContent(cur);
112                         if (key) {
113                                 temp.name = strdup((const char*)key);
114                                 MAS_LOGD("Name : %s", key);
115                                 xmlFree(key);
116                         }
117                 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_APPID)) {
118                         key = xmlNodeGetContent(cur);
119                         if (key) {
120                                 temp.app_id = strdup((const char*)key);
121                                 MAS_LOGD("ID : %s", key);
122                                 xmlFree(key);
123                         }
124                 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_ICON_PATH)) {
125                         key = xmlNodeGetContent(cur);
126                         if (key) {
127                                 temp.icon_path = strdup((const char*)key);
128                                 MAS_LOGD("Icon Path : %s", key);
129                                 xmlFree(key);
130                         }
131                 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_WAKEUP_ENGINE_APPID)) {
132                         key = xmlNodeGetContent(cur);
133                         if (key) {
134                                 temp.wakeup_engine = strdup((const char*)key);
135                                 MAS_LOGD("Wakeup Engine : %s", key);
136                                 xmlFree(key);
137                         }
138                 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_CUSTOM_UI)) {
139                         key = xmlNodeGetContent(cur);
140                         if (key) {
141                                 if (0 == xmlStrcasecmp(key, reinterpret_cast<const xmlChar*>("true"))) {
142                                         temp.custom_ui_option = true;
143                                 }
144                                 MAS_LOGD("Use custom UI : %d", temp.custom_ui_option);
145                                 xmlFree(key);
146                         }
147                 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_VOICE_KEY_SUPPORT_MODE)) {
148                         key = xmlNodeGetContent(cur);
149                         if (key) {
150                                 if (xmlStrcmp(cur->name, (const xmlChar*)VOICE_KEY_SUPPORT_MODE_STRING_ALL)) {
151                                         temp.voice_key_support_mode = VOICE_KEY_SUPPORT_MODE_ALL;
152                                 } else if (xmlStrcmp(cur->name, (const xmlChar*)VOICE_KEY_SUPPORT_MODE_STRING_TAP_TO_TALK)) {
153                                         temp.voice_key_support_mode = VOICE_KEY_SUPPORT_MODE_TAP_TO_TALK;
154                                 } else if (xmlStrcmp(cur->name, (const xmlChar*)VOICE_KEY_SUPPORT_MODE_STRING_PUSH_TO_TALK)) {
155                                         temp.voice_key_support_mode = VOICE_KEY_SUPPORT_MODE_PUSH_TO_TALK;
156                                 } else {
157                                         temp.voice_key_support_mode = VOICE_KEY_SUPPORT_MODE_NONE;
158                                 }
159                                 MAS_LOGD("Voice key support mode : %s", cur->name);
160                                 xmlFree(key);
161                         }
162                 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_VOICE_KEY_TAP_DURATION)) {
163                         key = xmlNodeGetContent(cur);
164                         if (key) {
165                                 temp.voice_key_tap_duration = atof((const char*)key);
166                                 MAS_LOGD("Voice key tap duration : %s", key);
167                                 xmlFree(key);
168                         }
169                 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_AUDIO_DATA_PROCESSOR)) {
170                         key = xmlNodeGetContent(cur);
171                         if (key) {
172                                 temp.audio_data_processing_appid = std::string{reinterpret_cast<char*>(key)};
173                                 xmlFree(key);
174                         }
175                 }
176
177                 cur = cur->next;
178         }
179
180         if (callback) {
181                 callback(&temp, user_data);
182         }
183
184         if (temp.app_id) {
185                 free((void*)temp.app_id);
186         }
187         if (temp.name) {
188                 free((void*)temp.name);
189         }
190         if (temp.icon_path) {
191                 free((void*)temp.icon_path);
192         }
193         for (loop = 0; loop < temp.cnt_wakeup; loop++) {
194                 if (temp.wakeup_list[loop]) {
195                         free((void*)(temp.wakeup_list[loop]));
196                 }
197         }
198         for (loop = 0; loop < temp.cnt_lang; loop++) {
199                 if (temp.supported_lang[loop]) {
200                         free((void*)(temp.supported_lang[loop]));
201                 }
202         }
203         if (temp.wakeup_engine) {
204                 free((void*)temp.wakeup_engine);
205         }
206
207         xmlFreeDoc(doc);
208
209         return 0;
210 }
211
212 int CServiceConfig::get_assistant_info(service_config_assistant_info_cb callback, void* user_data)
213 {
214         const char *suffix = ".xml";
215
216         DIR *d;
217         struct dirent *dir;
218         d = opendir(MA_ASSISTANT_INFO);
219
220         if (d) {
221                 while (NULL != (dir = readdir(d))) {
222                         if (suffix && strlen(suffix) <= strlen(dir->d_name)) {
223                                 if (0 == strcmp(dir->d_name + strlen(dir->d_name) - strlen(suffix), suffix)) {
224                                         char fullpath[_POSIX_PATH_MAX];
225                                         snprintf(fullpath, _POSIX_PATH_MAX - 1, "%s/%s", MA_ASSISTANT_INFO, dir->d_name);
226                                         MAS_LOGD("Parsing file : %s\n", fullpath);
227                                         parse_assistant_info(callback, fullpath, user_data);
228                                 }
229                         }
230                 }
231                 closedir(d);
232         }
233
234         return 0;
235 }
236
237 int CServiceConfig::add_custom_wake_word(const char* wake_word, const char* language,
238         char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
239         char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
240 {
241         if (nullptr == wake_word || nullptr == language) return -1;
242
243         bool found = false;
244         for (int loop = 0;false == found && loop < MAX_WAKEUP_WORDS_NUM;loop++) {
245                 if (0 == strncmp(wakeup_word_storage[loop], wake_word, MAX_WAKEUP_WORD_LEN) &&
246                         0 == strncmp(wakeup_language_storage[loop], language, MAX_SUPPORTED_LANGUAGE_LEN)) {
247                         LOGE("The wakeup word already exists!");
248                         return -1; /* Already exists */
249                 }
250                 if (0 == strlen(wakeup_word_storage[loop])) {
251                         strncpy(wakeup_word_storage[loop], wake_word, MAX_WAKEUP_WORD_LEN);
252                         wakeup_word_storage[loop][MAX_WAKEUP_WORD_LEN - 1] = '\0';
253                         strncpy(wakeup_language_storage[loop], language, MAX_SUPPORTED_LANGUAGE_LEN);
254                         wakeup_language_storage[loop][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
255                         found = true;
256                 }
257         }
258         if (!found) {
259                 LOGE("No empty slot found while trying to add new wake word!");
260                 return -1;
261         }
262         return 0;
263 }
264
265 int CServiceConfig::remove_custom_wake_word(const char* wake_word, const char* language,
266         char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
267         char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
268 {
269         if (nullptr == wake_word || nullptr == language) return -1;
270
271         bool found = false;
272         for (int loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
273                 if (0 == strncmp(wakeup_word_storage[loop], wake_word, MAX_WAKEUP_WORD_LEN) &&
274                         0 == strncmp(wakeup_language_storage[loop], language, MAX_SUPPORTED_LANGUAGE_LEN)) {
275                         for (int shift = loop;shift < MAX_WAKEUP_WORDS_NUM - 1;shift++) {
276                                 strncpy(wakeup_word_storage[shift],
277                                         wakeup_word_storage[shift + 1], MAX_WAKEUP_WORD_LEN);
278                                 wakeup_word_storage[shift][MAX_WAKEUP_WORD_LEN - 1] = '\0';
279                                 strncpy(wakeup_language_storage[shift],
280                                         wakeup_language_storage[shift + 1], MAX_SUPPORTED_LANGUAGE_LEN);
281                                 wakeup_language_storage[shift][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
282                         }
283                         memset(wakeup_word_storage[MAX_WAKEUP_WORDS_NUM - 1],
284                                 0x00, sizeof(char) * MAX_WAKEUP_WORD_LEN);
285                         memset(wakeup_language_storage[MAX_WAKEUP_WORDS_NUM - 1],
286                                 0x00, sizeof(char) * MAX_SUPPORTED_LANGUAGE_LEN);
287
288                         loop--; /* Just in case there are duplicated items */
289                         found = true;
290                 }
291         }
292         if (!found) return -1;
293         return 0;
294 }
295
296 int CServiceConfig::load_custom_wake_words(const char* app_id,
297         char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
298         char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
299 {
300         const char delimeter = '|';
301
302         /* Add 1 for additional pipe character */
303         char wakeup_words[MAX_WAKEUP_WORDS_NUM * (MAX_WAKEUP_WORD_LEN + 1)];
304         char wakeup_languages[MAX_WAKEUP_WORDS_NUM * (MAX_SUPPORTED_LANGUAGE_LEN + 1)];
305         memset(wakeup_words, 0x00, sizeof(wakeup_words));
306         memset(wakeup_languages, 0x00, sizeof(wakeup_languages));
307
308         bool existing = false;
309         preference_is_existing("custom_wakeup_words", &existing);
310         if (!existing) return -1;
311         preference_is_existing("custom_wakeup_languages", &existing);
312         if (!existing) return -1;
313
314         char* custom_wakeup_words = NULL;
315         preference_get_string("custom_wakeup_words", &custom_wakeup_words);
316         if (NULL == custom_wakeup_words) return -1;
317         strncpy(wakeup_words, custom_wakeup_words, sizeof(wakeup_words) - 1);
318         wakeup_words[sizeof(wakeup_words) - 1] = '\0';
319         LOGD("Custom wakeup words loaded : %s", wakeup_words);
320         free(custom_wakeup_words);
321         custom_wakeup_words = NULL;
322
323         char* custom_wakeup_languages = NULL;
324         preference_get_string("custom_wakeup_languages", &custom_wakeup_languages);
325         if (NULL == custom_wakeup_languages) return -1;
326         strncpy(wakeup_languages, custom_wakeup_languages, sizeof(wakeup_languages) - 1);
327         wakeup_languages[sizeof(wakeup_languages) - 1] = '\0';
328         LOGD("Custom wakeup languages loaded : %s", wakeup_languages);
329         free(custom_wakeup_languages);
330         custom_wakeup_languages = NULL;
331
332         char *word_start = wakeup_words;
333         char *language_start = wakeup_languages;
334         char *word_end = NULL;
335         char *language_end = NULL;
336         int index = 0;
337         while (index < MAX_WAKEUP_WORDS_NUM) {
338                 word_end = strchrnul(word_start, delimeter);
339                 language_end = strchrnul(language_start, delimeter);
340                 if ('\0' == *word_end || '\0' == *language_end) break;
341                 *word_end = '\0';
342                 *language_end = '\0';
343                 if (0 == strlen(word_start)) break;
344                 strncpy(wakeup_word_storage[index], word_start, MAX_WAKEUP_WORD_LEN - 1);
345                 strncpy(wakeup_language_storage[index], language_start, MAX_SUPPORTED_LANGUAGE_LEN - 1);
346                 word_start = word_end + 1;
347                 language_start = language_end + 1;
348                 LOGD("Added custom wakeup word : (%s) (%s)",
349                         wakeup_word_storage[index], wakeup_language_storage[index]);
350                 index++;
351         }
352
353         return 0;
354 }
355
356 int CServiceConfig::save_custom_wake_words(const char* app_id,
357         char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
358         char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
359 {
360         const char* delimeter = "|";
361         /* Add 1 for additional pipe character */
362         char wakeup_words[MAX_WAKEUP_WORDS_NUM * (MAX_WAKEUP_WORD_LEN + 1)];
363         char wakeup_languages[MAX_WAKEUP_WORDS_NUM * (MAX_SUPPORTED_LANGUAGE_LEN + 1)];
364         memset(wakeup_words, 0x00, sizeof(wakeup_words));
365         memset(wakeup_languages, 0x00, sizeof(wakeup_languages));
366         for (int loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
367                 if (strlen(wakeup_word_storage[loop]) > 0) {
368                         int wakeup_words_len = strlen(wakeup_words);
369                         strncat(wakeup_words, wakeup_word_storage[loop],
370                                 sizeof(wakeup_words) - wakeup_words_len - 1);
371                         strncat(wakeup_words, delimeter, strlen(delimeter));
372                         int wakeup_languages_len = strlen(wakeup_languages);
373                         strncat(wakeup_languages, wakeup_language_storage[loop],
374                                 sizeof(wakeup_languages) - wakeup_languages_len - 1);
375                         strncat(wakeup_languages, delimeter, strlen(delimeter));
376                 }
377         }
378         wakeup_words[sizeof(wakeup_words) - 1] = '\0';
379         wakeup_languages[sizeof(wakeup_languages) - 1] = '\0';
380         preference_set_string("custom_wakeup_words", wakeup_words);
381         preference_set_string("custom_wakeup_languages", wakeup_languages);
382         return 0;
383 }
384
385 int CServiceConfig::get_custom_wake_word_num(
386         char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
387         char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
388 {
389         int num = 0;
390         for (int loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
391                 if (0 < strlen(wakeup_word_storage[loop])) {
392                         num++;
393                 }
394         }
395         return num;
396 }
397
398 bool CServiceConfig::has_custom_wake_word(const char* wake_word, const char* language,
399         char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
400         char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
401 {
402         if (nullptr == wake_word || nullptr == language) return false;
403
404         for (int loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
405                 if (0 == strncmp(wakeup_word_storage[loop], wake_word, MAX_WAKEUP_WORD_LEN) &&
406                         0 == strncmp(wakeup_language_storage[loop], language, MAX_SUPPORTED_LANGUAGE_LEN)) {
407                         return true;
408                 }
409         }
410         return false;
411 }