Example #1
0
AutoUpdater::VersionInfo AutoUpdater::getUpdateVersion()
{
    VersionInfo versionInfo;
    versionInfo.timestamp = 0;

    // Updates only for supported platforms
    if (platform.isEmpty())
        return versionInfo;

    QNetworkAccessManager *manager = new QNetworkAccessManager;
    QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(checkURI)));
    while (!reply->isFinished())
        qApp->processEvents();

    if (reply->error() != QNetworkReply::NoError)
    {
        qWarning() << "AutoUpdater: getUpdateVersion: network error: "<<reply->errorString();
        reply->deleteLater();
        manager->deleteLater();
        return versionInfo;
    }

    QByteArray data = reply->readAll();
    reply->deleteLater();
    manager->deleteLater();
    if (data.size() < (int)(1+crypto_sign_BYTES))
        return versionInfo;

    // Check updater protocol version
    if ((int)data[0] != '2')
    {
        qWarning() << "AutoUpdater: getUpdateVersion: Bad version "<<(uint8_t)data[0];
        return versionInfo;
    }

    // Check the signature
    QByteArray sigData = data.mid(1, crypto_sign_BYTES);
    unsigned char* sig = (unsigned char*)sigData.data();
    QByteArray msgData = data.mid(1+crypto_sign_BYTES);
    unsigned char* msg = (unsigned char*)msgData.data();

    if (crypto_sign_verify_detached(sig, msg, msgData.size(), key) != 0)
    {
        qCritical() << "AutoUpdater: getUpdateVersion: RECEIVED FORGED VERSION FILE FROM "<<updateServer;
        return versionInfo;
    }

    int sepPos = msgData.indexOf('!');
    versionInfo.timestamp = QString(msgData.left(sepPos)).toInt();
    versionInfo.versionString = msgData.mid(sepPos+1);

    qDebug() << "timestamp:"<<versionInfo.timestamp << ", str:"<<versionInfo.versionString;

    return versionInfo;
}
bool CheckCloudConnection::checkServer()
{
	if (verbose)
		fprintf(stderr, "Checking cloud connection...\n");

	QTimer timer;
	timer.setSingleShot(true);
	QEventLoop loop;
	QNetworkRequest request;
	request.setRawHeader("Accept", "text/plain");
	request.setRawHeader("User-Agent", getUserAgent().toUtf8());
	request.setRawHeader("Client-Id", getUUID().toUtf8());
	request.setUrl(QString(prefs.cloud_base_url) + TEAPOT);
	QNetworkAccessManager *mgr = new QNetworkAccessManager();
	reply = mgr->get(request);
	connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
	connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
	connect(reply, &QNetworkReply::sslErrors, this, &CheckCloudConnection::sslErrors);
	for (int seconds = 1; seconds <= prefs.cloud_timeout; seconds++) {
		timer.start(1000); // wait the given number of seconds (default 5)
		loop.exec();
		if (timer.isActive()) {
			// didn't time out, did we get the right response?
			timer.stop();
			if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == HTTP_I_AM_A_TEAPOT &&
			    reply->readAll() == QByteArray(MILK)) {
				reply->deleteLater();
				mgr->deleteLater();
				if (verbose > 1)
					qWarning() << "Cloud storage: successfully checked connection to cloud server";
				git_storage_update_progress(false, "successfully checked cloud connection");
				return true;
			}
		} else if (seconds < prefs.cloud_timeout) {
			QString text = QString("waited %1 sec for cloud connetion").arg(seconds);
			git_storage_update_progress(false, qPrintable(text));
		} else {
			disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
			reply->abort();
		}
	}
	git_storage_update_progress(false, "cloud connection failed");
	prefs.git_local_only = true;
	if (verbose)
		qDebug() << "connection test to cloud server failed" <<
			    reply->error() << reply->errorString() <<
			    reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() <<
			    reply->readAll();
	reply->deleteLater();
	mgr->deleteLater();
	if (verbose)
		qWarning() << "Cloud storage: unable to connect to cloud server";
	return false;
}
Example #3
0
void HttpClientPrivate::handleFinish(bool debug,
                                     const QString &successMessage,
                                     const QString &errorMessage,
                                     std::function<void (const QString &)> successHandler,
                                     std::function<void (const QString &)> errorHandler,
                                     QNetworkReply *reply, QNetworkAccessManager *manager) {
    if (reply->error() == QNetworkReply::NoError) {
        // 请求成功
        if (debug) {
            qDebug().noquote() << QString("[成功]请求结束: %1").arg(successMessage);
        }

        if (nullptr != successHandler) {
            successHandler(successMessage);
        }
    } else {
        // 请求失败
        if (debug) {
            qDebug().noquote() << QString("[失败]请求结束: %1").arg(errorMessage);
        }

        if (nullptr != errorHandler) {
            errorHandler(errorMessage);
        }
    }

    // 释放资源
    reply->deleteLater();

    if (nullptr != manager) {
        manager->deleteLater();
    }
}
Example #4
0
void testGetRequest()
{
    QString url = "http://m.baidu.com/s?word=abc&ts=1223145&rq=ab";
    QNetworkAccessManager* networkAccessManager = new QNetworkAccessManager();
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
    //request.setRawHeader("Accept-Encoding", "gzip, deflate, sdch");
    request.setRawHeader("Accept-Language", "h-CN,zh;q=0.8");
    request.setRawHeader("Host", "m.baidu.com");
    request.setRawHeader("Referer", "http://m.baidu.com");
    request.setRawHeader("Connection", "keep-alive");
    request.setRawHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36");
    QNetworkReply* reply = networkAccessManager->get(request);
    QEventLoop loop;
    NetWorkCookieJar* cookieJar = new NetWorkCookieJar(networkAccessManager);
    networkAccessManager->setCookieJar(cookieJar);
    QTimer timer;
    timer.setSingleShot(true);
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
    timer.start(5000);
    loop.exec();
    timer.stop();
    qDebug() << request.rawHeaderList();
    qDebug() << reply->readAll();
    qDebug() << cookieJar->getCookies();
    networkAccessManager->deleteLater();
    reply->deleteLater();
}
QString WizKMGetDocumentEditStatusURL()
{
    static QString strUrl = 0;
    if (strUrl.isEmpty())
    {
        QString strCmd = "note_edit_status_url";
        QString strRequestUrl = WizService::ApiEntry::standardCommandUrl(strCmd);

        QNetworkAccessManager* net = new QNetworkAccessManager();
        QNetworkReply* reply = net->get(QNetworkRequest(strRequestUrl));

        QEventLoop loop;
        QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
        loop.exec();

        if (reply->error()) {
            return 0;
        }

        strUrl = QString::fromUtf8(reply->readAll().constData());

        net->deleteLater();
    }

    return strUrl;
}
Example #6
0
void YouTube::parseVideoPage(QNetworkReply *reply) {
    QNetworkAccessManager *manager = qobject_cast<QNetworkAccessManager*>(sender());

    QMap<int, QString> formats;
    QString response(QByteArray::fromPercentEncoding(reply->readAll()));
    response = response.split("fmt_stream_map=url=").at(1);
    QList<QString> parts = response.split(",url=");
    int key;
    for (int i = 0; i < parts.length(); i++) {
        QString part = parts[i];
        QString url(QByteArray::fromPercentEncoding(part.left(part.indexOf("&type=video")).toAscii()).replace("%2C", ","));
        key = part.split("&itag=").at(1).split("&").first().toInt();
        formats[key] = url;
    }
    QList<int> flist;
    flist << 22 << 35 << 34 << 18 << 5;
    QString videoUrl;
    int index = flist.indexOf(playbackFormat);
    while ((videoUrl == "") && index < flist.size()) {
        videoUrl = formats.value(flist.at(index), "");
        index++;
    }
    if (!videoUrl.startsWith("http")) {
        emit alert(tr("Error: Unable to retrieve video"));
        emit videoUrlError();
    }
    else {
        emit gotVideoUrl(videoUrl);
    }
//        qDebug() << videoUrl;
    reply->deleteLater();
    manager->deleteLater();
}
bool CheckCloudConnection::checkServer()
{
	QTimer timer;
	timer.setSingleShot(true);
	QEventLoop loop;
	QNetworkRequest request;
	request.setRawHeader("Accept", "text/plain");
	request.setRawHeader("User-Agent", getUserAgent().toUtf8());
	request.setUrl(QString(prefs.cloud_base_url) + TEAPOT);
	QNetworkAccessManager *mgr = new QNetworkAccessManager();
	reply = mgr->get(request);
	connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
	connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
	connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>)));
	timer.start(2000); // wait two seconds
	loop.exec();
	if (timer.isActive()) {
		// didn't time out, did we get the right response?
		timer.stop();
		if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == HTTP_I_AM_A_TEAPOT &&
		    reply->readAll() == QByteArray(MILK)) {
			reply->deleteLater();
			mgr->deleteLater();
			if (verbose > 1)
				qWarning() << "Cloud storage: successfully checked connection to cloud server";
			return true;
		}
	} else {
		disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
		reply->abort();
	}
	if (verbose)
		qDebug() << "connection test to cloud server failed" <<
			    reply->error() << reply->errorString() <<
			    reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() <<
			    reply->readAll();
	reply->deleteLater();
	mgr->deleteLater();
	if (verbose)
		qWarning() << "Cloud storage: unable to connect to cloud server";
	return false;
}
Example #8
0
QByteArray AutoUpdater::getUpdateFlist()
{
    QByteArray flist;

    QNetworkAccessManager *manager = new QNetworkAccessManager;
    QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(flistURI)));
    while (!reply->isFinished())
        qApp->processEvents();

    if (reply->error() != QNetworkReply::NoError)
    {
        qWarning() << "AutoUpdater: getUpdateFlist: network error: "<<reply->errorString();
        reply->deleteLater();
        manager->deleteLater();
        return flist;
    }

    flist = reply->readAll();
    reply->deleteLater();
    manager->deleteLater();

    return flist;
}
Example #9
0
QString ApiEntryPrivate::requestUrl(const QString& strUrl)
{
    QNetworkAccessManager* net = new QNetworkAccessManager();
    QNetworkReply* reply = net->get(QNetworkRequest(strUrl));

    QEventLoop loop;
    connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();

    if (reply->error()) {
        return 0;
    }

    QString strRequestedUrl = QString::fromUtf8(reply->readAll().constData());

    net->deleteLater();

    return strRequestedUrl;
}
Example #10
0
QString ApiEntryPrivate::requestUrl(const QString& strUrl)
{
    QNetworkAccessManager* net = new QNetworkAccessManager();
    QNetworkReply* reply = net->get(QNetworkRequest(strUrl));

    CWizAutoTimeOutEventLoop loop(reply);
    loop.exec(QEventLoop::ExcludeUserInputEvents);    

    if (loop.timeOut())
        return NULL;

    if (loop.error() != QNetworkReply::NoError)
        return NULL;

    //NOTE: reply has been delete in event loop, should not be deleted here
//    reply->deleteLater();

    net->deleteLater();

    return loop.result();
}
Example #11
0
void YouTube::parseLiveVideoPage(QNetworkReply *reply) {
    QNetworkAccessManager *manager = qobject_cast<QNetworkAccessManager*>(sender());

    QByteArray response = reply->readAll();
    response = QByteArray::fromPercentEncoding(response.simplified().replace(QByteArray(" "), QByteArray("")));
//    qDebug() << response;
    int pos = response.indexOf("fmt_stream_map=") + 18;
    int pos2 = response.indexOf('|', pos);
    response = response.mid(pos, pos2 - pos);
    QByteArray videoUrl = response.replace(QByteArray("\\/"), QByteArray("/")).replace(QByteArray("\\u0026"), QByteArray("&")).replace(QByteArray("%2C"), QByteArray(","));
    if (!(videoUrl.startsWith("http"))) {
        emit alert(tr("Error: Unable to retrieve video"));
        emit videoUrlError();
    }
    else {
        emit gotVideoUrl(QString(videoUrl));
    }
//        qDebug() << videoUrl;
    reply->deleteLater();
    manager->deleteLater();
}
bool HermelinWebPage::handleUri(const QString& originmsg)
{
    QString msg = originmsg;
    if (msg.startsWith("hermelin:")) {
        msg = msg.mid(6);
        QString type = msg.section("/", 0, 0);
        QString method = msg.section("/", 1, 1);
        if (type == "system") {
            if (method == "notify") {
                QString notify_type = QUrl::fromPercentEncoding(msg.section("/", 2, 2).toUtf8());
                QString title = QUrl::fromPercentEncoding(msg.section("/", 3, 3).toUtf8());
                QString summary = QUrl::fromPercentEncoding(msg.section("/", 4, 4).toUtf8());
                QString image = QUrl::fromPercentEncoding(msg.section("/", 5, 5).toUtf8());

                m_mainWindow->notification(notify_type, title, summary, image);
            } else if (method == "unread_alert") {
                QString number = QUrl::fromPercentEncoding(msg.section("/", 2, 2).toUtf8());
                m_mainWindow->unreadAlert(number);
            } else if (method == "load_settings") {
                QString settingString = QUrl::fromPercentEncoding(msg.section("/", 2, -1).toUtf8());
                currentFrame()->evaluateJavaScript("hermelin_qt = " + settingString + ";");
                QString proxyType = currentFrame()->evaluateJavaScript("hermelin_qt.proxy_type").toString();
                QNetworkProxy proxy;
                QNetworkAccessManager* nm = NULL;
#ifdef HAVE_KDE
                if (proxyType == "none") {
                    nm = new QNetworkAccessManager(this);
                }
#else
                if (proxyType == "system")
                {
                    nm = new QNetworkAccessManager(this);
                    QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery();
                    proxy = proxies[0];
                }
#endif
                if (proxyType == "http" || proxyType == "socks") {
                    nm = new QNetworkAccessManager(this);
                    bool proxyAuth = currentFrame()->evaluateJavaScript("hermelin_qt.proxy_auth").toBool();
                    int proxyPort = currentFrame()->evaluateJavaScript("hermelin_qt.proxy_port").toInt();
                    QString proxyHost = currentFrame()->evaluateJavaScript("hermelin_qt.proxy_host").toString();
                    QString proxyAuthName = currentFrame()->evaluateJavaScript("hermelin_qt.proxy_auth_name").toString();
                    QString proxyAuthPassword = currentFrame()->evaluateJavaScript("hermelin_qt.proxy_auth_password").toString();

                    proxy = QNetworkProxy(proxyType == "socks" ? QNetworkProxy::Socks5Proxy : QNetworkProxy::HttpProxy,
                                        proxyHost,
                                        proxyPort);

                    if (proxyAuth) {
                        proxy.setUser(proxyAuthName);
                        proxy.setPassword(proxyAuthPassword);
                    }
                }
                if (proxy.type() != QNetworkProxy::NoProxy) {
                    QNetworkProxy::setApplicationProxy(proxy);
                }

                if (nm != NULL) {
                    QNetworkAccessManager* oldnm = networkAccessManager();
                    oldnm->setParent(NULL);
                    oldnm->deleteLater();
                    nm->setProxy(QNetworkProxy::DefaultProxy);
                    setNetworkAccessManager(nm);
                }
            } else if (method == "sign_in") {
                m_mainWindow->setSignIn(true);
            } else if (method == "sign_out") {
                m_mainWindow->setSignIn(false);
            }
        } else if (type == "action") {
            if (method == "search") {

            } else if (method == "choose_file") {
                QFileDialog dialog;
                dialog.setAcceptMode(QFileDialog::AcceptOpen);
                dialog.setFileMode(QFileDialog::ExistingFile);
                dialog.setNameFilter(tr("Images (*.png *.bmp *.jpg *.gif)"));
                int result = dialog.exec();
                if (result) {
                    QStringList fileNames = dialog.selectedFiles();
                    if (fileNames.size() > 0) {
                        QString callback = msg.section("/", 2, 2);
                        currentFrame()->evaluateJavaScript(QString("%1(\"%2\")").arg(callback, QUrl::fromLocalFile(fileNames[0]).toString().replace("file://", "")));
                    }
                }
            } else if (method == "save_avatar") {
            } else if (method == "log") {
                qDebug() << msg;
            } else if (method == "paste_clipboard_text") {
                triggerAction(QWebPage::Paste);
            } else if (method == "set_clipboard_text") {
                QClipboard *clipboard = QApplication::clipboard();
                if (clipboard)
                    clipboard->setText(msg.section("/", 2, -1));
            }
        } else if (type == "request") {
            QString json = QUrl::fromPercentEncoding(msg.section("/", 1, -1).toUtf8());
            currentFrame()->evaluateJavaScript(QString("hermelin_qt_request_json = %1 ;").arg(json));
            QString request_uuid = currentFrame()->evaluateJavaScript(QString("hermelin_qt_request_json.uuid")).toString();
            QString request_method = currentFrame()->evaluateJavaScript(QString("hermelin_qt_request_json.method")).toString();
            QString request_url = currentFrame()->evaluateJavaScript(QString("hermelin_qt_request_json.url")).toString();
            QMap<QString, QVariant> request_params = currentFrame()->evaluateJavaScript(QString("hermelin_qt_request_json.params")).toMap();
            QMap<QString, QVariant> request_headers = currentFrame()->evaluateJavaScript(QString("hermelin_qt_request_json.headers")).toMap();
            QList<QVariant> request_files = currentFrame()->evaluateJavaScript(QString("hermelin_qt_request_json.files")).toList();

            HermelinRequest* request = new HermelinRequest(
                request_uuid,
                request_method,
                request_url,
                request_params,
                request_headers,
                request_files,
                userAgentForUrl(request_url),
                networkAccessManager());
            connect(request, SIGNAL(requestFinished(HermelinRequest*, QByteArray, QString, bool)), this, SLOT(requestFinished(HermelinRequest*, QByteArray, QString, bool)));
            if (!request->doRequest())
                delete request;
        }
Example #13
0
 ~YandexNarodScope()
 {
     networkManager->deleteLater();
 }
void DialogCameraView::DownloadPicture()
{
    string u;

    if (camera->get_param("type") == "axis")
    {
        string cam = "1";
        if (camera->get_param("model") != "") cam = camera->get_param("model").c_str();
        u = "http://" + camera->get_param("host") + ":" + camera->get_param("port") + "/axis-cgi/jpg/image.cgi?camera=" + cam;
    }
    else if (camera->get_param("type") == "gadspot")
    {
        u = "http://" + camera->get_param("host") + ":" + camera->get_param("port") + "/Jpeg/CamImg.jpg";
    }
    else if (camera->get_param("type") == "planet")
    {
        if (camera->get_param("model") == "ICA-300" ||
            camera->get_param("model") == "ICA-302" ||
            camera->get_param("model") == "ICA-500")
        {
            u = "http://" + camera->get_param("host") + ":" + camera->get_param("port") + "/Jpeg/CamImg.jpg";
        }
        else
        {
            u = "http://" + camera->get_param("host") + ":" + camera->get_param("port") + "/goform/video2";
        }
    }
    else if (camera->get_param("type") == "standard_mjpeg")
    {
        u = camera->get_param("url_jpeg");
    }

    qDebug() << u.c_str();

    QNetworkAccessManager *netmanager = new QNetworkAccessManager(this);
    connect(netmanager, &QNetworkAccessManager::finished, [=](QNetworkReply *reply) {

        if (reply->error() != QNetworkReply::NoError)
        {
            QMessageBox::warning(this, "Calaos Installer", tr("Calaos Installer: Erreur !"), reply->errorString());

            return;
        }

        qDebug() << QImageReader::supportedImageFormats();

        QByteArray res = reply->readAll();
        QImage img = QImage::fromData(res);
        reply->deleteLater();
        netmanager->deleteLater();

        if (img.isNull())
            QMessageBox::warning(this, "Calaos Installer", tr("Calaos Installer: Error, image is NULL !"));

        ui->label_cam->setPixmap(QPixmap::fromImage(img));

        DownloadPicture();
    });

    QNetworkRequest request(QUrl(u.c_str()));
    netmanager->get(request);
}
Example #15
0
void ReverseGeoLookupThread::run() {
	if (geo_lookup_data.isEmpty())
		return;

	QNetworkRequest request;
	QNetworkAccessManager *rgl = new QNetworkAccessManager();
	QEventLoop loop;
	QString mapquestURL("http://open.mapquestapi.com/nominatim/v1/reverse.php?format=json&accept-language=%1&lat=%2&lon=%3");
	QString geonamesURL("http://api.geonames.org/findNearbyPlaceNameJSON?language=%1&lat=%2&lng=%3&radius=50&username=dirkhh");
	QString geonamesOceanURL("http://api.geonames.org/oceanJSON?language=%1&lat=%2&lng=%3&radius=50&username=dirkhh");
	QString divelogsURL("https://www.divelogs.de/mapsearch_divespotnames.php?lat=%1&lng=%2&radius=50");
	QTimer timer;

	request.setRawHeader("Accept", "text/json");
	request.setRawHeader("User-Agent", getUserAgent().toUtf8());
	connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));

	Q_FOREACH (const GeoLookupInfo& info, geo_lookup_data ) {
		struct dive_site *ds = info.uuid ? get_dive_site_by_uuid(info.uuid) : &displayed_dive_site;

		// first check the findNearbyPlaces API from geonames - that should give us country, state, city
		request.setUrl(geonamesURL.arg(uiLanguage(NULL)).arg(info.lat.udeg / 1000000.0).arg(info.lon.udeg / 1000000.0));

		QNetworkReply *reply = rgl->get(request);
		timer.setSingleShot(true);
		connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
		timer.start(5000);   // 5 secs. timeout
		loop.exec();

		if(timer.isActive()) {
			timer.stop();
			if(reply->error() > 0) {
				report_error("got error accessing geonames.org: %s", qPrintable(reply->errorString()));
				goto clear_reply;
			}
			int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
			if (v < 200 || v >= 300)
				goto clear_reply;
			QByteArray fullReply = reply->readAll();
			QJsonParseError errorObject;
			QJsonDocument jsonDoc = QJsonDocument::fromJson(fullReply, &errorObject);
			if (errorObject.error != QJsonParseError::NoError) {
				report_error("error parsing geonames.org response: %s", qPrintable(errorObject.errorString()));
				goto clear_reply;
			}
			QJsonObject obj = jsonDoc.object();
			QVariant geoNamesObject = obj.value("geonames").toVariant();
			QVariantList geoNames = geoNamesObject.toList();
			if (geoNames.count() > 0) {
				QVariantMap firstData = geoNames.at(0).toMap();
				int ri = 0, l3 = -1, lt = -1;
				if (ds->taxonomy.category == NULL) {
					ds->taxonomy.category = alloc_taxonomy();
				} else {
					// clear out the data (except for the ocean data)
					int ocean;
					if ((ocean = taxonomy_index_for_category(&ds->taxonomy, TC_OCEAN)) > 0) {
						ds->taxonomy.category[0] = ds->taxonomy.category[ocean];
						ds->taxonomy.nr = 1;
					} else {
						// ocean is -1 if there is no such entry, and we didn't copy above
						// if ocean is 0, so the following gets us the correct count
						ds->taxonomy.nr = ocean + 1;
					}
				}
				// get all the data - OCEAN is special, so start at COUNTRY
				for (int j = TC_COUNTRY; j < TC_NR_CATEGORIES; j++) {
					if (firstData[taxonomy_api_names[j]].isValid()) {
						ds->taxonomy.category[ri].category = j;
						ds->taxonomy.category[ri].origin = taxonomy::GEOCODED;
						free((void*)ds->taxonomy.category[ri].value);
						ds->taxonomy.category[ri].value = copy_string(qPrintable(firstData[taxonomy_api_names[j]].toString()));
						ri++;
					}
				}
				ds->taxonomy.nr = ri;
				l3 = taxonomy_index_for_category(&ds->taxonomy, TC_ADMIN_L3);
				lt = taxonomy_index_for_category(&ds->taxonomy, TC_LOCALNAME);
				if (l3 == -1 && lt != -1) {
					// basically this means we did get a local name (what we call town), but just like most places
					// we didn't get an adminName_3 - which in some regions is the actual city that town belongs to,
					// then we copy the town into the city
					ds->taxonomy.category[ri].value = copy_string(ds->taxonomy.category[lt].value);
					ds->taxonomy.category[ri].origin = taxonomy::COPIED;
					ds->taxonomy.category[ri].category = TC_ADMIN_L3;
					ds->taxonomy.nr++;
				}
				mark_divelist_changed(true);
			} else {
				report_error("geonames.org did not provide reverse lookup information");
				qDebug() << "no reverse geo lookup; geonames returned\n" << fullReply;
			}
		} else {
			report_error("timeout accessing geonames.org");
			disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
			reply->abort();
		}
		// next check the oceans API to figure out the body of water
		request.setUrl(geonamesOceanURL.arg(uiLanguage(NULL)).arg(info.lat.udeg / 1000000.0).arg(info.lon.udeg / 1000000.0));
		reply = rgl->get(request);
		connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
		timer.start(5000);   // 5 secs. timeout
		loop.exec();
		if(timer.isActive()) {
			timer.stop();
			if(reply->error() > 0) {
				report_error("got error accessing oceans API of geonames.org: %s", qPrintable(reply->errorString()));
				goto clear_reply;
			}
			int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
			if (v < 200 || v >= 300)
				goto clear_reply;
			QByteArray fullReply = reply->readAll();
			QJsonParseError errorObject;
			QJsonDocument jsonDoc = QJsonDocument::fromJson(fullReply, &errorObject);
			if (errorObject.error != QJsonParseError::NoError) {
				report_error("error parsing geonames.org response: %s", qPrintable(errorObject.errorString()));
				goto clear_reply;
			}
			QJsonObject obj = jsonDoc.object();
			QVariant oceanObject = obj.value("ocean").toVariant();
			QVariantMap oceanName = oceanObject.toMap();
			if (oceanName["name"].isValid()) {
				int idx;
				if (ds->taxonomy.category == NULL)
					ds->taxonomy.category = alloc_taxonomy();
				idx = taxonomy_index_for_category(&ds->taxonomy, TC_OCEAN);
				if (idx == -1)
					idx = ds->taxonomy.nr;
				if (idx < TC_NR_CATEGORIES) {
					ds->taxonomy.category[idx].category = TC_OCEAN;
					ds->taxonomy.category[idx].origin = taxonomy::GEOCODED;
					ds->taxonomy.category[idx].value = copy_string(qPrintable(oceanName["name"].toString()));
					if (idx == ds->taxonomy.nr)
						ds->taxonomy.nr++;
				}
				mark_divelist_changed(true);
			}
		} else {
			report_error("timeout accessing geonames.org");
			disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
			reply->abort();
		}

clear_reply:
		reply->deleteLater();
	}
	rgl->deleteLater();
}