Postpone base control initialization
[platform/core/appfw/app-core.git] / src / base / appcore_base_control.c
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #define _GNU_SOURCE
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <malloc.h>
26 #include <linux/limits.h>
27 #include <glib.h>
28 #include <bundle_internal.h>
29 #include <pkgmgr-info.h>
30 #include <aul_svc.h>
31 #include <aul_svc_internal.h>
32
33 #include "appcore_base.h"
34 #include "appcore_base_private.h"
35 #include "appcore_base_control.h"
36
37 struct appcore_base_control_s {
38         char *id;
39         appcore_base_control_cb callback;
40         void *user_data;
41 };
42
43 struct control_info_s {
44         char *id;
45         char *operation;
46         char *uri;
47         char *uri_scheme;
48         char *uri_host;
49         char *mime;
50         char *mime_type;
51         char *mime_subtype;
52 };
53
54 static GList *__controls;
55 static GList *__control_infos;
56 static bool __control_info_initialized;
57
58 static void __destroy_control_info(gpointer data)
59 {
60         struct control_info_s *info = (struct control_info_s *)data;
61
62         if (!info)
63                 return;
64
65         if (info->mime_subtype)
66                 free(info->mime_subtype);
67         if (info->mime_type)
68                 free(info->mime_type);
69         if (info->mime)
70                 free(info->mime);
71         if (info->uri_host)
72                 free(info->uri_host);
73         if (info->uri_scheme)
74                 free(info->uri_scheme);
75         if (info->uri)
76                 free(info->uri);
77         if (info->operation)
78                 free(info->operation);
79         if (info->id)
80                 free(info->id);
81         free(info);
82 }
83
84 static struct control_info_s *__create_control_info(const char *id,
85                 const char *operation, const char *mime,
86                 const char *uri)
87 {
88         struct control_info_s *info;
89
90         info = calloc(1, sizeof(struct control_info_s));
91         if (!info) {
92                 _ERR("Out of memory");
93                 return NULL;
94         }
95
96         info->id = strdup(id);
97         if (!info->id) {
98                 _ERR("Failed to duplicate app-control ID");
99                 free(info);
100                 return NULL;
101         }
102
103         info->operation = strdup(operation);
104         if (!info->operation) {
105                 _ERR("Failed to duplicate app-control operation");
106                 __destroy_control_info(info);
107                 return NULL;
108         }
109
110         info->mime = strdup(mime ? mime : "NULL");
111         if (!info->mime) {
112                 _ERR("Failed to duplicate app-control MIME-type");
113                 __destroy_control_info(info);
114                 return NULL;
115         }
116
117         info->uri = strdup(uri ? uri : "NULL");
118         if (!info->uri)  {
119                 _ERR("Failed to duplicate app-control URI");
120                 __destroy_control_info(info);
121                 return NULL;
122         }
123
124         return info;
125 }
126
127 static struct control_info_s *__create_control_info_from_bundle(bundle *b)
128 {
129         struct control_info_s *info;
130         aul_svc_info_h svc_info;
131         int r;
132
133         r = aul_svc_info_create(b, &svc_info);
134         if (r != AUL_SVC_RET_OK)
135                 return NULL;
136
137         info = calloc(1, sizeof(struct control_info_s));
138         if (!info) {
139                 _ERR("Out of memory");
140                 goto err;
141         }
142
143         r = aul_svc_info_get_operation(svc_info, &info->operation);
144         if (r != AUL_SVC_RET_OK)
145                 goto err;
146
147         r = aul_svc_info_get_uri(svc_info, &info->uri);
148         if (r != AUL_SVC_RET_OK)
149                 goto err;
150
151         r = aul_svc_info_get_uri_scheme(svc_info, &info->uri_scheme);
152         if (r != AUL_SVC_RET_OK)
153                 goto err;
154
155         r = aul_svc_info_get_uri_host(svc_info, &info->uri_host);
156         if (r != AUL_SVC_RET_OK)
157                 goto err;
158
159         r = aul_svc_info_get_mime(svc_info, &info->mime);
160         if (r != AUL_SVC_RET_OK)
161                 goto err;
162
163         r = aul_svc_info_get_mime_type(svc_info, &info->mime_type);
164         if (r != AUL_SVC_RET_OK)
165                 goto err;
166
167         r = aul_svc_info_get_mime_subtype(svc_info, &info->mime_subtype);
168         if (r != AUL_SVC_RET_OK)
169                 goto err;
170
171         aul_svc_info_destroy(svc_info);
172
173         return info;
174 err:
175         __destroy_control_info(info);
176         aul_svc_info_destroy(svc_info);
177
178         return NULL;
179 }
180
181 static gint __compare_control_infos(gconstpointer a, gconstpointer b)
182 {
183         struct control_info_s *a_info = (struct control_info_s *)a;
184         struct control_info_s *b_info = (struct control_info_s *)b;
185         char mime[256];
186
187         if (strcmp(a_info->operation, b_info->operation) != 0)
188                 return -1;
189
190         if (!strcmp(a_info->uri, b_info->uri) &&
191                         !strcmp(a_info->mime, b_info->mime))
192                 return 0;
193
194         if (!strcmp(a_info->uri, b_info->uri)) {
195                 if (!strcmp(b_info->mime, "NULL") &&
196                                 !strcmp(b_info->mime_subtype, "%")) {
197                         snprintf(mime, sizeof(mime), "%s/*",
198                                         b_info->mime_type);
199                         if (!strcmp(a_info->mime, mime))
200                                 return 0;
201                 }
202
203                 if (!strcmp(b_info->mime, "NULL") &&
204                                 !strcmp(b_info->mime_type, "%")) {
205                         if (!strcmp(a_info->mime, "*/*"))
206                                 return 0;
207                 }
208         }
209
210         return -1;
211 }
212
213 static struct control_info_s *__find_control_info(bundle *b)
214 {
215         struct control_info_s *info;
216         struct control_info_s b_info;
217         char uri[256];
218         GList *found;
219
220         info = __create_control_info_from_bundle(b);
221         if (!info)
222                 return NULL;
223
224         b_info = *info;
225
226         /* Step 1 */
227         found = g_list_find_custom(__control_infos, &b_info,
228                         __compare_control_infos);
229         if (found) {
230                 __destroy_control_info(info);
231                 return found->data;
232         }
233
234         /* Step 2 */
235         if (strcmp(b_info.uri_scheme, "NULL") != 0 &&
236                         strcmp(b_info.uri_host, "NULL") != 0) {
237                 snprintf(uri, sizeof(uri), "%s://%s",
238                                 b_info.uri_scheme, b_info.uri_host);
239                 b_info.uri = uri;
240                 found = g_list_find_custom(__control_infos, &b_info,
241                                 __compare_control_infos);
242                 if (found) {
243                         __destroy_control_info(info);
244                         return found->data;
245                 }
246         }
247
248         /* Step 3 */
249         b_info.uri = info->uri_scheme;
250         found = g_list_find_custom(__control_infos, &b_info,
251                         __compare_control_infos);
252         if (found) {
253                 __destroy_control_info(info);
254                 return found->data;
255         }
256
257         /* Step 4 */
258         b_info.uri = "*";
259         found = g_list_find_custom(__control_infos, &b_info,
260                         __compare_control_infos);
261         if (found) {
262                 __destroy_control_info(info);
263                 return found->data;
264         }
265
266         /* Step 5 */
267         if (!strcmp(b_info.uri_scheme, "file") &&
268                         strcmp(b_info.mime, "NULL") != 0) {
269                 b_info.uri = "NULL";
270                 found = g_list_find_custom(__control_infos, &b_info,
271                                 __compare_control_infos);
272                 if (found) {
273                         __destroy_control_info(info);
274                         return found->data;
275                 }
276         }
277
278         __destroy_control_info(info);
279
280         return NULL;
281 }
282
283 static int __foreach_app_control_cb(const char *operation,
284                 const char *uri, const char *mime, const char *id,
285                 void *user_data)
286 {
287         struct control_info_s *info;
288
289         info = __create_control_info(id, operation, mime, uri);
290         if (!info)
291                 return -1;
292
293         __control_infos = g_list_append(__control_infos, info);
294
295         return 0;
296 }
297
298 int appcore_base_control_init(void)
299 {
300         pkgmgrinfo_appinfo_h handle;
301         char appid[512];
302         int r;
303
304         if (__control_info_initialized)
305                 return APPCORE_BASE_ERROR_NONE;
306
307         r = aul_app_get_appid_bypid(getpid(), appid, sizeof(appid));
308         if (r != AUL_R_OK) {
309                 _ERR("Failed to get application ID. result(%x)", r);
310                 return APPCORE_BASE_ERROR_IO_ERROR;
311         }
312
313         r = pkgmgrinfo_appinfo_get_appinfo(appid, &handle);
314         if (r != PMINFO_R_OK) {
315                 _ERR("Failed to get app info. result(%x)", r);
316                 return APPCORE_BASE_ERROR_IO_ERROR;
317         }
318
319         r = pkgmgrinfo_appinfo_foreach_appcontrol_v2(handle,
320                         __foreach_app_control_cb, NULL);
321         if (r != PMINFO_R_OK) {
322                 _ERR("Failed to retrieve app-control. result(%x)", r);
323                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
324                 return APPCORE_BASE_ERROR_IO_ERROR;
325         }
326
327         pkgmgrinfo_appinfo_destroy_appinfo(handle);
328
329         __control_info_initialized = true;
330
331         return APPCORE_BASE_ERROR_NONE;
332 }
333
334 void appcore_base_control_fini(void)
335 {
336         if (__controls) {
337                 g_list_free_full(__controls,
338                                 (GDestroyNotify)appcore_base_control_remove);
339                 __controls = NULL;
340         }
341
342         if (__control_infos) {
343                 g_list_free_full(__control_infos, __destroy_control_info);
344                 __control_infos = NULL;
345         }
346
347         __control_info_initialized = false;
348 }
349
350 int appcore_base_control_invoke(bundle *b)
351 {
352         struct appcore_base_control_s *ctrl;
353         struct control_info_s *info;
354         GList *iter;
355
356         if (!b) {
357                 _ERR("Invalid parameter");
358                 return APPCORE_BASE_ERROR_INVALID_PARAMETER;
359         }
360
361         if (!__controls)
362                 return APPCORE_BASE_ERROR_NONE;
363
364         info = __find_control_info(b);
365         if (!info)
366                 return APPCORE_BASE_ERROR_NONE;
367
368         iter = __controls;
369         while (iter) {
370                 ctrl = (struct appcore_base_control_s *)iter->data;
371                 if (!strcmp(ctrl->id, info->id))
372                         ctrl->callback(b, ctrl->user_data);
373
374                 iter = g_list_next(iter);
375         }
376
377         _DBG("[app-control] id(%s)", info->id);
378         return APPCORE_BASE_ERROR_NONE;
379 }
380
381 static bool __control_info_exists(const char *id)
382 {
383         struct control_info_s *info;
384         GList *iter;
385
386         iter = __control_infos;
387         while (iter) {
388                 info = (struct control_info_s *)iter->data;
389                 if (!strcmp(info->id, id))
390                         return true;
391
392                 iter = g_list_next(iter);
393         }
394
395         return false;
396 }
397
398 EXPORT_API int appcore_base_control_add(const char *id,
399                 appcore_base_control_cb callback, void *user_data,
400                 appcore_base_control_h *h)
401 {
402         struct appcore_base_control_s *ctrl;
403         int r;
404
405         if (!id || !callback || !h) {
406                 _ERR("Invalid parameter");
407                 return APPCORE_BASE_ERROR_INVALID_PARAMETER;
408         }
409
410         r = appcore_base_control_init();
411         if (r < 0) {
412                 _ERR("Failed to initialize app-control info");
413                 return r;
414         }
415
416         if (!__control_info_exists(id)) {
417                 _ERR("Failed to find control info(%s)", id);
418                 return APPCORE_BASE_ERROR_KEY_NOT_FOUND;
419         }
420
421         ctrl = calloc(1, sizeof(struct appcore_base_control_s));
422         if (!ctrl) {
423                 _ERR("Out of memory");
424                 return APPCORE_BASE_ERROR_OUT_OF_MEMORY;
425         }
426
427         ctrl->id = strdup(id);
428         if (!ctrl->id) {
429                 _ERR("Failed to duplicate app-control ID");
430                 free(ctrl);
431                 return APPCORE_BASE_ERROR_OUT_OF_MEMORY;
432         }
433
434         ctrl->callback = callback;
435         ctrl->user_data = user_data;
436
437         __controls = g_list_append(__controls, ctrl);
438
439         *h = ctrl;
440
441         return APPCORE_BASE_ERROR_NONE;
442 }
443
444 EXPORT_API int appcore_base_control_remove(appcore_base_control_h h)
445 {
446         struct appcore_base_control_s *ctrl;
447
448         if (!h || !g_list_find(__controls, h)) {
449                 _ERR("Invalid parameter");
450                 return APPCORE_BASE_ERROR_INVALID_PARAMETER;
451         }
452
453         ctrl = (struct appcore_base_control_s *)h;
454         __controls = g_list_remove(__controls, ctrl);
455
456         if (ctrl->id)
457                 free(ctrl->id);
458         free(ctrl);
459
460         return APPCORE_BASE_ERROR_NONE;
461 }