149e4416454d96579d1131122c263b0f0006a451
[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 <QtSql/QSqlQuery>
22 #include <QtSql/QSqlError>
23 #include "calllistener.h"
24 #include "settings.h"
25 #include "cache.h"
26 #include "contactmanager.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), connectionManager_(0),
42 closeConnection_(false), initialized_(false), box_(0), label_(0),
43 retries_(-1), site_(Eniro::FI), autoconnect_(false)
44 {
45 }
46
47 CallListener::~CallListener()
48 {
49     end();
50 }
51
52 void CallListener::begin()
53 {
54     systemBus_.connect(CALL_SERVICE_NAME,
55                        CALL_SERVICE_PATH,
56                        CALL_SERVICE_INTERFACE,
57                        CALL_SIGNAL_INCOMING,
58                        this,
59                        SLOT(incomingCall(QDBusObjectPath, QString)));
60
61     systemBus_.connect(CALL_SERVICE_NAME,
62                        CALL_SERVICE_PATH,
63                        CALL_SERVICE_INTERFACE,
64                        CALL_SIGNAL_RELEASE,
65                        this,
66                        SLOT(callTerminate()));
67
68     site_ = Eniro::stringToSite(Settings::instance()->get("site"));
69     connectionName_ = Settings::instance()->get("connection");
70     autoconnect_ = (Settings::instance()->get("autoconnect") == "1");
71     Settings::close();
72
73     qDebug() << "Starting...";
74
75 }
76
77 void CallListener::end()
78 {
79     systemBus_.disconnect(CALL_SERVICE_NAME,
80                           CALL_SERVICE_PATH,
81                           CALL_SERVICE_INTERFACE,
82                           CALL_SIGNAL_INCOMING,
83                           this,
84                           SLOT(incomingCall(QDBusObjectPath, QString)));
85
86     systemBus_.disconnect(CALL_SERVICE_NAME,
87                           CALL_SERVICE_PATH,
88                           CALL_SERVICE_INTERFACE,
89                           CALL_SIGNAL_RELEASE,
90                           this,
91                           SLOT(callTerminate()));
92
93     searchClose();
94
95 }
96
97 void CallListener::search(Eniro::SearchDetails const& details)
98 {
99     qDebug() << "Search called";
100
101     searchInit();
102
103     Eniro::Result result;
104
105     if(Cache::instance().findItem(details.query, result))
106     {
107
108         qDebug() << "Found from cache";
109
110         showDelayedResult(createResult(result.name,
111                                        result.street,
112                                        result.city), BANNER_DELAY);
113     }
114     else
115     {
116         retries_ = 0;
117         currentSearch_ = details.query;
118
119         showDelayedResult(tr("Searching..."), BANNER_DELAY);
120
121         if(!handleConnection())
122         {
123             qDebug() << "Unable to connect";
124             return;
125         }
126
127         qDebug() << "Starting to search...";
128
129         eniro_->search(details);
130     }
131
132 }
133
134 void CallListener::requestFinished(QVector <Eniro::Result> const& results,
135                                    Eniro::SearchDetails const& details,
136                                    bool error)
137 {
138     // If box is not visible, the call must have been terminated already
139     if(!initialized_ || !box_->isVisible())
140     {
141         return;
142     }
143
144     QString message;
145
146     if(error)
147     {
148         qDebug() << "Error: " << eniro_->errorString();
149
150         if(retries_ < NUMBER_OF_RETRIES && retries_ >= 0)
151         {
152             retries_++;
153             eniro_->search(Eniro::SearchDetails(currentSearch_));
154             return;
155         }
156         else
157         {
158             timedMessage_ = "";
159             showError(tr("Search failed:") + " " + eniro_->errorString() + ".");
160         }
161     }
162     else
163     {
164         timedMessage_ = "";
165
166         if(results.size() == 0)
167         {
168             message = tr("Phone number was not found");
169             showResult(message);
170         }
171         else
172         {
173             message = createResult(results.at(0).name, results.at(0).street,
174                                    results.at(0).city);
175             showResult(message);
176             Eniro::Result result = results.at(0);
177             result.number = details.query;
178             Cache::instance().addItem(result);
179         }
180     }
181
182     retries_ = -1;
183     currentSearch_ = "";
184
185     if(closeConnection_ && connectionManager_)
186     {
187         connectionManager_->disconnect(true);
188         closeConnection_ = false;
189     }
190 }
191
192 QString CallListener::createResult(QString const& name, QString const& street, QString const& city)
193 {
194     QString result = "<b>" + name + "</b>";
195
196     if(!street.isEmpty() || !city.isEmpty())
197     {
198         result += "<br>";
199
200         if(!street.isEmpty())
201         {
202             result += street + ", ";
203         }
204
205         result += city;
206     }
207
208     return result;
209 }
210
211 void CallListener::showResult(QString const& text)
212 {
213     if(!initialized_)
214     {
215         return;
216     }
217
218     label_->setText("<font color='black'>" + text + "</font>");
219
220     if(box_->isVisible())
221     {
222         box_->hide();
223     }
224
225     box_->show();
226 }
227
228 void CallListener::incomingCall(QDBusObjectPath path, QString number)
229 {
230     qDebug() << "Incoming: " << number;
231
232     ContactManager cm;
233
234     if(!cm.numberExists(number))
235     {
236         qDebug() << "Number doesn't exist";
237
238         systemBus_.connect(CALL_SERVICE_NAME,
239                            path.path(),
240                            CALL_SERVICE_INSTANCE_NAME,
241                            CALL_SIGNAL_TERMINATED,
242                            this,
243                            SLOT(callTerminate()));
244
245         search(Eniro::SearchDetails(number));
246     }
247     else
248     {
249         qDebug() << "Number exists";
250     }
251 }
252
253 void CallListener::callTerminate()
254 {
255     if(initialized_ && box_ && box_->isVisible())
256     {
257         box_->hide();
258     }
259
260     if(closeConnection_ && connectionManager_)
261     {
262         connectionManager_->disconnect(true);
263         closeConnection_ = false;
264     }
265
266     searchClose();
267 }
268
269 void CallListener::showDelayedResult(QString const& text, int delay)
270 {
271     timedMessage_ = text;
272     QTimer::singleShot(delay, this, SLOT(showTimedMessage()));
273 }
274
275 void CallListener::showTimedMessage()
276 {
277     if(timedMessage_.size() == 0 || !initialized_)
278     {
279         return;
280     }
281
282     showResult(timedMessage_);
283
284     timedMessage_ = "";
285 }
286
287 void CallListener::searchInit()
288 {
289     qDebug() << "Initializing search...";
290
291     if(initialized_)
292     {
293         qDebug() << "Already initialized";
294         return;
295     }
296
297     connectionManager_ = new ConnectionManager;
298
299     eniro_ = new Eniro(site_);
300     eniro_->setMaxResults(1);
301     eniro_->setFindNumber(false);
302     eniro_->setTimeout(REQUEST_TIMEOUT);
303
304     connect(eniro_, SIGNAL(requestFinished(QVector <Eniro::Result> const&,
305                                            Eniro::SearchDetails const&, bool)),
306                                            this, SLOT(requestFinished(QVector <Eniro::Result> const&,
307                                                                       Eniro::SearchDetails const&, bool)));
308     box_ = new InformationBox;
309     label_ = new QLabel("", box_);
310     label_->setMargin(8);
311     box_->setWidget(label_);
312     initialized_ = true;
313 }
314
315 void CallListener::searchClose()
316 {
317     initialized_ = false;
318
319     qDebug() << "Closing search...";
320
321     if(eniro_)
322     {
323         disconnect(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     }
328
329     delete connectionManager_;
330     connectionManager_ = 0;
331     delete eniro_;
332     eniro_ = 0;
333     delete box_;
334     box_ = 0;
335     label_ = 0;
336 }
337
338 bool CallListener::handleConnection()
339 {
340     if(!connectionManager_)
341     {
342         qDebug() << "Error: connection manager not initialized";
343         return false;
344     }
345
346     if(connectionManager_->isConnected())
347     {
348         closeConnection_ = false;
349         return true;
350     }
351
352     closeConnection_ = true;
353     int retries = 0;
354
355     if(autoconnect_)
356     {
357         QString conn;
358
359         if(connectionName_.size() != 0 && connectionName_ != "0")
360         {
361             conn = connectionName_;
362         }
363         else
364         {
365             ConnectionManager::Connection best;
366
367             if(!connectionManager_->getBestConnection(best))
368             {
369                 showError(tr("No network connections found."));
370                 return false;
371             }
372
373             conn = best.id;
374         }
375
376         while(retries < CONNECT_RETRIES)
377         {
378             if(connectionManager_->connect(conn))
379             {
380                 break;
381             }
382             else if(connectionManager_->error() == ConnectionManager::INVALID_IAP)
383             {
384                 showError(tr("Selected access point doesn't exist."));
385                 return false;
386             }
387
388             retries++;
389         }
390     }
391     else
392     {
393         while(retries < CONNECT_RETRIES)
394         {
395             if(connectionManager_->connect())
396             {
397                 break;
398             }
399             else
400             {
401                 qDebug() << "Automatic connection failed";
402             }
403
404             retries++;
405         }
406     }
407
408     if(retries >= CONNECT_RETRIES)
409     {
410         ConnectionManager::NetworkMode mode = connectionManager_->getNetworkMode();
411
412         if(mode != ConnectionManager::NETWORK_3G &&
413            mode != ConnectionManager::NETWORK_3_5G)
414         {
415             showError(tr("No 3G or WLAN network available."));
416         }
417         else
418         {
419             showError(tr("Unable to connect to network."));
420         }
421
422         return false;
423     }
424
425     return true;
426 }
427
428 void CallListener::showError(QString const& msg)
429 {
430     qDebug() << "Error: " << msg;
431     box_->setTimeout(ERROR_BANNER_TIMEOUT);
432     showResult(msg);
433 }