Fix memory leak
[platform/core/appfw/shortcut.git] / lib / src / shortcut_internal.c
1 /*
2  * Copyright (c) 2011 - 2017 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 #include <gio/gio.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <string.h>
23
24 #include <aul.h>
25 #include <dlog.h>
26 #include <glib.h>
27 #include <stdio.h>
28
29 #include "shortcut.h"
30 #include "shortcut_private.h"
31 #include "shortcut_internal.h"
32
33 #define SHORTCUT_PKGNAME_LEN 512
34 #define REQUEST_ID_LEN 40
35 #define TIMEOUT 4000
36
37 #define PROVIDER_BUS_NAME "org.tizen.data_provider_service"
38 #define PROVIDER_OBJECT_PATH "/org/tizen/data_provider_service"
39 #define PROVIDER_SHORTCUT_INTERFACE_NAME "org.tizen.data_provider_shortcut_service"
40
41 #define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
42 #define DBUS_PATH_DBUS "/org/freedesktop/DBus"
43 #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus"
44
45 static GDBusConnection *_gdbus_conn = NULL;
46 static int monitor_id = 0;
47 static int provider_monitor_id = 0;
48
49 typedef struct _shortcut_request_cb_info {
50         int (*request_cb)(const char *appid, const char *name, int type, const char *content, const char *icon, pid_t pid, double period, int allow_duplicate, void *data);
51         void *data;
52 } shortcut_request_cb_info;
53
54 typedef struct _shortcut_remove_cb_info {
55         int (*remove_cb)(const char *package_name, const char *name, int sender_pid, void *user_data);
56         void *data;
57 } shortcut_remove_cb_info;
58
59 static shortcut_request_cb_info _request_callback_info;
60 static shortcut_remove_cb_info _remove_callback_info;
61
62 static void _shortcut_send_return(int ret_val, const char *request_id)
63 {
64         int ret;
65         GDBusMessage *reply = NULL;
66
67         ret = _dbus_init();
68         if (ret != SHORTCUT_ERROR_NONE) {
69                 SHORTCUT_ERR("Can't init dbus %d", ret);
70                 return;
71         }
72
73         _send_sync_shortcut(g_variant_new("(is)", ret_val, request_id),
74                             &reply, "send_return_value");
75         if (reply)
76                 g_object_unref(reply);
77 }
78
79 /* LCOV_EXCL_START */
80 static void _add_shortcut_notify(GVariant *parameters)
81 {
82         int ret = SHORTCUT_ERROR_NONE;
83         const char *appid;
84         const char *name;
85         int type;
86         const char *content;
87         const char *icon;
88         int allow_duplicate;
89         int sender_pid;
90         const char *request_id;
91
92         g_variant_get(parameters, "(&si&s&si&s&si)", &request_id, &sender_pid, &appid, &name, &type, &content, &icon, &allow_duplicate);
93         SHORTCUT_DBG("_add_shortcut_notify sender pid : [%d] appid : [%s]", sender_pid, appid);
94
95         if (_request_callback_info.request_cb != NULL)
96                 ret = _request_callback_info.request_cb(appid, name, type, content, icon, sender_pid, -1.0f, allow_duplicate, _request_callback_info.data);
97         else
98                 SHORTCUT_DBG("request_cb is null.");
99
100         _shortcut_send_return(ret, request_id);
101 }
102 /* LCOV_EXCL_STOP */
103
104 /* LCOV_EXCL_START */
105 static void _add_shortcut_widget_notify(GVariant *parameters)
106 {
107         int ret = SHORTCUT_ERROR_NONE;
108         const char *appid;
109         const char *name;
110         int type;
111         const char *content;
112         const char *icon;
113         int allow_duplicate;
114         int sender_pid;
115         double period;
116         const char *request_id;
117
118         g_variant_get(parameters, "(&si&s&si&s&sdi)", &request_id, &sender_pid, &appid, &name, &type, &content, &icon, &period, &allow_duplicate);
119         SHORTCUT_DBG("_add_shortcut_widget_notify sender pid : [%d] appid : [%s]", sender_pid, appid);
120
121         if (_request_callback_info.request_cb != NULL)
122                 ret = _request_callback_info.request_cb(appid, name, type, content, icon, sender_pid, period, allow_duplicate, _request_callback_info.data);
123         else
124                 SHORTCUT_DBG("request_cb is null.");
125
126         _shortcut_send_return(ret, request_id);
127 }
128 /* LCOV_EXCL_STOP */
129
130 static void _remove_shortcut_notify(GVariant *parameters)
131 {
132         int ret = SHORTCUT_ERROR_NONE;
133         const char *appid;
134         const char *name;
135         int sender_pid;
136         const char *request_id;
137
138         g_variant_get(parameters, "(&si&s&s)", &request_id, &sender_pid, &appid, &name);
139         SHORTCUT_DBG("_remove_shortcut_notify sender pid : [%d] appid : [%s]", sender_pid, appid);
140
141         if (_remove_callback_info.remove_cb != NULL)
142                 ret = _remove_callback_info.remove_cb(appid, name, sender_pid, _remove_callback_info.data);
143         else
144                 SHORTCUT_DBG("remove_cb is null.");
145
146         _shortcut_send_return(ret, request_id);
147 }
148
149 /* LCOV_EXCL_START */
150 static void _handle_shortcut_notify(GDBusConnection *connection,
151                 const gchar     *sender_name,
152                 const gchar     *object_path,
153                 const gchar     *interface_name,
154                 const gchar     *signal_name,
155                 GVariant        *parameters,
156                 gpointer         user_data)
157 {
158         SHORTCUT_DBG("signal_name : [%s]", signal_name);
159         if (g_strcmp0(signal_name, "add_shortcut_notify") == 0)
160                 _add_shortcut_notify(parameters);
161         else if (g_strcmp0(signal_name, "add_shortcut_widget_notify") == 0)
162                 _add_shortcut_widget_notify(parameters);
163         else if (g_strcmp0(signal_name, "remove_shortcut_notify") == 0)
164                 _remove_shortcut_notify(parameters);
165 }
166 /* LCOV_EXCL_STOP */
167
168 int _dbus_init(void)
169 {
170         GError *error = NULL;
171
172         if (_gdbus_conn == NULL) {
173                 _gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
174
175                 if (_gdbus_conn == NULL) {
176                         /* LCOV_EXCL_START */
177                         if (error != NULL) {
178
179                                 SHORTCUT_ERR("Failed to get dbus [%s]", error->message);
180                                 g_error_free(error);
181
182                         }
183                         return SHORTCUT_ERROR_IO_ERROR;
184                         /* LCOV_EXCL_STOP */
185                 }
186                 shortcut_error_quark();
187         }
188
189         return SHORTCUT_ERROR_NONE;
190 }
191
192 int _dbus_signal_init(void)
193 {
194         int ret = SHORTCUT_ERROR_NONE;
195         int id;
196
197         if (monitor_id == 0) {
198                 id = g_dbus_connection_signal_subscribe(
199                                 _gdbus_conn,
200                                 PROVIDER_BUS_NAME,
201                                 PROVIDER_SHORTCUT_INTERFACE_NAME,       /* interface */
202                                 NULL,                                   /* member */
203                                 PROVIDER_OBJECT_PATH,                   /* path */
204                                 NULL,                                   /* arg0 */
205                                 G_DBUS_SIGNAL_FLAGS_NONE,
206                                 _handle_shortcut_notify,
207                                 NULL,
208                                 NULL);
209                 SHORTCUT_DBG("subscribe id : %d", id);
210                 if (id == 0) {
211                         /* LCOV_EXCL_START */
212                         ret = SHORTCUT_ERROR_IO_ERROR;
213                         SHORTCUT_ERR("Failed to _register_noti_dbus_interface");
214                         /* LCOV_EXCL_STOP */
215                 } else {
216                         SHORTCUT_INFO("get dbus connection success");
217                         monitor_id = id;
218                 }
219         }
220
221         return ret;
222 }
223
224 char *_shortcut_get_pkgname_by_pid(void)
225 {
226         char pkgname[SHORTCUT_PKGNAME_LEN + 1] = { 0, };
227         char buf[SHORTCUT_PKGNAME_LEN + 1] = { 0, };
228         int pid, ret;
229         int fd;
230         char *dup_pkgname;
231
232         pid = getpid();
233
234         ret = aul_app_get_pkgname_bypid(pid, pkgname, sizeof(pkgname));
235         if (ret != 0) {
236                 /* LCOV_EXCL_START */
237                 snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
238
239                 fd = open(buf, O_RDONLY);
240                 if (fd < 0)
241                         return NULL;
242
243                 ret = read(fd, pkgname, sizeof(pkgname) - 1);
244                 close(fd);
245
246                 if (ret <= 0)
247                         return NULL;
248
249                 pkgname[ret] = '\0';
250                 /* LCOV_EXCL_STOP */
251                 /*!
252                  * \NOTE
253                  * "ret" is not able to be larger than "sizeof(pkgname) - 1",
254                  * if the system is not going wrong.
255                  */
256         } else {
257                 if (strlen(pkgname) <= 0)
258                         return NULL;
259         }
260
261         dup_pkgname = strdup(pkgname);
262         if (!dup_pkgname)
263                 SHORTCUT_ERR("Heap: %d\n", errno); /* LCOV_EXCL_LINE */
264
265         return dup_pkgname;
266 }
267
268 /*
269  * implement user request
270  */
271 int _send_sync_shortcut(GVariant *body, GDBusMessage **reply, char *cmd)
272 {
273         GError *err = NULL;
274         GDBusMessage *msg;
275         int ret = SHORTCUT_ERROR_NONE;
276
277         msg = g_dbus_message_new_method_call(
278                         PROVIDER_BUS_NAME,
279                         PROVIDER_OBJECT_PATH,
280                         PROVIDER_SHORTCUT_INTERFACE_NAME,
281                         cmd);
282         if (!msg) {
283                 /* LCOV_EXCL_START */
284                 SHORTCUT_ERR("Can't allocate new method call");
285                 if (body)
286                         g_variant_unref(body);
287                 return SHORTCUT_ERROR_OUT_OF_MEMORY;
288                 /* LCOV_EXCL_STOP */
289         }
290
291         if (body != NULL)
292                 g_dbus_message_set_body(msg, body);
293
294         *reply = g_dbus_connection_send_message_with_reply_sync(
295                         _gdbus_conn,
296                         msg,
297                         G_DBUS_SEND_MESSAGE_FLAGS_NONE,
298                         TIMEOUT,
299                         NULL,
300                         NULL,
301                         &err);
302
303         g_object_unref(msg);
304
305         if (!*reply) {
306                 /* LCOV_EXCL_START */
307                 ret = SHORTCUT_ERROR_COMM;
308                 if (err != NULL) {
309                         SHORTCUT_ERR("No reply. cmd = %s,  error = %s", cmd, err->message);
310                         if (err->code == G_DBUS_ERROR_ACCESS_DENIED)
311                                 ret = SHORTCUT_ERROR_PERMISSION_DENIED;
312                         g_error_free(err);
313                 }
314                 return ret;
315                 /* LCOV_EXCL_STOP */
316         }
317
318         if (g_dbus_message_to_gerror(*reply, &err)) {
319                 /* LCOV_EXCL_START */
320                 if (err->code == G_DBUS_ERROR_ACCESS_DENIED)
321                         ret = SHORTCUT_ERROR_PERMISSION_DENIED;
322                 else
323                         ret = err->code;
324
325                 SHORTCUT_ERR("_send_sync_shortcut error %s err code: %d", err->message, ret);
326                 g_error_free(err);
327                 return ret;
328                 /* LCOV_EXCL_STOP */
329         }
330
331         SHORTCUT_DBG("_send_sync_shortcut done !!");
332         return SHORTCUT_ERROR_NONE;
333 }
334
335 int _send_service_register(void)
336 {
337         GDBusMessage *reply = NULL;
338         int result;
339
340         result = _send_sync_shortcut(g_variant_new("(i)", getuid()), &reply, "shortcut_service_register");
341         if (reply)
342                 g_object_unref(reply);
343         SHORTCUT_DBG("_send_service_register done");
344         return result;
345 }
346
347 static void _send_message_with_reply_sync_cb(GDBusConnection *connection,
348                 GAsyncResult *res,
349                 gpointer user_data)
350 {
351         int result;
352         GError *err = NULL;
353         GDBusMessage *reply = NULL;
354         GVariant *body;
355         struct result_cb_item *cb_item = (struct result_cb_item *)user_data;
356
357         if (cb_item == NULL) {
358                 /* LCOV_EXCL_START */
359                 SHORTCUT_ERR("Failed to get a callback item");
360                 return;
361                 /* LCOV_EXCL_STOP */
362         }
363
364         reply = g_dbus_connection_send_message_with_reply_finish(
365                         connection,
366                         res,
367                         &err);
368
369         if (!reply) {
370                 /* LCOV_EXCL_START */
371                 if (err != NULL) {
372                         SHORTCUT_ERR("No reply. error = %s", err->message);
373                         g_error_free(err);
374                 }
375                 result = SHORTCUT_ERROR_COMM;
376                 /* LCOV_EXCL_STOP */
377         }
378
379         if (g_dbus_message_to_gerror(reply, &err)) {
380                 /* LCOV_EXCL_START */
381                 if (err->code == G_DBUS_ERROR_ACCESS_DENIED)
382                         result = SHORTCUT_ERROR_PERMISSION_DENIED;
383                 else
384                         result = err->code;
385
386                 SHORTCUT_ERR("_send_message_with_reply_sync_cb error %s err code: %d", err->message, result);
387                 g_error_free(err);
388                 /* LCOV_EXCL_STOP */
389         } else {
390                 body = g_dbus_message_get_body(reply);
391                 g_variant_get(body, "(i)", &result);
392         }
393
394         if (cb_item->result_internal_cb)
395                 cb_item->result_internal_cb(result, getpid(), cb_item->data); /* LCOV_EXCL_LINE */
396         else if (cb_item->result_cb)
397                 cb_item->result_cb(result, cb_item->data);
398
399         if (reply)
400                 g_object_unref(reply);
401
402         free(cb_item);
403 }
404
405 int _send_async_shortcut(GVariant *body, struct result_cb_item *cb_item, char *cmd)
406 {
407         GDBusMessage *msg;
408
409         msg = g_dbus_message_new_method_call(
410                         PROVIDER_BUS_NAME,
411                         PROVIDER_OBJECT_PATH,
412                         PROVIDER_SHORTCUT_INTERFACE_NAME,
413                         cmd);
414         if (!msg) {
415                 /* LCOV_EXCL_START */
416                 SHORTCUT_ERR("Can't allocate new method call");
417                 return SHORTCUT_ERROR_OUT_OF_MEMORY;
418                 /* LCOV_EXCL_STOP */
419         }
420
421         if (g_variant_is_floating(body))
422                 g_variant_ref(body);
423
424         if (body != NULL)
425                 g_dbus_message_set_body(msg, body);
426
427         g_dbus_connection_send_message_with_reply(
428                         _gdbus_conn,
429                         msg,
430                         G_DBUS_SEND_MESSAGE_FLAGS_NONE,
431                         -1,
432                         NULL,
433                         NULL,
434                         (GAsyncReadyCallback)_send_message_with_reply_sync_cb,
435                         cb_item);
436
437         if (msg)
438                 g_object_unref(msg);
439
440         SHORTCUT_DBG("_send_async_shortcut done !!");
441         return SHORTCUT_ERROR_NONE;
442 }
443
444 int _check_privilege(void)
445 {
446         GDBusMessage *reply = NULL;
447         int ret = SHORTCUT_ERROR_NONE;
448
449         ret = _send_sync_shortcut(NULL, &reply, "check_privilege");
450
451         if (reply)
452                 g_object_unref(reply);
453
454         return ret;
455 }
456
457
458 /* LCOV_EXCL_START */
459 static void _on_name_appeared(GDBusConnection *connection,
460                 const gchar     *name,
461                 const gchar     *name_owner,
462                 gpointer         user_data)
463 {
464         SHORTCUT_DBG("name appeared : %s", name);
465         _send_service_register();
466 }
467 /* LCOV_EXCL_STOP */
468
469 /* LCOV_EXCL_START */
470 static void _on_name_vanished(GDBusConnection *connection,
471                 const gchar     *name,
472                 gpointer         user_data)
473 {
474         SHORTCUT_DBG("name vanished : %s", name);
475 }
476 /* LCOV_EXCL_STOP */
477
478 void _ipc_monitor_fini(void)
479 {
480         if (provider_monitor_id) {
481                 g_bus_unwatch_name(provider_monitor_id);
482                 provider_monitor_id = 0;
483         }
484
485         if (monitor_id) {
486                 g_dbus_connection_signal_unsubscribe(_gdbus_conn, monitor_id);
487                 monitor_id = 0;
488         }
489
490         if (_gdbus_conn) {
491                 g_object_unref(_gdbus_conn);
492                 _gdbus_conn = NULL;
493         }
494
495 }
496
497 void _set_request_cb(shortcut_request_cb request_cb, void *data)
498 {
499         _request_callback_info.request_cb = request_cb;
500         _request_callback_info.data = data;
501 }
502
503 void _unset_request_cb(void)
504 {
505         if (_remove_callback_info.remove_cb == NULL &&
506                 _remove_callback_info.data == NULL)
507                 _ipc_monitor_fini();
508
509         _request_callback_info.request_cb = NULL;
510         _request_callback_info.data = NULL;
511 }
512
513 void _set_remove_cb(shortcut_remove_cb remove_cb, void *data)
514 {
515         _remove_callback_info.remove_cb = remove_cb;
516         _remove_callback_info.data = data;
517 }
518
519 void _unset_remove_cb(void)
520 {
521         if (_request_callback_info.request_cb == NULL &&
522                 _request_callback_info.data == NULL)
523                 _ipc_monitor_fini();
524
525         _remove_callback_info.remove_cb = NULL;
526         _remove_callback_info.data = NULL;
527 }
528
529 int _dbus_set_watch_name(void)
530 {
531         if (provider_monitor_id == 0) {
532                 provider_monitor_id = g_bus_watch_name_on_connection(
533                                 _gdbus_conn,
534                                 PROVIDER_BUS_NAME,
535                                 G_BUS_NAME_WATCHER_FLAGS_NONE,
536                                 _on_name_appeared,
537                                 _on_name_vanished,
538                                 NULL,
539                                 NULL);
540
541                 if (provider_monitor_id == 0) {
542                         /* LCOV_EXCL_START */
543                         SHORTCUT_ERR("watch on name fail");
544                         return SHORTCUT_ERROR_IO_ERROR;
545                         /* LCOV_EXCL_STOP */
546                 }
547         }
548
549         return SHORTCUT_ERROR_NONE;
550 }
551
552 char *_make_request_id(void)
553 {
554         static int id = 0;
555         char request_id[REQUEST_ID_LEN];
556
557         g_atomic_int_inc(&id);
558         snprintf(request_id, sizeof(request_id), "%d@%d", getpid(), id);
559
560         SHORTCUT_DBG("The request_id of shortcut is [%s]", request_id);
561
562         return strdup(request_id);
563 }
564
565 int _ready_to_send(char **appid, char **request_id)
566 {
567         int ret;
568
569         ret = _dbus_init();
570         if (ret != SHORTCUT_ERROR_NONE) {
571                 /* LCOV_EXCL_START */
572                 SHORTCUT_ERR("Can't init dbus %d", ret);
573                 return ret;
574                 /* LCOV_EXCL_STOP */
575         }
576
577         ret = _check_privilege();
578         if (ret != SHORTCUT_ERROR_NONE)
579                 return ret;
580
581         *appid = _shortcut_get_pkgname_by_pid();
582         if (*appid == NULL) {
583                 /* LCOV_EXCL_START */
584                 SHORTCUT_ERR("Can't get appid");
585                 return SHORTCUT_ERROR_IO_ERROR;
586                 /* LCOV_EXCL_STOP */
587         }
588
589         *request_id = _make_request_id();
590         if (*request_id == NULL) {
591                 SHORTCUT_ERR("Can't get request_id");
592                 free(*appid);
593                 *appid = NULL;
594                 return SHORTCUT_ERROR_OUT_OF_MEMORY;
595         }
596
597         return SHORTCUT_ERROR_NONE;
598 }
599
600 EAPI int shortcut_add_to_home_sync(const char *name, shortcut_type type,
601                 const char *uri, const char *icon, int allow_duplicate)
602 {
603         int ret;
604         char *appid;
605         char *request_id = NULL;
606         GVariant *body;
607         GVariant *reply_body;
608         GDBusMessage *reply = NULL;
609
610         CHECK_SHORTCUT_FEATURE();
611
612         if (ADD_TO_HOME_IS_DYNAMICBOX(type)) {
613                 /* LCOV_EXCL_START */
614                 SHORTCUT_ERR("Invalid type used for adding a shortcut\n");
615                 return SHORTCUT_ERROR_INVALID_PARAMETER;
616                 /* LCOV_EXCL_STOP */
617         }
618
619         ret = _ready_to_send(&appid, &request_id);
620         if (ret != SHORTCUT_ERROR_NONE) {
621                 /* LCOV_EXCL_START */
622                 SHORTCUT_ERR("ready to send error [%d]", ret);
623                 return ret;
624                 /* LCOV_EXCL_STOP */
625         }
626
627         if (!name)
628                 name = "";
629
630         if (!uri)
631                 uri = "";
632
633         if (!icon)
634                 icon = "";
635
636         body = g_variant_new("(sississi)", request_id, getpid(), appid, name,
637                         type, uri, icon, allow_duplicate);
638
639         ret = _send_sync_shortcut(body, &reply, "add_shortcut");
640         if (ret == SHORTCUT_ERROR_NONE) {
641                 reply_body = g_dbus_message_get_body(reply);
642                 g_variant_get(reply_body, "(i)", &ret);
643         }
644
645         if (appid)
646                 free(appid);
647         if (body)
648                 g_variant_unref(body);
649         if (request_id)
650                 free(request_id);
651         if (reply)
652                 g_object_unref(reply);
653
654         SHORTCUT_DBG("result[%d]", ret);
655
656         return ret;
657 }
658
659 EAPI int shortcut_add_to_home_widget_sync(const char *name,
660                 shortcut_widget_size_e size, const char *widget_id,
661                 const char *icon, double period, int allow_duplicate)
662 {
663         int ret;
664         char *appid;
665         char *request_id = NULL;
666         GVariant *body;
667         GVariant *reply_body;
668         GDBusMessage *reply = NULL;
669
670         CHECK_SHORTCUT_FEATURE();
671
672         if (name == NULL) {
673                 SHORTCUT_ERR("AppID is null\n");
674                 return SHORTCUT_ERROR_INVALID_PARAMETER;
675         }
676
677         if (!SHORTCUT_IS_WIDGET_SIZE(size)) {
678                 /* LCOV_EXCL_START */
679                 SHORTCUT_ERR("Invalid type used for adding a widget\n");
680                 return SHORTCUT_ERROR_INVALID_PARAMETER;
681                 /* LCOV_EXCL_STOP */
682         }
683
684         ret = _ready_to_send(&appid, &request_id);
685         if (ret != SHORTCUT_ERROR_NONE) {
686                 /* LCOV_EXCL_START */
687                 SHORTCUT_ERR("ready to send error [%d]", ret);
688                 return ret;
689                 /* LCOV_EXCL_STOP */
690         }
691
692         body = g_variant_new("(sississdi)", request_id, getpid(), widget_id,
693                         name, size, NULL, icon, period, allow_duplicate);
694
695         ret = _send_sync_shortcut(body, &reply, "add_shortcut_widget");
696         if (ret == SHORTCUT_ERROR_NONE) {
697                 reply_body = g_dbus_message_get_body(reply);
698                 g_variant_get(reply_body, "(i)", &ret);
699         }
700
701         if (appid)
702                 free(appid);
703         if (body)
704                 g_variant_unref(body);
705         if (request_id)
706                 free(request_id);
707         if (reply)
708                 g_object_unref(reply);
709
710         SHORTCUT_DBG("result[%d]", ret);
711
712         return ret;
713 }
714
715 EAPI int shortcut_remove_from_home_sync(const char *name)
716 {
717         int ret;
718         char *appid;
719         char *request_id = NULL;
720         GVariant *body;
721         GVariant *reply_body;
722         GDBusMessage *reply = NULL;
723
724         CHECK_SHORTCUT_FEATURE();
725
726         if (name == NULL) {
727                 SHORTCUT_ERR("name is NULL.");
728                 return SHORTCUT_ERROR_INVALID_PARAMETER;
729         }
730
731         ret = _ready_to_send(&appid, &request_id);
732         if (ret != SHORTCUT_ERROR_NONE) {
733                 /* LCOV_EXCL_START */
734                 SHORTCUT_ERR("ready to send error [%d]", ret);
735                 return ret;
736                 /* LCOV_EXCL_STOP */
737         }
738
739         body = g_variant_new("(siss)", request_id, getpid(), appid, name);
740
741         ret = _send_sync_shortcut(body, &reply, "remove_shortcut");
742         if (ret == SHORTCUT_ERROR_NONE) {
743                 reply_body = g_dbus_message_get_body(reply);
744                 g_variant_get(reply_body, "(i)", &ret);
745         }
746
747         if (appid)
748                 free(appid);
749         if (body)
750                 g_variant_unref(body);
751         if (request_id)
752                 free(request_id);
753         if (reply)
754                 g_object_unref(reply);
755
756         SHORTCUT_DBG("result[%d]", ret);
757
758         return ret;
759 }