ac246ab8fa3f82ca250cad7a0dd108f34f834b0c
[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
185     if(error)
186     {
187         if(http_.error() == QHttp::Aborted)
188         {
189             return;
190         }
191
192         qDebug() << "Error: " << http_.errorString();
193         handleHttpError(id);
194     }
195     else
196     {
197         QByteArray result = http_.readAll();
198         handleHttpData(id, result);
199     }
200 }
201
202 QString Source::ucFirst(QString& str)
203 {
204     if (str.size() < 1) {
205         return "";
206     }
207
208     QStringList tokens = str.split(" ");
209     QList<QString>::iterator tokItr;
210
211     for (tokItr = tokens.begin(); tokItr != tokens.end(); ++tokItr)
212     {
213         (*tokItr) = (*tokItr).at(0).toUpper() + (*tokItr).mid(1);
214     }
215
216     return tokens.join(" ");
217 }
218
219 QString& Source::cleanUpNumber(QString& number)
220 {
221     return number.replace(numberCleaner_, "");
222 }
223
224 QString& Source::stripTags(QString& string)
225 {
226     return string.replace(tagStripper_, "");
227 }
228
229 QString& Source::htmlEntityDecode(QString& string)
230 {
231     static const QString entities[] =
232     {
233         "quot",
234         "apos",
235         "amp",
236         "lt",
237         "gt",
238         "nbsp",
239         "Agrave",
240         "Aacute",
241         "Acirc",
242         "Atilde",
243         "Auml",
244         "Aring",
245         "AElig",
246         "Ccedil",
247         "Egrave",
248         "Eacute",
249         "Ecirc",
250         "Euml",
251         "Igrave",
252         "Iacute",
253         "Icirc",
254         "Iuml",
255         "ETH",
256         "Ntilde",
257         "Ograve",
258         "Oacute",
259         "Ocirc",
260         "Otilde",
261         "Ouml",
262         "Oslash",
263         "Ugrave",
264         "Uacute",
265         "Ucirc",
266         "Uuml",
267         "Yacute",
268         "THORN",
269         "szlig",
270         "agrave",
271         "aacute",
272         "acirc",
273         "atilde",
274         "auml",
275         "aring",
276         "aelig",
277         "ccedil",
278         "egrave",
279         "eacute",
280         "ecirc",
281         "euml",
282         "igrave",
283         "iacute",
284         "icirc",
285         "iuml",
286         "eth",
287         "ntilde",
288         "ograve",
289         "oacute",
290         "ocirc",
291         "otilde",
292         "ouml",
293         "oslash",
294         "ugrave",
295         "uacute",
296         "ucirc",
297         "uuml",
298         "yacute",
299         "thorn",
300         "yuml"
301     };
302
303     static const int entityValues[] =
304     {
305         34,
306         39,
307         38,
308         60,
309         62,
310         32,
311         192,
312         193,
313         194,
314         195,
315         196,
316         197,
317         198,
318         199,
319         200,
320         201,
321         202,
322         203,
323         204,
324         205,
325         206,
326         207,
327         208,
328         209,
329         210,
330         211,
331         212,
332         213,
333         214,
334         216,
335         217,
336         218,
337         219,
338         220,
339         221,
340         222,
341         223,
342         224,
343         225,
344         226,
345         227,
346         228,
347         229,
348         230,
349         231,
350         232,
351         233,
352         234,
353         235,
354         236,
355         237,
356         238,
357         239,
358         240,
359         241,
360         242,
361         243,
362         244,
363         245,
364         246,
365         248,
366         249,
367         250,
368         251,
369         252,
370         253,
371         254,
372         255
373     };
374
375     static int const COUNT = sizeof(entityValues) / sizeof(entityValues[0]);
376
377     for(int i = 0; i < COUNT; i++)
378     {
379         string = string.replace("&" + entities[i] + ";", QChar(entityValues[i]));
380     }
381
382     static QRegExp entityCleaner("&#([0-9]{1,3});");
383     entityCleaner.setMinimal(true);
384
385     int pos = 0;
386
387     while((pos = entityCleaner.indexIn(string, pos)) != -1)
388     {
389         QString match = entityCleaner.cap(1);
390
391         int value = match.toInt();
392
393         if(value >= 1 && value <= 255)
394         {
395             string = string.replace(pos, match.length() + 3, QChar(value));
396         }
397
398         pos += entityCleaner.matchedLength();
399     }
400
401
402    return string;
403 }
404
405 void Source::fixUrl(QUrl& url)
406 {
407     QByteArray path = url.encodedQuery().replace('+', "%2B");
408     url.setEncodedQuery(path);
409 }
410
411 bool Source::isPhoneNumber(QString const& string)
412 {
413     static QRegExp check("^([0-9 -]{7,25})$");
414     return check.exactMatch(string);
415 }
416
417 Source::SearchDetails::SearchDetails(QString const& q,
418                                      QString const& loc,
419                                      SearchType t)
420 {
421     query = q;
422     location = loc;
423     type = t;
424 }