Release version 1.6.27
[platform/core/appfw/data-provider-master.git] / src / shortcut_service.c
1 /*
2  * Copyright 2016  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <dlog.h>
17 #include <gio/gio.h>
18 #include <shortcut_db.h>
19 #include <shortcut.h>
20 #include "service_common.h"
21 #include "shortcut_service.h"
22 #include "debug.h"
23
24 #define PROVIDER_SHORTCUT_INTERFACE_NAME "org.tizen.data_provider_shortcut_service"
25 #define SHORTCUT_INVOCATION_KEY_POS 0
26
27 static GHashTable *_monitoring_hash;
28 static GHashTable *_invocation_hash;
29
30 static void _on_name_appeared(GDBusConnection *connection,
31                 const gchar     *name,
32                 const gchar     *name_owner,
33                 gpointer         user_data)
34 {
35         DBG("name [%s]", name);
36 }
37
38 static void _on_name_vanished(GDBusConnection *connection,
39                 const gchar     *name,
40                 gpointer         user_data)
41 {
42         DBG("name [%s]", name);
43         monitoring_info_s *info = (monitoring_info_s *)user_data;
44
45         if (info) {
46                 DBG("vanished uid [%d]", info->uid);
47                 g_bus_unwatch_name(info->watcher_id);
48                 delete_monitoring_list(&_monitoring_hash, name, info->uid);
49
50                 if (info->bus_name)
51                         free(info->bus_name);
52                 free(info);
53         }
54 }
55
56 static void _shortcut_dbus_method_call_handler(GDBusConnection *conn,
57                 const gchar *sender, const gchar *object_path,
58                 const gchar *iface_name, const gchar *method_name,
59                 GVariant *parameters, GDBusMethodInvocation *invocation,
60                 gpointer user_data)
61 {
62         /* TODO : sender authority(privilege) check */
63         DBG("shortcut method_name [%s]", method_name);
64         GVariant *reply_body = NULL;
65         int ret = SHORTCUT_ERROR_NOT_SUPPORTED;
66         uid_t uid = get_sender_uid(sender);
67
68         if (g_strcmp0(method_name, "shortcut_service_register") == 0) {
69                 ret = service_register(parameters, &reply_body, sender,
70                  _on_name_appeared, _on_name_vanished, &_monitoring_hash, uid);
71         } else if (g_strcmp0(method_name, "add_shortcut") == 0) {
72                 shortcut_add(parameters, invocation, uid);
73                 return;
74         } else if (g_strcmp0(method_name, "add_shortcut_widget") == 0) {
75                 shortcut_add_widget(parameters, invocation, uid);
76                 return;
77         } else if (g_strcmp0(method_name, "remove_shortcut") == 0) {
78                 shortcut_remove(parameters, invocation, uid);
79                 return;
80         } else if (g_strcmp0(method_name, "get_list") == 0) {
81                 ret = shortcut_get_shortcut_service_list(parameters, &reply_body, uid);
82         } else if (g_strcmp0(method_name, "check_privilege") == 0) {
83                 ret = shortcut_check_privilege();
84         } else if (g_strcmp0(method_name, "send_return_value") == 0) {
85                 ret = shortcut_send_return_value(parameters, &reply_body);
86         }
87
88         if (ret == SERVICE_COMMON_ERROR_NONE) {
89                 DBG("shortcut service success, method[%s]", method_name);
90                 g_dbus_method_invocation_return_value(
91                                 invocation, reply_body);
92         } else {
93                 DBG("shortcut service fail, method_name[%s] err[%d]",
94                         method_name, ret);
95                 g_dbus_method_invocation_return_error(
96                                 invocation,
97                                 SHORTCUT_ERROR,
98                                 ret,
99                                 "shortcut service error");
100         }
101 }
102
103 static const GDBusInterfaceVTable _shortcut_interface_vtable = {
104                 _shortcut_dbus_method_call_handler,
105                 NULL,
106                 NULL
107 };
108
109 int shortcut_register_dbus_interface(void)
110 {
111         static gchar introspection_xml[] =
112                         "  <node>"
113                         "  <interface name='org.tizen.data_provider_shortcut_service'>"
114                         "        <method name='shortcut_service_register'>"
115                         "          <arg type='i' name='uid' direction='in'/>"
116                         "        </method>"
117
118                         "        <method name='get_list'>"
119                         "          <arg type='v' name='package_name' direction='in'/>"
120                         "          <arg type='i' name='shortcut_cnt' direction='out'/>"
121                         "          <arg type='a(v)' name='shortcut_list' direction='out'/>"
122                         "        </method>"
123
124                         "        <method name='add_shortcut'>"
125                         "          <arg type='s' name='request_id' direction='in'/>"
126                         "          <arg type='i' name='pid' direction='in'/>"
127                         "          <arg type='s' name='appid' direction='in'/>"
128                         "          <arg type='s' name='name' direction='in'/>"
129                         "          <arg type='i' name='type' direction='in'/>"
130                         "          <arg type='s' name='uri' direction='in'/>"
131                         "          <arg type='s' name='icon' direction='in'/>"
132                         "          <arg type='i' name='allow_duplicate' direction='in'/>"
133                         "          <arg type='i' name='return_value' direction='out'/>"
134                         "        </method>"
135
136                         "        <method name='add_shortcut_widget'>"
137                         "          <arg type='s' name='request_id' direction='in'/>"
138                         "          <arg type='i' name='pid' direction='in'/>"
139                         "          <arg type='s' name='widget_id' direction='in'/>"
140                         "          <arg type='s' name='name' direction='in'/>"
141                         "          <arg type='i' name='size' direction='in'/>"
142                         "          <arg type='s' name='uri' direction='in'/>"
143                         "          <arg type='s' name='icon' direction='in'/>"
144                         "          <arg type='d' name='period' direction='in'/>"
145                         "          <arg type='i' name='allow_duplicate' direction='in'/>"
146                         "          <arg type='i' name='return_value' direction='out'/>"
147                         "        </method>"
148
149                         "        <method name='remove_shortcut'>"
150                         "          <arg type='s' name='request_id' direction='in'/>"
151                         "          <arg type='i' name='pid' direction='in'/>"
152                         "          <arg type='s' name='appid' direction='in'/>"
153                         "          <arg type='s' name='name' direction='in'/>"
154                         "          <arg type='i' name='return_value' direction='out'/>"
155                         "        </method>"
156
157                         "        <method name='check_privilege'>"
158                         "        </method>"
159
160                         "        <method name='send_return_value'>"
161                         "          <arg type='i' name='return_value' direction='in'/>"
162                         "          <arg type='s' name='request_id' direction='in'/>"
163                         "        </method>"
164                         "  </interface>"
165                         "  </node>";
166
167         return service_common_register_dbus_interface(introspection_xml, _shortcut_interface_vtable);
168 }
169
170 static void _release_shortcut_info(gpointer data)
171 {
172         if (data == NULL)
173                 return;
174
175         shortcut_info_s *shortcut = (shortcut_info_s *)data;
176
177         if (shortcut->package_name)
178                 free(shortcut->package_name);
179         if (shortcut->icon)
180                 free(shortcut->icon);
181         if (shortcut->name)
182                 free(shortcut->name);
183         if (shortcut->extra_key)
184                 free(shortcut->extra_key);
185         if (shortcut->extra_data)
186                 free(shortcut->extra_data);
187         free(shortcut);
188 }
189
190 /* get_list */
191 int shortcut_get_shortcut_service_list(GVariant *parameters, GVariant **reply_body, uid_t uid)
192 {
193         int count;
194         GList *shortcut_list = NULL;
195         GList *iter_list = NULL;
196         GVariant *param_body = NULL;
197         GVariant *body = NULL;
198         shortcut_info_s *shortcut;
199         GVariantDict dict;
200         char *package_name = NULL;
201         GVariantBuilder *builder;
202
203         g_variant_get(parameters, "(v)", &param_body);
204         g_variant_dict_init(&dict, param_body);
205         g_variant_dict_lookup(&dict, "package_name", "&s", &package_name);
206         g_variant_dict_end(&dict);
207
208         count = shortcut_db_get_list(package_name, &shortcut_list);
209         builder = g_variant_builder_new(G_VARIANT_TYPE("a(v)"));
210         if (count > 0) {
211                 iter_list = g_list_first(shortcut_list);
212                 for (; iter_list != NULL; iter_list = iter_list->next) {
213                         shortcut = iter_list->data;
214                         body = g_variant_new("(sssss)",
215                                 shortcut->package_name, shortcut->icon, shortcut->name, shortcut->extra_key, shortcut->extra_data);
216                         g_variant_builder_add(builder, "(v)", body);
217                 }
218                 g_list_free_full(shortcut_list, (GDestroyNotify)_release_shortcut_info);
219         }
220
221         *reply_body = g_variant_new("(ia(v))", count, builder);
222         g_variant_builder_unref(builder);
223
224         if (*reply_body == NULL) {
225                 ERR("Failed to make reply");
226                 return SHORTCUT_ERROR_OUT_OF_MEMORY;
227         }
228
229         INFO("count[%d]", count);
230         return SERVICE_COMMON_ERROR_NONE;
231 }
232
233 static GDBusMethodInvocation *_get_invocation(char *request_id)
234 {
235         GDBusMethodInvocation *find_invocation;
236
237         find_invocation = (GDBusMethodInvocation *)g_hash_table_lookup(_invocation_hash, request_id);
238         if (!find_invocation)
239                 return NULL;
240
241         return find_invocation;
242 }
243
244 static void _add_invocation(GDBusMethodInvocation *invocation, char *request_id)
245 {
246         GDBusMethodInvocation *find_invocation;
247
248         if (request_id == NULL)
249                 return;
250
251         find_invocation = _get_invocation(request_id);
252         if (find_invocation)
253                 return;
254
255         g_hash_table_insert(_invocation_hash, strdup(request_id), invocation);
256
257         DBG("Invocation key [%s]", request_id);
258 }
259
260 static void _remove_invocation(char *request_id)
261 {
262         if (request_id == NULL)
263                 return;
264
265         g_hash_table_remove(_invocation_hash, request_id);
266
267         DBG("Invocation key [%s]", request_id);
268 }
269
270 /* add_shortcut */
271 void shortcut_add(GVariant *parameters, GDBusMethodInvocation *invocation, uid_t uid)
272 {
273         int ret = SERVICE_COMMON_ERROR_NONE;
274         char *request_id = NULL;
275
276         g_variant_get_child(parameters, SHORTCUT_INVOCATION_KEY_POS, "&s", &request_id);
277
278         _add_invocation(invocation, request_id);
279
280         ret = send_notify(parameters, "add_shortcut_notify", &_monitoring_hash, PROVIDER_SHORTCUT_INTERFACE_NAME, uid);
281         if (ret != SERVICE_COMMON_ERROR_NONE)
282                 ERR("Failed to send notify [%d]", ret);
283         else
284                 DBG("Success to send notify");
285
286 }
287
288 /* add_shortcut_widget */
289 void shortcut_add_widget(GVariant *parameters, GDBusMethodInvocation *invocation, uid_t uid)
290 {
291         int ret = SERVICE_COMMON_ERROR_NONE;
292         char *request_id = NULL;
293
294         g_variant_get_child(parameters, SHORTCUT_INVOCATION_KEY_POS, "&s", &request_id);
295
296         _add_invocation(invocation, request_id);
297
298         ret = send_notify(parameters, "add_shortcut_widget_notify", &_monitoring_hash, PROVIDER_SHORTCUT_INTERFACE_NAME, uid);
299         if (ret != SERVICE_COMMON_ERROR_NONE)
300                 ERR("Failed to send notify [%d]", ret);
301         else
302                 DBG("Success to send notify");
303 }
304
305 /* remove_shortcut */
306 void shortcut_remove(GVariant *parameters, GDBusMethodInvocation *invocation, uid_t uid)
307 {
308         int ret = SERVICE_COMMON_ERROR_NONE;
309         char *request_id = NULL;
310
311         g_variant_get_child(parameters, SHORTCUT_INVOCATION_KEY_POS, "&s", &request_id);
312
313         _add_invocation(invocation, request_id);
314
315         ret = send_notify(parameters, "remove_shortcut_notify", &_monitoring_hash, PROVIDER_SHORTCUT_INTERFACE_NAME, uid);
316         if (ret != SERVICE_COMMON_ERROR_NONE)
317                 ERR("Failed to send notify [%d]", ret);
318         else
319                 DBG("Success to send notify");
320 }
321
322 /*  check shortcut privilege */
323 int shortcut_check_privilege(void)
324 {
325         return SERVICE_COMMON_ERROR_NONE;
326 }
327
328 int shortcut_send_return_value(GVariant *parameters, GVariant **reply_body)
329 {
330         int return_value;
331         char *request_id = NULL;
332         GDBusMethodInvocation *invocation = NULL;
333
334         g_variant_get(parameters, "(i&s)", &return_value, &request_id);
335
336         if (request_id == NULL)
337                 return SHORTCUT_ERROR_INVALID_PARAMETER;
338
339         invocation = _get_invocation(request_id);
340         if (!invocation)
341                 return SHORTCUT_ERROR_INVALID_PARAMETER;
342
343         g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", return_value));
344         _remove_invocation(request_id);
345
346         *reply_body = g_variant_new("()");
347         if (*reply_body == NULL) {
348                 ERR("Failed to make reply");
349                 return SHORTCUT_ERROR_OUT_OF_MEMORY;
350         }
351
352         DBG("Success to send return value");
353         return SHORTCUT_ERROR_NONE;
354 }
355
356 /*!
357  * MAIN THREAD
358  * Do not try to do anyother operation in these functions
359  */
360 HAPI int shortcut_service_init(void)
361 {
362         int result;
363
364         _monitoring_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
365         _invocation_hash = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
366
367         result = shortcut_db_init();
368         if (result != SHORTCUT_ERROR_NONE) {
369                 ERR("Failed to init DB[%d]", result);
370                 return result;
371         }
372
373         result = shortcut_register_dbus_interface();
374         if (result != SERVICE_COMMON_ERROR_NONE) {
375                 ERR("Failed to register dbus interface [%d]", result);
376                 return result;
377         }
378
379         INFO("Initialization success");
380         return result;
381 }
382
383 HAPI int shortcut_service_fini(void)
384 {
385         g_hash_table_destroy(_invocation_hash);
386
387         DBG("Finalization success");
388         return SERVICE_COMMON_ERROR_NONE;
389 }
390
391 /* End of a file */