Unnecessary includes removed.
[jenirok] / src / common / connectionmanager.cpp
1 /*
2  * This file is part of Jenirok.
3  *
4  * Jenirok is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * Jenirok is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with Jenirok.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18
19 #include <QtCore/QDebug>
20 #include <QtCore/QTimerEvent>
21 #include <QtCore/QVariant>
22 #include <QtCore/QStringList>
23 #include <QtGui/QApplication>
24 #include <QtDBus/QDBusArgument>
25 #include <QtDBus/QDBusConnection>
26 #include <icd/dbus_api.h>
27 #include "connectionmanager.h"
28
29
30 ConnectionManager::ConnectionManager(QObject* parent): QObject(parent),
31 blocking_(true), stateReady_(false), connectionReady_(false), scanReady_(false),
32 connected_(false), timeout_(false), numberOfConnections_(0),
33 scannedConnections_(0), timer_(0), error_(NO_ERROR), connections_(0)
34 {
35     QDBusConnection systemBus = QDBusConnection::systemBus();
36
37     icd2interface_ = new QDBusInterface(ICD_DBUS_API_INTERFACE,
38                                         ICD_DBUS_API_PATH, ICD_DBUS_API_INTERFACE,
39                                         systemBus, this);
40
41     systemBus.connect(ICD_DBUS_API_INTERFACE, ICD_DBUS_API_PATH,
42                       ICD_DBUS_API_INTERFACE, ICD_DBUS_API_STATE_SIG,
43                       this, SLOT(stateChange(const QDBusMessage&)));
44
45     systemBus.connect(ICD_DBUS_API_INTERFACE, ICD_DBUS_API_PATH,
46                       ICD_DBUS_API_INTERFACE, ICD_DBUS_API_CONNECT_SIG,
47                       this, SLOT(connectionChange(const QDBusMessage&)));
48
49     systemBus.connect(ICD_DBUS_API_INTERFACE, ICD_DBUS_API_PATH,
50                       ICD_DBUS_API_INTERFACE, ICD_DBUS_API_SCAN_SIG,
51                       this, SLOT(scanResult(const QDBusMessage&)));
52
53 }
54
55 ConnectionManager::~ConnectionManager()
56 {
57     QDBusConnection systemBus = QDBusConnection::systemBus();
58
59     systemBus.disconnect(ICD_DBUS_API_INTERFACE, ICD_DBUS_API_PATH,
60                          ICD_DBUS_API_INTERFACE, ICD_DBUS_API_STATE_SIG,
61                          this, SLOT(stateChange(const QDBusMessage&)));
62
63     systemBus.disconnect(ICD_DBUS_API_INTERFACE, ICD_DBUS_API_PATH,
64                          ICD_DBUS_API_INTERFACE, ICD_DBUS_API_CONNECT_SIG,
65                          this, SLOT(connectionChange(const QDBusMessage&)));
66
67     systemBus.disconnect(ICD_DBUS_API_INTERFACE, ICD_DBUS_API_PATH,
68                          ICD_DBUS_API_INTERFACE, ICD_DBUS_API_SCAN_SIG,
69                          this, SLOT(scanResult(const QDBusMessage&)));
70 }
71
72 void ConnectionManager::setBlocking(bool value)
73 {
74     blocking_ = value;
75 }
76
77 bool ConnectionManager::connect()
78 {
79     connectionReady_ = false;
80     unsigned int flags = static_cast<unsigned int>(ICD_CONNECTION_FLAG_USER_EVENT);
81     icd2interface_->call(ICD_DBUS_API_CONNECT_REQ, QVariant(flags));
82
83     if(blocking_)
84     {
85         waitSignal(&connectionReady_);
86         return connected_;
87     }
88
89     return true;
90 }
91
92 bool ConnectionManager::connect(ConnectionManager::Connection const& connection)
93 {
94     return connect(connection.id);
95 }
96
97 bool ConnectionManager::connect(QString const& id)
98 {
99     QDBusMessage msg = QDBusMessage::createMethodCall("com.nokia.icd",
100                                                       "/com/nokia/icd",
101                                                       "com.nokia.icd",
102                                                       "connect");
103     QList<QVariant> arguments;
104
105     arguments.append(QVariant(id));
106
107     unsigned int val = 0;
108
109     arguments.append(QVariant(val));
110
111     msg.setArguments(arguments);
112
113     QDBusMessage rep = QDBusConnection::systemBus().call(msg);
114
115     if(rep.type() == QDBusMessage::ErrorMessage)
116     {
117         if(rep.errorName() == "com.nokia.icd.error.invalid_iap")
118         {
119             error_ = INVALID_IAP;
120         }
121         else
122         {
123             error_ = UNKNOWN_ERROR;
124         }
125
126         return false;
127     }
128
129     return true;
130 }
131
132 bool ConnectionManager::getBestConnection(Connection& connection, ConnectionType type)
133 {
134     bool blockingValue = blocking_;
135
136     blocking_ = true;
137
138     QList<Connection> connections;
139
140     if(!scanConnections(connections))
141     {
142         return false;
143     }
144
145     blocking_ = blockingValue;
146
147     if(connections.size() == 0)
148     {
149         error_ = NO_AVAILABLE_CONNECTIONS;
150         return false;
151     }
152
153     int biggestWlan = -1;
154     int biggestGprs = -1;
155     int bestWlan = -1;
156     int bestGprs = -1;
157
158     for(int i = 0; i < connections.size(); i++)
159     {
160        switch(connections.at(i).type)
161        {
162        case WLAN:
163            if(type != GPRS && connections.at(i).strength > biggestWlan)
164            {
165                biggestWlan = connections.at(i).strength;
166                bestWlan = i;
167            }
168            break;
169
170        case GPRS:
171            if(type != WLAN && connections.at(i).strength > biggestGprs)
172            {
173                biggestGprs = connections.at(i).strength;
174                bestGprs = i;
175            }
176            break;
177
178        default:
179            qDebug() << "Unknown connection type";
180        }
181     }
182
183     if(bestWlan >= 0)
184     {
185         connection = connections.at(bestWlan);
186         return true;
187     }
188     else if(bestGprs >= 0)
189     {
190         connection = connections.at(bestGprs);
191         return true;
192     }
193     else
194     {
195         error_ = NO_AVAILABLE_CONNECTIONS;
196         return false;
197     }
198
199 }
200
201 bool ConnectionManager::disconnect(bool force)
202 {
203     // Forced disconnect is not allowed if connection
204     // was not initialized by this class
205     if(!connected_ && force)
206     {
207         return false;
208     }
209
210     connectionReady_ = false;
211     unsigned int flags;
212
213     if(force)
214     {
215         flags = static_cast<unsigned int>(ICD_CONNECTION_FLAG_UI_EVENT);
216     }
217     else
218     {
219         flags = static_cast<unsigned int>(ICD_CONNECTION_FLAG_USER_EVENT);
220     }
221
222     icd2interface_->call(ICD_DBUS_API_DISCONNECT_REQ, QVariant(flags));
223     connected_ = false;
224     return true;
225 }
226
227 bool ConnectionManager::isConnected()
228 {
229     stateReady_ = false;
230     QDBusMessage rep = icd2interface_->call(ICD_DBUS_API_STATE_REQ);
231
232     unsigned int numOfReplies = rep.arguments().value(0).value<unsigned int>();
233
234     if(numOfReplies == 0)
235     {
236         emit isConnectedReply(false);
237         return false;
238     }
239
240     if(blocking_)
241     {
242         waitSignal(&stateReady_);
243         return connected_;
244     }
245
246     return true;
247 }
248
249 bool ConnectionManager::scanConnections(QList<ConnectionManager::Connection>& connections,
250                                         ConnectionManager::ConnectionType type)
251 {
252     unsigned int flags = static_cast<unsigned int>(ICD_SCAN_REQUEST_ACTIVE_SAVED);
253     scanReady_ = false;
254     scannedConnections_ = 0;
255     connections_ = &connections;
256
257     QStringList networks;
258
259     switch(type)
260     {
261     case WLAN:
262         networks << "WLAN_INFRA" << "WLAN_ADHOC";
263         break;
264     case GPRS:
265         networks << "GPRS";
266         break;
267     default:
268         break;
269     }
270
271     QDBusMessage rep = icd2interface_->call(ICD_DBUS_API_SCAN_REQ,
272                                             QVariant(flags),
273                                             QVariant(networks));
274
275     numberOfConnections_ = rep.arguments().value(0).toList().size();
276
277     if(numberOfConnections_ == 0)
278     {
279         connections_ = 0;
280         qDebug() << "No connections";
281         return false;
282     }
283
284     if(blocking_)
285     {
286         bool ret = waitSignal(&scanReady_);
287         connections_ = 0;
288         return ret;
289     }
290
291     return true;
292 }
293
294 ConnectionManager::Error ConnectionManager::error() const
295 {
296     return error_;
297 }
298
299 void ConnectionManager::stateChange(const QDBusMessage& rep)
300 {
301     unsigned int status = rep.arguments().value(7).value<unsigned int>();
302
303     switch(status)
304     {
305     case ICD_STATE_CONNECTING:
306         break;
307     case ICD_STATE_CONNECTED:
308         connected_ = true;
309         stateReady_ = true;
310         break;
311     case ICD_STATE_DISCONNECTING:
312         break;
313     case ICD_STATE_DISCONNECTED:
314         connected_ = false;
315         stateReady_ = true;
316         break;
317     case ICD_STATE_LIMITED_CONN_ENABLED:
318         connected_ = true;
319         stateReady_ = true;
320         break;
321     case ICD_STATE_LIMITED_CONN_DISABLED:
322         connected_ = false;
323         stateReady_ = true;
324         break;
325     case ICD_STATE_SEARCH_START:
326         break;
327     case ICD_STATE_SEARCH_STOP:
328         break;
329     case ICD_STATE_INTERNAL_ADDRESS_ACQUIRED:
330         break;
331     default:
332         qDebug() << "Unknown connection status";
333         break;
334     }
335
336     if(stateReady_)
337     {
338         emit isConnectedReply(connected_);
339     }
340
341 }
342
343 void ConnectionManager::connectionChange(const QDBusMessage& rep)
344 {
345     unsigned int status = rep.arguments().value(6).value<unsigned int>();
346
347     switch(status)
348     {
349     case ICD_CONNECTION_SUCCESSFUL:
350         connected_ = true;
351         connectionReady_ = true;
352         break;
353     case ICD_CONNECTION_NOT_CONNECTED:
354         connected_ = false;
355         connectionReady_ = true;
356         break;
357     case ICD_CONNECTION_DISCONNECTED:
358         connected_ = false;
359         connectionReady_ = true;
360         break;
361     default:
362         qDebug() << "Unknown connection status";
363         break;
364     }
365
366     if(connectionReady_)
367     {
368         emit connectReply(connected_);
369     }
370 }
371
372 void ConnectionManager::scanResult(const QDBusMessage& rep)
373 {
374     if(!connections_)
375     {
376         return;
377     }
378
379     QList<QVariant> args = rep.arguments();
380
381     unsigned int status = args.value(0).value<unsigned int>();
382
383     if(status == ICD_SCAN_COMPLETE)
384     {
385         scannedConnections_++;
386     }
387
388     if(scannedConnections_ >= numberOfConnections_)
389     {
390         scanReady_ = true;
391         connections_ = 0;
392         emit scanReady();
393         return;
394     }
395
396     if(status != ICD_SCAN_NEW)
397     {
398         return;
399     }
400
401     Connection connection;
402     connection.id = QString(args.value(10).toByteArray());
403     connection.name = args.value(8).toString();
404     connection.strength = args.value(11).toInt();
405
406     QString type = args.value(7).toString();
407
408     if(type == "GPRS")
409     {
410         connection.type = GPRS;
411     }
412     else if(type == "WLAN_INFRA" || type == "WLAN_ADHOC")
413     {
414         connection.type = WLAN;
415     }
416     else
417     {
418         qDebug() << "Unknown connection type: " << type;
419         return;
420     }
421
422     emit newConnection(connection);
423
424     connections_->push_back(connection);
425 }
426
427 bool ConnectionManager::waitSignal(bool* ready)
428 {
429     timeout_ = false;
430     timer_ = startTimer(TIMEOUT);
431
432     while(!*ready && !timeout_)
433     {
434         QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
435     }
436
437     killTimer(timer_);
438
439     return *ready || !timeout_;
440 }
441
442 void ConnectionManager::timerEvent(QTimerEvent* event)
443 {
444     Q_UNUSED(event);
445     killTimer(timer_);
446     timeout_ = true;
447     timer_ = 0;
448
449     qDebug() << "Connection request timed out";
450 }