Unnecessary includes removed.
[jenirok] / src / daemon / calllistener.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/QTimer>
21 #include "calllistener.h"
22 #include "settings.h"
23 #include "cache.h"
24 #include "contactmanager.h"
25 #include "connectionmanager.h"
26 #include "db.h"
27
28 namespace
29 {
30     const QString CALL_SERVICE_NAME = "com.nokia.csd";
31     const QString CALL_SERVICE_PATH = "/com/nokia/csd/call";
32     const QString CALL_SERVICE_INTERFACE = "com.nokia.csd.Call";
33     const QString CALL_SERVICE_INSTANCE_NAME = "com.nokia.csd.Call.Instance";
34     const QString CALL_SIGNAL_INCOMING = "Coming";
35     const QString CALL_SIGNAL_RELEASE = "Release";
36     const QString CALL_SIGNAL_TERMINATED = "Terminated";
37 }
38
39 QDBusConnection CallListener::systemBus_ = QDBusConnection::systemBus();
40
41 CallListener::CallListener(): eniro_(0),
42 closeConnection_(false), initialized_(false), box_(0), label_(0),
43 retries_(-1), site_(Eniro::FI), timer_(0)
44 {
45 }
46
47 CallListener::~CallListener()
48 {
49     end();
50     DB::removeDatabase();
51 }
52
53 bool CallListener::begin()
54 {
55     if(Settings::instance()->getConnectionType() == Settings::ALWAYS_ASK)
56     {
57         qDebug() << "Bad connection settings, unable to start";
58         return false;
59     }
60
61     systemBus_.connect(CALL_SERVICE_NAME,
62                        CALL_SERVICE_PATH,
63                        CALL_SERVICE_INTERFACE,
64                        CALL_SIGNAL_INCOMING,
65                        this,
66                        SLOT(incomingCall(QDBusObjectPath, QString)));
67
68     systemBus_.connect(CALL_SERVICE_NAME,
69                        CALL_SERVICE_PATH,
70                        CALL_SERVICE_INTERFACE,
71                        CALL_SIGNAL_RELEASE,
72                        this,
73                        SLOT(callTerminate()));
74
75     site_ = Eniro::stringToSite(Settings::instance()->get("site"));
76
77     qDebug() << "Starting...";
78
79     return true;
80
81 }
82
83 void CallListener::end()
84 {
85     systemBus_.disconnect(CALL_SERVICE_NAME,
86                           CALL_SERVICE_PATH,
87                           CALL_SERVICE_INTERFACE,
88                           CALL_SIGNAL_INCOMING,
89                           this,
90                           SLOT(incomingCall(QDBusObjectPath, QString)));
91
92     systemBus_.disconnect(CALL_SERVICE_NAME,
93                           CALL_SERVICE_PATH,
94                           CALL_SERVICE_INTERFACE,
95                           CALL_SIGNAL_RELEASE,
96                           this,
97                           SLOT(callTerminate()));
98
99     searchClose();
100
101 }
102
103 void CallListener::search(Eniro::SearchDetails const& details)
104 {
105     qDebug() << "Search called";
106
107     searchInit();
108
109     Eniro::Result result;
110
111     if(Cache::instance().findItem(details.query, result))
112     {
113
114         qDebug() << "Found from cache";
115
116         showDelayedResult(createResult(result.name,
117                                        result.street,
118                                        result.city), BANNER_DELAY);
119     }
120     else
121     {
122         retries_ = 0;
123         currentSearch_ = details.query;
124
125         if(!handleConnection())
126         {
127             qDebug() << "Unable to connect";
128             return;
129         }
130
131         showDelayedResult(tr("Searching..."), BANNER_DELAY);
132
133         qDebug() << "Starting to search...";
134
135         eniro_->search(details);
136     }
137
138 }
139
140 void CallListener::requestFinished(QVector <Eniro::Result> const& results,
141                                    Eniro::SearchDetails const& details,
142                                    bool error)
143 {
144     // If box is not visible, the call must have been terminated already
145     if(!initialized_ || !box_->isVisible())
146     {
147         return;
148     }
149
150     QString message;
151
152     if(error)
153     {
154         qDebug() << "Error: " << eniro_->errorString();
155
156         if(retries_ < SEARCH_RETRIES && retries_ >= 0)
157         {
158             retries_++;
159             eniro_->search(Eniro::SearchDetails(currentSearch_));
160             return;
161         }
162         else
163         {
164             timedMessage_ = "";
165             QString errorString;
166             Eniro::Error error = eniro_->error();
167
168             switch(error)
169             {
170             case Eniro::TIMEOUT:
171                 errorString = tr("Request timed out");
172                 break;
173             default:
174                 errorString = eniro_->errorString();
175                 break;
176             }
177
178             showError(tr("Searching failed:") + " " + errorString + ".");
179         }
180     }
181     else
182     {
183         timedMessage_ = "";
184
185         if(results.size() == 0)
186         {
187             message = tr("Phone number was not found");
188             showResult(message);
189         }
190         else
191         {
192             message = createResult(results.at(0).name, results.at(0).street,
193                                    results.at(0).city);
194             showResult(message);
195             Eniro::Result result = results.at(0);
196             result.number = details.query;
197             Cache::instance().addItem(result);
198         }
199     }
200
201     retries_ = -1;
202     currentSearch_ = "";
203
204     if(closeConnection_)
205     {
206         ConnectionManager cm;
207         cm.disconnect(true);
208         closeConnection_ = false;
209     }
210 }
211
212 QString CallListener::createResult(QString const& name, QString const& street, QString const& city)
213 {
214     QString result = "<b>" + name + "</b>";
215
216     if(!street.isEmpty() || !city.isEmpty())
217     {
218         result += "<br>";
219
220         if(!street.isEmpty())
221         {
222             result += street + ", ";
223         }
224
225         result += city;
226     }
227
228     return result;
229 }
230
231 void CallListener::showResult(QString const& text)
232 {
233     if(!initialized_)
234     {
235         return;
236     }
237
238     label_->setText("<font color='black'>" + text + "</font>");
239
240     if(box_->isVisible())
241     {
242         box_->hide();
243     }
244
245     box_->show();
246 }
247
248 void CallListener::incomingCall(QDBusObjectPath path, QString number)
249 {
250     qDebug() << "Incoming: " << number;
251
252     ContactManager cm;
253
254     if(!cm.numberExists(number))
255     {
256         qDebug() << "Number doesn't exist";
257
258         systemBus_.connect(CALL_SERVICE_NAME,
259                            path.path(),
260                            CALL_SERVICE_INSTANCE_NAME,
261                            CALL_SIGNAL_TERMINATED,
262                            this,
263                            SLOT(callTerminate()));
264
265         search(Eniro::SearchDetails(number));
266     }
267     else
268     {
269         qDebug() << "Number exists";
270     }
271 }
272
273 void CallListener::callTerminate()
274 {
275     if(box_ && box_->isVisible())
276     {
277         box_->hide();
278     }
279
280     if(closeConnection_)
281     {
282         ConnectionManager cm;
283         cm.disconnect(true);
284         closeConnection_ = false;
285     }
286
287     searchClose();
288 }
289
290 void CallListener::showDelayedResult(QString const& text, int delay)
291 {
292     timedMessage_ = text;
293     QTimer::singleShot(delay, this, SLOT(showTimedMessage()));
294 }
295
296 void CallListener::showTimedMessage()
297 {
298     if(timedMessage_.size() == 0 || !initialized_)
299     {
300         return;
301     }
302
303     showResult(timedMessage_);
304
305     timedMessage_ = "";
306 }
307
308 void CallListener::searchInit()
309 {
310     qDebug() << "Initializing search...";
311
312     if(initialized_)
313     {
314         qDebug() << "Already initialized";
315         return;
316     }
317
318     eniro_ = new Eniro(site_);
319     eniro_->setMaxResults(1);
320     eniro_->setFindNumber(false);
321     eniro_->setTimeout(REQUEST_TIMEOUT);
322
323     connect(eniro_, SIGNAL(requestFinished(QVector <Eniro::Result> const&,
324                                            Eniro::SearchDetails const&, bool)),
325                                            this, SLOT(requestFinished(QVector <Eniro::Result> const&,
326                                                                       Eniro::SearchDetails const&, bool)));
327     box_ = new InformationBox;
328     label_ = new QLabel("", box_);
329     label_->setMargin(8);
330     label_->setWordWrap(true);
331     box_->setWidget(label_);
332     initialized_ = true;
333 }
334
335 void CallListener::searchClose()
336 {
337     initialized_ = false;
338
339     qDebug() << "Closing search...";
340
341     if(eniro_)
342     {
343         disconnect(eniro_, SIGNAL(requestFinished(QVector <Eniro::Result> const&,
344                                                   Eniro::SearchDetails const&, bool)),
345                                                   this, SLOT(requestFinished(QVector <Eniro::Result> const&,
346                                                                              Eniro::SearchDetails const&, bool)));
347     }
348
349     delete eniro_;
350     eniro_ = 0;
351     delete box_;
352     box_ = 0;
353     label_ = 0;
354 }
355
356 bool CallListener::handleConnection()
357 {
358     if(!initialized_)
359     {
360         return false;
361     }
362
363     ConnectionManager cm;
364
365     if(cm.isConnected())
366     {
367         closeConnection_ = false;
368         return true;
369     }
370
371     closeConnection_ = true;
372
373     Settings::ConnectionType configType = Settings::instance()->getConnectionType();
374
375     if(configType == Settings::ALWAYS_ASK)
376     {
377         showError(tr("Automatic connecting is not allowed by settings."));
378         return false;
379     }
380
381     showDelayedResult(tr("Connecting..."), BANNER_DELAY);
382
383     ConnectionManager::Connection best;
384
385     ConnectionManager::ConnectionType lookupType = ConnectionManager::NO_TYPE;
386
387     switch(configType)
388     {
389     case Settings::WLAN:
390         lookupType = ConnectionManager::WLAN;
391         break;
392     case Settings::GPRS:
393         lookupType = ConnectionManager::GPRS;
394         break;
395     default:
396         lookupType = ConnectionManager::NO_TYPE;
397         break;
398     }
399
400     int cretries = 0;
401
402     while(cretries < CONNECTION_LOOKUP_RETRIES)
403     {
404         if(!initialized_)
405         {
406             return false;
407         }
408
409         if(cm.getBestConnection(best, lookupType))
410         {
411             break;
412         }
413
414         qDebug() << "No connections found, retrying...";
415
416         cretries++;
417
418         sleep(WAIT_BETWEEN_RETRIES);
419
420     }
421
422     if(cretries >= CONNECTION_LOOKUP_RETRIES)
423     {
424         showError(tr("No available 3G or WLAN networks found."));
425         return false;
426     }
427
428     int retries = 0;
429
430     while(retries < CONNECT_RETRIES)
431     {
432         if(!initialized_)
433         {
434             return false;
435         }
436
437         sleep(WAIT_BETWEEN_RETRIES);
438
439         if(cm.connect(best.id))
440         {
441             break;
442         }
443         else if(cm.error() == ConnectionManager::INVALID_IAP)
444         {
445             showError(tr("Selected access point doesn't exist."));
446             return false;
447         }
448
449         qDebug() << "Unable to connect, retrying...";
450         retries++;
451
452     }
453
454     if(initialized_ && retries >= CONNECT_RETRIES)
455     {
456         showError(tr("Unable to connect to network."));
457         return false;
458     }
459
460     return initialized_;
461 }
462
463 void CallListener::showError(QString const& msg)
464 {
465     qDebug() << "Error: " << msg;
466     box_->setTimeout(ERROR_BANNER_TIMEOUT);
467     showResult(msg);
468 }
469
470 void CallListener::timerEvent(QTimerEvent* event)
471 {
472     Q_UNUSED(event);
473     killTimer(timer_);
474     timer_ = 0;
475 }
476
477 void CallListener::sleep(int ms)
478 {
479     if(timer_)
480     {
481         killTimer(timer_);
482     }
483
484     timer_ = startTimer(ms);
485
486     while(timer_)
487     {
488         QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
489     }
490 }