backup for routing authorizing
[situare] / src / routing / routingservice.cpp
1 /*
2    Situare - A location system for Facebook
3    Copyright (C) 2010  Ixonos Plc. Authors:
4
5       Henri Lampela - henri.lampela@ixonos.com
6       Sami Rämö - sami.ramo@ixonos.com
7
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.
11
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.
16
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,
20    USA.
21 */
22
23 #include <QDebug>
24 #include <QtGlobal>
25 #include <QStringList>
26 #include <QNetworkReply>
27 #include <QPointF>
28 #include <QCryptographicHash>
29
30 #if defined(Q_WS_MAEMO_5) & defined(ARMEL)
31 #include <QDBusInterface>
32 #include <QDBusMessage>
33 #endif
34
35 #include "common.h"
36 #include "network/networkaccessmanager.h"
37 #include "parser.h"
38 #include "route.h"
39 #include "routesegment.h"
40
41 #include "routingservice.h"
42
43 // defines for IMEI retrieval via dbus
44 #define SIM_DBUS_SERVICE  "com.nokia.phone.SIM"
45 #define SIM_DBUS_PATH     "/com/nokia/phone/SIM/security"
46 #define SIM_DBUS_IFACE    "Phone.Sim.Security"
47 #define SIM_IMEI_REQ      "get_imei"
48
49 const int NO_ERROR = 0;
50
51 // cloudmade
52 const QString CLOUDMADE_AUTH_PART = "http://auth.cloudmade.com/token/";
53 const QString CLOUDMADE_API_KEY = "0cea0072adbf42ce823f4c78b974f12d";
54
55
56 RoutingService::RoutingService(QObject *parent)
57         : QObject(parent)
58 {
59     qDebug() << __PRETTY_FUNCTION__;
60
61     m_pendingRequest.clear();
62     m_token.clear();
63
64     m_networkManager = NetworkAccessManager::instance();
65     connect(m_networkManager, SIGNAL(finished(QNetworkReply*)),
66             this, SLOT(requestFinished(QNetworkReply*)), Qt::QueuedConnection);
67
68 }
69
70 RoutingService::~RoutingService()
71 {
72     qDebug() << __PRETTY_FUNCTION__;
73 }
74
75 void RoutingService::parseRouteData(const QByteArray &jsonReply)
76 {
77     qDebug() << __PRETTY_FUNCTION__;
78
79     qWarning() << __PRETTY_FUNCTION__ << jsonReply;
80
81     QJson::Parser parser;
82     bool ok;
83     QVariantMap result = parser.parse (jsonReply, &ok).toMap();
84     if (!ok) {
85         emit error(ErrorContext::SITUARE, SituareError::INVALID_JSON);
86         return;
87     } else {
88         if(result.value("status").toInt() == NO_ERROR) {
89             QVariant routeSummary = result.value("route_summary");
90             QMap<QString, QVariant> routeSummaryMap = routeSummary.toMap();
91
92             Route route;
93             route.setEndPointName(routeSummaryMap["end_point"].toString());
94             route.setStartPointName(routeSummaryMap["start_point"].toString());
95             route.setTotalDistance(routeSummaryMap["total_distance"].toInt());
96             route.setTotalTime(routeSummaryMap["total_time"].toInt());
97
98             foreach(QVariant routeGeometry, result["route_geometry"].toList()) {
99                 QStringList list = routeGeometry.toStringList();
100                 route.appendGeometryPoint(QPointF(list.at(1).toDouble(), list.at(0).toDouble()));
101             }
102
103             foreach(QVariant routeInstructions, result["route_instructions"].toList()) {
104                 QStringList list = routeInstructions.toStringList();
105                 RouteSegment segment;
106                 segment.setInstruction(list.at(0));
107                 segment.setLength(list.at(1).toDouble());
108                 segment.setPositionIndex(list.at(2).toInt());
109                 segment.setTime(list.at(3).toInt());
110                 segment.setLengthCaption(list.at(4));
111                 segment.setEarthDirection(list.at(5));
112                 segment.setAzimuth(list.at(6).toDouble());
113                 if (list.count() == 8) {
114                     segment.setTurnType(list.at(7));
115                     segment.setTurnAngle(list.at(8).toDouble());
116                 }
117                 route.appendSegment(segment);
118             }
119
120             emit routeParsed(route);
121         }
122     }
123 }
124
125 void RoutingService::requestAuthorizationToken()
126 {
127     qWarning() << __PRETTY_FUNCTION__;
128
129     // create token request of format: http://auth.cloudmade.com/token/APIKEY?userid=UserID
130     // where APIKEY is our application specific key and userID is md5 hashed value of IMEI code
131     QString url = CLOUDMADE_AUTH_PART;
132     url.append(CLOUDMADE_API_KEY);
133     QString uidPart = "?userid=";
134     QByteArray rawData;
135
136 #ifdef Q_WS_MAEMO_5
137     // get the device IMEI code
138     QDBusInterface interface(SIM_DBUS_SERVICE, SIM_DBUS_PATH, SIM_DBUS_IFACE,
139                              QDBusConnection::systemBus());
140
141     QDBusMessage reply = interface.call(SIM_IMEI_REQ);
142     if (reply.type() == QDBusMessage::ErrorMessage)
143         qDebug() << reply.errorMessage();
144     else {
145         QList<QVariant> args = reply.arguments();
146         qWarning() << QString("Phone's IMEI: %1").arg(args.at(0).toString());
147         rawData = args.at(0).toByteArray();
148     }
149 #else
150     // for desktop we need to use login name
151     rawData.append(system("whoami"));
152 #endif
153
154     QCryptographicHash crypto(QCryptographicHash::Md5);
155     crypto.addData(rawData);
156     uidPart.append(crypto.result().toHex());
157
158     url.append(uidPart);
159     sendRequest(url);
160 }
161
162 void RoutingService::requestFinished(QNetworkReply *reply)
163 {
164     qWarning() << __PRETTY_FUNCTION__;
165
166     if (m_currentRequests.contains(reply)) {
167         qWarning() << reply->readAll();
168         if (reply->error()) {
169             emit error(ErrorContext::NETWORK, reply->error());
170         } else if(reply->url().toString().contains(CLOUDMADE_AUTH_PART)) {
171             m_token = reply->readAll();
172             m_pendingRequest.append(m_token);
173             sendRequest(m_pendingRequest);
174             m_pendingRequest.clear();
175             qWarning() << m_token;
176         } else {
177             parseRouteData(reply->readAll());
178         }
179
180         m_currentRequests.removeAll(reply);
181         reply->deleteLater();
182     }
183 }
184
185 void RoutingService::requestRoute(QPointF from, QPointF to)
186 {
187     qWarning() << __PRETTY_FUNCTION__;
188
189     QString url = "http://routes.cloudmade.com/";
190     url.append(CLOUDMADE_API_KEY);
191     url.append("/api/0.3/");
192     url.append(QString::number(from.x()) + "," + QString::number(from.y()) + ",");
193     url.append(QString::number(to.x()) + "," + QString::number(to.y()));
194     url.append("/car/fastest.js?lang=en&units=km&token=");
195
196     if(m_token.isEmpty()) {
197         m_pendingRequest.append(url);
198         requestAuthorizationToken();
199     } else {
200         url.append(m_token);
201         sendRequest(QUrl(url));
202     }
203     //sendRequest(QUrl("http://routes.cloudmade.com/BC9A493B41014CAABB98F0471D759707/api/0.3/47.25976,9.58423,47.26117,9.59882/bicycle.js"));
204 }
205
206 void RoutingService::sendRequest(const QUrl &url)
207 {
208     qWarning() << __PRETTY_FUNCTION__;
209     qWarning() << url.toString();
210
211     QNetworkRequest request;
212
213     request.setUrl(url);
214     request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
215
216     QByteArray ba;
217     QNetworkReply *reply = m_networkManager->post(request, ba, true);
218
219     m_currentRequests.append(reply);
220 }