One more fix to connection handling.
[jenirok] / src / common / source.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 "source.h"
21 #include "eniro.h"
22 #include "mobil1881.h"
23 #include "dastelefonbuch.h"
24
25 namespace
26 {
27     static const QString SOURCE_NAMES[Source::SOURCE_COUNT] =
28     {
29          "Eniro (FI, SE, DK)",
30          "1881 Mobil (NO)",
31          "Das Telefonbuch (DE)"
32     };
33
34     static const QString SOURCE_IDS[Source::SOURCE_COUNT] =
35     {
36          "eniro",
37          "1881mobil",
38          "dastelefonbuch"
39     };
40
41 }
42
43 // Regexp used to remove everything except numbers from string
44 QRegExp Source::numberCleaner_ = QRegExp("([^0-9]+)");
45
46 // Removes html tags from string
47 QRegExp Source::tagStripper_ = QRegExp("<([^>]+)>");
48
49 Source* Source::getSource(Source::SourceId id, QObject* parent)
50 {
51     switch(id)
52     {
53     case ENIRO:
54         return new Eniro(parent);
55         break;
56     case MOBIL1881:
57         return new Mobil1881(parent);
58         break;
59     case DASTELEFONBUCH:
60         return new DasTelefonbuch(parent);
61         break;
62     default:
63         qDebug() << "Unknown source:" << id;
64     }
65
66     return 0;
67 }
68
69 Source::SourceId Source::stringToId(QString const& str)
70 {
71     for(int i = 0; i < SOURCE_COUNT; i++)
72     {
73         if(SOURCE_IDS[i] == str || SOURCE_NAMES[i] == str)
74         {
75             return static_cast<SourceId>(i);
76         }
77     }
78
79     return ENIRO;
80 }
81
82 void Source::getSources(QList<SourceDetails>& list)
83 {
84     for(int i = 0; i < SOURCE_COUNT; i++)
85     {
86         SourceDetails details;
87         details.type = static_cast<SourceId>(i);
88         details.name = SOURCE_NAMES[i];
89         details.id = SOURCE_IDS[i];
90         list.push_back(details);
91     }
92 }
93
94 Source::Source(QObject* parent): QObject(parent),
95 maxResults_(DEFAULT_MAX_RESULTS), timeout_(0), timerId_(0), findNumber_(true),
96 error_(NO_ERROR), loggedIn_(false)
97 {
98     connect(&http_, SIGNAL(requestFinished(int, bool)), this, SLOT(httpReady(int, bool)));
99 }
100
101 Source::~Source()
102 {
103     abort();
104 }
105
106 void Source::abort()
107 {
108     http_.abort();
109 }
110
111 void Source::setMaxResults(unsigned int results)
112 {
113     maxResults_ = results;
114 }
115
116 unsigned int Source::getMaxResults() const
117 {
118     return maxResults_;
119 }
120
121 void Source::getSearchTypes(QList<SearchType>& types) const
122 {
123     types.clear();
124     types.push_back(PERSONS);
125     types.push_back(YELLOW_PAGES);
126 }
127
128 void Source::setTimeout(unsigned int timeout)
129 {
130     timeout_ = timeout;
131     resetTimeout();
132 }
133
134 unsigned int Source::getTimeout() const
135 {
136     return timeout_;
137 }
138
139 void Source::resetTimeout()
140 {
141     if(timerId_)
142     {
143         killTimer(timerId_);
144     }
145     if(timeout_)
146     {
147         timerId_ = startTimer(timeout_);
148     }
149 }
150
151 void Source::timerEvent(QTimerEvent* t)
152 {
153     Q_UNUSED(t);
154 }
155
156 void Source::setFindNumber(bool value)
157 {
158     findNumber_ = value;
159 }
160
161 bool Source::getFindNumber() const
162 {
163     return findNumber_;
164 }
165
166 Source::Error Source::error() const
167 {
168     return error_;
169 }
170
171 const QString& Source::errorString() const
172 {
173     return errorString_;
174 }
175
176 void Source::setError(Source::Error error, QString const& errorString)
177 {
178     error_ = error;
179     errorString_ = errorString;
180 }
181
182 void Source::httpReady(int id, bool error)
183 {
184     if(error)
185     {
186         if(http_.error() == QHttp::Aborted)
187         {
188             return;
189         }
190
191         qDebug() << "Error: " << http_.errorString();
192         handleHttpError(id);
193     }
194     else
195     {
196         QByteArray result = http_.readAll();
197         handleHttpData(id, result);
198     }
199 }
200
201 QString Source::ucFirst(QString& str)
202 {
203     if (str.size() < 1) {
204         return "";
205     }
206
207     QStringList tokens = str.split(" ");
208     QList<QString>::iterator tokItr;
209
210     for (tokItr = tokens.begin(); tokItr != tokens.end(); ++tokItr)
211     {
212         (*tokItr) = (*tokItr).at(0).toUpper() + (*tokItr).mid(1);
213     }
214
215     return tokens.join(" ");
216 }
217
218 QString& Source::cleanUpNumber(QString& number)
219 {
220     return number.replace(numberCleaner_, "");
221 }
222
223 QString& Source::stripTags(QString& string)
224 {
225     return string.replace(tagStripper_, "");
226 }
227
228 QString& Source::htmlEntityDecode(QString& string)
229 {
230     static const QString entities[] =
231     {
232         "quot",
233         "apos",
234         "amp",
235         "lt",
236         "gt",
237         "nbsp",
238         "Agrave",
239         "Aacute",
240         "Acirc",
241         "Atilde",
242         "Auml",
243         "Aring",
244         "AElig",
245         "Ccedil",
246         "Egrave",
247         "Eacute",
248         "Ecirc",
249         "Euml",
250         "Igrave",
251         "Iacute",
252         "Icirc",
253         "Iuml",
254         "ETH",
255         "Ntilde",
256         "Ograve",
257         "Oacute",
258         "Ocirc",
259         "Otilde",
260         "Ouml",
261         "Oslash",
262         "Ugrave",
263         "Uacute",
264         "Ucirc",
265         "Uuml",
266         "Yacute",
267         "THORN",
268         "szlig",
269         "agrave",
270         "aacute",
271         "acirc",
272         "atilde",
273         "auml",
274         "aring",
275         "aelig",
276         "ccedil",
277         "egrave",
278         "eacute",
279         "ecirc",
280         "euml",
281         "igrave",
282         "iacute",
283         "icirc",
284         "iuml",
285         "eth",
286         "ntilde",
287         "ograve",
288         "oacute",
289         "ocirc",
290         "otilde",
291         "ouml",
292         "oslash",
293         "ugrave",
294         "uacute",
295         "ucirc",
296         "uuml",
297         "yacute",
298         "thorn",
299         "yuml"
300     };
301
302     static const int entityValues[] =
303     {
304         34,
305         39,
306         38,
307         60,
308         62,
309         32,
310         192,
311         193,
312         194,
313         195,
314         196,
315         197,
316         198,
317         199,
318         200,
319         201,
320         202,
321         203,
322         204,
323         205,
324         206,
325         207,
326         208,
327         209,
328         210,
329         211,
330         212,
331         213,
332         214,
333         216,
334         217,
335         218,
336         219,
337         220,
338         221,
339         222,
340         223,
341         224,
342         225,
343         226,
344         227,
345         228,
346         229,
347         230,
348         231,
349         232,
350         233,
351         234,
352         235,
353         236,
354         237,
355         238,
356         239,
357         240,
358         241,
359         242,
360         243,
361         244,
362         245,
363         246,
364         248,
365         249,
366         250,
367         251,
368         252,
369         253,
370         254,
371         255
372     };
373
374     static int const COUNT = sizeof(entityValues) / sizeof(entityValues[0]);
375
376     for(int i = 0; i < COUNT; i++)
377     {
378         string = string.replace("&" + entities[i] + ";", QChar(entityValues[i]));
379     }
380
381     static QRegExp entityCleaner("&#([0-9]{1,3});");
382     entityCleaner.setMinimal(true);
383
384     int pos = 0;
385
386     while((pos = entityCleaner.indexIn(string, pos)) != -1)
387     {
388         QString match = entityCleaner.cap(1);
389
390         int value = match.toInt();
391
392         if(value >= 1 && value <= 255)
393         {
394             string = string.replace(pos, match.length() + 3, QChar(value));
395         }
396
397         pos += entityCleaner.matchedLength();
398     }
399
400
401    return string;
402 }
403
404 void Source::fixUrl(QUrl& url)
405 {
406     QByteArray path = url.encodedQuery().replace('+', "%2B");
407     url.setEncodedQuery(path);
408 }
409
410 bool Source::isPhoneNumber(QString const& string)
411 {
412     static QRegExp check("^([0-9 -]{7,25})$");
413     return check.exactMatch(string);
414 }
415
416 Source::SearchDetails::SearchDetails(QString const& q,
417                                      QString const& loc,
418                                      SearchType t)
419 {
420     query = q;
421     location = loc;
422     type = t;
423 }