diff --git a/headers/private/shared/Geolocation.h b/headers/private/shared/Geolocation.h new file mode 100644 index 0000000000..8641a54cf0 --- /dev/null +++ b/headers/private/shared/Geolocation.h @@ -0,0 +1,29 @@ +/* + * Copyright 2014, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _GEOLOCATION_H +#define _GEOLOCATION_H + + +#include + + +class BGeolocation { +public: + BGeolocation(); + BGeolocation(const BUrl& service); + + status_t LocateSelf(float& latitude, float& longitude); + status_t Locate(const BString placeName, float& latitude, + float& longitude); + status_t Name(const float latitude, const float longitude, + BString& name); + +private: + BUrl fService; + static const BUrl kDefaultService; +}; + + +#endif diff --git a/src/kits/network/libnetapi/Geolocation.cpp b/src/kits/network/libnetapi/Geolocation.cpp new file mode 100644 index 0000000000..d459e43de9 --- /dev/null +++ b/src/kits/network/libnetapi/Geolocation.cpp @@ -0,0 +1,139 @@ +/* + * Copyright 2014, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +BGeolocation::BGeolocation() + : fService(kDefaultService) +{ +} + + +BGeolocation::BGeolocation(const BUrl& service) + : fService(service) +{ +} + + +status_t +BGeolocation::LocateSelf(float& latitude, float& longitude) +{ + // Enumerate wifi network and build JSON message + BNetworkRoster& roster = BNetworkRoster::Default(); + uint32 interfaceCookie = 0; + BNetworkInterface interface; + + BString query("{\"wifiAccessPoints\":["); + int32 count = 0; + + while (roster.GetNextInterface(&interfaceCookie, interface) == B_OK) { + uint32 networkCookie = 0; + wireless_network network; + + BNetworkDevice device(interface.Name()); + // TODO is that the correct way to enumerate devices? + + while (device.GetNextNetwork(networkCookie, network) == B_OK) { + if (count != 0) + query += ';'; + + count++; + + query += "\n{\"macAddress\":\""; + query += network.address.ToString().ToUpper(); + query += "\", \"signalStrength\":"; + query << (int)network.signal_strength; + query += ", \"signalToNoiseRatio\":"; + query << (int)network.noise_level; + query += '}'; + } + + } + + query += "]}"; + + // Check that we have enough data (we need at least 2 networks) + if (count < 2) + return B_DEVICE_NOT_FOUND; + + class GeolocationListener: public BUrlProtocolListener + { + public: + virtual ~GeolocationListener() {}; + + void DataReceived(BUrlRequest*, const char* data, off_t position, + ssize_t size) { + result.WriteAt(position, data, size); + } + BMallocIO result; + }; + + GeolocationListener listener; + + // Send Request (POST JSON message) + BUrlRequest* request = BUrlProtocolRoster::MakeRequest(fService, &listener); + if (request == NULL) + return B_BAD_DATA; + + BHttpRequest* http = dynamic_cast(request); + if (http == NULL) { + delete request; + return B_BAD_DATA; + } + + BMemoryIO* io = new BMemoryIO(query.String(), query.Length()); + http->AdoptInputData(io, query.Length()); + + status_t result = http->Run(); + if (result < 0) { + delete http; + return result; + } + + while (http->IsRunning()) + snooze(10000); + + // Parse reply + const BHttpResult& reply = (const BHttpResult&)http->Result(); + if (reply.StatusCode() != 200) { + delete http; + return B_ERROR; + } + + BMessage data; + result = BJson::Parse(data, (char*)listener.result.Buffer()); + delete http; + if (result != B_OK) { + return result; + } + + BMessage location; + result = data.FindMessage("location", &location); + if(result != B_OK) + return result; + + BString lat = location.FindString("latitude"); + BString lon = location.FindString("longitude"); + + latitude = strtof(lat.String(), NULL); + longitude = strtof(lon.String(), NULL); + + return B_OK; +} + + +const BUrl BGeolocation::kDefaultService = BUrl( + "http://openbmap.org/api/json.php5"); diff --git a/src/kits/network/libnetapi/Jamfile b/src/kits/network/libnetapi/Jamfile index 47647009d8..2f8fc3c6e7 100644 --- a/src/kits/network/libnetapi/Jamfile +++ b/src/kits/network/libnetapi/Jamfile @@ -56,6 +56,14 @@ for architectureObject in [ MultiArchSubDirSetup ] { Socket.cpp SecureSocket.cpp + # TODO: another add-on for file:// (a much simpler one) + FileRequest.cpp + + Geolocation.cpp + + # TODO: another add-on for gopher:// + GopherRequest.cpp + # TODO: The HTTP stuff should all go into an add-on. It needs # linking against libcrypto.so and only the add-on should link # against it. @@ -67,12 +75,6 @@ for architectureObject in [ MultiArchSubDirSetup ] { HttpResult.cpp HttpTime.cpp - # TODO: another add-on for file:// (a much simpler one) - FileRequest.cpp - - # TODO: another add-on for gopher:// - GopherRequest.cpp - notifications.cpp $(md5Sources) diff --git a/src/tests/kits/net/service/GeolocationTest.cpp b/src/tests/kits/net/service/GeolocationTest.cpp new file mode 100644 index 0000000000..8863b865ab --- /dev/null +++ b/src/tests/kits/net/service/GeolocationTest.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2014, Haiku, inc. + * Distributed under the terms of the MIT licence + */ + + +#include "GeolocationTest.h" + +#include + +#include +#include + + +GeolocationTest::GeolocationTest() +{ +} + + +void +GeolocationTest::TestLocateSelf() +{ + BGeolocation locator; + float latitude, longitude; + status_t result = locator.LocateSelf(latitude, longitude); + + CPPUNIT_ASSERT_EQUAL(B_OK, result); + printf("Your position is: %f %f\n", latitude, longitude); +} + + +/* static */ void +GeolocationTest::AddTests(BTestSuite& parent) +{ + CppUnit::TestSuite& suite = *new CppUnit::TestSuite("GeolocationTest"); + + suite.addTest(new CppUnit::TestCaller( + "GeolocationTest::LocateSelf", &GeolocationTest::TestLocateSelf)); + + parent.addTest("GeolocationTest", &suite); +}; diff --git a/src/tests/kits/net/service/GeolocationTest.h b/src/tests/kits/net/service/GeolocationTest.h new file mode 100644 index 0000000000..271412aee7 --- /dev/null +++ b/src/tests/kits/net/service/GeolocationTest.h @@ -0,0 +1,23 @@ +/* + * Copyright 2014 Haiku, inc. + * Distributed under the terms of the MIT License. + */ +#ifndef GEOLOCATION_TEST_H +#define GEOLOCAITON_TEST_H + + +#include +#include + + +class GeolocationTest: public BTestCase { +public: + GeolocationTest(); + + void TestLocateSelf(); + + static void AddTests(BTestSuite& suite); +}; + + +#endif diff --git a/src/tests/kits/net/service/Jamfile b/src/tests/kits/net/service/Jamfile index 0902bdc05f..3ab1c87bf3 100644 --- a/src/tests/kits/net/service/Jamfile +++ b/src/tests/kits/net/service/Jamfile @@ -1,10 +1,13 @@ SubDir HAIKU_TOP src tests kits net service ; +UsePrivateHeaders private shared ; + UnitTestLib servicekittest.so : ServiceKitTestAddon.cpp CookieTest.cpp DataTest.cpp + GeolocationTest.cpp HttpTest.cpp UrlTest.cpp diff --git a/src/tests/kits/net/service/ServiceKitTestAddon.cpp b/src/tests/kits/net/service/ServiceKitTestAddon.cpp index d79c8d5f89..d25f2150e5 100644 --- a/src/tests/kits/net/service/ServiceKitTestAddon.cpp +++ b/src/tests/kits/net/service/ServiceKitTestAddon.cpp @@ -9,6 +9,7 @@ #include "CookieTest.h" #include "DataTest.h" +#include "GeolocationTest.h" #include "HttpTest.h" #include "UrlTest.h" @@ -22,6 +23,7 @@ getTestSuite() UrlTest::AddTests(*suite); HttpTest::AddTests(*suite); DataTest::AddTests(*suite); + GeolocationTest::AddTests(*suite); return suite; }