cba286e8145998594c6c934aa65dcc0eeb583cac
[platform/core/uifw/libds-tizen.git] / src / libds-tizen / keyrouter / keyrouter.c
1 #include <unistd.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <errno.h>
5 #include <assert.h>
6 #include <stdint.h>
7 #include <stdbool.h>
8
9 #include <libds/log.h>
10 #include "libds-tizen/keyrouter.h"
11
12 #include "util.h"
13 #include "keyrouter.h"
14
15 static void
16 keyrouter_bind(struct wl_client *client, void *data, uint32_t version,
17         uint32_t id);
18 static bool
19 keyrouter_check_privilege(struct ds_tizen_keyrouter_client *keyrouter_client,
20         struct wl_client *client, uint32_t mode, uint32_t keycode);
21 static void
22 keyrouter_options_set(struct ds_tizen_keyrouter *keyrouter);
23
24 static void
25 keyrouter_handle_display_destroy(struct wl_listener *listener, void *data)
26 {
27     struct ds_tizen_keyrouter *keyrouter;
28
29     keyrouter = wl_container_of(listener, keyrouter, display_destroy);
30
31     ds_inf("Global destroy: ds_tizen_keyrouter(%p)", keyrouter);
32
33     wl_signal_emit(&keyrouter->events.destroy, keyrouter);
34
35     tizen_security_finish();
36
37     free(keyrouter->opts);
38
39     wl_list_remove(&keyrouter->display_destroy.link);
40
41     wl_global_destroy(keyrouter->global);
42
43     keyrouter_grab_destroy(keyrouter->keyrouter_grab);
44
45     free(keyrouter);
46 }
47
48 WL_EXPORT struct ds_tizen_keyrouter *
49 ds_tizen_keyrouter_create(struct wl_display *display)
50 {
51     struct ds_tizen_keyrouter *keyrouter;
52
53     keyrouter = calloc(1, sizeof *keyrouter);
54     if (!keyrouter) {
55         return NULL;
56     }
57
58     keyrouter->keyrouter_grab = keyrouter_grab_create();
59     if (keyrouter->keyrouter_grab == NULL) {
60         ds_err("Failed to create keyrouter.");
61         free(keyrouter);
62         return NULL;
63     }
64
65     keyrouter->global = wl_global_create(display, &tizen_keyrouter_interface,
66             2, keyrouter, keyrouter_bind);
67     if (!keyrouter->global) {
68         keyrouter_grab_destroy(keyrouter->keyrouter_grab);
69         free(keyrouter);
70         return NULL;
71     }
72
73     wl_list_init(&keyrouter->clients);
74
75     wl_signal_init(&keyrouter->events.destroy);
76
77     keyrouter->display_destroy.notify = keyrouter_handle_display_destroy;
78     wl_display_add_destroy_listener(display, &keyrouter->display_destroy);
79
80     keyrouter_options_set(keyrouter);
81
82     if (!tizen_security_init()) {
83         ds_inf("tizen_security_init() is not sucessful. keyrouter works without security.");
84     }
85
86     ds_inf("Global created: ds_tizen_keyrouter(%p)", keyrouter);
87
88     return keyrouter;
89 }
90
91 WL_EXPORT void
92 ds_tizen_keyrouter_add_destroy_listener(struct ds_tizen_keyrouter *keyrouter,
93         struct wl_listener *listener)
94 {
95     wl_signal_add(&keyrouter->events.destroy, listener);
96 }
97
98 static void
99 keyrouter_handle_keygrab_set(struct wl_client *client,
100         struct wl_resource *resource, struct wl_resource *surface,
101         uint32_t key, uint32_t mode)
102 {
103     struct ds_tizen_keyrouter_client *keyrouter_client;
104     struct ds_tizen_keyrouter *keyrouter;
105     int res = TIZEN_KEYROUTER_ERROR_NONE;
106     bool ret;
107
108     keyrouter_client = wl_resource_get_user_data(resource);
109     keyrouter = keyrouter_client->keyrouter;
110
111     ret = keyrouter_check_privilege(keyrouter_client, client, mode, key);
112     if (ret == false) {
113         tizen_keyrouter_send_keygrab_notify(resource, surface,
114             key, mode, TIZEN_KEYROUTER_ERROR_NO_PERMISSION);
115         return;
116     }
117
118     res = keyrouter_grab_grab_key(keyrouter->keyrouter_grab,
119         mode, key, (void *)client);
120     if (res == TIZEN_KEYROUTER_ERROR_NONE && keyrouter_client->grabbed != true)
121         keyrouter_client->grabbed = true;
122
123     tizen_keyrouter_send_keygrab_notify(resource, surface, key, mode, res);
124 }
125
126 static void
127 keyrouter_handle_keygrab_unset(struct wl_client *client,
128         struct wl_resource *resource, struct wl_resource *surface,  uint32_t key)
129 {
130     struct ds_tizen_keyrouter_client *keyrouter_client;
131     struct ds_tizen_keyrouter *keyrouter;
132     int res = TIZEN_KEYROUTER_ERROR_NONE;
133     bool ret;
134
135     keyrouter_client = wl_resource_get_user_data(resource);
136     keyrouter = keyrouter_client->keyrouter;
137
138     /* ungrab TOP POSITION grab first, this grab mode is not check privilege */
139     keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
140         TIZEN_KEYROUTER_MODE_TOPMOST, key, (void *)client);
141
142     ret = keyrouter_check_privilege(keyrouter_client,
143         client, TIZEN_KEYROUTER_MODE_NONE, key);
144     if (ret == false) {
145         tizen_keyrouter_send_keygrab_notify(resource, surface, key,
146             TIZEN_KEYROUTER_MODE_NONE, TIZEN_KEYROUTER_ERROR_NO_PERMISSION);
147         return;
148     }
149
150     keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
151         TIZEN_KEYROUTER_MODE_EXCLUSIVE, key, (void *)client);
152     keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
153         TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE, key, (void *)client);
154     keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
155         TIZEN_KEYROUTER_MODE_TOPMOST, key, (void *)client);
156     keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
157         TIZEN_KEYROUTER_MODE_SHARED, key, (void *)client);
158
159     tizen_keyrouter_send_keygrab_notify(resource, surface, key, TIZEN_KEYROUTER_MODE_NONE, res);
160 }
161
162 static void
163 keyrouter_handle_get_keygrab_status(struct wl_client *client,
164         struct wl_resource *resource, struct wl_resource *surface, uint32_t key)
165 {
166     tizen_keyrouter_send_keygrab_notify(resource, surface, key,
167             TIZEN_KEYROUTER_MODE_NONE, TIZEN_KEYROUTER_ERROR_NO_PERMISSION);
168 }
169
170 static int
171 keyrouter_get_array_length(const struct wl_array *array)
172 {
173     int *data = NULL;
174     int count = 0;
175
176     wl_array_for_each(data, array) {
177         count++;
178     }
179
180     return count;
181 }
182
183 static void
184 keyrouter_handle_keygrab_set_list(struct wl_client *client,
185         struct wl_resource *resource, struct wl_resource *surface, struct wl_array *grab_list)
186 {
187     struct ds_tizen_keyrouter_client *keyrouter_client;
188     struct ds_tizen_keyrouter *keyrouter;
189     struct wl_array *return_list;
190     struct ds_tizen_grab_data *grab_data = NULL;
191     int res = TIZEN_KEYROUTER_ERROR_NONE;
192     bool ret;
193
194     keyrouter_client = wl_resource_get_user_data(resource);
195     keyrouter = keyrouter_client->keyrouter;
196
197     if ((keyrouter_get_array_length(grab_list) % 3) != 0) {
198         ds_err("Invalid keycode and grab mode pair. Check arguments in a list.");
199         tizen_keyrouter_send_keygrab_notify_list(resource, surface, NULL);
200         return;
201     }
202
203     wl_array_for_each(grab_data, grab_list) {
204         ret = keyrouter_check_privilege(keyrouter_client, client, grab_data->mode, grab_data->key);
205         if (ret == false) {
206             grab_data->err = TIZEN_KEYROUTER_ERROR_NO_PERMISSION;
207         } else {
208             res = keyrouter_grab_grab_key(keyrouter->keyrouter_grab,
209                 grab_data->mode, grab_data->key, (void *)client);
210             if (res == TIZEN_KEYROUTER_ERROR_NONE && keyrouter_client->grabbed != true)
211                 keyrouter_client->grabbed = true;
212
213             grab_data->err = res;
214         }
215     }
216
217     return_list = grab_list;
218
219     tizen_keyrouter_send_keygrab_notify_list(resource, surface, return_list);
220 }
221
222 static void
223 keyrouter_handle_keygrab_unset_list(struct wl_client *client,
224         struct wl_resource *resource, struct wl_resource *surface,
225         struct wl_array *ungrab_list)
226 {
227     struct ds_tizen_keyrouter_client *keyrouter_client;
228     struct ds_tizen_keyrouter *keyrouter;
229     struct wl_array *return_list = NULL;
230     struct ds_tizen_ungrab_data *ungrab_data = NULL;
231     bool ret;
232
233     keyrouter_client = wl_resource_get_user_data(resource);
234     keyrouter = keyrouter_client->keyrouter;
235
236     if ((keyrouter_get_array_length(ungrab_list) % 3) != 0) {
237         ds_err("Invalid keycode and grab mode pair. Check arguments in a list.");
238         tizen_keyrouter_send_keygrab_notify_list(resource, surface, NULL);
239         return;
240     }
241
242     wl_array_for_each(ungrab_data, ungrab_list) {
243         keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
244             TIZEN_KEYROUTER_MODE_TOPMOST, ungrab_data->key, (void *)client);
245
246         ret = keyrouter_check_privilege(keyrouter_client, client,
247             TIZEN_KEYROUTER_MODE_TOPMOST, ungrab_data->key);
248         if (!ret) {
249             ungrab_data->err = TIZEN_KEYROUTER_ERROR_NO_PERMISSION;
250         } else {
251             keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
252                 TIZEN_KEYROUTER_MODE_EXCLUSIVE, ungrab_data->key, (void *)client);
253
254             keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
255                 TIZEN_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE, ungrab_data->key, (void *)client);
256
257             keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
258                 TIZEN_KEYROUTER_MODE_TOPMOST, ungrab_data->key, (void *)client);
259
260             keyrouter_grab_ungrab_key(keyrouter->keyrouter_grab,
261                 TIZEN_KEYROUTER_MODE_SHARED, ungrab_data->key, (void *)client);
262
263             ungrab_data->err = TIZEN_KEYROUTER_ERROR_NONE;
264         }
265     }
266
267     return_list = ungrab_list;
268
269     tizen_keyrouter_send_keygrab_notify_list(resource, surface, return_list);
270 }
271
272 static void
273 keyrouter_handle_get_keygrab_list(struct wl_client *client,
274         struct wl_resource *resource, struct wl_resource *surface)
275 {
276     tizen_keyrouter_send_getgrab_notify_list(resource, surface, NULL);
277 }
278
279 static void
280 keyrouter_handle_set_register_none_key(struct wl_client *client,
281         struct wl_resource *resource, struct wl_resource *surface,
282         uint32_t data)
283 {
284     tizen_keyrouter_send_set_register_none_key_notify(resource, NULL, 0);
285 }
286
287 static void
288 keyrouter_handle_get_keyregister_status(struct wl_client *client,
289         struct wl_resource *resource, uint32_t key)
290 {
291     tizen_keyrouter_send_keyregister_notify(resource, (int)false);
292 }
293
294 static void
295 keyrouter_handle_set_input_config(struct wl_client *client,
296         struct wl_resource *resource, struct wl_resource *surface,
297         uint32_t config_mode, uint32_t value)
298 {
299     tizen_keyrouter_send_set_input_config_notify(resource, (int)false);
300 }
301
302 static void
303 keyrouter_handle_destory(struct wl_client *client,
304         struct wl_resource *resource)
305 {
306     wl_resource_destroy(resource);
307 }
308
309 static const struct tizen_keyrouter_interface tizen_keyrouter_impl = {
310    keyrouter_handle_keygrab_set,
311    keyrouter_handle_keygrab_unset,
312    keyrouter_handle_get_keygrab_status,
313    keyrouter_handle_keygrab_set_list,
314    keyrouter_handle_keygrab_unset_list,
315    keyrouter_handle_get_keygrab_list,
316    keyrouter_handle_set_register_none_key,
317    keyrouter_handle_get_keyregister_status,
318    keyrouter_handle_set_input_config,
319    keyrouter_handle_destory
320 };
321
322 static void
323 keyrouter_handle_resource_destory(struct wl_resource *resource)
324 {
325     struct ds_tizen_keyrouter_client *keyrouter_client = wl_resource_get_user_data(resource);
326
327     wl_list_remove(&keyrouter_client->link);
328     free(keyrouter_client);
329 }
330
331 static void
332 keyrouter_bind(struct wl_client *client, void *data, uint32_t version,
333         uint32_t id)
334 {
335     struct ds_tizen_keyrouter *keyrouter = data;
336     struct ds_tizen_keyrouter_client *keyrouter_client;
337
338     keyrouter_client = calloc(1, sizeof *keyrouter_client);
339     if (keyrouter_client == NULL) {
340         wl_client_post_no_memory(client);
341         return;
342     }
343
344     keyrouter_client->resource =
345         wl_resource_create(client, &tizen_keyrouter_interface, MIN(version, 2), id);
346     if (keyrouter_client->resource == NULL) {
347         ds_err("wl_resource_create() failed.(version :%d, id:%d)", version, id);
348         free(keyrouter_client);
349         wl_client_post_no_memory(client);
350         return;
351     }
352
353     wl_resource_set_implementation(keyrouter_client->resource, &tizen_keyrouter_impl,
354         keyrouter_client, keyrouter_handle_resource_destory);
355
356     wl_list_insert(&keyrouter->clients, &keyrouter_client->link);
357 }
358
359 static bool
360 keyrouter_check_privilege(struct ds_tizen_keyrouter_client *keyrouter_client,
361         struct wl_client *client, uint32_t mode, uint32_t keycode)
362 {
363     struct ds_tizen_keyrouter *keyrouter = keyrouter_client->keyrouter;
364
365     pid_t pid = 0;
366     uid_t uid = 0;
367     gid_t gid = 0;
368
369     /* Top position grab is always allowed. This mode do not need privilege.*/
370     if (mode == TIZEN_KEYROUTER_MODE_TOPMOST)
371         return true;
372
373     // check no privilege option on the keycode
374     if (keyrouter->opts) {
375         if (keyrouter->opts[keycode].no_privilege)
376             return true;
377     }
378
379     // grabbed client is already checked the privilege before.
380     if (keyrouter_client->grabbed)
381         return true;
382
383     wl_client_get_credentials(client, &pid, &uid, &gid);
384
385     return tizen_security_check_privilege(pid, uid, "http://tizen.org/privilege/keygrab");
386 }
387
388 static void
389 keyrouter_options_set(struct ds_tizen_keyrouter *keyrouter)
390 {
391     FILE *file;
392     int keycode;
393     char *ret, *tmp, *buf_ptr, buf[1024] = {0,};
394
395     keyrouter->opts = calloc(KEYROUTER_MAX_KEYS,
396         sizeof(struct ds_tizen_keyrouter_key_options));
397     if (!keyrouter->opts) {
398         return;
399     }
400
401     file = fopen(KEYLAYOUT_DIR, "r");
402     if (!file) {
403         ds_err("Failed to open key layout file(%s): (err msg: %m)\n", KEYLAYOUT_DIR);
404         free(keyrouter->opts);
405         keyrouter->opts = NULL;
406         return;
407     }
408
409     while (!feof(file)) {
410         ret = fgets(buf, 1024, file);
411         if (!ret) continue;
412
413         tmp = strtok_r(buf, " ", &buf_ptr);
414         tmp = strtok_r(NULL, " ", &buf_ptr);
415         if (!tmp) continue;
416         keycode = atoi(tmp);
417         if ((0 >= keycode) || (keycode >= KEYROUTER_MAX_KEYS)) {
418             ds_err("Currently %d key is invalid to support\n", keycode);
419             continue;
420         }
421
422         keyrouter->opts[keycode].enabled = true;
423
424         if (strstr(buf_ptr, "no_priv") != NULL) {
425             keyrouter->opts[keycode].no_privilege = true;
426         }
427     }
428
429     fclose(file);
430 }