Updated this component to use Bluez 5 API calls. This fixes TIVI-2936
[profile/ivi/wrt-plugins-ivi-bt.git] / src / BluetoothAdapter.cpp
1 //
2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 #include <pcrecpp.h>
19
20 #include <Logger.h>
21 #include <JSWebAPIErrorFactory.h>
22 #include <system_info.h>
23 #include <JSUtil.h>
24
25 #include "BluetoothAdapter.h"
26 #include "BluetoothCallbackUtil.h"
27 #include "JSBluetoothDevice.h"
28 #include "JSBluetoothServiceHandler.h"
29 #include "JSBluetoothSocket.h"
30 #include "GlobalContextManager.h"
31
32 // BLUEZ
33 #include "utils.h"
34
35 #define BLUEZ_PREFIX            "org.bluez"
36 #define BLUEZ_SERVICE           BLUEZ_PREFIX
37 #define BLUEZ_ADAPTER_IFACE     BLUEZ_PREFIX ".Adapter1"
38 #define BLUEZ_DEVICE_IFACE      BLUEZ_PREFIX ".Device1"
39 #define BLUEZ_AGENT_IFACE       BLUEZ_PREFIX ".Agent1"
40 #define BLUEZ_OBJECT_IFACE      "org.freedesktop.DBus.ObjectManager"
41
42 #define AGENT_PATH              "/org/bluez/agent_pairing"
43 #define AGENT_CAPABILITIES      "KeyboardDisplay"
44
45 #define PINCODE        "123456"
46 #define PASSKEY         123456
47
48 #define CONNMAN_PREFIX                     "net.connman"
49 #define CONNMAN_SERVICE                    CONNMAN_PREFIX
50 #define CONNMAN_MANAGER_IFACE              CONNMAN_PREFIX ".Manager"
51 #define CONNMAN_TECHNOLOGY_IFACE           CONNMAN_PREFIX ".Technology"
52 // BLUEZ
53
54 using namespace DeviceAPI::Common;
55
56 namespace DeviceAPI
57 {
58 namespace Bluetooth
59 {
60
61 bool BluetoothAdapter::foreachBondedDevicesCB(bt_device_info_s *deviceInfo, void *userData, char *devicePath)
62 {
63         BluetoothAdapterPtr adapter = static_cast<BluetoothAdapterPtr>(userData);
64         if(!adapter)
65         {
66                 LoggerW("userData is NULL");
67                 return true;
68         }
69
70         if(deviceInfo == NULL)
71         {
72                 LoggerW("deviceInfo is NULL");
73                 return true;
74         }
75
76         std::vector<BluetoothDeviceSharedPtr>::iterator iter;
77         for(iter = adapter->knownDevices.begin(); iter != adapter->knownDevices.end(); ++iter)
78         {
79                 BluetoothDeviceSharedPtr foundDevice = *iter;
80
81                 if(!strcmp(foundDevice->getAddress().c_str(), deviceInfo->remote_address))
82                 {
83                         foundDevice->updateInfo(deviceInfo);
84                         break;
85                 }
86         }
87
88         if(iter == adapter->knownDevices.end())
89         {
90                 BluetoothDeviceSharedPtr device(new BluetoothDevice(deviceInfo, devicePath));
91                 adapter->knownDevices.push_back(device);
92         }
93
94         return true;
95 }
96
97 void BluetoothAdapter::onSocketConnected(int result, bt_socket_connection_state_e state, bt_socket_connection_s *connection, void *userData)
98 {
99         BluetoothAdapterPtr object = static_cast<BluetoothAdapterPtr>(userData);
100         if(!object)
101         {
102                 LoggerW("userData is NULL");
103                 return;
104         }
105
106         if(!connection)
107         {
108                 LoggerW("connection is NULL");
109                 return;
110         }
111
112         if(connection->local_role == BT_SOCKET_SERVER)
113         {
114                 RegisteredUUIDMapT::iterator iter = object->mRegisteredUUID.find(connection->service_uuid);
115
116                 if(iter == object->mRegisteredUUID.end())
117                 {
118                         LoggerW("Connection state is changed unexpectedly");
119                         return;
120                 }
121
122                 if(state == BT_SOCKET_CONNECTED)    // connected when Server
123                 {
124                         if(result == BT_ERROR_NONE)
125                         {
126                                 // Update BluetoothServiceHandler
127                                 BluetoothServiceHandlerPtr service = iter->second;
128                                 service->setConnectionState(true);
129
130                                 // Call BluetoothServiceHandler.onconnect
131                                 BluetoothSocketPtr socket = new BluetoothSocket(connection);
132                                 MultiCallbackUserDataPtr callback = service->getOnConnect();
133                                 JSContextRef context = callback->getContext();
134                                 JSObjectRef socketObj = JSBluetoothSocket::createJSObject(context, socket);
135                                 if(callback)
136                                         callback->invokeCallback("onconnect", socketObj);
137
138                                 // Update mConnectedSocket
139                                 object->mConnectedSocket.insert(std::pair<int, BluetoothSocketPtr>(connection->socket_fd, socket));
140                                 bt_socket_set_data_received_cb(onSocketReceivedCB, userData);
141                         }
142                         else
143                         {
144                                 LoggerW("Establishing a connection failed");
145                         }
146                         return;
147                 }
148                 else    // disconnected when Server
149                 {
150                         if(result == BT_ERROR_NONE)
151                         {
152                                 // Update BluetoothServiceHandler
153                                 BluetoothServiceHandlerPtr service = iter->second;
154                                 service->setConnectionState(false);
155
156                                 // call BluetoothSocket.onclose;
157                                 ConnectedSocketMapT::iterator i = object->mConnectedSocket.find(connection->socket_fd);
158                                 if(i == object->mConnectedSocket.end())
159                                 {
160                                         LoggerW("Unknown connected socket");
161                                         return;
162                                 }
163                                 //BluetoothSocketSharedPtr socket = i->second;
164                                 BluetoothSocketPtr socket = i->second;
165                                 socket->setConnectionState(false);
166                                 MultiCallbackUserDataPtr callback = socket->getOnClose();
167                                 if(callback)
168                                         callback->invokeCallback("onclose");
169
170                                 // Update mConnectedSocket
171                                 object->mConnectedSocket.erase(i);
172                         }
173                         else
174                         {
175                                 LoggerW("Disconnecting a connection failed");
176                         }
177                 }
178         }
179         else if(connection->local_role == BT_SOCKET_CLIENT)
180         {
181
182                 if(state == BT_SOCKET_CONNECTED)    // connected when Client
183                 {
184                         std::string remoteAddress(connection->remote_address);
185                         ConnReqMultiMapT::iterator iter;
186                         do
187                         {
188                                 iter = object->mConnReqMap.find(remoteAddress);
189                                 if(iter != object->mConnReqMap.end() && !strcmp(iter->second->mUUID.c_str(), connection->service_uuid))
190                                 {
191                                         break;
192                                 }
193                         }
194                         while(iter != object->mConnReqMap.end());
195
196                         if(iter == object->mConnReqMap.end())
197                         {
198                                 LoggerW("Connection state is changed unexpectedly");
199                                 return;
200                         }
201
202                         MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(iter->second->mUserData);
203
204                         if(result == BT_ERROR_NONE)
205                         {
206                                 // Update mConnectedSocket
207                                 BluetoothSocketPtr socket = new BluetoothSocket(connection);
208                                 object->mConnectedSocket.insert(std::pair<int, BluetoothSocketPtr>(connection->socket_fd, socket));
209                                 bt_socket_set_data_received_cb(onSocketReceivedCB, userData);
210
211                                 // Call successcallback of connectToServiceByUUID
212                                 JSContextRef context = callback->getContext();
213                                 JSObjectRef socketObj = JSBluetoothSocket::createJSObject(context, socket);
214                                 if(callback)
215                                         callback->invokeCallback("success", socketObj);
216
217                                 // Update mConnReqMap
218                                 object->mConnReqMap.erase(iter);
219                         }
220                         else
221                         {
222                                 // Call errorcallback of connectToServiceByUUID
223                                 JSContextRef context = callback->getContext();
224                                 NotFoundException error("Not found");
225                                 if(callback)
226                                         callback->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
227
228                                 // Update mConnReqMap
229                                 object->mConnReqMap.erase(iter);
230                         }
231                         return;
232                 }
233                 else    // disconnected when Client
234                 {
235                         if(result == BT_ERROR_NONE)
236                         {
237                                 // call BluetoothSocket.onclose;
238                                 ConnectedSocketMapT::iterator i = object->mConnectedSocket.find(connection->socket_fd);
239                                 if(i == object->mConnectedSocket.end())
240                                 {
241                                         LoggerW("Unknown connected socket");
242                                         return;
243                                 }
244
245                                 BluetoothSocketPtr socket = i->second;
246                                 socket->setConnectionState(false);
247                                 MultiCallbackUserDataPtr callback = socket->getOnClose();
248                                 if(callback)
249                                         callback->invokeCallback("onclose");
250
251                                 // Update mConnectedSocket
252                                 object->mConnectedSocket.erase(i);
253                         }
254                         else
255                         {
256                                 LoggerW("Disconnecting a connection failed");
257                         }
258                 }
259         }
260         else
261         {
262                 LoggerW("Unknown role");
263                 return;
264         }
265
266         if(object->mConnectedSocket.size() == 0)
267         {
268                 bt_socket_unset_data_received_cb();
269         }
270
271         if(object->mRegisteredUUID.size() == 0 && object->mConnReqMap.size() == 0 && object->mConnectedSocket.size() == 0)
272         {
273                 bt_socket_unset_connection_state_changed_cb();
274         }
275 }
276
277 void BluetoothAdapter::onSocketReceivedCB(bt_socket_received_data_s *data, void *userData)
278 {
279         BluetoothAdapterPtr object = static_cast<BluetoothAdapterPtr>(userData);
280
281         if(!object)
282         {
283                 LoggerW("userData is NULL");
284                 return;
285         }
286
287         if(!data)
288         {
289                 LoggerW("data is NULL");
290                 return;
291         }
292
293         ConnectedSocketMapT::iterator i = object->mConnectedSocket.find(data->socket_fd);
294         if(i == object->mConnectedSocket.end())
295         {
296                 LoggerW("Unknown connected socket");
297                 return;
298         }
299
300         // Store received data
301         BluetoothSocketPtr socket = i->second;
302         socket->storeRecivedData(data->data, static_cast<unsigned long>(data->data_size));
303
304         // Call BluetoothSocket.onmessage
305         MultiCallbackUserDataPtr callback = socket->getOnMessage();
306         if(callback)
307                 callback->invokeCallback("onmessage");
308 }
309
310 BluetoothAdapter::BluetoothAdapter():
311         mAdapterPath(NULL),
312         mAgentRegistrationId(-1),
313         mAgentIntrospectionData(NULL),
314         mBluetoothTechnology(NULL),
315         mEnabled(false)
316 {
317
318         mBluetoothTechnology = getBluetoothTechnology();
319         if(!mBluetoothTechnology)
320         {
321                 LoggerE("Failed to get BT technology");
322         }
323
324         mAdapterPath = getDefaultAdapter();
325         if(!mAdapterPath)
326         {
327                 LoggerE("Unable to get default adapter");
328         }
329
330
331         Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, "org.freedesktop.DBus.ObjectManager",
332                                  "/", "InterfacesAdded", BluetoothAdapter::handleSignal,
333                                  this);
334         Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, "org.freedesktop.DBus.ObjectManager",
335                                  "/", "InterfacesRemoved", BluetoothAdapter::handleSignal,
336                                  this);
337         memset(&mAgentIfaceVTable, 0, sizeof(mAgentIfaceVTable));
338
339         if(isAdapterPowered())
340         {
341                 LoggerD("Adapter is powered");
342                 mEnabled = true;
343         }
344         else
345         {
346                 LoggerD("Adapter is not powered");
347         }
348
349         if(mAdapterPath)
350         {
351                 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, "org.freedesktop.DBus.ObjectManager",
352                                          mAdapterPath, "InterfacesAdded", BluetoothAdapter::handleSignal,
353                                          this);
354         }
355 }
356
357 BluetoothAdapter::~BluetoothAdapter()
358 {
359         // unset platform callback
360         bt_socket_unset_connection_state_changed_cb();
361         bt_socket_unset_data_received_cb();
362
363         for(int i = 0; i <= DESTROY_BONDING; i++)
364         {
365                 mUserDataList[i].reset();
366         }
367         mRegisteredUUID.clear();
368         mConnReqMap.clear();
369         mFoundDevices.clear();
370         mConnectedSocket.clear();
371 }
372
373 void BluetoothAdapter::unloadFrame(JSContextRef context)
374 {
375         LoggerD("Clean mUserDataList");
376         for(int i = 0; i <= DESTROY_BONDING; i++)
377         {
378                 if(mUserDataList[i])
379                 {
380                         MultiCallbackUserDataPtr callback = mUserDataList[i];
381                         if(!GlobalContextManager::getInstance()->isAliveGlobalContext(callback->getContext()))
382                         {
383                                 mUserDataList[i].reset();
384                         }
385                 }
386         }
387
388         LoggerD("Clean mConnReqMap");
389         for(ConnReqMultiMapT::iterator iter = mConnReqMap.begin(); iter != mConnReqMap.end(); )
390         {
391                 ConnReqMultiMapT::iterator temp = iter++;
392                 MultiCallbackUserDataPtr callback = temp->second->mUserData;
393                 if(!callback && !GlobalContextManager::getInstance()->isAliveGlobalContext(callback->getContext()))
394                 {
395                         mConnReqMap.erase(temp);
396                 }
397         }
398 }
399
400 void BluetoothAdapter::unregisterUUID(std::string &uuid)
401 {
402         mRegisteredUUID.erase(mRegisteredUUID.find(uuid));
403         if(mRegisteredUUID.size() == 0 && mConnReqMap.size() == 0 && mConnectedSocket.size() == 0)
404         {
405                 bt_socket_unset_connection_state_changed_cb();
406         }
407 }
408
409 bool BluetoothAdapter::closeConnectedSocket(int socket)
410 {
411         if(mEnabled == true)
412         {
413                 ConnectedSocketMapT::iterator iter = mConnectedSocket.find(socket);
414                 if(iter == mConnectedSocket.end())
415                 {
416                         LoggerW("Already disconnected");
417                         return true;
418                 }
419
420                 mConnectedSocket.erase(iter);
421                 if(mConnectedSocket.size() == 0)
422                 {
423                         bt_socket_unset_data_received_cb();
424                 }
425
426                 if(mRegisteredUUID.size() == 0 && mConnReqMap.size() == 0 && mConnectedSocket.size() == 0)
427                 {
428                         bt_socket_unset_connection_state_changed_cb();
429                 }
430
431                 return true;
432         }
433         else
434         {
435                 LoggerE("Bluetooth is not powered");
436                 return false;
437         }
438 }
439
440 void BluetoothAdapter::removeConnReq(std::string &remoteAddress)
441 {
442         mConnReqMap.erase(remoteAddress);
443
444         if(mRegisteredUUID.size() == 0 && mConnReqMap.size() == 0 && mConnectedSocket.size() == 0)
445         {
446                 if(bt_socket_unset_connection_state_changed_cb() != BT_ERROR_NONE)
447                 {
448                         LoggerW("Unsetting connection event callback failed");
449                 }
450         }
451 }
452
453 BluetoothAdapter* BluetoothAdapter::getInstance()
454 {
455         static BluetoothAdapter instance;
456         return &instance;
457 }
458
459 bool BluetoothAdapter::isBluetoothSupported()
460 {
461         bool isSupported = true;
462
463         /*    if(system_info_get_value_bool(SYSTEM_INFO_KEY_BLUETOOTH_SUPPORTED, &isSupported) != SYSTEM_INFO_ERROR_NONE) {
464                 LoggerE("Can't know whether Bluetooth is supported or not");
465             }
466         */
467         return isSupported;
468 }
469
470 bool BluetoothAdapter::isValidAddress(std::string &address)
471 {
472         pcrecpp::RE re("(([0-9a-zA-Z]+):)+([0-9a-zA-Z]+)");
473         std::string compareAddress = "00:12:47:08:9A:A6";
474
475         if (!re.FullMatch(address))
476         {
477                 LoggerE("Invalid address");
478                 return false;
479         }
480
481         if (address.size() != compareAddress.size())
482         {
483                 LoggerE("Invalid size");
484                 return false;
485         }
486
487         return true;
488 }
489
490 bool BluetoothAdapter::isValidUUID(std::string &uuid)
491 {
492         pcrecpp::RE re("(([0-9a-zA-Z]+)-)+([0-9a-zA-Z]+)");
493         std::string compareUUID = "00001101-0000-1000-8000-00805F9B34FB";
494
495         if (!re.FullMatch(uuid))
496         {
497                 LoggerE("Invalid UUID");
498                 return false;
499         }
500
501         if (uuid.size() != compareUUID.size())
502         {
503                 LoggerE("Invalid size");
504                 return false;
505         }
506
507         return true;
508 }
509
510 std::string BluetoothAdapter::getName() const
511 {
512         const char* name = NULL;
513         std::string str = "";
514
515         if(!mAdapterPath)
516         {
517                 LoggerD("No BT adapter");
518                 return str;
519         }
520
521         // get adapter properties and check Name property
522         GError *err = NULL;
523         GVariant *reply = NULL;
524         reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
525                                              BLUEZ_SERVICE,
526                                              mAdapterPath,
527                                              "org.freedesktop.DBus.Properties",
528                                              "Get",
529                                              g_variant_new("(ss)", "org.bluez.Adapter1", "Name"),
530                                              NULL,
531                                              G_DBUS_CALL_FLAGS_NONE,
532                                              -1,
533                                              NULL,
534                                              &err);
535         if(err || !reply)
536         {
537                 if(err)
538                         g_error_free(err);
539                 LoggerE("Failed to get 'Name' property");
540                 return str;
541         }
542
543         GVariant *value;
544         g_variant_get(reply, "(v)", &value);
545         name = g_variant_get_string(value, NULL);
546         str = name;
547
548         g_variant_unref(reply);
549
550         return str;
551 }
552
553 void BluetoothAdapter::setName(std::string &name, MultiCallbackUserDataPtr userData)
554 {
555         if(mEnabled == true)
556         {
557                 std::string adapterName = getName();
558                 if(adapterName == name)     // in case of same name
559                 {
560                         LoggerD("same name");
561                         BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
562                         return;
563                 }
564
565                 if(mAdapterPath)
566                 {
567                         GError *err = NULL;
568
569                         g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
570                                                      BLUEZ_SERVICE,
571                                                      mAdapterPath,
572                                                      "org.freedesktop.DBus.Properties",
573                                                      "Set",
574                                                      g_variant_new("(ssv)", "org.bluez.Adapter1", "Name", g_variant_new_string(name.c_str())),
575                                                      NULL,
576                                                      G_DBUS_CALL_FLAGS_NONE,
577                                                      -1,
578                                                      NULL,
579                                                      &err);
580
581                         if(err)
582                         {
583                                 LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);
584                                 UnknownException *error = new UnknownException(err->message);
585                                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
586                                 g_error_free(err);
587                                 return;
588                         }
589
590                         if(userData)
591                                 userData->invokeCallback("success");
592                 }
593                 else
594                 {
595                         LoggerE("No BT adapter");
596                         UnknownException *error = new UnknownException("No BT adapter");
597                         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
598                         return;
599                 }
600         }
601 }
602
603 std::string BluetoothAdapter::getAddress() const
604 {
605         const char* address = NULL;
606         std::string str = "";
607
608         if(!mAdapterPath)
609         {
610                 LoggerD("No BT adapter");
611                 return str;
612         }
613
614         // get adapter properties and check Address property
615         GError *err = NULL;
616         GVariant *reply = NULL;
617         reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
618                                              BLUEZ_SERVICE,
619                                              mAdapterPath,
620                                              "org.freedesktop.DBus.Properties",
621                                              "Get",
622                                              g_variant_new("(ss)", "org.bluez.Adapter1", "Address"),
623                                              NULL,
624                                              G_DBUS_CALL_FLAGS_NONE,
625                                              -1,
626                                              NULL,
627                                              &err);
628         if(err || !reply)
629         {
630                 if(err)
631                         g_error_free(err);
632                 LoggerE("Failed to get 'Address' property");
633                 return str;
634         }
635
636         //GVariantIter *iter;
637         GVariant *value;
638         g_variant_get(reply, "(v)", &value);
639         address = g_variant_get_string(value, NULL);
640         str = address;
641         //const char *key;
642         /*
643           while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
644               if(!strcmp(key, "Address")) {
645                   address = g_variant_get_string(value, NULL);
646                   if(address)
647                       str = address;
648                   break;
649               }
650           }
651         */
652         g_variant_unref(reply);
653
654         return str;
655 }
656
657 bool BluetoothAdapter::getPowered() const
658 {
659         return mEnabled;
660 }
661
662 void BluetoothAdapter::setPowered(bool powered, MultiCallbackUserDataPtr userData)
663 {
664         bool btTechnologyPowered = isBtTechnologyPowered();
665         if(!powered)   // Powering OFF BT. It is enough to take down BT technology - it will take down Adapter as well
666         {
667                 if(!btTechnologyPowered)   // already powered OFF
668                 {
669                         LoggerE("BT already powered OFF ... calling success callback.");
670                         BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
671                         return;
672                 }
673                 else
674                 {
675                         if(setBluetoothPowered(powered))   // BT powered OFF successfuly
676                         {
677                                 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
678                         }
679                         else
680                         {
681                                 LoggerE("Failed to Power OFF BT technology - trying to Power OFF the Adapter directly");
682                                 if(setAdapterPowered(powered))
683                                 {
684                                         BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
685                                 }
686                                 else
687                                 {
688                                         LoggerE("Failed to Power OFF both, BT and adapter as well ... calling error callback");
689                                         UnknownException *error = new UnknownException("Failed to Power OFF BT/Adapter");
690                                         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
691                                 }
692                         }
693                 }
694         }
695         else   // Powering ON BT
696         {
697                 if(btTechnologyPowered)   // already Powered ON
698                 {
699                         if(mEnabled)   // already Powered On
700                         {
701                                 LoggerD("BT/Adapter already powered ON ... calling success callback.");
702                                 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
703                         }
704                         else   // BT powered, but Adapter is not - try to power it ON
705                         {
706                                 LoggerE("BT technology is Powered ON, but adapter is not, trying to Power it ON");
707                                 if(setAdapterPowered(powered))   // successfuly powered ON ... calling success callback
708                                 {
709                                         LoggerE("successfull power on.... sending syncToAsyncSuccess");
710                                         BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
711                                 }
712                                 else
713                                 {
714                                         LoggerE("Failed to Power ON BT adapter ... calling error callback");
715                                         UnknownException *error = new UnknownException("Failed to Power ON BT adapter");
716                                         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
717                                 }
718                         }
719                 }
720                 else
721                 {
722                         if(!setBluetoothPowered(powered))
723                         {
724                                 LoggerE("Failed to Power ON BT technology ... calling error callback");
725                                 UnknownException *error = new UnknownException("Failed to Power ON BT technology");
726                                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
727                         }
728                         /*
729                         else { // BT technology powered ON (it should power ON adapter as well, but just in case, call Power ON on adapter as well)
730                             if(setAdapterPowered(powered)) {
731                                 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
732                             }
733                             else {
734                                 LoggerE("Failed to Power ON BT adapter ... calling error callback");
735                                 UnknownException *error = new UnknownException("Failed to Power ON BT adapter");
736                                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
737                             }
738                         }
739                         */
740                         else
741                         {
742                                 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
743                         }
744                 }
745         }
746
747         mUserDataList[SET_POWERED].reset();
748 }
749
750 bool BluetoothAdapter::getVisible() const
751 {
752         if(!mAdapterPath)
753         {
754                 LoggerD("No BT adapter");
755                 return false;
756         }
757
758         // get adapter properties and check Discoverable property
759         GError *err = NULL;
760         GVariant *reply = NULL;
761         reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
762                                              BLUEZ_SERVICE,
763                                              mAdapterPath,
764                                              "org.freedesktop.DBus.Properties",
765                                              "Get",
766                                              g_variant_new("(ss)", "org.bluez.Adapter1", "Discoverable"),
767                                              NULL,
768                                              G_DBUS_CALL_FLAGS_NONE,
769                                              -1,
770                                              NULL,
771                                              &err);
772         if(err || !reply)
773         {
774                 if(err)
775                         g_error_free(err);
776                 LoggerE("Failed to get 'Discoverable' property");
777                 return false;
778         }
779
780         bool visible = false;
781         GVariant *value;
782         g_variant_get(reply, "(v)", &value);
783         visible = g_variant_get_boolean(value);
784
785         g_variant_unref(reply);
786
787         return visible;
788 }
789
790 void BluetoothAdapter::setVisible(bool visible, unsigned int timeout, MultiCallbackUserDataPtr userData)
791 {
792         UnknownException *error = new UnknownException("NOT IMPLEMENTED");
793         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
794         /*
795         if(mEnabled == true) {
796             bt_adapter_visibility_mode_e discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE;
797             if(visible == true) {
798                 if(timeout == 0)
799                     discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_GENERAL_DISCOVERABLE;
800                 else
801                     discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_LIMITED_DISCOVERABLE;
802             }
803
804             bt_adapter_visibility_mode_e current = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE;
805             int time = 0;
806             if(bt_adapter_get_visibility(&current , &time) != BT_ERROR_NONE) {
807                 LoggerE("bt_adapter_get_visibility() failed");
808                 UnknownException *error = new UnknownException("Can't get current visibility");
809                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
810                 return;
811             }
812
813             if(discoverable_mode == current) {
814                 if(discoverable_mode != BT_ADAPTER_VISIBILITY_MODE_LIMITED_DISCOVERABLE) {
815                     LoggerD("same visibility");
816                     BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
817                     return;
818                 }
819                 else if((unsigned int)time == timeout) {
820                     LoggerD("same visibility");
821                     BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
822                     return;
823                 }
824             }
825
826             if(mUserDataList[SET_VISIBLE] == NULL) {
827                 bt_adapter_set_visibility_mode_changed_cb(onVisibilityChangedCB, this);
828                 mUserDataList[SET_VISIBLE] = userData;
829             } else {
830                 UnknownException *error = new UnknownException("Already requested");
831                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
832                 return;
833             }
834
835             mRequestedVisibility = discoverable_mode;
836             int ret = bt_adapter_set_visibility(discoverable_mode, timeout);
837             switch(ret) {
838                 case BT_ERROR_NONE:
839                 {
840                     LoggerD("bt_adapter_set_visibility() succeeded");
841                     return;
842                 }
843                 case BT_ERROR_INVALID_PARAMETER:
844                 {
845                     InvalidValuesException *error = new InvalidValuesException("Invalid value");
846                     BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
847                     break;
848                 }
849                 default:
850                 {
851                     UnknownException *error = new UnknownException("Unknown error");
852                     BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
853                 }
854             }
855
856             bt_adapter_unset_visibility_mode_changed_cb();
857             mUserDataList[SET_VISIBLE].reset();
858         } else {   // Not enabled
859             ServiceNotAvailableException *error =  new ServiceNotAvailableException("Bluetooth device is turned off");
860             BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
861         }
862         */
863 }
864
865 void BluetoothAdapter::setChangeListener(MultiCallbackUserDataPtr userData)
866 {
867         if(mChangeListener == NULL)
868                 mChangeListener = userData;
869 }
870
871 void BluetoothAdapter::unsetChangeListener()
872 {
873         if(mChangeListener != NULL)
874                 mChangeListener.reset();
875 }
876
877
878 void BluetoothAdapter::discoverDevices(MultiCallbackUserDataPtr userData)
879 {
880         if(!mAdapterPath)
881         {
882                 LoggerE("No BT adapter");
883                 UnknownException *error = new UnknownException("No BT adapter");
884                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
885                 return;
886         }
887
888         if(mUserDataList[DISCOVER_DEVICES] == NULL)
889         {
890                 mUserDataList[DISCOVER_DEVICES] = userData;
891         }
892         else
893         {
894                 LoggerE("Already requested");
895                 UnknownException *error = new UnknownException("Already requested");
896                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
897                 return;
898         }
899
900         if(mEnabled == true)
901         {
902                 GError *err = NULL;
903                 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
904                                              BLUEZ_SERVICE,
905                                              mAdapterPath,
906                                              BLUEZ_ADAPTER_IFACE,
907                                              "StartDiscovery",
908                                              NULL,
909                                              NULL,
910                                              G_DBUS_CALL_FLAGS_NONE,
911                                              -1,
912                                              NULL,
913                                              &err);
914                 if(err)
915                 {
916                         LoggerE("Failed to 'StartDiscovery' on adapter " << mAdapterPath << " : " << err->message);
917                         UnknownException *error = new UnknownException(err->message);
918                         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
919                         g_error_free(err);
920                         mUserDataList[DISCOVER_DEVICES].reset();
921                 }
922                 else
923                 {
924                         LoggerD("Call to 'StartDiscovery' succeeded");
925
926                         // store MAC address of previously found device into mDisappearedDevices
927                         mDisappearedDevices.clear();
928                         for(auto iter = mFoundDevices.begin();
929                                 iter != mFoundDevices.end(); iter++)
930                         {
931                                 BluetoothDeviceSharedPtr foundDevice = *iter;
932                                 mDisappearedDevices.push_back(foundDevice->getAddress());
933                         }
934
935                         mFoundDevices.clear();
936
937                         // 'onstarted' callback is called after receiving 'Discovering' property changed to 'true' ... see handleSignal() method
938                         //if(userData)
939                         //    userData->invokeCallback("onstarted");
940
941                         Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, "org.freedesktop.DBus.Properties",
942                                                  mAdapterPath, "PropertiesChanged", BluetoothAdapter::handleSignal,
943                                                  this);
944
945                         return;
946                 }
947         }
948         else       // Not enabled
949         {
950                 LoggerE("Bluetooth device is turned off");
951                 ServiceNotAvailableException *error =  new ServiceNotAvailableException("Bluetooth device is turned off");
952                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
953         }
954
955         mUserDataList[DISCOVER_DEVICES].reset();
956 }
957
958 void BluetoothAdapter::stopDiscovery(MultiCallbackUserDataPtr userData)
959 {
960         if(mUserDataList[DISCOVER_DEVICES] == NULL)   // not doing discovery
961         {
962                 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
963                 return;
964         }
965
966         if(!mAdapterPath)
967         {
968                 LoggerE("No BT adapter");
969                 UnknownException *error = new UnknownException("No BT adapter");
970                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
971         }
972         else if(mEnabled == true)
973         {
974                 GError *err = NULL;
975                 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
976                                              BLUEZ_SERVICE,
977                                              mAdapterPath,
978                                              BLUEZ_ADAPTER_IFACE,
979                                              "StopDiscovery",
980                                              NULL,
981                                              NULL,
982                                              G_DBUS_CALL_FLAGS_NONE,
983                                              -1,
984                                              NULL,
985                                              &err);
986                 if(err)
987                 {
988                         LoggerE("Failed to 'StopDiscovery': " << err->message);
989                         UnknownException *error = new UnknownException(err->message);
990                         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
991                         g_error_free(err);
992                 }
993                 else
994                 {
995                         BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
996                         return;
997                 }
998         }
999         else       // Not enabled
1000         {
1001                 ServiceNotAvailableException *error =  new ServiceNotAvailableException("Bluetooth device is turned off");
1002                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1003         }
1004
1005         mUserDataList[DISCOVER_DEVICES].reset();
1006 }
1007
1008 void BluetoothAdapter::getKnownDevices(MultiCallbackUserDataPtr userData)
1009 {
1010         BluetoothCallbackUtil::syncToAsyncDeviceArrayCallback(userData);
1011 }
1012
1013 void BluetoothAdapter::getDevice(std::string &address, MultiCallbackUserDataPtr userData)
1014 {
1015         BluetoothCallbackUtil::syncToAsyncDeviceCallback(userData, address);
1016 }
1017
1018 void BluetoothAdapter::createBonding(std::string &address, MultiCallbackUserDataPtr userData)
1019 {
1020         if(!isValidAddress(address))
1021         {
1022                 LoggerE("Wrong address");
1023                 NotFoundException *error = new NotFoundException("Wrong address");
1024                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1025                 return;
1026         }
1027
1028         if(!mAdapterPath)
1029         {
1030                 LoggerE("No BT adapter");
1031                 NotFoundException *error = new NotFoundException("No BT adapter");
1032                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1033                 return;
1034         }
1035
1036         if(mUserDataList[CREATE_BONDING] == NULL)
1037         {
1038                 mCreateBondingAddress = address;
1039                 mUserDataList[CREATE_BONDING] = userData;
1040         }
1041         else
1042         {
1043                 LoggerE("Already requested");
1044                 UnknownException *error = new UnknownException("Already requested");
1045                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1046                 return;
1047         }
1048
1049         char* devicePath = NULL;
1050
1051         for (int i = 0; i < mFoundDevices.size(); i++)
1052         {
1053                 if (mFoundDevices[i]->getAddress() == address)
1054                 {
1055                         LoggerE("checking mFoundDevices -> " << mFoundDevices[i]->getAddress());
1056                         devicePath = mFoundDevices[i]->getDevicePath();
1057                         break;
1058                 }
1059         }
1060
1061         if (!devicePath)
1062                 devicePath = getDeviceFromAddress(address);
1063
1064         if(mEnabled == true)
1065         {
1066                 //     if(setupAgent(AGENT_PATH)) {
1067                 if (!devicePath)
1068                 {
1069                         LoggerE("devicePath was null, setting to empty string");
1070                         devicePath = "";
1071                 }
1072
1073                 if (devicePath != NULL)
1074                 {
1075
1076                         // CreatePairedDevice has to be ASYNC DBUS call
1077                         g_dbus_connection_call( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1078                                                 BLUEZ_SERVICE,
1079                                                 devicePath,
1080                                                 BLUEZ_DEVICE_IFACE,
1081                                                 "Pair",
1082                                                 NULL,
1083                                                 NULL,
1084                                                 G_DBUS_CALL_FLAGS_NONE,
1085                                                 -1,
1086                                                 NULL,
1087                                                 BluetoothAdapter::asyncCreatePairedDeviceCallback,
1088                                                 this);
1089
1090                 }
1091                 else
1092                         LoggerE("No bluetooth device path found!");
1093                 //   }
1094                 /*
1095                    else
1096                    {
1097                        LoggerE("Failed to set-up Bluez Agent for pairing");
1098                        ServiceNotAvailableException *error =  new ServiceNotAvailableException("Failed to set-up Bluez Agent for pairing");
1099                        BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1100                    }
1101                    */
1102         }
1103
1104         else
1105         {
1106                 // Not enabled
1107                 LoggerE("BLUEZ Bluetooth device is turned off");
1108                 ServiceNotAvailableException *error =  new ServiceNotAvailableException("Bluetooth device is turned off");
1109                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1110         }
1111         LoggerD("done with createPairedDevice");
1112 }
1113
1114 void BluetoothAdapter::destroyBonding(std::string &address, MultiCallbackUserDataPtr userData)
1115 {
1116         if(!isValidAddress(address))
1117         {
1118                 LoggerE("Wrong address");
1119                 NotFoundException *error = new NotFoundException("Wrong address");
1120                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1121                 return;
1122         }
1123
1124         // get device info before removing, 'cause after removing you loose access to it ('FindDevice' will not find it)
1125         bt_device_info_s deviceInfo;
1126         bool hasDeviceInfo = getDeviceInfoByAddress(&deviceInfo, address.c_str());
1127
1128         if(!removeDevice(address.c_str()))
1129         {
1130                 if(userData)
1131                 {
1132                         JSContextRef context = userData->getContext();
1133                         UnknownException error("Failed to remove device");
1134                         userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1135                 }
1136
1137                 return;
1138         }
1139
1140         if(userData)
1141         {
1142                 if(hasDeviceInfo)
1143                 {
1144                         BluetoothDeviceSharedPtr device(new BluetoothDevice(&deviceInfo));
1145                         JSContextRef context = userData->getContext();
1146                         JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(context, device);
1147                         userData->invokeCallback("success", deviceObj);
1148                 }
1149                 else
1150                 {
1151                         JSContextRef context = userData->getContext();
1152                         UnknownException error("Failed to get device info");
1153                         userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1154                 }
1155                 freeDeviceInfo(&deviceInfo);
1156         }
1157 }
1158
1159 void BluetoothAdapter::registerRFCOMMServiceByUUID(std::string &uuid, std::string &name, MultiCallbackUserDataPtr userData)
1160 {
1161         BluetoothCallbackUtil::syncToAsyncServiceCallback(userData, uuid, name);
1162 }
1163
1164 void BluetoothAdapter::connectToServiceByUUID(std::string &remoteAddress, std::string &uuid, Common::MultiCallbackUserDataPtr userData)
1165 {
1166         if(!isValidUUID(uuid))
1167         {
1168                 LoggerE("Wrong UUID");
1169                 InvalidValuesException *error = new InvalidValuesException("Wrong UUID");
1170                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1171                 return;
1172         }
1173
1174
1175         if(mEnabled == true)
1176         {
1177                 int ret = bt_socket_connect_rfcomm(remoteAddress.c_str(), uuid.c_str());
1178
1179                 switch(ret)
1180                 {
1181                 case BT_ERROR_NONE:
1182                 {
1183                         LoggerD("bt_socket_connect_rfcomm() succeeded");
1184                         bt_socket_set_connection_state_changed_cb(onSocketConnected, this);
1185
1186                         BluetoothConnReqPtr connReq = new BluetoothConnReq(uuid, userData);
1187                         mConnReqMap.insert(std::pair<std::string, BluetoothConnReqPtr>(remoteAddress, connReq));
1188                         break;
1189                 }
1190                 case BT_ERROR_INVALID_PARAMETER:
1191                 case BT_ERROR_REMOTE_DEVICE_NOT_BONDED:
1192                 {
1193                         InvalidValuesException *error = new InvalidValuesException("Invalid value");
1194                         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1195                         break;
1196                 }
1197                 default:
1198                 {
1199                         UnknownException *error = new UnknownException("Unknown error");
1200                         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1201                 }
1202                 }
1203         }
1204         else       // Not enabled
1205         {
1206                 ServiceNotAvailableException *error =  new ServiceNotAvailableException("Bluetooth device is turned off");
1207                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1208         }
1209 }
1210
1211 void BluetoothAdapter::returnKnownDevices(Common::MultiCallbackUserDataPtr userData)
1212 {
1213         char *result;
1214         bool done = false;
1215
1216         GError * error = nullptr;
1217         GDBusProxy * managerProxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL,
1218                                     "org.bluez",
1219                                     "/",
1220                                     "org.freedesktop.DBus.ObjectManager",
1221                                     nullptr,&error);
1222         if(error)
1223         {
1224                 LoggerE("could not create ObjManager proxy");
1225                 // DebugOut(DebugOut::Error)<<"Could not create ObjectManager proxy for Bluez: "<<error->message<<endl;
1226                 g_error_free(error);
1227         }
1228
1229         GVariant * objectMap = g_dbus_proxy_call_sync(managerProxy, "GetManagedObjects",nullptr, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1230
1231         if(error)
1232         {
1233                 LoggerE("failed to get GetManagedObj");
1234                 //DebugOut(DebugOut::Error)<<"Failed call to GetManagedObjects: "<<error->message<<endl;
1235                 g_object_unref(managerProxy);
1236                 g_error_free(error);
1237         }
1238
1239         GVariantIter* iter;
1240         char* objPath;
1241         GVariantIter* level2Dict;
1242
1243         g_variant_get(objectMap, "(a{oa{sa{sv}}})",&iter);
1244
1245         while(g_variant_iter_next(iter, "{oa{sa{sv}}}",&objPath, &level2Dict))
1246         {
1247                 char * interfaceName;
1248                 GVariantIter* innerDict;
1249
1250                 while(g_variant_iter_next(level2Dict, "{sa{sv}}", &interfaceName, &innerDict))
1251                 {
1252                         if(!strcmp(interfaceName, "org.bluez.Device1"))
1253                         {
1254                                 char* propertyName;
1255                                 GVariant* value;
1256
1257                                 while(done == false && g_variant_iter_next(innerDict,"{sv}", &propertyName, &value))
1258                                 {
1259
1260                                         if(!strcmp(propertyName, "Paired"))
1261                                         {
1262                                                 bool paired = false;
1263
1264                                                 g_variant_get(value,"b",&paired);
1265
1266                                                 if (paired)
1267                                                 {
1268                                                         bt_device_info_s deviceInfo;
1269
1270                                                         if(getDeviceInfo(&deviceInfo, objPath))
1271                                                                 foreachBondedDevicesCB(&deviceInfo, this, objPath);
1272
1273                                                         freeDeviceInfo(&deviceInfo);
1274                                                 }
1275                                         }
1276                                         g_free(propertyName);
1277                                         g_variant_unref(value);
1278                                 }
1279                         }
1280                         g_free(interfaceName);
1281                         g_variant_iter_free(innerDict);
1282                 }
1283                 g_free(objPath);
1284                 g_variant_iter_free(level2Dict);
1285         }
1286         g_variant_iter_free(iter);
1287
1288 }
1289
1290 void BluetoothAdapter::returnDevice(std::string &address, Common::MultiCallbackUserDataPtr userData)
1291 {
1292         if(!isValidAddress(address))
1293         {
1294                 LoggerE("Wrong address");
1295                 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), NotFoundException("Wrong address")));
1296                 return;
1297         }
1298
1299         if(mEnabled == true)
1300         {
1301                 bt_device_info_s deviceInfo;
1302                 bool success = getDeviceInfoByAddress(&deviceInfo, address.c_str());
1303
1304                 if(success)
1305                 {
1306                         BluetoothDeviceSharedPtr device(new BluetoothDevice(&deviceInfo));
1307                         LoggerD("invoke successCallback");
1308                         userData->invokeCallback("success", JSBluetoothDevice::createJSObject(userData->getContext(), device));
1309                         return;
1310                 }
1311                 else
1312                 {
1313                         JSContextRef context = userData->getContext();
1314                         UnknownException error("Failed to get device info");
1315                         userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1316                 }
1317                 freeDeviceInfo(&deviceInfo);
1318
1319                 std::vector<BluetoothDeviceSharedPtr>::iterator iter;
1320                 for(iter = mFoundDevices.begin(); iter != mFoundDevices.end(); ++iter)
1321                 {
1322                         BluetoothDeviceSharedPtr foundDevice = *iter;
1323                         if(!strcmp(foundDevice->getAddress().c_str(), address.c_str()))
1324                         {
1325                                 LoggerD("Found in mFoundDevices");
1326                                 userData->invokeCallback("success", JSBluetoothDevice::createJSObject(userData->getContext(), foundDevice));
1327                                 break;
1328                         }
1329                 }
1330
1331                 if(iter == mFoundDevices.end())
1332                 {
1333                         LoggerE("Can't find this device");
1334
1335                         userData->invokeCallback(
1336                             "error",
1337                             JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), NotFoundException("There is no device with the given address"))
1338                         );
1339                 }
1340         }
1341         else       // Not enabled
1342         {
1343                 LoggerE("Bluetooth device is turned off");
1344                 userData->invokeCallback(
1345                     "error",
1346                     JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), ServiceNotAvailableException("Bluetooth device is turned off"))
1347                 );
1348         }
1349 }
1350
1351 void BluetoothAdapter::returnRegisteredService(std::string &uuid, std::string &name, Common::MultiCallbackUserDataPtr userData)
1352 {
1353         if(!isValidUUID(uuid))
1354         {
1355                 LoggerE("Wrong UUID");
1356                 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Wrong UUID")));
1357                 return;
1358         }
1359
1360         if(mEnabled == true)
1361         {
1362
1363                 bool isRegistered;
1364                 if(bt_adapter_is_service_used(uuid.c_str(), &isRegistered) == BT_ERROR_NONE && isRegistered == true)
1365                 {
1366                         LoggerD("Already registered");
1367                         userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Already registered")));
1368                         return;
1369                 }
1370
1371                 int socket = -1;
1372                 int ret = bt_socket_create_rfcomm(uuid.c_str(), &socket);
1373
1374                 switch(ret)
1375                 {
1376                 case BT_ERROR_NONE:
1377                 {
1378                         LoggerD("bt_socket_create_rfcomm() succeeded");
1379                         int ret = bt_socket_listen_and_accept_rfcomm(socket, 0);
1380                         switch(ret)
1381                         {
1382                         case BT_ERROR_NONE:
1383                         {
1384                                 LoggerD("bt_socket_listen() succeeded");
1385                                 bt_socket_set_connection_state_changed_cb(onSocketConnected, this);
1386
1387                                 BluetoothServiceHandlerPtr serviceHandler = new BluetoothServiceHandler(uuid, name, socket);
1388                                 mRegisteredUUID.insert(std::pair<std::string, BluetoothServiceHandlerPtr>(uuid, serviceHandler));
1389
1390                                 JSObjectRef serviceObj = JSBluetoothServiceHandler::createJSObject(userData->getContext(), serviceHandler);
1391                                 userData->invokeCallback("success", serviceObj);
1392                                 break;
1393                         }
1394                         case BT_ERROR_INVALID_PARAMETER:
1395                         {
1396                                 LoggerD("Invalid value");
1397                                 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Invalid value")));
1398                                 break;
1399                         }
1400                         default:
1401                         {
1402                                 LoggerD("Unknown exception");
1403                                 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), UnknownException("Unknown exception")));
1404                         }
1405                         }
1406
1407                         break;
1408                 }
1409                 case BT_ERROR_INVALID_PARAMETER:
1410                 {
1411                         LoggerD("Invalid value");
1412                         userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Invalid value")));
1413                         break;
1414                 }
1415                 default:
1416                 {
1417                         LoggerD("Unknown exception");
1418                         userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), UnknownException("Unknown exception")));
1419                 }
1420                 }
1421         }
1422         else       // Not enabled
1423         {
1424                 LoggerE("Bluetooth device is turned off");
1425                 userData->invokeCallback(
1426                     "error",
1427                     JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), ServiceNotAvailableException("Bluetooth device is turned off"))
1428                 );
1429         }
1430 }
1431
1432 bool BluetoothAdapter::isBtTechnologyPowered()
1433 {
1434
1435         if(!mBluetoothTechnology)
1436         {
1437                 LoggerE("Invalid BT technology to get 'Powered' state.");
1438                 return false;
1439         }
1440
1441         GError *err = NULL;
1442         GVariant *reply = NULL;
1443         reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1444                                              CONNMAN_SERVICE,
1445                                              mBluetoothTechnology,
1446                                              CONNMAN_TECHNOLOGY_IFACE,
1447                                              "GetProperties",
1448                                              NULL,
1449                                              NULL,
1450                                              G_DBUS_CALL_FLAGS_NONE,
1451                                              -1,
1452                                              NULL,
1453                                              &err);
1454         if(err || !reply)
1455         {
1456                 if(err)
1457                         g_error_free(err);
1458                 return false;
1459         }
1460
1461         GVariantIter *iter;
1462         g_variant_get(reply, "(a{sv})", &iter);
1463         const char *key;
1464         GVariant *value;
1465         bool powered = false;
1466         while(g_variant_iter_next(iter, "{sv}", &key, &value))
1467         {
1468                 if(!strcmp(key, "Powered"))
1469                 {
1470                         powered = g_variant_get_boolean(value);
1471                         break;
1472                 }
1473         }
1474
1475         g_variant_unref(reply);
1476
1477         return powered;
1478 }
1479
1480
1481
1482 gchar* BluetoothAdapter::getDefaultAdapter() const
1483 {
1484         char *result;
1485         bool done = false;
1486
1487         GError * error = nullptr;
1488         GDBusProxy * managerProxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL,
1489                                     "org.bluez",
1490                                     "/",
1491                                     "org.freedesktop.DBus.ObjectManager",
1492                                     nullptr,&error);
1493         if(error)
1494         {
1495                 LoggerE("could not create ObjManager proxy");
1496                 // DebugOut(DebugOut::Error)<<"Could not create ObjectManager proxy for Bluez: "<<error->message<<endl;
1497                 g_error_free(error);
1498                 return "";
1499         }
1500
1501         GVariant * objectMap = g_dbus_proxy_call_sync(managerProxy, "GetManagedObjects",nullptr, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1502
1503         if(error)
1504         {
1505                 LoggerE("failed to get GetManagedObj");
1506                 //DebugOut(DebugOut::Error)<<"Failed call to GetManagedObjects: "<<error->message<<endl;
1507                 g_object_unref(managerProxy);
1508                 g_error_free(error);
1509                 return "";
1510         }
1511
1512         GVariantIter* iter;
1513         char* objPath;
1514         GVariantIter* level2Dict;
1515
1516         g_variant_get(objectMap, "(a{oa{sa{sv}}})",&iter);
1517
1518         while(g_variant_iter_next(iter, "{oa{sa{sv}}}",&objPath, &level2Dict))
1519         {
1520                 char * interfaceName;
1521                 GVariantIter* innerDict;
1522                 while(g_variant_iter_next(level2Dict, "{sa{sv}}", &interfaceName, &innerDict))
1523                 {
1524                         if(!strcmp(interfaceName, "org.bluez.Adapter1"))
1525                         {
1526                                 char* propertyName;
1527                                 GVariant* value;
1528
1529                                 while(done == false && g_variant_iter_next(innerDict,"{sv}", &propertyName, &value))
1530                                 {
1531                                         if(!strcmp(propertyName, "Address"))
1532                                         {
1533                                                 char* addr;
1534                                                 g_variant_get(value,"s",&addr);
1535
1536                                                 result = objPath?strdup(objPath):NULL;
1537                                                 done = true;
1538
1539                                                 g_free(addr);
1540                                         }
1541                                         g_free(propertyName);
1542                                         g_variant_unref(value);
1543                                 }
1544                         }
1545                         g_free(interfaceName);
1546                         g_variant_iter_free(innerDict);
1547                 }
1548                 g_free(objPath);
1549                 g_variant_iter_free(level2Dict);
1550         }
1551         g_variant_iter_free(iter);
1552
1553         return result;
1554 }
1555
1556 gchar* BluetoothAdapter::getDeviceFromAddress(std::string &address) const
1557 {
1558         char *result = NULL;
1559         bool done = false;
1560
1561         GError * error = nullptr;
1562         GDBusProxy * managerProxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL,
1563                                     "org.bluez",
1564                                     "/",
1565                                     "org.freedesktop.DBus.ObjectManager",
1566                                     nullptr,&error);
1567         if(error)
1568         {
1569                 LoggerE("could not create ObjManager proxy");
1570                 // DebugOut(DebugOut::Error)<<"Could not create ObjectManager proxy for Bluez: "<<error->message<<endl;
1571                 g_error_free(error);
1572                 return "";
1573         }
1574
1575         GVariant * objectMap = g_dbus_proxy_call_sync(managerProxy, "GetManagedObjects",nullptr, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1576
1577         if(error)
1578         {
1579                 LoggerE("failed to get GetManagedObj");
1580                 //DebugOut(DebugOut::Error)<<"Failed call to GetManagedObjects: "<<error->message<<endl;
1581                 g_object_unref(managerProxy);
1582                 g_error_free(error);
1583                 return "";
1584         }
1585
1586         GVariantIter* iter;
1587         char* objPath;
1588         GVariantIter* level2Dict;
1589
1590         g_variant_get(objectMap, "(a{oa{sa{sv}}})",&iter);
1591
1592         while(g_variant_iter_next(iter, "{oa{sa{sv}}}",&objPath, &level2Dict))
1593         {
1594                 char * interfaceName;
1595                 GVariantIter* innerDict;
1596                 while(g_variant_iter_next(level2Dict, "{sa{sv}}", &interfaceName, &innerDict))
1597                 {
1598                         if(!strcmp(interfaceName, "org.bluez.Device1"))
1599                         {
1600                                 char* propertyName;
1601                                 GVariant* value;
1602
1603                                 while(done == false && g_variant_iter_next(innerDict,"{sv}", &propertyName, &value))
1604                                 {
1605                                         if(!strcmp(propertyName, "Address"))
1606                                         {
1607                                                 char* addr;
1608                                                 g_variant_get(value,"s",&addr);
1609                                                 if(addr && std::string(addr) == address)
1610                                                 {
1611
1612                                                         result = objPath?strdup(objPath):NULL;
1613                                                         done = true;
1614                                                         LoggerD("getDeviceFromAddress found : " << result);
1615                                                 }
1616
1617                                                 g_free(addr);
1618                                         }
1619                                         g_free(propertyName);
1620                                         g_variant_unref(value);
1621                                 }
1622                         }
1623                         g_free(interfaceName);
1624                         g_variant_iter_free(innerDict);
1625                 }
1626                 g_free(objPath);
1627                 g_variant_iter_free(level2Dict);
1628         }
1629         g_variant_iter_free(iter);
1630
1631         return result;
1632 }
1633
1634 bool BluetoothAdapter::isAdapterPowered()
1635 {
1636
1637         if(!mAdapterPath)
1638                 return false;
1639
1640         // get adapter properties and check if it's Powered
1641         GError *err = NULL;
1642         GVariant *reply = NULL;
1643         reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
1644                                              BLUEZ_SERVICE,
1645                                              mAdapterPath,
1646                                              "org.freedesktop.DBus.Properties",
1647                                              "Get",
1648                                              g_variant_new("(ss)", "org.bluez.Adapter1", "Powered"),
1649                                              NULL,
1650                                              G_DBUS_CALL_FLAGS_NONE,
1651                                              -1,
1652                                              NULL,
1653                                              &err);
1654
1655         if(err || !reply)
1656         {
1657                 if(err)
1658                         g_error_free(err);
1659                 return false;
1660         }
1661
1662         bool powered = false;
1663         GVariant *value;
1664         g_variant_get(reply, "(v)", &value);
1665         powered = g_variant_get_boolean(value);
1666
1667         g_variant_unref(reply);
1668
1669         return powered;
1670 }
1671
1672 void BluetoothAdapter::handleSignal(GDBusConnection  *connection,
1673                                     const gchar      *sender,
1674                                     const gchar      *object_path,
1675                                     const gchar      *interface_name,
1676                                     const gchar      *signal_name,
1677                                     GVariant         *parameters,
1678                                     gpointer          user_data)
1679 {
1680         LoggerE("signal received: '" << interface_name << "' -> '" << signal_name << "' -> '" << object_path << "'");
1681
1682         BluetoothAdapter *ctx = static_cast<BluetoothAdapter*>(user_data);
1683         if(!ctx)
1684         {
1685                 LoggerD("Failed to cast to BluetoothAdapter");
1686                 return;
1687         }
1688
1689
1690         if(!strcmp(interface_name, "org.freedesktop.DBus.ObjectManager"))
1691         {
1692                 if(!strcmp(signal_name, "InterfacesAdded"))
1693                 {
1694
1695                         char *objPath = NULL;
1696                         GVariantIter* iter;
1697
1698                         g_variant_get(parameters, "(oa{sa{sv}})", &objPath, &iter);
1699
1700                         if(objPath)
1701                         {
1702
1703                                 GVariantIter* iter2;
1704                                 char *interface = NULL;
1705
1706                                 while(g_variant_iter_next(iter, "{sa{sv}}",&interface, &iter2))
1707                                 {
1708
1709                                         if(!strcmp(interface, "org.bluez.Adapter1"))
1710                                         {
1711                                                 gchar * adapterPath = ctx->getDefaultAdapter();
1712                                                 free(ctx->mAdapterPath);
1713                                                 ctx->mAdapterPath = adapterPath;
1714
1715                                                 if(adapterPath)
1716                                                 {
1717                                                         Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, "org.freedesktop.DBus.Properties",
1718                                                                                  adapterPath, "PropertiesChanged", BluetoothAdapter::handleSignal,
1719                                                                                  ctx);
1720                                                 }
1721                                         }
1722
1723                                         else if(!strcmp(interface, "org.bluez.Device1"))
1724                                         {
1725                                                 bt_adapter_device_discovery_info_s discoveryInfo;
1726                                                 discoveryInfo.remote_name = NULL;
1727                                                 discoveryInfo.remote_address = NULL;
1728                                                 discoveryInfo.service_uuid = NULL;
1729                                                 discoveryInfo.service_count = 0;
1730
1731                                                 const char *key;
1732                                                 GVariant *value;
1733
1734                                                 while(g_variant_iter_next(iter2, "{sv}", &key, &value))
1735                                                 {
1736                                                         if(!strcmp(key, "Address"))
1737                                                         {
1738                                                                 const char *address = g_variant_get_string(value, NULL);
1739                                                                 discoveryInfo.remote_address = address?strdup(address):NULL;
1740                                                         }
1741
1742                                                         else if(!strcmp(key, "Name"))
1743                                                         {
1744                                                                 const char *name = g_variant_get_string(value, NULL);
1745                                                                 discoveryInfo.remote_name = name?strdup(name):NULL;
1746                                                         }
1747
1748                                                         else if(!strcmp(key, "Paired"))
1749                                                         {
1750                                                                 discoveryInfo.is_bonded = g_variant_get_boolean(value);
1751                                                         }
1752
1753                                                         else if(!strcmp(key, "Class"))
1754                                                         {
1755                                                                 guint32 _class = g_variant_get_uint32(value);
1756                                                                 uint8_t minor = _class & 0xff;
1757                                                                 uint8_t major = (_class >> 8) & 0xff;
1758                                                                 discoveryInfo.bt_class.minor_device_class = (bt_minor_device_class_e) minor;
1759                                                                 discoveryInfo.bt_class.major_device_class = (bt_major_device_class_e) major;
1760                                                                 //discoveryInfo.bt_class.major_service_class_mask =
1761                                                         }
1762
1763                                                         else if(!strcmp(key, "UUIDs"))
1764                                                         {
1765                                                                 GVariantIter *iter;
1766                                                                 const char *uuid = NULL;
1767                                                                 g_variant_get(value, "as", &iter);
1768                                                                 discoveryInfo.service_count = g_variant_iter_n_children(iter);
1769                                                                 discoveryInfo.service_uuid = (char**)malloc(discoveryInfo.service_count*sizeof(char*));
1770                                                                 char **uuids = discoveryInfo.service_uuid; // make a copy of ptr, since we will modify the pointer
1771                                                                 while(g_variant_iter_next(iter, "s", &uuid))
1772                                                                 {
1773                                                                         *uuids++ = uuid?strdup(uuid):NULL;
1774                                                                 }
1775                                                         }
1776                                                 }
1777
1778                                                 if(!discoveryInfo.remote_address)
1779                                                 {
1780                                                         ctx->freeDiscoveryInfo(&discoveryInfo);
1781                                                         return;
1782                                                 }
1783
1784                                                 if(!discoveryInfo.remote_name)
1785                                                 {
1786                                                         LoggerD("discovery info ... remote_name is null for " << discoveryInfo.remote_address);
1787                                                         discoveryInfo.remote_name = strdup("");
1788                                                 }
1789
1790                                                 LoggerD("Found BT device: " << discoveryInfo.remote_address << " ... " << (discoveryInfo.remote_name?discoveryInfo.remote_name:""));
1791
1792                                                 if(ctx->mUserDataList[DISCOVER_DEVICES] != NULL)
1793                                                 {
1794                                                         // requested event
1795                                                         MultiCallbackUserDataPtr callback =
1796                                                             static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[DISCOVER_DEVICES]);
1797
1798                                                         if(callback)
1799                                                         {
1800                                                                 if(!ctx->isDeviceInList(ctx->mFoundDevices, discoveryInfo.remote_address))
1801                                                                 {
1802                                                                         // create BluetoothDevice
1803                                                                         BluetoothDeviceSharedPtr device(new BluetoothDevice(&discoveryInfo, objPath));
1804                                                                         JSContextRef context = callback->getContext();
1805                                                                         JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(context, device);
1806                                                                         ctx->mFoundDevices.push_back(device);
1807
1808                                                                         // remove MAC address of found device from mDisappearedDevices
1809                                                                         for(auto iter = ctx->mDisappearedDevices.begin(); iter != ctx->mDisappearedDevices.end(); iter++)
1810                                                                         {
1811                                                                                 if(!strcmp(discoveryInfo.remote_address, (*iter).c_str()))
1812                                                                                 {
1813                                                                                         ctx->mDisappearedDevices.erase(iter);
1814                                                                                         break;
1815                                                                                 }
1816                                                                         }
1817
1818                                                                         callback->invokeCallback("ondevicefound", deviceObj);
1819                                                                 }
1820                                                         }
1821                                                 }
1822
1823                                                 ctx->freeDiscoveryInfo(&discoveryInfo);
1824                                         }
1825                                 }
1826                         }
1827                 }
1828                 else if(!strcmp(signal_name, "AdapterRemoved"))
1829                 {
1830                         const char *adapter = NULL;
1831                         g_variant_get(parameters, "(o)", &adapter);
1832                         if(adapter)
1833                         {
1834                                 LoggerD("Adapter removed: " << adapter);
1835                         }
1836                 }
1837         }
1838         else if(!strcmp(interface_name, BLUEZ_ADAPTER_IFACE))
1839         {
1840                 if(!strcmp(signal_name, "PropertyChanged"))
1841                 {
1842                         const char *name;
1843                         GVariant *var;
1844                         g_variant_get(parameters, "(sv)", &name, &var);
1845                         LoggerD("\tname=" << name);
1846                         if(!strcmp(name, "Name"))
1847                         {
1848                                 const char *_name = g_variant_get_string(var, NULL);
1849                                 ctx->onNameChanged(_name);
1850                         }
1851                         else if(!strcmp(name, "Powered"))
1852                         {
1853                                 bool powered = g_variant_get_boolean(var);
1854                                 ctx->onPoweredChanged(powered);
1855                         }
1856                         else if(!strcmp(name, "Discoverable"))
1857                         {
1858                                 bool visible = g_variant_get_boolean(var);
1859                                 ctx->onVisibilityChanged(visible);
1860                         }
1861                         else if(!strcmp(name, "Discovering"))
1862                         {
1863                                 bool discovering = g_variant_get_boolean(var);
1864                                 if(discovering)   // discovery started
1865                                 {
1866                                         MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[DISCOVER_DEVICES]);
1867                                         if(callback)
1868                                         {
1869                                                 callback->invokeCallback("onstarted");
1870                                         }
1871                                 }
1872                                 else   // discovery completed
1873                                 {
1874                                         LoggerD("Discovery completed");
1875                                         if(ctx->mUserDataList[DISCOVER_DEVICES] != NULL)
1876                                         {
1877                                                 MultiCallbackUserDataPtr callback =
1878                                                     static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[DISCOVER_DEVICES]);
1879
1880                                                 if(callback)
1881                                                 {
1882                                                         if(ctx->mDisappearedDevices.size() > 0)
1883                                                         {
1884                                                                 LoggerD("There are disappeared devices");
1885                                                                 for(auto iter = ctx->mDisappearedDevices.begin();
1886                                                                         iter != ctx->mDisappearedDevices.end(); iter++)
1887                                                                 {
1888
1889                                                                         callback->invokeCallback("ondevicedisappeared",
1890                                                                                                  JSUtil::toJSValueRef(callback->getContext(), *iter));
1891                                                                 }
1892                                                         }
1893
1894                                                         if(ctx->mFoundDevices.size() > 0)   // There are found devices
1895                                                         {
1896                                                                 LoggerD("There are found devices");
1897                                                                 int num = ctx->mFoundDevices.size();
1898                                                                 JSObjectRef devices[num];
1899                                                                 for(int i = 0; i < num; i++)
1900                                                                 {
1901                                                                         JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(callback->getContext(), ctx->mFoundDevices[i]);
1902                                                                         devices[i] = deviceObj;
1903                                                                 }
1904
1905                                                                 ctx->mUserDataList[DISCOVER_DEVICES].reset();
1906
1907                                                                 callback->invokeCallback(
1908                                                                     "onfinished",
1909                                                                     JSObjectMakeArray(callback->getContext(), num, devices, NULL) );
1910                                                         }
1911                                                         else    // There is no found device
1912                                                         {
1913                                                                 LoggerD("There is no found device");
1914                                                                 ctx->mUserDataList[DISCOVER_DEVICES].reset();
1915
1916                                                                 callback->invokeCallback(
1917                                                                     "onfinished",
1918                                                                     JSObjectMakeArray(callback->getContext(), 0, NULL, NULL) );
1919                                                         }
1920                                                 }
1921
1922                                                 Utils::removeSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_ADAPTER_IFACE, object_path, "DeviceFound");
1923
1924                                                 GError *err = NULL;
1925                                                 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1926                                                                              BLUEZ_SERVICE,
1927                                                                              ctx->mAdapterPath,
1928                                                                              BLUEZ_ADAPTER_IFACE,
1929                                                                              "StopDiscovery",
1930                                                                              NULL,
1931                                                                              NULL,
1932                                                                              G_DBUS_CALL_FLAGS_NONE,
1933                                                                              -1,
1934                                                                              NULL,
1935                                                                              &err);
1936                                                 if(err)
1937                                                         g_error_free(err);
1938                                         }
1939                                 }
1940                         }
1941                 }
1942         }
1943         /*
1944         else if(!strcmp(interface_name, CONNMAN_TECHNOLOGY_IFACE)) {
1945             if(!strcmp(signal_name, "PropertyChanged")) {
1946                 const char *name;
1947                 GVariant *value;
1948                 g_variant_get(parameters, "(sv)", &name, &value);
1949                 if(!strcmp(name, "Powered")) {
1950                     bool powered = g_variant_get_boolean(value);
1951                     ctx->onPoweredChanged(powered);
1952                 }
1953             }
1954         }
1955         */
1956 }
1957
1958 bool BluetoothAdapter::isDeviceInList(std::vector<BluetoothDeviceSharedPtr> list, const char *address)
1959 {
1960
1961         bool exists = false;
1962         for(auto iter = list.begin(); iter != list.end(); iter++)
1963         {
1964                 if(!strcmp((*iter)->getAddress().c_str(), address))
1965                 {
1966                         exists = true;
1967                         break;
1968                 }
1969         }
1970
1971         return exists;
1972 }
1973
1974 bool BluetoothAdapter::setAdapterPowered(bool value)
1975 {
1976         if(mAdapterPath)
1977         {
1978                 GError *err = NULL;
1979
1980                 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
1981                                              BLUEZ_SERVICE,
1982                                              mAdapterPath,
1983                                              "org.freedesktop.DBus.Properties",
1984                                              "Set",
1985                                              g_variant_new("(ssv)", "org.bluez.Adapter1", "Powered", g_variant_new_boolean(value)),
1986                                              NULL,
1987                                              G_DBUS_CALL_FLAGS_NONE,
1988                                              -1,
1989                                              NULL,
1990                                              &err);
1991
1992                 if(err)
1993                 {
1994                         LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);
1995                         g_error_free(err);
1996                         return false;
1997                 }
1998
1999                 return true;
2000         }
2001
2002         return false;
2003 }
2004
2005 void BluetoothAdapter::onPoweredChanged(bool powered)
2006 {
2007         mEnabled = powered;
2008
2009         if(mChangeListener != NULL)
2010         {
2011                 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mChangeListener);
2012                 if(callback)
2013                 {
2014                         JSContextRef context = callback->getContext();
2015                         JSValueRef value =  JSValueMakeBoolean(context, powered);
2016
2017                         callback->invokeCallback("onstatechanged", value);
2018                 }
2019         }
2020
2021         if(!powered && mUserDataList[DISCOVER_DEVICES] != NULL)
2022                 mUserDataList[DISCOVER_DEVICES].reset();
2023 }
2024
2025 void BluetoothAdapter::onNameChanged(const char *name)
2026 {
2027         if(mUserDataList[SET_NAME] != NULL)    // requested event
2028         {
2029                 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mUserDataList[SET_NAME]);
2030                 mUserDataList[SET_NAME].reset();
2031                 if(callback)
2032                         callback->invokeCallback("success");
2033         }
2034         else    // unexpected event
2035         {
2036                 LoggerW("Bluetooth name is changed unexpectedly");
2037         }
2038
2039         if(mChangeListener != NULL)
2040         {
2041                 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mChangeListener);
2042                 if(callback)
2043                 {
2044                         JSContextRef context = callback->getContext();
2045                         JSStringRef nameRef = JSStringCreateWithUTF8CString(name);
2046                         JSValueRef value = JSValueMakeString(context, nameRef);
2047
2048                         callback->invokeCallback("onnamechanged", value);
2049                 }
2050         }
2051 }
2052
2053 void BluetoothAdapter::onVisibilityChanged(bool visible)
2054 {
2055         if(mChangeListener != NULL)
2056         {
2057                 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mChangeListener);
2058                 if(callback)
2059                 {
2060                         JSContextRef context = callback->getContext();
2061                         JSValueRef value =  JSValueMakeBoolean(context, visible);
2062
2063                         callback->invokeCallback("onvisibilitychanged", value);
2064                 }
2065         }
2066 }
2067
2068 void BluetoothAdapter::asyncCreatePairedDeviceCallback(GObject *source, GAsyncResult *result, gpointer user_data)
2069 {
2070
2071         BluetoothAdapter *ctx = static_cast<BluetoothAdapter*>(user_data);
2072         if(!ctx)
2073         {
2074                 LoggerE("Failed to cast to BluetoothAdapter");
2075                 return;
2076         }
2077
2078         GError *err = NULL;
2079         GVariant *reply;
2080         reply = g_dbus_connection_call_finish(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), result, &err);
2081         if(err || !reply)
2082         {
2083                 LoggerE("Failed to CreatePairedDevice: " << (err?err->message:"Invalid reply"));
2084                 if(ctx->mUserDataList[CREATE_BONDING] != NULL)
2085                 {
2086                         MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[CREATE_BONDING]);
2087                         if(callback)
2088                         {
2089                                 NotFoundException *error = new NotFoundException("Failed to CreatePairedDevice");
2090                                 BluetoothCallbackUtil::syncToAsyncErrorCallback(callback, error);
2091                         }
2092                 }
2093                 if(err)
2094                         g_error_free(err);
2095         }
2096
2097         else
2098         {
2099                 LoggerE("Got reply from CreatePairedDevice");
2100                 if(ctx->mUserDataList[CREATE_BONDING] != NULL)
2101                 {
2102                         MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[CREATE_BONDING]);
2103                         if(callback)
2104                         {
2105                                 bt_device_info_s deviceInfo;
2106                                 if(ctx->getDeviceInfoByAddress(&deviceInfo, ctx->mCreateBondingAddress.c_str()))
2107                                 {
2108                                         BluetoothDeviceSharedPtr device(new BluetoothDevice(&deviceInfo));
2109                                         JSContextRef context = callback->getContext();
2110                                         JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(context, device);
2111                                         callback->invokeCallback("success", deviceObj);
2112                                 }
2113                                 else
2114                                 {
2115                                         LoggerE("CreatePairedDevice failed to get device info");
2116                                         JSContextRef context = callback->getContext();
2117                                         UnknownException error("Failed to get device info");
2118                                         callback->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
2119                                 }
2120                                 ctx->freeDeviceInfo(&deviceInfo);
2121                         }
2122                 }
2123         }
2124
2125         ctx->mCreateBondingAddress.clear();
2126         ctx->mUserDataList[CREATE_BONDING].reset();
2127
2128         g_variant_unref(reply);
2129 }
2130
2131 bool BluetoothAdapter::setupAgent(const char *agent)
2132 {
2133         GVariant *reply;
2134
2135         if(!agent)
2136         {
2137                 LoggerE("Invalid agent path");
2138                 return false;
2139         }
2140
2141         GError *err = NULL;
2142
2143         if(mAgentRegistrationId > 0)   // already registered
2144         {
2145                 LoggerE("Bluez agent for pairing already registered ... possibly not Released after previous pairing");
2146
2147                 // unregister Agent
2148                 bool unregistered = g_dbus_connection_unregister_object(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), mAgentRegistrationId);
2149                 if(unregistered)
2150                         mAgentRegistrationId = -1;
2151         }
2152
2153         reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
2154                                              BLUEZ_SERVICE,
2155                                              "/org/bluez",
2156                                              "org.bluez.AgentManager1",
2157                                              "RegisterAgent",
2158                                              g_variant_new("(ss)", agent, ""),
2159                                              NULL,
2160                                              G_DBUS_CALL_FLAGS_NONE,
2161                                              -1,
2162                                              NULL,
2163                                              &err);
2164
2165         if(err)
2166         {
2167                 LoggerE("Failed to register object: " << agent << " : " << err->message);
2168                 g_error_free(err);
2169                 return false;
2170         }
2171
2172
2173         GVariant *value;
2174         g_variant_get(reply, "(i)", &value);
2175         mAgentRegistrationId = g_variant_get_int16(value);
2176
2177         LoggerE("object registered with id=" << mAgentRegistrationId);
2178
2179         return true;
2180 }
2181
2182 void BluetoothAdapter::agentHandleMethodCall( GDBusConnection       *connection,
2183         const gchar           *sender,
2184         const gchar           *object_path,
2185         const gchar           *interface_name,
2186         const gchar           *method_name,
2187         GVariant              *parameters,
2188         GDBusMethodInvocation *invocation,
2189         gpointer               user_data)
2190 {
2191
2192         LoggerD("entered\n\tsender=" << sender << "\n\tobject_path=" << object_path << "\n\tinterface_name=" << interface_name << "\n\tmethod_name=" << method_name);
2193
2194         BluetoothAdapter *ctx = static_cast<BluetoothAdapter*>(user_data);
2195         if(!ctx)
2196         {
2197                 LoggerD("Failed to cast to BluetoothAdapter");
2198                 g_dbus_method_invocation_return_value(invocation, NULL);
2199                 return;
2200         }
2201
2202         if(!strcmp(method_name, "Authorize"))
2203         {
2204                 g_dbus_method_invocation_return_value(invocation, NULL);
2205         }
2206         else if(!strcmp(method_name, "RequestPinCode"))
2207         {
2208                 g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", PINCODE));
2209         }
2210         else if(!strcmp(method_name, "RequestPasskey"))
2211         {
2212                 g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", PASSKEY));
2213         }
2214         else if (!strcmp(method_name, "Release"))
2215         {
2216                 if(!strcmp(object_path, AGENT_PATH))   // released agent for pairing
2217                 {
2218                         bool unregistered = g_dbus_connection_unregister_object(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), ctx->mAgentRegistrationId);
2219                         if(unregistered)
2220                                 ctx->mAgentRegistrationId = -1;
2221                 }
2222                 g_dbus_method_invocation_return_value(invocation, NULL);
2223         }
2224         else
2225         {
2226                 // DisplayPasskey, DisplayPinCode, RequestConfirmation, ConfirmModeChange, Cancel
2227                 g_dbus_method_invocation_return_value(invocation, NULL);
2228         }
2229 }
2230
2231 bool BluetoothAdapter::isDevicePaired(const char *device)
2232 {
2233
2234         if(!device)
2235                 return false;
2236
2237         // get device properties and check if it's Paired
2238         GError *err = NULL;
2239         GVariant *reply = NULL;
2240         reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
2241                                              BLUEZ_SERVICE,
2242                                              device,
2243                                              "org.freedesktop.DBus.Properties",
2244                                              "Get",
2245                                              g_variant_new("(ss)", "org.bluez.Device1", "Paired"),
2246                                              NULL,
2247                                              G_DBUS_CALL_FLAGS_NONE,
2248                                              -1,
2249                                              NULL,
2250                                              &err);
2251
2252         if(err || !reply)
2253         {
2254                 if(err)
2255                         g_error_free(err);
2256                 return false;
2257         }
2258
2259         bool paired = false;
2260         GVariant *value;
2261         g_variant_get(reply, "(v)", &value);
2262         paired = g_variant_get_boolean(value);
2263
2264         g_variant_unref(reply);
2265
2266         return paired;
2267 }
2268
2269 bool BluetoothAdapter::getDeviceInfoByAddress(bt_device_info_s *deviceInfo, const char *address)
2270 {
2271
2272         // to assure that when leaving the method, these fields
2273         // will be either set/allocated, or NULL
2274         deviceInfo->remote_name = NULL;
2275         deviceInfo->remote_address = NULL;
2276         deviceInfo->service_uuid = NULL;
2277         deviceInfo->service_count = 0;
2278
2279         if(!deviceInfo || !address)
2280                 return false;
2281
2282         if(!mAdapterPath)
2283                 return false;
2284
2285         std::string addressStr = std::string(address);
2286         char* device = getDeviceFromAddress(addressStr);
2287
2288         if(!device)
2289         {
2290                 LoggerE("Failed to find " << address << " device: trying again");
2291                 return false;
2292         }
2293
2294         bool success = false;
2295
2296         if(device)
2297         {
2298                 success = getDeviceInfo(deviceInfo, device);
2299         }
2300
2301         return success;
2302 }
2303
2304 // don't forget to free memory of remote_name and remote_address
2305 bool BluetoothAdapter::getDeviceInfo(bt_device_info_s *deviceInfo, const char *device)
2306 {
2307
2308         // to assure that when leaving the method, these fields
2309         // will be either set/allocated, or NULL
2310         deviceInfo->remote_name = NULL;
2311         deviceInfo->remote_address = NULL;
2312         deviceInfo->service_uuid = NULL;
2313         deviceInfo->service_count = 0;
2314
2315         if(!deviceInfo || !device)
2316                 return false;
2317
2318         GError *err = NULL;
2319         GVariant *reply = NULL;
2320         reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
2321                                              BLUEZ_SERVICE,
2322                                              device,
2323                                              "org.freedesktop.DBus.Properties",
2324                                              "GetAll",
2325                                              g_variant_new("(s)", "org.bluez.Device1"),
2326                                              NULL,
2327                                              G_DBUS_CALL_FLAGS_NONE,
2328                                              -1,
2329                                              NULL,
2330                                              &err);
2331
2332         if(err || !reply)
2333         {
2334                 LoggerE("Failed to 'GetAll': " << err->message);
2335                 if(err)
2336                         g_error_free(err);
2337                 return false;
2338         }
2339
2340         GVariantIter *iter;
2341         g_variant_get(reply, "(a{sv})", &iter);
2342         const char *key;
2343         GVariant *value;
2344         while(g_variant_iter_next(iter, "{sv}", &key, &value))
2345         {
2346                 //LoggerD("KEY: " << key);
2347                 if(!strcmp(key, "Name"))
2348                 {
2349                         const char *name = g_variant_get_string(value, NULL);
2350                         deviceInfo->remote_name = strdup(name);
2351                 }
2352                 else if(!strcmp(key, "Address"))
2353                 {
2354                         const char *address = g_variant_get_string(value, NULL);
2355                         deviceInfo->remote_address = strdup(address);
2356                 }
2357                 else if(!strcmp(key, "Paired"))
2358                 {
2359                         deviceInfo->is_bonded = g_variant_get_boolean(value);
2360                 }
2361                 else if(!strcmp(key, "Connected"))
2362                 {
2363                         deviceInfo->is_connected = g_variant_get_boolean(value);
2364                 }
2365                 else if(!strcmp(key, "Trusted"))
2366                 {
2367                         deviceInfo->is_authorized = g_variant_get_boolean(value);
2368                 }
2369                 else if(!strcmp(key, "Class"))
2370                 {
2371                         guint32 _class = g_variant_get_uint32(value);
2372                         uint8_t minor = _class & 0xff;
2373                         uint8_t major = (_class >> 8) & 0xff;
2374                         deviceInfo->bt_class.minor_device_class = (bt_minor_device_class_e) minor;
2375                         deviceInfo->bt_class.major_device_class = (bt_major_device_class_e) major;
2376                         //deviceInfo->bt_class.major_service_class_mask =
2377                 }
2378                 else if(!strcmp(key, "UUIDs"))
2379                 {
2380                         GVariantIter *iter;
2381                         const char *uuid = NULL;
2382                         g_variant_get(value, "as", &iter);
2383                         deviceInfo->service_count = g_variant_iter_n_children(iter);
2384                         deviceInfo->service_uuid = (char**)malloc(deviceInfo->service_count*sizeof(char*));
2385                         char **uuids = deviceInfo->service_uuid; // make a copy of ptr, since we will modify the pointer
2386                         while(g_variant_iter_next(iter, "s", &uuid))
2387                         {
2388                                 *uuids++ = uuid?strdup(uuid):NULL;
2389                         }
2390                 }
2391         }
2392
2393         g_variant_unref(reply);
2394
2395         return true;
2396 }
2397
2398 // frees allocated memory by its members
2399 // Doesn't free/delete deviceInfo itself
2400 void BluetoothAdapter::freeDeviceInfo(bt_device_info_s *deviceInfo)
2401 {
2402
2403         if(!deviceInfo)
2404                 return;
2405
2406         free(deviceInfo->remote_address);
2407         free(deviceInfo->remote_name);
2408         for(int i=0; i<deviceInfo->service_count; i++)
2409         {
2410                 free(deviceInfo->service_uuid[i]);
2411         }
2412         free(deviceInfo->service_uuid);
2413 }
2414
2415 // frees allocated memory by its members
2416 // Doesn't free/delete discoveryInfo itself
2417 void BluetoothAdapter::freeDiscoveryInfo(bt_adapter_device_discovery_info_s *discoveryInfo)
2418 {
2419
2420         if(!discoveryInfo)
2421                 return;
2422
2423         free(discoveryInfo->remote_address);
2424         free(discoveryInfo->remote_name);
2425         for(int i=0; i<discoveryInfo->service_count; i++)
2426         {
2427                 free(discoveryInfo->service_uuid[i]);
2428         }
2429         free(discoveryInfo->service_uuid);
2430 }
2431
2432 bool BluetoothAdapter::removeDevice(const char *address)
2433 {
2434
2435         if(!address)
2436                 return false;
2437
2438         if(!mAdapterPath)
2439                 return false;
2440
2441         std::string addressStr = std::string(address);
2442         char* device = getDeviceFromAddress(addressStr);
2443
2444         if(!device)
2445         {
2446                 LoggerE("Failed to find " << address << " device:");
2447                 return false;
2448         }
2449
2450         // now we can remove the device
2451
2452         GError *err = NULL;
2453         bool success = true;
2454         if(device)
2455         {
2456                 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
2457                                              BLUEZ_SERVICE,
2458                                              mAdapterPath,
2459                                              BLUEZ_ADAPTER_IFACE,
2460                                              "RemoveDevice",
2461                                              g_variant_new("(o)", device), // floating variants are consumed
2462                                              NULL,
2463                                              G_DBUS_CALL_FLAGS_NONE,
2464                                              -1,
2465                                              NULL,
2466                                              &err);
2467                 if(err)
2468                 {
2469                         LoggerE("Failed to 'RemoveDevice': " << err->message);
2470                         g_error_free(err);
2471                         success = false;
2472                 }
2473         }
2474
2475         LoggerD("removed device : " << device);
2476
2477         return success;
2478 }
2479
2480 // CONNMAN
2481 char *BluetoothAdapter::getBluetoothTechnology()
2482 {
2483
2484         GError *err = NULL;
2485         GVariant *reply = NULL;
2486         reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
2487                                              CONNMAN_SERVICE,
2488                                              "/",
2489                                              CONNMAN_MANAGER_IFACE,
2490                                              "GetTechnologies",
2491                                              NULL,
2492                                              NULL,
2493                                              G_DBUS_CALL_FLAGS_NONE,
2494                                              -1,
2495                                              NULL,
2496                                              &err);
2497
2498         if(err || !reply)
2499         {
2500                 LoggerE("Failed to call 'GetTechnologies' DBUS method: " << (err?err->message:"reply is null"));
2501                 if(err)
2502                         g_error_free(err);
2503                 return NULL;
2504         }
2505
2506         char *technology = NULL, *result = NULL;
2507         GVariantIter *props = NULL;
2508         GVariantIter *technologies = NULL;
2509         g_variant_get(reply, "(a(oa{sv}))", &technologies);
2510         while(g_variant_iter_next(technologies, "(oa{sv})", &technology, &props))
2511         {
2512                 if(technology && strstr(technology, "bluetooth"))
2513                 {
2514                         result = strdup(technology);
2515                         /*
2516                         // get the current Powered state
2517                         const char *key;
2518                         GVariant *value;
2519                         while(g_variant_iter_next(props, "{sv}", &key, &value)) {
2520                             if(!strcmp(key, "Powered")) {
2521                                 bool powered = g_variant_get_boolean(value);
2522                                 mEnabled = powered;
2523                                 LoggerD("Bluetooth is initially Powered " << (powered?"ON":"OFF"));
2524                                 break;
2525                             }
2526                         }
2527                         */
2528                         break;
2529                 }
2530         }
2531
2532         g_variant_unref(reply);
2533         LoggerD("getTech result = " << result);
2534         return result;
2535 }
2536
2537 bool BluetoothAdapter::setBluetoothPowered(bool value)
2538 {
2539
2540         if(mBluetoothTechnology)
2541         {
2542                 GError *err = NULL;
2543                 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
2544                                              CONNMAN_SERVICE,
2545                                              mBluetoothTechnology,
2546                                              CONNMAN_TECHNOLOGY_IFACE,
2547                                              "SetProperty",
2548                                              g_variant_new ("(sv)", // floating parameters are consumed, no cleanup/unref needed
2549                                                      "Powered",
2550                                                      g_variant_new_boolean(value)
2551                                                            ),
2552                                              NULL,
2553                                              G_DBUS_CALL_FLAGS_NONE,
2554                                              -1,
2555                                              NULL,
2556                                              &err);
2557
2558                 if(err)
2559                 {
2560                         if((value  && strstr(err->message, "Already enabled")) || // it's not an error, 'casue the BT is already Powered ON
2561                                 (!value && strstr(err->message, "Already disabled")))  // it's not an error, 'cause the BT is already Powered OFF
2562                         {
2563                                 g_error_free(err);
2564                                 return true;
2565                         }
2566                         LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);
2567                         g_error_free(err);
2568                         return false;
2569                 }
2570
2571                 return true;
2572         }
2573
2574         return false;
2575 }
2576
2577 } // Bluetooth
2578 } // DeviceAPI
2579