|(.*)
|(.*)
)";
static const QString NUMBER_REGEXP = "
(.*)
";
static const QString LOGIN_CHECK = "
results = it.value()->results;
SearchDetails details = it.value()->details;
abort();
setError(TIMEOUT, TIMEOUT_STRING);
emit requestFinished(results, details, true);
}
}
}
void Eniro::login(QString const& username,
QString const& password)
{
username_ = username;
password_ = password;
loggedIn_ = true;
}
void Eniro::logout()
{
username_ = "";
password_ = "";
loggedIn_ = false;
}
void Eniro::search(SearchDetails const& details)
{
resetTimeout();
SearchType type = details.type;
// Only logged in users can use other than person search
if(!loggedIn_ && site_ == FI)
{
type = PERSONS;
}
QUrl url = createUrl(details.query, details.location);
QString what;
if(loggedIn_ || site_ != FI)
{
switch(type)
{
case YELLOW_PAGES:
what = "mobcs";
break;
case PERSONS:
what = "mobwp";
break;
default:
what = "moball";
break;
}
}
else
{
what = "moball";
}
url.addQueryItem("what", what);
http_.setHost(url.host(), url.port(80));
int id = http_.get(url.encodedPath() + '?' + url.encodedQuery());
QVector
results;
// Store search data for later identification
SearchData* newData = new SearchData;
newData->details = details;
newData->results = results;
newData->foundNumbers = 0;
newData->numbersTotal = 0;
// Store request id so that it can be identified later
pendingSearches_[id] = newData;
}
void Eniro::handleHttpData(int id, QByteArray const& data)
{
searchMap::const_iterator searchIt;
numberMap::const_iterator numberIt;
// Check if request is pending search request
if((searchIt = pendingSearches_.find(id)) !=
pendingSearches_.end())
{
if(data.isEmpty())
{
setError(CONNECTION_FAILURE, "Server returned empty data");
emitRequestFinished(id, searchIt.value(), true);
return;
}
// Load results from html data
loadResults(id, data);
}
// Check if request is pending number requests
else if((numberIt = pendingNumberRequests_.find(id)) !=
pendingNumberRequests_.end())
{
if(data.isEmpty())
{
setError(CONNECTION_FAILURE, "Server returned empty data");
emitRequestFinished(id, searchIt.value(), true);
return;
}
// Load number from html data
loadNumber(id, data);
}
// Check for login request
else if(pendingLoginRequests_.find(id) !=
pendingLoginRequests_.end())
{
bool success = true;
// If html source contains LOGIN_CHECK, login failed
if(data.indexOf(LOGIN_CHECK) != -1)
{
success = false;
}
emit loginStatus(success);
}
}
void Eniro::handleHttpError(int id)
{
searchMap::const_iterator searchIt;
numberMap::const_iterator numberIt;
// Check if request is pending search request
if((searchIt = pendingSearches_.find(id)) !=
pendingSearches_.end())
{
setError(CONNECTION_FAILURE, http_.errorString());
emitRequestFinished(id, searchIt.value(), true);
}
// Check if request is pending number requests
else if((numberIt = pendingNumberRequests_.find(id)) !=
pendingNumberRequests_.end())
{
setError(CONNECTION_FAILURE, http_.errorString());
delete pendingNumberRequests_[id];
pendingNumberRequests_.remove(id);
}
// Check for login request
else if(pendingLoginRequests_.find(id) !=
pendingLoginRequests_.end())
{
emit loginStatus(false);
}
}
// Loads results from html source code
void Eniro::loadResults(int id, QString const& httpData)
{
searchMap::iterator it = pendingSearches_.find(id);
QRegExp rx("((" + YELLOW_REGEXP + ")|(" + PERSON_REGEXP + ")|(" + SINGLE_REGEXP + "))");
rx.setMinimal(true);
bool requestsPending = false;
int pos = 0;
QString data;
// Find all matches
while((pos = rx.indexIn(httpData, pos)) != -1)
{
pos += rx.matchedLength();
data = rx.cap(1);
data = stripTags(data);
QStringList rows = data.split('\n');
for(int i = 0; i < rows.size(); i++)
{
// Remove white spaces
QString trimmed = rows.at(i).trimmed().toLower();
// Remove empty strings
if(trimmed.isEmpty())
{
rows.removeAt(i);
i--;
}
else
{
// Convert words to uppercase
rows[i] = ucFirst(trimmed);
}
}
Result result;
switch(site_)
{
case FI:
result.country = "Finland";
break;
case SE:
result.country = "Sweden";
break;
case DK:
result.country = "Denmark";
break;
}
int size = rows.size();
switch(size)
{
case 1:
result.name = rows[0];
break;
case 2:
result.name = rows[0];
result.city = rows[1];
break;
case 3:
if(isPhoneNumber(rows[1]))
{
result.name = rows[0];
result.number = cleanUpNumber(rows[1]);
result.city = rows[2];
}
else
{
result.name = rows[0];
result.street = rows[1];
result.city = rows[2];
}
break;
case 4:
result.name = rows[0];
// Remove slashes and spaces from number
result.number = cleanUpNumber(rows[1]);
result.street = rows[2];
result.city = rows[3];
break;
default:
bool ok = false;
for(int a = 0; a < size && a < 8; a++)
{
if(isPhoneNumber(rows[a]))
{
result.name = rows[0];
result.number = cleanUpNumber(rows[a]);
for(int i = a + 1; i < size && i < 8; i++)
{
if(!isPhoneNumber(rows[i]) && size > i + 1 && isStreet(rows[i]))
{
result.street = rows[i];
result.city = rows[i+1];
ok = true;
break;
}
}
}
}
if(ok)
{
break;
}
continue;
}
it.value()->results.push_back(result);
unsigned int foundResults = ++(it.value()->numbersTotal);
// If phone number search is enabled, we have to make another
// request to find it out
if(getFindNumber() && size < 4 && (loggedIn_ || site_ != FI) &&
it.value()->details.type != YELLOW_PAGES)
{
requestsPending = true;
getNumberForResult(id, it.value()->results.size() - 1, it.value()->details);
}
// Otherwise result is ready
else
{
emit resultAvailable(result, it.value()->details);
}
unsigned int maxResults = getMaxResults();
// Stop searching if max results is reached
if(maxResults && (foundResults >= maxResults))
{
break;
}
}
// If there were no results or no phone numbers needed to
// be fetched, the whole request is ready
if(it.value()->numbersTotal == 0 || !requestsPending)
{
bool error = false;
if(httpData.indexOf(LOGIN_CHECK) != -1)
{
setError(INVALID_LOGIN, INVALID_LOGIN_STRING),
error = true;
}
emitRequestFinished(it.key(), it.value(), error);
}
}
// Loads phone number from html source
void Eniro::loadNumber(int id, QString const& result)
{
numberMap::iterator numberIt = pendingNumberRequests_.find(id);
// Make sure that id exists in pending number requests
if(numberIt == pendingNumberRequests_.end() || numberIt.value() == 0)
{
return;
}
searchMap::iterator searchIt = pendingSearches_.find(numberIt.value()->searchId);
if(searchIt == pendingSearches_.end() || searchIt.value() == 0)
{
return;
}
QRegExp rx(NUMBER_REGEXP);
rx.setMinimal(true);
int pos = 0;
bool error = true;
if((pos = rx.indexIn(result, pos)) != -1)
{
QString data = rx.cap(1);
data = stripTags(data);
QString trimmed = data.trimmed();
if(!trimmed.isEmpty())
{
// Remove whitespaces from number
searchIt.value()->results[numberIt.value()->index].number = cleanUpNumber(trimmed);
emit resultAvailable(searchIt.value()->results[numberIt.value()->index], searchIt.value()->details);
unsigned int found = ++searchIt.value()->foundNumbers;
// Check if all numbers have been found
if(found >= searchIt.value()->numbersTotal)
{
emitRequestFinished(searchIt.key(), searchIt.value(), false);
}
// If number was found, there was no error
error = false;
}
}
if(error)
{
setError(INVALID_LOGIN, INVALID_LOGIN_STRING);
emitRequestFinished(searchIt.key(), searchIt.value(), true);
}
// Remove number request
int key = numberIt.key();
delete pendingNumberRequests_[key];
pendingNumberRequests_[key] = 0;
pendingNumberRequests_.remove(key);
}
QUrl Eniro::createUrl(QString const& query, QString const& location)
{
QUrl url(SITE_URLS[site_] + "query");
if(!query.isEmpty())
{
url.addQueryItem("search_word", query);
}
if(!location.isEmpty())
{
url.addQueryItem("geo_area", location);
}
unsigned int maxResults = getMaxResults();
if(maxResults)
{
url.addQueryItem("hpp", QString::number(maxResults));
}
if(loggedIn_ && site_ == FI)
{
url.addQueryItem("login_name", username_);
url.addQueryItem("login_password", password_);
}
fixUrl(url);
return url;
}
// Creates a new request for phone number retrieval
void Eniro::getNumberForResult(int id, int index, SearchDetails const& details)
{
QUrl url = createUrl(details.query, details.location);
url.addQueryItem("what", "mobwpinfo");
url.addQueryItem("search_number", QString::number(index + 1));
http_.setHost(url.host(), url.port(80));
int requestId = http_.get(url.encodedPath() + '?' + url.encodedQuery());
NumberData* number = new NumberData;
number->searchId = id;
number->index = index;
pendingNumberRequests_[requestId] = number;
}
void Eniro::emitRequestFinished(int key, SearchData* data, bool error)
{
emit requestFinished(data->results, data->details, error);
delete pendingSearches_[key];
pendingSearches_[key] = 0;
pendingSearches_.remove(key);
}
QMap Eniro::getSites()
{
QMap sites;
for(int i = 0; i < SITE_COUNT; i++)
{
SiteDetails details;
details.name = SITE_NAMES[i];
details.id = SITE_IDS[i];
sites[static_cast(i)] = details;
}
return sites;
}
Eniro::Site Eniro::stringToSite(QString const& str)
{
Site site = FI;
QString lower = str.toLower();
for(int i = 0; i < SITE_COUNT; i++)
{
if(lower == SITE_NAMES[i] || lower == SITE_IDS[i])
{
site = static_cast (i);
break;
}
}
return site;
}
bool Eniro::isStreet(QString const& str)
{
static QRegExp number("([0-9]+)");
int a = number.indexIn(str);
int b = str.indexOf(" ");
if((a == -1 && b == -1) || (a != -1 && b != -1))
{
return true;
}
return false;
}