2017-04-27 18:26:05 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "desktop-widgets/subsurfacewebservices.h"
|
2018-06-03 20:15:19 +00:00
|
|
|
#include "core/qthelper.h"
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "core/webservice.h"
|
2018-09-08 17:46:11 +00:00
|
|
|
#include "core/settings/qPrefCloudStorage.h"
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "desktop-widgets/mainwindow.h"
|
|
|
|
#include "desktop-widgets/usersurvey.h"
|
2019-11-13 14:08:40 +00:00
|
|
|
#include "commands/command.h"
|
2019-05-31 14:09:14 +00:00
|
|
|
#include "core/trip.h"
|
2019-08-05 17:41:15 +00:00
|
|
|
#include "core/errorhelper.h"
|
2019-03-03 21:29:40 +00:00
|
|
|
#include "core/file.h"
|
2017-07-15 20:43:19 +00:00
|
|
|
#include "desktop-widgets/mapwidget.h"
|
2017-04-04 17:21:30 +00:00
|
|
|
#include "desktop-widgets/tab-widgets/maintab.h"
|
2019-11-24 14:02:34 +00:00
|
|
|
#include "core/selection.h"
|
2016-04-05 05:02:03 +00:00
|
|
|
#include "core/membuffer.h"
|
|
|
|
#include "core/cloudstorage.h"
|
2018-05-11 15:25:41 +00:00
|
|
|
#include "core/subsurface-string.h"
|
2019-12-09 08:52:10 +00:00
|
|
|
#include "core/uploadDiveLogsDE.h"
|
2019-12-09 10:47:59 +00:00
|
|
|
#include "core/settings/qPrefCloudStorage.h"
|
2013-06-06 14:31:55 +00:00
|
|
|
|
2013-11-15 02:57:09 +00:00
|
|
|
#include <QDir>
|
|
|
|
#include <QHttpMultiPart>
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QXmlStreamReader>
|
2013-06-06 14:31:55 +00:00
|
|
|
#include <qdesktopservices.h>
|
2014-04-25 17:44:23 +00:00
|
|
|
#include <QShortcut>
|
2015-02-17 14:01:49 +00:00
|
|
|
#include <QDebug>
|
2019-03-03 21:29:40 +00:00
|
|
|
#include <errno.h>
|
2019-08-05 18:07:10 +00:00
|
|
|
#include <zip.h>
|
2013-06-06 13:33:15 +00:00
|
|
|
|
2013-11-15 02:57:09 +00:00
|
|
|
#ifdef Q_OS_UNIX
|
2014-02-28 04:09:57 +00:00
|
|
|
#include <unistd.h> // for dup(2)
|
2013-11-15 02:57:09 +00:00
|
|
|
#endif
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
#include <QUrlQuery>
|
2014-01-15 08:30:34 +00:00
|
|
|
|
2014-08-27 21:12:05 +00:00
|
|
|
#ifndef PATH_MAX
|
|
|
|
#define PATH_MAX 4096
|
|
|
|
#endif
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
WebServices::WebServices(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f), reply(0)
|
2013-10-25 00:30:21 +00:00
|
|
|
{
|
|
|
|
ui.setupUi(this);
|
2014-02-28 04:09:57 +00:00
|
|
|
connect(ui.buttonBox, SIGNAL(clicked(QAbstractButton *)), this, SLOT(buttonClicked(QAbstractButton *)));
|
2013-10-25 00:30:21 +00:00
|
|
|
connect(ui.download, SIGNAL(clicked(bool)), this, SLOT(startDownload()));
|
2013-11-15 02:57:09 +00:00
|
|
|
connect(ui.upload, SIGNAL(clicked(bool)), this, SLOT(startUpload()));
|
2013-11-15 01:47:35 +00:00
|
|
|
connect(&timeout, SIGNAL(timeout()), this, SLOT(downloadTimedOut()));
|
2013-10-25 00:30:21 +00:00
|
|
|
ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
|
2013-11-15 01:47:35 +00:00
|
|
|
timeout.setSingleShot(true);
|
2013-12-09 17:23:32 +00:00
|
|
|
defaultApplyText = ui.buttonBox->button(QDialogButtonBox::Apply)->text();
|
2015-02-23 17:09:48 +00:00
|
|
|
userAgent = getUserAgent();
|
2013-10-25 00:30:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void WebServices::hidePassword()
|
|
|
|
{
|
|
|
|
ui.password->hide();
|
|
|
|
ui.passLabel->hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebServices::hideUpload()
|
|
|
|
{
|
|
|
|
ui.upload->hide();
|
2013-11-15 02:57:09 +00:00
|
|
|
ui.download->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebServices::hideDownload()
|
|
|
|
{
|
|
|
|
ui.download->hide();
|
|
|
|
ui.upload->show();
|
2013-10-25 00:30:21 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 01:47:35 +00:00
|
|
|
void WebServices::downloadTimedOut()
|
|
|
|
{
|
|
|
|
if (!reply)
|
|
|
|
return;
|
|
|
|
|
|
|
|
reply->deleteLater();
|
|
|
|
reply = NULL;
|
|
|
|
resetState();
|
2013-11-15 02:57:09 +00:00
|
|
|
ui.status->setText(tr("Operation timed out"));
|
2013-11-15 01:47:35 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 00:52:08 +00:00
|
|
|
void WebServices::updateProgress(qint64 current, qint64 total)
|
|
|
|
{
|
|
|
|
if (!reply)
|
|
|
|
return;
|
2013-12-07 01:10:32 +00:00
|
|
|
if (total == -1) {
|
|
|
|
total = INT_MAX / 2 - 1;
|
|
|
|
}
|
2013-11-15 00:52:08 +00:00
|
|
|
if (total >= INT_MAX / 2) {
|
|
|
|
// over a gigabyte!
|
|
|
|
if (total >= Q_INT64_C(1) << 47) {
|
|
|
|
total >>= 16;
|
|
|
|
current >>= 16;
|
|
|
|
}
|
|
|
|
total >>= 16;
|
|
|
|
current >>= 16;
|
|
|
|
}
|
|
|
|
ui.progressBar->setRange(0, total);
|
|
|
|
ui.progressBar->setValue(current);
|
2014-09-12 16:29:56 +00:00
|
|
|
ui.status->setText(tr("Transferring data..."));
|
2013-11-15 00:52:08 +00:00
|
|
|
|
|
|
|
// reset the timer: 30 seconds after we last got any data
|
|
|
|
timeout.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebServices::connectSignalsForDownload(QNetworkReply *reply)
|
|
|
|
{
|
|
|
|
connect(reply, SIGNAL(finished()), this, SLOT(downloadFinished()));
|
|
|
|
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
|
|
|
|
this, SLOT(downloadError(QNetworkReply::NetworkError)));
|
2014-02-28 04:09:57 +00:00
|
|
|
connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this,
|
|
|
|
SLOT(updateProgress(qint64, qint64)));
|
2013-11-15 01:47:35 +00:00
|
|
|
|
|
|
|
timeout.start(30000); // 30s
|
2013-11-15 00:52:08 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 00:50:46 +00:00
|
|
|
void WebServices::resetState()
|
|
|
|
{
|
|
|
|
ui.download->setEnabled(true);
|
2013-11-15 02:57:09 +00:00
|
|
|
ui.upload->setEnabled(true);
|
|
|
|
ui.userID->setEnabled(true);
|
|
|
|
ui.password->setEnabled(true);
|
2013-11-15 00:50:46 +00:00
|
|
|
ui.progressBar->reset();
|
2014-02-28 04:09:57 +00:00
|
|
|
ui.progressBar->setRange(0, 1);
|
2013-11-15 00:50:46 +00:00
|
|
|
ui.status->setText(QString());
|
2013-12-09 17:23:32 +00:00
|
|
|
ui.buttonBox->button(QDialogButtonBox::Apply)->setText(defaultApplyText);
|
2013-11-15 00:50:46 +00:00
|
|
|
}
|
|
|
|
|
2013-06-06 14:57:12 +00:00
|
|
|
|
2013-10-25 00:52:11 +00:00
|
|
|
// #
|
|
|
|
// #
|
|
|
|
// # Divelogs DE Web Service Implementation.
|
|
|
|
// #
|
|
|
|
// #
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
struct DiveListResult {
|
2013-11-15 02:57:09 +00:00
|
|
|
QString errorCondition;
|
|
|
|
QString errorDetails;
|
|
|
|
QByteArray idList; // comma-separated, suitable to be sent in the fetch request
|
|
|
|
int idCount;
|
|
|
|
};
|
|
|
|
|
|
|
|
static DiveListResult parseDiveLogsDeDiveList(const QByteArray &xmlData)
|
|
|
|
{
|
2013-12-07 01:09:08 +00:00
|
|
|
/* XML format seems to be:
|
|
|
|
* <DiveDateReader version="1.0">
|
|
|
|
* <DiveDates>
|
|
|
|
* <date diveLogsId="nnn" lastModified="YYYY-MM-DD hh:mm:ss">DD.MM.YYYY hh:mm</date>
|
|
|
|
* [repeat <date></date>]
|
|
|
|
* </DiveDates>
|
|
|
|
* </DiveDateReader>
|
|
|
|
*/
|
|
|
|
QXmlStreamReader reader(xmlData);
|
2018-07-03 14:52:20 +00:00
|
|
|
const QString invalidXmlError = gettextFromC::tr("Invalid response from server");
|
2013-12-07 01:09:08 +00:00
|
|
|
bool seenDiveDates = false;
|
|
|
|
DiveListResult result;
|
|
|
|
result.idCount = 0;
|
|
|
|
|
|
|
|
if (reader.readNextStartElement() && reader.name() != "DiveDateReader") {
|
|
|
|
result.errorCondition = invalidXmlError;
|
|
|
|
result.errorDetails =
|
2018-07-03 14:52:20 +00:00
|
|
|
gettextFromC::tr("Expected XML tag 'DiveDateReader', got instead '%1")
|
2014-05-22 18:40:22 +00:00
|
|
|
.arg(reader.name().toString());
|
2013-12-07 01:09:08 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (reader.readNextStartElement()) {
|
|
|
|
if (reader.name() != "DiveDates") {
|
|
|
|
if (reader.name() == "Login") {
|
|
|
|
QString status = reader.readElementText();
|
|
|
|
// qDebug() << "Login status:" << status;
|
|
|
|
|
|
|
|
// Note: there has to be a better way to determine a successful login...
|
|
|
|
if (status == "failed") {
|
|
|
|
result.errorCondition = "Login failed";
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// qDebug() << "Skipping" << reader.name();
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// process <DiveDates>
|
|
|
|
seenDiveDates = true;
|
|
|
|
while (reader.readNextStartElement()) {
|
|
|
|
if (reader.name() != "date") {
|
|
|
|
// qDebug() << "Skipping" << reader.name();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
QStringRef id = reader.attributes().value("divelogsId");
|
|
|
|
// qDebug() << "Found" << reader.name() << "with id =" << id;
|
|
|
|
if (!id.isEmpty()) {
|
|
|
|
result.idList += id.toLatin1();
|
|
|
|
result.idList += ',';
|
|
|
|
++result.idCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
reader.skipCurrentElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// chop the ending comma, if any
|
|
|
|
result.idList.chop(1);
|
|
|
|
|
|
|
|
if (!seenDiveDates) {
|
|
|
|
result.errorCondition = invalidXmlError;
|
2018-07-03 14:52:20 +00:00
|
|
|
result.errorDetails = gettextFromC::tr("Expected XML tag 'DiveDates' not found");
|
2013-12-07 01:09:08 +00:00
|
|
|
}
|
2013-11-15 02:57:09 +00:00
|
|
|
|
|
|
|
out:
|
2013-12-07 01:09:08 +00:00
|
|
|
if (reader.hasError()) {
|
|
|
|
// if there was an XML error, overwrite the result or other error conditions
|
|
|
|
result.errorCondition = invalidXmlError;
|
2018-07-03 14:52:20 +00:00
|
|
|
result.errorDetails = gettextFromC::tr("Malformed XML response. Line %1: %2")
|
2014-05-22 18:40:22 +00:00
|
|
|
.arg(reader.lineNumber())
|
|
|
|
.arg(reader.errorString());
|
2013-12-07 01:09:08 +00:00
|
|
|
}
|
|
|
|
return result;
|
2013-11-15 02:57:09 +00:00
|
|
|
}
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
DivelogsDeWebServices *DivelogsDeWebServices::instance()
|
2013-10-25 00:52:11 +00:00
|
|
|
{
|
2014-02-12 14:22:54 +00:00
|
|
|
static DivelogsDeWebServices *self = new DivelogsDeWebServices(MainWindow::instance());
|
2013-10-25 01:02:59 +00:00
|
|
|
return self;
|
2013-10-25 00:52:11 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 02:57:09 +00:00
|
|
|
void DivelogsDeWebServices::downloadDives()
|
2013-10-25 00:52:11 +00:00
|
|
|
{
|
2013-12-09 17:23:32 +00:00
|
|
|
uploadMode = false;
|
|
|
|
resetState();
|
2013-11-15 02:57:09 +00:00
|
|
|
hideUpload();
|
|
|
|
exec();
|
|
|
|
}
|
2013-10-25 00:52:11 +00:00
|
|
|
|
2014-05-20 16:33:32 +00:00
|
|
|
void DivelogsDeWebServices::prepareDivesForUpload(bool selected)
|
2013-12-05 16:31:40 +00:00
|
|
|
{
|
2013-12-20 01:03:21 +00:00
|
|
|
/* generate a random filename and create/open that file with zip_open */
|
|
|
|
QString filename = QDir::tempPath() + "/import-" + QString::number(qrand() % 99999999) + ".dld";
|
Improve error reporting when exporting a selection of 0 dives.
If no dives are selected when trying to export a selection, a message
is shown that no dives were selected, but it's immediately hidden
behind a message saying that a temporary file could not be created.
In fact, the creation of the temporary file wasn't never attempted,
so the message that the user actually sees is misleading.
The solution chosen here is to duplicate the check that at least some
dives are selected, and abort early if that case is detected, rather
than continuing on to show the additional misleading message. Not
elegant, but it gets the job done.
Better solutions to this include refactoring prepare_dives_for_divelogs
to return something more descriptive than a bool, remove that check
from prepare_dives_for_divelogs entirely since it doesn't seem to be
a good fit there, or switch to exceptions for handling these problems
rather than return values. I don't have sufficient familiarity with
the codebase to attempt these more invasive changes, but they
should be considered in the future.
On a final note, some of the other error messages in this file start
with a capital letter, but the one relevant to this particular PR
does not. Again, I'm not familiar enough with the codebase (or
translations) to know if that's safe to change, so I'll leave that
for another time or another developer.
Reported-by: John Plaxco
Signed-off-by: John Plaxco <john@johnplaxco.com>
2018-12-23 02:21:28 +00:00
|
|
|
if (!amount_selected) {
|
2018-12-23 12:35:05 +00:00
|
|
|
report_error(tr("No dives were selected").toUtf8());
|
Improve error reporting when exporting a selection of 0 dives.
If no dives are selected when trying to export a selection, a message
is shown that no dives were selected, but it's immediately hidden
behind a message saying that a temporary file could not be created.
In fact, the creation of the temporary file wasn't never attempted,
so the message that the user actually sees is misleading.
The solution chosen here is to duplicate the check that at least some
dives are selected, and abort early if that case is detected, rather
than continuing on to show the additional misleading message. Not
elegant, but it gets the job done.
Better solutions to this include refactoring prepare_dives_for_divelogs
to return something more descriptive than a bool, remove that check
from prepare_dives_for_divelogs entirely since it doesn't seem to be
a good fit there, or switch to exceptions for handling these problems
rather than return values. I don't have sufficient familiarity with
the codebase to attempt these more invasive changes, but they
should be considered in the future.
On a final note, some of the other error messages in this file start
with a capital letter, but the one relevant to this particular PR
does not. Again, I'm not familiar enough with the codebase (or
translations) to know if that's safe to change, so I'll leave that
for another time or another developer.
Reported-by: John Plaxco
Signed-off-by: John Plaxco <john@johnplaxco.com>
2018-12-23 02:21:28 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-12-09 08:52:10 +00:00
|
|
|
|
|
|
|
if (uploadDiveLogsDE::instance()->prepareDives(filename, selected)) {
|
2013-12-07 14:43:28 +00:00
|
|
|
QFile f(filename);
|
2013-12-12 01:56:35 +00:00
|
|
|
if (f.open(QIODevice::ReadOnly)) {
|
2013-12-07 14:43:28 +00:00
|
|
|
uploadDives((QIODevice *)&f);
|
|
|
|
f.close();
|
|
|
|
f.remove();
|
|
|
|
return;
|
2015-10-25 05:48:25 +00:00
|
|
|
} else {
|
|
|
|
report_error("Failed to open upload file %s\n", qPrintable(filename));
|
2013-12-07 14:43:28 +00:00
|
|
|
}
|
2015-04-28 17:42:54 +00:00
|
|
|
} else {
|
|
|
|
report_error("Failed to create upload file %s\n", qPrintable(filename));
|
2013-12-05 16:31:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-15 02:57:09 +00:00
|
|
|
void DivelogsDeWebServices::uploadDives(QIODevice *dldContent)
|
|
|
|
{
|
|
|
|
QHttpMultiPart mp(QHttpMultiPart::FormDataType);
|
|
|
|
QHttpPart part;
|
2013-12-09 13:29:57 +00:00
|
|
|
QFile *f = (QFile *)dldContent;
|
|
|
|
QFileInfo fi(*f);
|
|
|
|
QString args("form-data; name=\"userfile\"; filename=\"" + fi.absoluteFilePath() + "\"");
|
|
|
|
part.setRawHeader("Content-Disposition", args.toLatin1());
|
2013-11-15 02:57:09 +00:00
|
|
|
part.setBodyDevice(dldContent);
|
|
|
|
mp.append(part);
|
|
|
|
|
|
|
|
multipart = ∓
|
|
|
|
hideDownload();
|
2013-12-09 15:42:06 +00:00
|
|
|
resetState();
|
2013-12-09 17:23:32 +00:00
|
|
|
uploadMode = true;
|
|
|
|
ui.buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(true);
|
|
|
|
ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
|
|
|
|
ui.buttonBox->button(QDialogButtonBox::Apply)->setText(tr("Done"));
|
2013-11-15 02:57:09 +00:00
|
|
|
exec();
|
|
|
|
|
2013-12-09 15:42:06 +00:00
|
|
|
multipart = NULL;
|
|
|
|
if (reply != NULL && reply->isOpen()) {
|
|
|
|
reply->abort();
|
|
|
|
delete reply;
|
|
|
|
reply = NULL;
|
|
|
|
}
|
2013-11-15 02:57:09 +00:00
|
|
|
}
|
|
|
|
|
2015-03-25 05:41:38 +00:00
|
|
|
DivelogsDeWebServices::DivelogsDeWebServices(QWidget *parent, Qt::WindowFlags f) : WebServices(parent, f),
|
|
|
|
multipart(NULL),
|
|
|
|
uploadMode(false)
|
2013-11-15 02:57:09 +00:00
|
|
|
{
|
2019-03-19 15:22:51 +00:00
|
|
|
// should DivelogDE user and pass be stored in the prefs struct or something?
|
2019-12-09 10:47:59 +00:00
|
|
|
ui.userID->setText(qPrefCloudStorage::divelogde_user());
|
|
|
|
ui.password->setText(qPrefCloudStorage::divelogde_pass());
|
2014-04-11 06:17:35 +00:00
|
|
|
ui.saveUidLocal->hide();
|
2013-11-15 02:57:09 +00:00
|
|
|
hideUpload();
|
2014-04-25 17:44:23 +00:00
|
|
|
QShortcut *close = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), this);
|
|
|
|
connect(close, SIGNAL(activated()), this, SLOT(close()));
|
|
|
|
QShortcut *quit = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this);
|
|
|
|
connect(quit, SIGNAL(activated()), parent, SLOT(close()));
|
2013-10-25 00:52:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DivelogsDeWebServices::startUpload()
|
|
|
|
{
|
2019-12-09 10:47:59 +00:00
|
|
|
qPrefCloudStorage::set_divelogde_user(ui.userID->text());
|
|
|
|
qPrefCloudStorage::set_divelogde_pass(ui.password->text());
|
2013-12-09 14:45:54 +00:00
|
|
|
|
2013-11-15 02:57:09 +00:00
|
|
|
ui.status->setText(tr("Uploading dive list..."));
|
2014-02-28 04:09:57 +00:00
|
|
|
ui.progressBar->setRange(0, 0); // this makes the progressbar do an 'infinite spin'
|
2013-11-15 02:57:09 +00:00
|
|
|
ui.upload->setEnabled(false);
|
|
|
|
ui.userID->setEnabled(false);
|
|
|
|
ui.password->setEnabled(false);
|
2013-10-25 00:52:11 +00:00
|
|
|
|
2013-11-15 02:57:09 +00:00
|
|
|
QNetworkRequest request;
|
|
|
|
request.setUrl(QUrl("https://divelogs.de/DivelogsDirectImport.php"));
|
|
|
|
request.setRawHeader("Accept", "text/xml, application/xml");
|
2014-07-31 18:20:11 +00:00
|
|
|
request.setRawHeader("User-Agent", userAgent.toUtf8());
|
2013-11-15 02:57:09 +00:00
|
|
|
|
|
|
|
QHttpPart part;
|
|
|
|
part.setRawHeader("Content-Disposition", "form-data; name=\"user\"");
|
|
|
|
part.setBody(ui.userID->text().toUtf8());
|
|
|
|
multipart->append(part);
|
|
|
|
|
|
|
|
part.setRawHeader("Content-Disposition", "form-data; name=\"pass\"");
|
|
|
|
part.setBody(ui.password->text().toUtf8());
|
|
|
|
multipart->append(part);
|
|
|
|
|
|
|
|
reply = manager()->post(request, multipart);
|
|
|
|
connect(reply, SIGNAL(finished()), this, SLOT(uploadFinished()));
|
|
|
|
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
|
|
|
|
SLOT(uploadError(QNetworkReply::NetworkError)));
|
2014-02-28 04:09:57 +00:00
|
|
|
connect(reply, SIGNAL(uploadProgress(qint64, qint64)), this,
|
|
|
|
SLOT(updateProgress(qint64, qint64)));
|
2013-11-15 02:57:09 +00:00
|
|
|
|
|
|
|
timeout.start(30000); // 30s
|
2013-10-25 00:52:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DivelogsDeWebServices::startDownload()
|
|
|
|
{
|
2013-11-15 02:57:09 +00:00
|
|
|
ui.status->setText(tr("Downloading dive list..."));
|
2014-02-28 04:09:57 +00:00
|
|
|
ui.progressBar->setRange(0, 0); // this makes the progressbar do an 'infinite spin'
|
2013-11-15 02:57:09 +00:00
|
|
|
ui.download->setEnabled(false);
|
|
|
|
ui.userID->setEnabled(false);
|
|
|
|
ui.password->setEnabled(false);
|
|
|
|
|
|
|
|
QNetworkRequest request;
|
|
|
|
request.setUrl(QUrl("https://divelogs.de/xml_available_dives.php"));
|
|
|
|
request.setRawHeader("Accept", "text/xml, application/xml");
|
2014-07-31 18:20:11 +00:00
|
|
|
request.setRawHeader("User-Agent", userAgent.toUtf8());
|
2013-11-15 02:57:09 +00:00
|
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
|
|
|
|
|
|
|
QUrlQuery body;
|
|
|
|
body.addQueryItem("user", ui.userID->text());
|
2016-02-22 18:11:22 +00:00
|
|
|
body.addQueryItem("pass", ui.password->text().replace("+", "%2b"));
|
2013-11-15 02:57:09 +00:00
|
|
|
|
2014-01-15 08:30:33 +00:00
|
|
|
reply = manager()->post(request, body.query(QUrl::FullyEncoded).toLatin1());
|
2013-11-15 02:57:09 +00:00
|
|
|
connect(reply, SIGNAL(finished()), this, SLOT(listDownloadFinished()));
|
|
|
|
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
|
|
|
|
this, SLOT(downloadError(QNetworkReply::NetworkError)));
|
|
|
|
|
|
|
|
timeout.start(30000); // 30s
|
|
|
|
}
|
|
|
|
|
|
|
|
void DivelogsDeWebServices::listDownloadFinished()
|
|
|
|
{
|
|
|
|
if (!reply)
|
|
|
|
return;
|
|
|
|
QByteArray xmlData = reply->readAll();
|
|
|
|
reply->deleteLater();
|
|
|
|
reply = NULL;
|
|
|
|
|
|
|
|
// parse the XML data we downloaded
|
|
|
|
DiveListResult diveList = parseDiveLogsDeDiveList(xmlData);
|
|
|
|
if (!diveList.errorCondition.isEmpty()) {
|
|
|
|
// error condition
|
|
|
|
resetState();
|
|
|
|
ui.status->setText(diveList.errorCondition);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ui.status->setText(tr("Downloading %1 dives...").arg(diveList.idCount));
|
|
|
|
|
|
|
|
QNetworkRequest request;
|
2013-12-29 05:04:07 +00:00
|
|
|
request.setUrl(QUrl("https://divelogs.de/DivelogsDirectExport.php"));
|
2013-11-15 02:57:09 +00:00
|
|
|
request.setRawHeader("Accept", "application/zip, */*");
|
2014-07-31 18:20:11 +00:00
|
|
|
request.setRawHeader("User-Agent", userAgent.toUtf8());
|
2013-11-15 02:57:09 +00:00
|
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
|
|
|
|
|
|
|
QUrlQuery body;
|
|
|
|
body.addQueryItem("user", ui.userID->text());
|
2016-02-22 18:11:22 +00:00
|
|
|
body.addQueryItem("pass", ui.password->text().replace("+", "%2b"));
|
2013-11-15 02:57:09 +00:00
|
|
|
body.addQueryItem("ids", diveList.idList);
|
|
|
|
|
2014-01-15 08:30:33 +00:00
|
|
|
reply = manager()->post(request, body.query(QUrl::FullyEncoded).toLatin1());
|
2013-11-15 02:57:09 +00:00
|
|
|
connect(reply, SIGNAL(readyRead()), this, SLOT(saveToZipFile()));
|
|
|
|
connectSignalsForDownload(reply);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DivelogsDeWebServices::saveToZipFile()
|
|
|
|
{
|
|
|
|
if (!zipFile.isOpen()) {
|
|
|
|
zipFile.setFileTemplate(QDir::tempPath() + "/import-XXXXXX.dld");
|
|
|
|
zipFile.open();
|
|
|
|
}
|
2013-10-25 00:52:11 +00:00
|
|
|
|
2013-11-15 02:57:09 +00:00
|
|
|
zipFile.write(reply->readAll());
|
2013-10-25 00:52:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DivelogsDeWebServices::downloadFinished()
|
|
|
|
{
|
2013-11-15 02:57:09 +00:00
|
|
|
if (!reply)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ui.download->setEnabled(true);
|
|
|
|
ui.status->setText(tr("Download finished - %1").arg(reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()));
|
|
|
|
reply->deleteLater();
|
|
|
|
reply = NULL;
|
|
|
|
|
|
|
|
int errorcode;
|
|
|
|
zipFile.seek(0);
|
2013-12-20 01:01:54 +00:00
|
|
|
#if defined(Q_OS_UNIX) && defined(LIBZIP_VERSION_MAJOR)
|
2013-11-15 02:57:09 +00:00
|
|
|
int duppedfd = dup(zipFile.handle());
|
2015-06-22 13:46:01 +00:00
|
|
|
struct zip *zip = NULL;
|
|
|
|
if (duppedfd >= 0) {
|
|
|
|
zip = zip_fdopen(duppedfd, 0, &errorcode);
|
|
|
|
if (!zip)
|
|
|
|
::close(duppedfd);
|
2015-06-23 05:23:04 +00:00
|
|
|
} else {
|
|
|
|
QMessageBox::critical(this, tr("Problem with download"),
|
2019-03-24 10:07:45 +00:00
|
|
|
tr("The archive could not be opened:\n%1").arg(QString::fromLocal8Bit(strerror(errno))));
|
2015-06-23 05:23:04 +00:00
|
|
|
return;
|
2015-06-22 13:46:01 +00:00
|
|
|
}
|
2013-11-15 02:57:09 +00:00
|
|
|
#else
|
2013-12-20 01:02:34 +00:00
|
|
|
struct zip *zip = zip_open(QFile::encodeName(zipFile.fileName()), 0, &errorcode);
|
2013-11-15 02:57:09 +00:00
|
|
|
#endif
|
|
|
|
if (!zip) {
|
|
|
|
char buf[512];
|
|
|
|
zip_error_to_str(buf, sizeof(buf), errorcode, errno);
|
|
|
|
QMessageBox::critical(this, tr("Corrupted download"),
|
|
|
|
tr("The archive could not be opened:\n%1").arg(QString::fromLocal8Bit(buf)));
|
|
|
|
zipFile.close();
|
|
|
|
return;
|
|
|
|
}
|
2013-12-07 01:10:32 +00:00
|
|
|
// now allow the user to cancel or accept
|
|
|
|
ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true);
|
2013-11-15 02:57:09 +00:00
|
|
|
|
|
|
|
zip_close(zip);
|
|
|
|
zipFile.close();
|
2014-03-06 23:08:27 +00:00
|
|
|
#if defined(Q_OS_UNIX) && defined(LIBZIP_VERSION_MAJOR)
|
|
|
|
::close(duppedfd);
|
|
|
|
#endif
|
2013-11-15 02:57:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DivelogsDeWebServices::uploadFinished()
|
|
|
|
{
|
|
|
|
if (!reply)
|
|
|
|
return;
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
ui.progressBar->setRange(0, 1);
|
2013-11-15 02:57:09 +00:00
|
|
|
ui.upload->setEnabled(true);
|
2013-12-09 19:28:05 +00:00
|
|
|
ui.userID->setEnabled(true);
|
|
|
|
ui.password->setEnabled(true);
|
2013-12-09 17:23:32 +00:00
|
|
|
ui.buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(false);
|
|
|
|
ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true);
|
|
|
|
ui.buttonBox->button(QDialogButtonBox::Apply)->setText(tr("Done"));
|
2013-11-15 02:57:09 +00:00
|
|
|
ui.status->setText(tr("Upload finished"));
|
|
|
|
|
|
|
|
// check what the server sent us: it might contain
|
|
|
|
// an error condition, such as a failed login
|
|
|
|
QByteArray xmlData = reply->readAll();
|
2013-12-09 15:42:06 +00:00
|
|
|
reply->deleteLater();
|
|
|
|
reply = NULL;
|
2013-12-07 12:56:03 +00:00
|
|
|
char *resp = xmlData.data();
|
|
|
|
if (resp) {
|
|
|
|
char *parsed = strstr(resp, "<Login>");
|
|
|
|
if (parsed) {
|
2013-12-07 15:10:58 +00:00
|
|
|
if (strstr(resp, "<Login>succeeded</Login>")) {
|
|
|
|
if (strstr(resp, "<FileCopy>failed</FileCopy>")) {
|
|
|
|
ui.status->setText(tr("Upload failed"));
|
|
|
|
return;
|
|
|
|
}
|
2013-12-07 12:56:03 +00:00
|
|
|
ui.status->setText(tr("Upload successful"));
|
2013-12-07 15:10:58 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
ui.status->setText(tr("Login failed"));
|
|
|
|
return;
|
2013-12-05 16:31:40 +00:00
|
|
|
}
|
2013-12-07 15:10:58 +00:00
|
|
|
ui.status->setText(tr("Cannot parse response"));
|
2013-12-05 16:31:40 +00:00
|
|
|
}
|
2013-10-25 00:52:11 +00:00
|
|
|
}
|
|
|
|
|
2018-05-21 16:09:09 +00:00
|
|
|
void DivelogsDeWebServices::setStatusText(int)
|
2013-10-25 00:52:11 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-11-15 02:57:09 +00:00
|
|
|
void DivelogsDeWebServices::downloadError(QNetworkReply::NetworkError)
|
2013-10-25 00:52:11 +00:00
|
|
|
{
|
2013-11-15 02:57:09 +00:00
|
|
|
resetState();
|
2013-12-09 15:42:06 +00:00
|
|
|
ui.status->setText(tr("Error: %1").arg(reply->errorString()));
|
2013-11-15 02:57:09 +00:00
|
|
|
reply->deleteLater();
|
|
|
|
reply = NULL;
|
|
|
|
}
|
2013-10-25 00:52:11 +00:00
|
|
|
|
2013-11-15 02:57:09 +00:00
|
|
|
void DivelogsDeWebServices::uploadError(QNetworkReply::NetworkError error)
|
|
|
|
{
|
|
|
|
downloadError(error);
|
2013-10-25 00:52:11 +00:00
|
|
|
}
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
void DivelogsDeWebServices::buttonClicked(QAbstractButton *button)
|
2013-10-25 00:52:11 +00:00
|
|
|
{
|
2013-12-07 01:10:32 +00:00
|
|
|
ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
|
2014-01-16 04:50:56 +00:00
|
|
|
switch (ui.buttonBox->buttonRole(button)) {
|
|
|
|
case QDialogButtonBox::ApplyRole: {
|
2013-12-09 17:23:32 +00:00
|
|
|
/* in 'uploadMode' button is called 'Done' and closes the dialog */
|
|
|
|
if (uploadMode) {
|
|
|
|
hide();
|
|
|
|
close();
|
|
|
|
resetState();
|
|
|
|
break;
|
|
|
|
}
|
2013-12-07 12:33:43 +00:00
|
|
|
/* parse file and import dives */
|
2018-09-28 08:21:23 +00:00
|
|
|
struct dive_table table = { 0 };
|
2018-12-23 11:46:45 +00:00
|
|
|
struct trip_table trips = { 0 };
|
2019-03-03 14:12:22 +00:00
|
|
|
struct dive_site_table sites = { 0 };
|
|
|
|
parse_file(QFile::encodeName(zipFile.fileName()), &table, &trips, &sites);
|
|
|
|
Command::importDives(&table, &trips, &sites, IMPORT_MERGE_ALL_TRIPS, QStringLiteral("divelogs.de"));
|
2013-12-07 01:10:32 +00:00
|
|
|
|
2013-12-07 12:33:43 +00:00
|
|
|
/* store last entered user/pass in config */
|
2019-12-09 10:47:59 +00:00
|
|
|
qPrefCloudStorage::set_divelogde_user(ui.userID->text());
|
|
|
|
qPrefCloudStorage::set_divelogde_pass(ui.password->text());
|
2013-12-07 01:10:32 +00:00
|
|
|
hide();
|
|
|
|
close();
|
|
|
|
resetState();
|
2014-02-28 04:09:57 +00:00
|
|
|
} break;
|
2013-12-07 12:33:43 +00:00
|
|
|
case QDialogButtonBox::RejectRole:
|
|
|
|
// these two seem to be causing a crash:
|
|
|
|
// reply->deleteLater();
|
|
|
|
resetState();
|
|
|
|
break;
|
|
|
|
case QDialogButtonBox::HelpRole:
|
|
|
|
QDesktopServices::openUrl(QUrl("http://divelogs.de"));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2013-12-07 01:10:32 +00:00
|
|
|
}
|
2013-10-25 00:52:11 +00:00
|
|
|
}
|
2014-06-30 14:19:22 +00:00
|
|
|
|
2018-09-29 20:47:19 +00:00
|
|
|
UserSurveyServices::UserSurveyServices(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f)
|
2014-06-30 14:19:22 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-09-29 20:47:19 +00:00
|
|
|
QNetworkReply *UserSurveyServices::sendSurvey(QString values)
|
2014-06-30 14:19:22 +00:00
|
|
|
{
|
|
|
|
QNetworkRequest request;
|
2014-11-18 13:01:54 +00:00
|
|
|
request.setUrl(QString("http://subsurface-divelog.org/survey?%1").arg(values));
|
2014-06-30 14:19:22 +00:00
|
|
|
request.setRawHeader("Accept", "text/xml");
|
2018-09-29 20:47:19 +00:00
|
|
|
request.setRawHeader("User-Agent", getUserAgent().toUtf8());
|
|
|
|
QNetworkReply *reply = manager()->get(request);
|
2014-07-16 20:20:21 +00:00
|
|
|
return reply;
|
2016-02-22 18:11:22 +00:00
|
|
|
}
|