2 Situare - A location system for Facebook
3 Copyright (C) 2010 Ixonos Plc. Authors:
5 Henri Lampela - henri.lampela@ixonos.com
6 Sami Rämö - sami.ramo@ixonos.com
8 Situare is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 version 2 as published by the Free Software Foundation.
12 Situare is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Situare; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
25 #include <QStringList>
26 #include <QNetworkReply>
28 #include <QCryptographicHash>
30 #if defined(Q_WS_MAEMO_5) & defined(ARMEL)
31 #include <QDBusInterface>
32 #include <QDBusMessage>
36 #include "network/networkaccessmanager.h"
40 #include "routesegment.h"
42 #include "routingservice.h"
44 // defines for IMEI retrieval via dbus
45 #define SIM_DBUS_SERVICE "com.nokia.phone.SIM"
46 #define SIM_DBUS_PATH "/com/nokia/phone/SIM/security"
47 #define SIM_DBUS_IFACE "Phone.Sim.Security"
48 #define SIM_IMEI_REQ "get_imei"
50 const int NO_ERROR = 0;
53 const QString CLOUDMADE_AUTH_PART = "http://auth.cloudmade.com/token/";
54 const QString CLOUDMADE_API_KEY = "0cea0072adbf42ce823f4c78b974f12d";
57 const QString GEOCODE = "http://maps.google.com/maps/api/geocode/json?address=";
60 RoutingService::RoutingService(QObject *parent)
63 qDebug() << __PRETTY_FUNCTION__;
65 m_pendingRequest.clear();
68 m_networkManager = new NetworkAccessManager(this);
69 connect(m_networkManager, SIGNAL(finished(QNetworkReply*)),
70 this, SLOT(requestFinished(QNetworkReply*)), Qt::QueuedConnection);
74 void RoutingService::parseRouteData(const QByteArray &jsonReply)
76 qDebug() << __PRETTY_FUNCTION__;
80 QVariantMap result = parser.parse (jsonReply, &ok).toMap();
82 emit error(ErrorContext::SITUARE, SituareError::INVALID_JSON);
85 if(result.value("status").toInt() == NO_ERROR) {
86 QVariant routeSummary = result.value("route_summary");
87 QMap<QString, QVariant> routeSummaryMap = routeSummary.toMap();
90 route.setEndPointName(routeSummaryMap["end_point"].toString());
91 route.setStartPointName(routeSummaryMap["start_point"].toString());
92 route.setTotalDistance(routeSummaryMap["total_distance"].toInt());
93 route.setTotalTime(routeSummaryMap["total_time"].toInt());
95 foreach(QVariant routeGeometry, result["route_geometry"].toList()) {
96 QStringList list = routeGeometry.toStringList();
97 route.appendGeometryPoint(QPointF(list.at(1).toDouble(), list.at(0).toDouble()));
100 foreach(QVariant routeInstructions, result["route_instructions"].toList()) {
101 QStringList list = routeInstructions.toStringList();
102 RouteSegment segment;
103 segment.setInstruction(list.at(0));
104 segment.setLength(list.at(1).toDouble());
105 segment.setPositionIndex(list.at(2).toInt());
106 segment.setTime(list.at(3).toInt());
107 segment.setLengthCaption(list.at(4));
108 segment.setEarthDirection(list.at(5));
109 segment.setAzimuth(list.at(6).toDouble());
110 if (list.count() == 8) {
111 segment.setTurnType(list.at(7));
112 segment.setTurnAngle(list.at(8).toDouble());
114 route.appendSegment(segment);
117 emit routeParsed(route);
122 void RoutingService::parseSearchResults(const QByteArray &jsonReply)
124 qDebug() << __PRETTY_FUNCTION__;
126 const QString NO_DATA = "ZERO_RESULTS";
128 m_searchResults.clear();
130 QJson::Parser parser;
132 QVariantMap result = parser.parse (jsonReply, &ok).toMap();
134 emit error(ErrorContext::SITUARE, SituareError::INVALID_JSON);
137 if(result.value("status") != NO_DATA) {
138 foreach(QVariant hitVariant, result["results"].toList()) {
140 QMap<QString, QVariant> hitMap = hitVariant.toMap();
141 foreach(QVariant hitTypeVariant, hitMap["types"].toList()) {
142 QStringList hitTypeList = hitTypeVariant.toStringList();
143 foreach(QString hitType, hitTypeList) {
144 if(hitType != "political")
145 location.setLocationType(hitType);
148 location.setFormattedAddress(hitMap["formatted_address"].toString());
149 foreach(QVariant addrComponent, hitMap["address_components"].toList()) {
150 QMap<QString, QVariant> addrComponentMap = addrComponent.toMap();
151 foreach(QVariant addrType, addrComponentMap["types"].toList()) {
152 QStringList addrTypeList = addrType.toStringList();
153 foreach(QString type, addrTypeList) {
154 if(type == "street_number")
155 location.setStreetNumber(addrComponentMap["long_name"].toInt());
156 else if(type == "route")
157 location.setStreet(addrComponentMap["long_name"].toString());
158 else if(type == "locality")
159 location.setLocality(addrComponentMap["long_name"].toString());
160 else if(type == "country")
161 location.setCountry(addrComponentMap["long_name"].toString());
162 else if(type == "postal_code")
163 location.setPostalCode(addrComponentMap["long_name"].toInt());
167 QVariant geometryVariant = hitMap["geometry"];
168 QMap<QString, QVariant> geometryMap = geometryVariant.toMap();
169 QVariant locationVariant = geometryMap["location"];
170 QMap<QString, QVariant> locationMap = locationVariant.toMap();
171 location.setCoordinates(locationMap["lat"].toDouble(),
172 locationMap["lng"].toDouble());
174 m_searchResults.append(location);
176 emit locationDataParsed(m_searchResults);
181 void RoutingService::requestAuthorizationToken()
183 qDebug() << __PRETTY_FUNCTION__;
185 // create token request of format: http://auth.cloudmade.com/token/APIKEY?userid=UserID
186 // where APIKEY is our application specific key and userID is md5 hashed value of IMEI code
187 QString url = CLOUDMADE_AUTH_PART;
188 url.append(CLOUDMADE_API_KEY);
189 QString uidPart = "?userid=";
193 // get the device IMEI code
194 QDBusInterface interface(SIM_DBUS_SERVICE, SIM_DBUS_PATH, SIM_DBUS_IFACE,
195 QDBusConnection::systemBus());
197 QDBusMessage reply = interface.call(SIM_IMEI_REQ);
198 if (reply.type() == QDBusMessage::ErrorMessage)
199 qDebug() << reply.errorMessage();
201 QList<QVariant> args = reply.arguments();
202 qDebug() << QString("Phone's IMEI: %1").arg(args.at(0).toString());
203 rawData = args.at(0).toByteArray();
206 // for desktop we need to use login name
207 rawData.append(system("whoami"));
210 QCryptographicHash crypto(QCryptographicHash::Md5);
211 crypto.addData(rawData);
212 uidPart.append(crypto.result().toHex());
218 void RoutingService::requestFinished(QNetworkReply *reply)
220 qDebug() << __PRETTY_FUNCTION__;
222 if (m_currentRequests.contains(reply)) {
224 QByteArray replyArray = reply->readAll();
225 qDebug() << "Reply from: " << reply->url() << "reply " << replyArray;
227 if (reply->error()) {
228 emit error(ErrorContext::NETWORK, reply->error());
229 } else if(reply->url().toString().contains(CLOUDMADE_AUTH_PART)) {
230 m_token = replyArray;
231 m_pendingRequest.append(m_token);
232 sendRequest(m_pendingRequest);
233 m_pendingRequest.clear();
234 } else if(reply->url().toString().contains(GEOCODE)) {
235 parseSearchResults(replyArray);
237 parseRouteData(replyArray);
240 m_currentRequests.removeAll(reply);
241 reply->deleteLater();
245 void RoutingService::requestLocation(QString location)
247 qDebug() << __PRETTY_FUNCTION__;
249 const QString urlEnd = "&sensor=false";
251 QString url = GEOCODE;
252 url.append(location);
258 void RoutingService::requestRoute(QPointF from, QPointF to)
260 qDebug() << __PRETTY_FUNCTION__;
262 QString url = "http://routes.cloudmade.com/";
263 url.append(CLOUDMADE_API_KEY);
264 url.append("/api/0.3/");
265 url.append(QString::number(from.x()) + "," + QString::number(from.y()) + ",");
266 url.append(QString::number(to.x()) + "," + QString::number(to.y()));
267 url.append("/car/fastest.js?lang=en&units=km&token=");
269 if(m_token.isEmpty()) {
270 m_pendingRequest.append(url);
271 requestAuthorizationToken();
274 sendRequest(QUrl(url));
278 void RoutingService::sendRequest(const QUrl &url)
280 qDebug() << __PRETTY_FUNCTION__;
282 QNetworkRequest request;
285 request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
288 QNetworkReply *reply = m_networkManager->post(request, ba, false);
290 m_currentRequests.append(reply);