Add the missed hid-agent folder
[platform/core/connectivity/bluetooth-agent.git] / hid-agent / bluetooth-hid-agent.c
1 /*
2  * Copyright (c) 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
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <signal.h>
22 #include <fcntl.h>
23 #include <aul.h>
24
25 #include "bluetooth-hid-agent.h"
26
27 static GMainLoop *gmain_loop;
28 static char *g_obj_path;
29
30 static GDBusConnection *gdbus_conn;
31 static GDBusProxy *profile_gproxy;
32 static guint owner_sig_id;
33 static guint bluez_device_sig_id;
34 static guint name_owner_sig_id;
35
36 #define BT_HID_SIG_NUM 3
37 #define HID_DEVICE_UUID "00001124-0000-1000-8000-00805f9b43bf"
38 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
39
40 /*Below Inrospection data is exposed to application from agent*/
41 static const gchar hid_agent_introspection_xml[] =
42 "<node name='/'>"
43 "     <interface name='org.tizen.HidApp'>"
44 "               <method name='RegisterApplication'>"
45 "               </method>"
46 "               <method name='UnregisterApplication'>"
47 "               </method>"
48 "               <method name='IsHidConnected'>"
49 "                       <arg type='b' name='connected' direction='out'/>"
50 "               </method>"
51 "               <method name='IsHidConnectable'>"
52 "                       <arg type='b' name='connectable' direction='out'/>"
53 "               </method>"
54 "     </interface>"
55 "</node>";
56
57 static bt_hid_agent_info_t bt_hid_info = {0,};
58 static gboolean is_hid_connected;
59 static gboolean is_hid_connectable;
60 static struct sigaction bt_hid_sigoldact[BT_HID_SIG_NUM];
61 static int bt_hid_sig_to_handle[] = { SIGABRT, SIGSEGV, SIGTERM };
62
63 static void __bt_hid_agent_sigterm_handler(int signo);
64 static GError *__bt_hid_agent_set_error(bt_hid_agent_error_t error);
65
66 static void __on_log_glib(const gchar *log_domain, GLogLevelFlags log_level,
67                 const gchar *msg, gpointer user_data)
68 {
69         ERR_C("%s", msg);
70 }
71
72 static GQuark __bt_hid_agent_error_quark(void)
73 {
74         FN_START;
75         static GQuark quark;
76         if (!quark)
77                 quark = g_quark_from_static_string("hid-agent");
78
79         return quark;
80 }
81
82 static GError *__bt_hid_agent_set_error(bt_hid_agent_error_t error)
83 {
84         ERR("error[%d]", error);
85
86         switch (error) {
87         case BT_HID_AGENT_ERROR_NOT_AVAILABLE:
88                 return g_error_new(BT_HID_AGENT_ERROR, error,
89                                         BT_ERROR_NOT_AVAILABLE);
90         case BT_HID_AGENT_ERROR_NOT_CONNECTED:
91                 return g_error_new(BT_HID_AGENT_ERROR, error,
92                                         BT_ERROR_NOT_CONNECTED);
93         case BT_HID_AGENT_ERROR_CONNECTION_FAILED:
94                 return g_error_new(BT_HID_AGENT_ERROR, error,
95                                         BT_ERROR_NOT_CONNECTION_FAILED);
96         case BT_HID_AGENT_ERROR_BUSY:
97                 return g_error_new(BT_HID_AGENT_ERROR, error,
98                                         BT_ERROR_BUSY);
99         case BT_HID_AGENT_ERROR_INVALID_PARAM:
100                 return g_error_new(BT_HID_AGENT_ERROR, error,
101                                         BT_ERROR_INVALID_PARAM);
102         case BT_HID_AGENT_ERROR_ALREADY_EXIST:
103                 return g_error_new(BT_HID_AGENT_ERROR, error,
104                                         BT_ERROR_ALREADY_EXIST);
105         case BT_HID_AGENT_ERROR_ALREADY_CONNECTED:
106                 return g_error_new(BT_HID_AGENT_ERROR, error,
107                                         BT_ERROR_ALREADY_CONNECTED);
108         case BT_HID_AGENT_ERROR_NO_MEMORY:
109                 return g_error_new(BT_HID_AGENT_ERROR, error,
110                                         BT_ERROR_NO_MEMORY);
111         case BT_HID_AGENT_ERROR_NO_DATA:
112                 return g_error_new(BT_HID_AGENT_ERROR, error,
113                                         BT_ERROR_NO_DATA);
114         case BT_HID_AGENT_ERROR_I_O_ERROR:
115                 return g_error_new(BT_HID_AGENT_ERROR, error,
116                                         BT_ERROR_I_O_ERROR);
117         case BT_HID_AGENT_ERROR_APPLICATION:
118                 return g_error_new(BT_HID_AGENT_ERROR, error,
119                                         BT_ERROR_OPERATION_NOT_AVAILABLE);
120         case BT_HID_AGENT_ERROR_NOT_ALLOWED:
121                 return g_error_new(BT_HID_AGENT_ERROR, error,
122                                         BT_ERROR_OPERATION_NOT_ALLOWED);
123         case BT_HID_AGENT_ERROR_NOT_SUPPORTED:
124                 return g_error_new(BT_HID_AGENT_ERROR, error,
125                                         BT_ERROR_OPERATION_NOT_SUPPORTED);
126         case BT_HID_AGENT_ERROR_INVALID_FILE_DESCRIPTOR:
127                 return g_error_new(BT_HID_AGENT_ERROR, error,
128                                         BT_ERROR_INVALID_FILE_DESCRIPTOR);
129         case BT_HID_AGENT_ERROR_INTERNAL:
130         default:
131                 return g_error_new(BT_HID_AGENT_ERROR, error,
132                                                 BT_ERROR_INTERNAL);
133         }
134 }
135
136 static void __bt_hid_name_owner_changed_cb(GDBusConnection *connection,
137                                         const gchar *sender_name,
138                                         const gchar *object_path,
139                                         const gchar *interface_name,
140                                         const gchar *signal_name,
141                                         GVariant *parameters,
142                                         gpointer user_data)
143 {
144         char *name_owner = NULL;
145         char *old_owner = NULL;
146         char *new_owner = NULL;
147         int ret = 0;
148
149         if (strcasecmp(signal_name, "NameOwnerChanged") == 0) {
150                 g_variant_get(parameters, "(sss)", &name_owner, &old_owner, &new_owner);
151
152                 ret = _bt_hid_register_application(FALSE, name_owner);
153                 if (ret == BT_HID_AGENT_ERROR_NONE) {
154                         is_hid_connectable = FALSE;
155                         if (name_owner_sig_id > 0) {
156                                 g_dbus_connection_signal_unsubscribe(gdbus_conn,
157                                                         name_owner_sig_id);
158                                 name_owner_sig_id = 0;
159                         }
160                 }
161         }
162 }
163
164 static void __hid_agent_method(GDBusConnection *connection,
165                             const gchar *sender,
166                             const gchar *object_path,
167                             const gchar *interface_name,
168                             const gchar *method_name,
169                             GVariant *parameters,
170                             GDBusMethodInvocation *context,
171                             gpointer user_data)
172 {
173         INFO("method %s", method_name);
174         int ret = 0;
175         GError *err;
176
177         if (g_strcmp0(method_name, "RegisterApplication") == 0) {
178                 DBG("Sender = %s\n", sender);
179
180                 ret = _bt_hid_register_application(TRUE, sender);
181                 if (ret == BT_HID_AGENT_ERROR_NONE) {
182                         is_hid_connectable = TRUE;
183                         if (name_owner_sig_id == 0) {
184                                 name_owner_sig_id = g_dbus_connection_signal_subscribe(gdbus_conn,
185                                                 NULL, NULL, "NameOwnerChanged", NULL, NULL, 0,
186                                                 __bt_hid_name_owner_changed_cb, NULL, NULL);
187                         }
188                 } else {
189                         goto fail;
190                 }
191
192                 g_dbus_method_invocation_return_value(context, NULL);
193         } else if (g_strcmp0(method_name, "UnregisterApplication") == 0) {
194                 DBG("Sender = %s\n", sender);
195
196                 ret = _bt_hid_register_application(FALSE, sender);
197                 if (ret == BT_HID_AGENT_ERROR_NONE) {
198                         is_hid_connectable = FALSE;
199                         if (name_owner_sig_id > 0) {
200                                 g_dbus_connection_signal_unsubscribe(gdbus_conn,
201                                                         name_owner_sig_id);
202                                 name_owner_sig_id = 0;
203                         }
204                 } else {
205                         goto fail;
206                 }
207
208                 g_dbus_method_invocation_return_value(context, NULL);
209         } else if (g_strcmp0(method_name, "IsHidConnected") == 0) {
210                 DBG("Going to call IsHidConnected");
211                 INFO("is_hid_connected : %s",
212                         is_hid_connected ? "Connected" : "Disconnected");
213
214                 g_dbus_method_invocation_return_value(context,
215                                 g_variant_new("(b)", is_hid_connected));
216         } else if (g_strcmp0(method_name, "IsHidConnectable") == 0) {
217                 DBG("Going to call IsHidConnectable");
218                 INFO("is_hid_connectable : %s",
219                         is_hid_connectable ? "Connectable" : "Non-Connectable");
220
221                 g_dbus_method_invocation_return_value(context,
222                                 g_variant_new("(b)", is_hid_connectable));
223         }
224
225         return;
226
227 fail:
228         err = __bt_hid_agent_set_error(ret);
229         g_dbus_method_invocation_return_gerror(context, err);
230         g_error_free(err);
231 }
232
233 static const GDBusInterfaceVTable method_table = {
234         __hid_agent_method,
235         NULL,
236         NULL,
237 };
238
239 static GDBusNodeInfo *__bt_hid_create_method_node_info
240                                         (const gchar *introspection_data)
241 {
242         if (introspection_data == NULL)
243                 return NULL;
244
245         return g_dbus_node_info_new_for_xml(introspection_data, NULL);
246 }
247
248 static GDBusConnection *__bt_hid_get_gdbus_connection(void)
249 {
250         GDBusConnection *local_system_gconn = NULL;
251         GError *err = NULL;
252
253         if (gdbus_conn == NULL) {
254                 gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
255                 if (!gdbus_conn) {
256                         if (err) {
257                                 ERR("Unable to connect to dbus: %s", err->message);
258                                 g_clear_error(&err);
259                         }
260                         gdbus_conn = NULL;
261                 }
262         } else if (g_dbus_connection_is_closed(gdbus_conn)) {
263                 local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
264
265                 if (!local_system_gconn) {
266                         ERR("Unable to connect to dbus: %s", err->message);
267                         g_clear_error(&err);
268                 }
269
270                 gdbus_conn = local_system_gconn;
271         }
272         return gdbus_conn;
273 }
274
275 static gboolean __bt_hid_register_methods(void)
276 {
277         FN_START;
278         GError *error = NULL;
279         guint object_id;
280         guint owner_id;
281         GDBusNodeInfo *node_info;
282         GDBusConnection *conn;
283
284         owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
285                                 BT_HID_SERVICE_NAME,
286                                 G_BUS_NAME_OWNER_FLAGS_NONE,
287                                 NULL, NULL, NULL,
288                                 NULL, NULL);
289
290         DBG("owner_id is [%d]", owner_id);
291
292         conn = __bt_hid_get_gdbus_connection();
293         if (!conn) {
294                 ERR("Unable to get connection");
295                 return FALSE;
296         }
297
298         node_info = __bt_hid_create_method_node_info(hid_agent_introspection_xml);
299         if (node_info == NULL)
300                 return FALSE;
301
302         object_id = g_dbus_connection_register_object(conn,
303                                                 BT_HID_AGENT_OBJECT_PATH,
304                                                 node_info->interfaces[0],
305                                                 &method_table,
306                                                 NULL, NULL, &error);
307         g_dbus_node_info_unref(node_info);
308         if (object_id == 0) {
309                 if (error != NULL) {
310                         ERR("Failed to register: %s", error->message);
311                         g_error_free(error);
312                 }
313                 return FALSE;
314         }
315
316         FN_END;
317         return TRUE;
318 }
319
320 static GDBusProxy *__bt_hid_gdbus_init_profile_proxy(void)
321 {
322         FN_START;
323
324         GDBusProxy *proxy;
325         GError *err = NULL;
326         GDBusConnection *conn;
327
328         conn = __bt_hid_get_gdbus_connection();
329         if (!conn) {
330                 ERR("Unable to get connection");
331                 return NULL;
332         }
333
334         proxy =  g_dbus_proxy_new_sync(conn,
335                         G_DBUS_PROXY_FLAGS_NONE, NULL,
336                         BLUEZ_SERVICE_NAME, "/org/bluez",
337                         BLUEZ_PROFILE_MGMT_INTERFACE, NULL, &err);
338
339         if (!proxy) {
340                 if (err) {
341                         ERR("Unable to create proxy: %s", err->message);
342                          g_clear_error(&err);
343                 }
344                 return NULL;
345         }
346
347         profile_gproxy = proxy;
348
349         FN_END;
350         return proxy;
351 }
352
353 static GDBusProxy *__bt_hid_gdbus_get_profile_proxy(void)
354 {
355         return (profile_gproxy) ? profile_gproxy :
356                                   __bt_hid_gdbus_init_profile_proxy();
357 }
358
359 static GDBusProxy *__bt_hid_gdbus_get_service_proxy(const gchar *service,
360                                 const gchar *path, const gchar *interface)
361 {
362         FN_START;
363
364         GDBusProxy *proxy;
365         GError *err = NULL;
366         GDBusConnection *conn;
367
368         conn = __bt_hid_get_gdbus_connection();
369         if (!conn) {
370                 ERR("Unable to get connection");
371                 return NULL;
372         }
373
374         proxy =  g_dbus_proxy_new_sync(conn,
375                         G_DBUS_PROXY_FLAGS_NONE, NULL,
376                         service, path,
377                         interface, NULL, &err);
378
379         if (!proxy) {
380                 if (err) {
381                         ERR("Unable to create proxy: %s", err->message);
382                          g_clear_error(&err);
383                 }
384                 return NULL;
385         }
386
387         FN_END;
388         return proxy;
389 }
390
391 static GDBusProxy *__bt_hid_gdbus_get_device_proxy(char *object_path)
392 {
393         GDBusConnection *conn;
394         GError *err = NULL;
395         GDBusProxy *device_gproxy;
396
397         conn = __bt_hid_get_gdbus_connection();
398
399         if (conn == NULL)
400                 return NULL;
401
402         device_gproxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
403                                                 NULL, BLUEZ_SERVICE_NAME,
404                                                 object_path,
405                                                 BLUEZ_DEVICE_INTERFACE,
406                                                 NULL, &err);
407
408         if (device_gproxy == NULL && err) {
409                 ERR("Unable to create proxy: %s", err->message);
410                 g_clear_error(&err);
411                 return NULL;
412         }
413
414         return device_gproxy;
415 }
416
417 static int __bt_hid_agent_gdbus_method_send(const char *service,
418                                 GVariant *path, const char *interface,
419                                 const char *method)
420 {
421         FN_START;
422
423         GVariant *ret;
424         GDBusProxy *proxy;
425         GError *error = NULL;
426
427         proxy = __bt_hid_gdbus_get_service_proxy(service, g_obj_path, interface);
428         if (!proxy)
429                 return BT_HID_AGENT_ERROR_INTERNAL;
430
431         ret = g_dbus_proxy_call_sync(proxy,
432                                 method, path,
433                                 G_DBUS_CALL_FLAGS_NONE, -1,
434                                 NULL, &error);
435         if (ret == NULL) {
436                 /* dBUS-RPC is failed */
437                 ERR("dBUS-RPC is failed");
438                 if (error != NULL) {
439                         /* dBUS gives error cause */
440                         ERR("D-Bus API failure: errCode[%x], message[%s]",
441                                error->code, error->message);
442
443                         g_clear_error(&error);
444                 }
445                 g_object_unref(proxy);
446                 return BT_HID_AGENT_ERROR_INTERNAL;
447         }
448
449         g_variant_unref(ret);
450         g_object_unref(proxy);
451
452         return BT_HID_AGENT_ERROR_NONE;
453 }
454
455 static void __bt_hid_agent_sigterm_handler(int signo)
456 {
457         GDBusConnection *conn;
458         int i;
459
460         ERR_C("***** Signal handler came with signal %d *****", signo);
461
462         conn = __bt_hid_get_gdbus_connection();
463         if (!conn) {
464                 ERR("Unable to get G-DBus connection");
465                 goto done;
466         }
467
468         g_dbus_connection_flush(conn, NULL, NULL, NULL);
469         INFO("Flush g_dbus_connection");
470
471 done:
472         if (gmain_loop) {
473                 g_main_loop_quit(gmain_loop);
474                 INFO("Exiting");
475                 gmain_loop = NULL;
476         } else {
477                 INFO_C("Terminating HID agent");
478                 exit(0);
479         }
480
481         if (signo == SIGTERM)
482                 return;
483
484         for (i = 0; i < BT_HID_SIG_NUM; i++)
485                 sigaction(bt_hid_sig_to_handle[i], &(bt_hid_sigoldact[i]), NULL);
486
487         raise(signo);
488 }
489
490 static int __bt_hid_register_profile(const char *uuid,
491                  const char *name, const char *object)
492 {
493         FN_START;
494         GDBusProxy *proxy;
495         GVariant *ret;
496         GError *error = NULL;
497         GVariantBuilder *builder;
498
499         proxy = __bt_hid_gdbus_get_profile_proxy();
500
501         if (proxy == NULL)
502                 return BT_HID_AGENT_ERROR_INTERNAL;
503
504         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
505
506         g_variant_builder_add(builder, "{sv}",
507                         "Name", g_variant_new("s",
508                         name));
509
510         g_variant_builder_add(builder, "{sv}",
511                         "PSM", g_variant_new("q", 17));
512
513         ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
514                                 g_variant_new("(osa{sv})", BT_HID_BLUEZ_OBJECT_PATH,
515                                         HID_DEVICE_UUID, builder),
516                                 G_DBUS_CALL_FLAGS_NONE, -1,
517                                 NULL, &error);
518
519         g_variant_builder_unref(builder);
520
521         if (ret == NULL) {
522                 /* dBUS-RPC is failed */
523                 ERR("dBUS-RPC is failed");
524                 if (error != NULL) {
525                         /* dBUS gives error cause */
526                         ERR("D-Bus API failure: errCode[%x], message[%s]",
527                                 error->code, error->message);
528                         g_clear_error(&error);
529                 }
530                 return BT_HID_AGENT_ERROR_INTERNAL;
531         }
532         g_variant_unref(ret);
533
534         FN_END;
535         return BT_HID_AGENT_ERROR_NONE;
536 }
537
538 static void __bt_hid_agent_register(void)
539 {
540         FN_START;
541         int ret;
542
543         ret = __bt_hid_register_profile(HID_DEVICE_UUID,
544                                         "HID device", BT_HID_BLUEZ_OBJECT_PATH);
545         if (ret)
546                 ERR("Error in register");
547
548         FN_END;
549         return;
550 }
551
552 static void __bt_hid_agent_unregister(void)
553 {
554         FN_START;
555
556         if (g_obj_path) {
557                 __bt_hid_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
558                                                 g_variant_new("(o)", BT_HID_BLUEZ_OBJECT_PATH),
559                                                 BLUEZ_HID_INTERFACE_NAME,
560                                                 "UnregisterAgent");
561                 g_free(g_obj_path);
562                 g_obj_path = NULL;
563         }
564
565         FN_END;
566         return;
567 }
568
569 static void __bt_hid_agent_filter_cb(GDBusConnection *connection,
570                                                  const gchar *sender_name,
571                                                  const gchar *object_path,
572                                                  const gchar *interface_name,
573                                                  const gchar *signal_name,
574                                                  GVariant *parameters,
575                                                  gpointer user_data)
576 {
577         FN_START;
578         char *path = NULL;
579
580         GVariant *optional_param;
581
582         if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
583
584                 g_variant_get(parameters, "(&o@a{sa{sv}})",
585                                 &path, &optional_param);
586                 if (!path) {
587                         ERR("Invalid adapter path");
588                         return;
589                 }
590
591                 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
592                         g_obj_path = g_strdup(path);
593                         INFO("Adapter Path = [%s]", path);
594                         __bt_hid_agent_register();
595                 }
596         } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
597                 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
598                 if (!path)
599                         __bt_hid_agent_unregister();
600         }
601         FN_END;
602 }
603
604 void _bt_convert_device_path_to_address(const char *device_path,
605                                                 char *device_address)
606 {
607         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
608         char *dev_addr;
609
610         ret_if(device_path == NULL);
611         ret_if(device_address == NULL);
612
613         dev_addr = strstr(device_path, "dev_");
614         if (dev_addr != NULL) {
615                 char *pos = NULL;
616                 dev_addr += 4;
617                 g_strlcpy(address, dev_addr, sizeof(address));
618
619                 while ((pos = strchr(address, '_')) != NULL) {
620                         *pos = ':';
621                 }
622
623                 g_strlcpy(device_address, address, BT_ADDRESS_STRING_SIZE);
624         }
625 }
626
627 static void __bt_hid_device_filter_cb(GDBusConnection *connection,
628                                         const gchar *sender_name,
629                                         const gchar *object_path,
630                                         const gchar *interface_name,
631                                         const gchar *signal_name,
632                                         GVariant *parameters,
633                                         gpointer user_data)
634 {
635         DBG("sender_name = %s, object_path = %s", sender_name, object_path);
636
637          if (strcasecmp(signal_name, "ProfileStateChanged") == 0) {
638                 char *profile_uuid = NULL;
639                 bt_hid_state_t state = 0;
640
641                 g_variant_get(parameters, "(&si)", &profile_uuid, &state);
642                 if (g_strcmp0(profile_uuid, HID_DEVICE_UUID) == 0) {
643                         if (state == BT_HID_STATE_CONNECTED) {
644                                 g_free(bt_hid_info.object_path);
645                                 bt_hid_info.object_path = g_strdup(object_path);
646                                 DBG("device : [%s]", bt_hid_info.object_path);
647                         }
648                         _bt_hid_set_profile_state(state);
649                 }
650         }
651 }
652
653 static int __bt_hid_agent_get_adapter_path(GDBusConnection *conn, char *path)
654 {
655         GError *err = NULL;
656         GDBusProxy *manager_proxy = NULL;
657         GVariant *result = NULL;
658         char *adapter_path = NULL;
659
660         if (conn == NULL)
661                 return BT_HID_AGENT_ERROR_INTERNAL;
662
663         manager_proxy =  g_dbus_proxy_new_sync(conn,
664                         G_DBUS_PROXY_FLAGS_NONE, NULL,
665                         BLUEZ_SERVICE_NAME,
666                         "/",
667                         BT_MANAGER_INTERFACE,
668                         NULL, &err);
669
670         if (!manager_proxy) {
671                 ERR("Unable to create proxy: %s", err->message);
672                 goto fail;
673         }
674
675         result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL,
676                         G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
677         if (!result) {
678                 if (err != NULL)
679                         ERR("Fail to get DefaultAdapter (Error: %s)", err->message);
680                 else
681                         ERR("Fail to get DefaultAdapter");
682
683                 goto fail;
684         }
685
686         if (g_strcmp0(g_variant_get_type_string(result), "(o)")) {
687                 ERR("Incorrect result\n");
688                 goto fail;
689         }
690
691         g_variant_get(result, "(&o)", &adapter_path);
692
693         if (adapter_path == NULL ||
694                 strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) {
695                 ERR("Adapter path is inproper\n");
696                 goto fail;
697         }
698
699         if (path)
700                 g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX);
701
702         if (g_obj_path == NULL) {
703                 g_obj_path = g_strdup(adapter_path);
704                 INFO("Update g_obj_path [%s]", adapter_path);
705         }
706
707         g_variant_unref(result);
708         g_object_unref(manager_proxy);
709
710         return 0;
711
712 fail:
713         g_clear_error(&err);
714
715         if (result)
716                 g_variant_unref(result);
717
718         if (manager_proxy)
719                 g_object_unref(manager_proxy);
720
721         return BT_HID_AGENT_ERROR_INTERNAL;
722
723 }
724
725 static void __bt_hid_agent_dbus_init(void)
726 {
727         GDBusConnection *conn;
728
729         FN_START;
730
731         conn = __bt_hid_get_gdbus_connection();
732         if (conn == NULL) {
733                 ERR("Error in creating the gdbus connection");
734                 return;
735         }
736         if (!__bt_hid_register_methods()) {
737                 ERR("Error in __bt_hid_register_methods");
738                 return;
739         }
740
741         if (!__bt_hid_agent_get_adapter_path(conn, NULL)) {
742                 __bt_hid_agent_register();
743         }
744
745         owner_sig_id = g_dbus_connection_signal_subscribe(conn,
746                                 NULL, BT_MANAGER_INTERFACE, NULL, NULL, NULL, 0,
747                                 __bt_hid_agent_filter_cb, NULL, NULL);
748
749         bluez_device_sig_id = g_dbus_connection_signal_subscribe(conn,
750                                 NULL, BLUEZ_DEVICE_INTERFACE, NULL, NULL,
751                                 NULL, 0, __bt_hid_device_filter_cb,
752                                 NULL, NULL);
753
754         _bt_hid_set_profile_state(BT_HID_STATE_DISCONNECTED);
755
756         FN_END;
757 }
758
759 static void __bt_hid_agent_dbus_deinit(void)
760 {
761         if (profile_gproxy) {
762                 g_object_unref(profile_gproxy);
763                 profile_gproxy = NULL;
764         }
765
766         if (gdbus_conn) {
767                 if (owner_sig_id > 0)
768                         g_dbus_connection_signal_unsubscribe(gdbus_conn,
769                                                 owner_sig_id);
770
771                 if (bluez_device_sig_id > 0)
772                         g_dbus_connection_signal_unsubscribe(gdbus_conn,
773                                                 bluez_device_sig_id);
774
775                 if (name_owner_sig_id > 0)
776                         g_dbus_connection_signal_unsubscribe(gdbus_conn,
777                                                 name_owner_sig_id);
778
779                 owner_sig_id = 0;
780                 bluez_device_sig_id = 0;
781                 name_owner_sig_id = 0;
782
783                 g_object_unref(gdbus_conn);
784                 gdbus_conn = NULL;
785         }
786 }
787
788
789
790
791 bt_hid_agent_error_t __bt_hid_disconnect_profile(void)
792 {
793         FN_START;
794         GDBusProxy *proxy;
795
796         proxy = __bt_hid_gdbus_get_device_proxy(bt_hid_info.object_path);
797
798         if (proxy == NULL) {
799                 ERR("Error while getting proxy");
800                 return BT_HID_AGENT_ERROR_INTERNAL;
801         }
802
803         g_dbus_proxy_call(proxy, "DisconnectProfile",
804                         g_variant_new("(s)", HID_DEVICE_UUID),
805                         G_DBUS_CALL_FLAGS_NONE, 2000,
806                         NULL, NULL, NULL);
807
808         FN_END;
809
810         return BT_HID_AGENT_ERROR_NONE;
811 }
812
813 int main(void)
814 {
815         int i;
816         struct sigaction sa;
817
818
819         INFO_C("### Starting Bluetooth HID agent");
820
821 #if GLIB_VERSION_MIN_REQUIRED < GLIB_VERSION_2_36
822         g_type_init();
823 #endif
824
825         memset(&sa, 0, sizeof(sa));
826         sa.sa_flags = SA_NOCLDSTOP;
827         sa.sa_handler = __bt_hid_agent_sigterm_handler;
828
829         for (i = 0; i < BT_HID_SIG_NUM; i++)
830                 sigaction(bt_hid_sig_to_handle[i], &sa, &(bt_hid_sigoldact[i]));
831
832         g_log_set_default_handler(__on_log_glib, NULL);
833
834         gmain_loop = g_main_loop_new(NULL, FALSE);
835
836         __bt_hid_agent_dbus_init();
837
838         g_main_loop_run(gmain_loop);
839
840         __bt_hid_agent_dbus_deinit();
841
842         if (gmain_loop)
843                 g_main_loop_unref(gmain_loop);
844
845         INFO_C("### Terminating Bluetooth HID agent");
846         return 0;
847 }
848