2013-06-06 13:33:15 +00:00
|
|
|
#include "subsurfacewebservices.h"
|
2015-02-23 17:09:48 +00:00
|
|
|
#include "helpers.h"
|
2014-04-11 08:51:07 +00:00
|
|
|
#include "webservice.h"
|
2013-11-30 17:18:04 +00:00
|
|
|
#include "mainwindow.h"
|
2014-07-31 18:20:11 +00:00
|
|
|
#include "usersurvey.h"
|
2015-02-09 20:27:59 +00:00
|
|
|
#include "divelist.h"
|
2015-02-09 20:43:41 +00:00
|
|
|
#include "globe.h"
|
2015-02-09 20:58:40 +00:00
|
|
|
#include "maintab.h"
|
2015-02-09 21:51:31 +00:00
|
|
|
#include "display.h"
|
2015-04-28 18:28:53 +00:00
|
|
|
#include "membuffer.h"
|
2013-12-05 00:29:55 +00:00
|
|
|
#include <errno.h>
|
2013-06-06 14:31:55 +00:00
|
|
|
|
2013-11-15 02:57:09 +00:00
|
|
|
#include <QDir>
|
|
|
|
#include <QHttpMultiPart>
|
|
|
|
#include <QMessageBox>
|
2013-06-06 14:57:12 +00:00
|
|
|
#include <QSettings>
|
2013-11-15 02:57:09 +00:00
|
|
|
#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>
|
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
|
|
|
|
|
2013-06-06 14:57:12 +00:00
|
|
|
struct dive_table gps_location_table;
|
2015-02-13 15:14:30 +00:00
|
|
|
|
|
|
|
// we don't overwrite any existing GPS info in the dive
|
|
|
|
// so get the dive site and if there is none or there is one without GPS fix, add it
|
|
|
|
static void copy_gps_location(struct dive *from, struct dive *to)
|
|
|
|
{
|
|
|
|
struct dive_site *ds = get_dive_site_for_dive(to);
|
|
|
|
if (!ds || !dive_site_has_gps_location(ds)) {
|
|
|
|
struct dive_site *gds = get_dive_site_for_dive(from);
|
|
|
|
if (!ds) {
|
|
|
|
// simply link to the one created for the fake dive
|
|
|
|
to->dive_site_uuid = gds->uuid;
|
|
|
|
} else {
|
|
|
|
ds->latitude = gds->latitude;
|
|
|
|
ds->longitude = gds->longitude;
|
|
|
|
if (same_string(ds->name, ""))
|
|
|
|
ds->name = copy_string(gds->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-06-06 14:57:12 +00:00
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
#define SAME_GROUP 6 * 3600 // six hours
|
2014-04-17 02:56:42 +00:00
|
|
|
//TODO: C Code. static functions are not good if we plan to have a test for them.
|
2013-11-14 22:59:06 +00:00
|
|
|
static bool merge_locations_into_dives(void)
|
|
|
|
{
|
Change in logic while aplying gps fixes to dives
We were actually searching dives which match the dowloaded position
fixes. So we're also trying to take into account if the fix is automatic
or no based on a limited amount of predefined strings (bad idea, as the
user can change in companion app settings the predefined string).
This way, in actual implementation, if program concludes that a fix has
been manually got or, simply, the user is unlucky enough to have all the
position fixes out of the dive time, find_dive_n_near() function will
pair fix and dive in an ordered way (1st fix -> 1st dive; 2nd fix -> 2nd
dive ...) which is probably erroneous, except for manual position fixes.
BTW actual implementation can't pair the same gps position with more
than one dive, which would be the case, e.g. in repetitive dives while at
anchor in the same point.
The patch changes the logic:
- Search positions for defined dives (instead of dives for defined
positions) without care if position has manually or automatically been
set.
- Only take care of those dives that don't have a position yet.
- It makes two assumptions:
a.- If the position fix has been taken during the dive time, is
correct. If there are more than one inside the dive time, takes the
first one (closest to the DC's reported time).
b.- If not during diving time, the correct one is the nearest fix
before the dive begins (also the usual case if manually fixed from the
smartphone just before jump into the water). But will work too if there
is only one fix *in SAME_GROUP range* after the dive (another usual
case).
- Finally, as copy_gps_location() in dive.h is used only here, let it
take care of naming the dive if user hasn't named it yet.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-07-16 05:23:34 +00:00
|
|
|
int i, j, tracer=0, changed=0;
|
|
|
|
struct dive *gpsfix, *nextgpsfix, *dive;
|
2013-11-14 22:59:06 +00:00
|
|
|
|
|
|
|
sort_table(&gps_location_table);
|
|
|
|
|
Change in logic while aplying gps fixes to dives
We were actually searching dives which match the dowloaded position
fixes. So we're also trying to take into account if the fix is automatic
or no based on a limited amount of predefined strings (bad idea, as the
user can change in companion app settings the predefined string).
This way, in actual implementation, if program concludes that a fix has
been manually got or, simply, the user is unlucky enough to have all the
position fixes out of the dive time, find_dive_n_near() function will
pair fix and dive in an ordered way (1st fix -> 1st dive; 2nd fix -> 2nd
dive ...) which is probably erroneous, except for manual position fixes.
BTW actual implementation can't pair the same gps position with more
than one dive, which would be the case, e.g. in repetitive dives while at
anchor in the same point.
The patch changes the logic:
- Search positions for defined dives (instead of dives for defined
positions) without care if position has manually or automatically been
set.
- Only take care of those dives that don't have a position yet.
- It makes two assumptions:
a.- If the position fix has been taken during the dive time, is
correct. If there are more than one inside the dive time, takes the
first one (closest to the DC's reported time).
b.- If not during diving time, the correct one is the nearest fix
before the dive begins (also the usual case if manually fixed from the
smartphone just before jump into the water). But will work too if there
is only one fix *in SAME_GROUP range* after the dive (another usual
case).
- Finally, as copy_gps_location() in dive.h is used only here, let it
take care of naming the dive if user hasn't named it yet.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-07-16 05:23:34 +00:00
|
|
|
for_each_dive (i, dive) {
|
|
|
|
if (!dive_has_gps_location(dive)) {
|
2015-02-11 18:33:36 +00:00
|
|
|
for (j = tracer; (gpsfix = get_dive_from_table(j, &gps_location_table)) !=NULL; j++) {
|
2015-06-25 05:38:44 +00:00
|
|
|
if (time_during_dive_with_offset(dive, gpsfix->when, SAME_GROUP)) {
|
|
|
|
qDebug() << "processing gpsfix @" << get_dive_date_string(gpsfix->when) << "which is withing six hours of dive from" <<
|
|
|
|
get_dive_date_string(dive->when) << "until" << get_dive_date_string(dive->when + dive->duration.seconds);
|
Change in logic while aplying gps fixes to dives
We were actually searching dives which match the dowloaded position
fixes. So we're also trying to take into account if the fix is automatic
or no based on a limited amount of predefined strings (bad idea, as the
user can change in companion app settings the predefined string).
This way, in actual implementation, if program concludes that a fix has
been manually got or, simply, the user is unlucky enough to have all the
position fixes out of the dive time, find_dive_n_near() function will
pair fix and dive in an ordered way (1st fix -> 1st dive; 2nd fix -> 2nd
dive ...) which is probably erroneous, except for manual position fixes.
BTW actual implementation can't pair the same gps position with more
than one dive, which would be the case, e.g. in repetitive dives while at
anchor in the same point.
The patch changes the logic:
- Search positions for defined dives (instead of dives for defined
positions) without care if position has manually or automatically been
set.
- Only take care of those dives that don't have a position yet.
- It makes two assumptions:
a.- If the position fix has been taken during the dive time, is
correct. If there are more than one inside the dive time, takes the
first one (closest to the DC's reported time).
b.- If not during diving time, the correct one is the nearest fix
before the dive begins (also the usual case if manually fixed from the
smartphone just before jump into the water). But will work too if there
is only one fix *in SAME_GROUP range* after the dive (another usual
case).
- Finally, as copy_gps_location() in dive.h is used only here, let it
take care of naming the dive if user hasn't named it yet.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-07-16 05:23:34 +00:00
|
|
|
/*
|
|
|
|
* If position is fixed during dive. This is the good one.
|
|
|
|
* Asign and mark position, and end gps_location loop
|
|
|
|
*/
|
2015-06-25 05:38:44 +00:00
|
|
|
if (time_during_dive_with_offset(dive, gpsfix->when, 0)) {
|
|
|
|
qDebug() << "gpsfix is during the dive, pick that one";
|
2015-02-13 15:14:30 +00:00
|
|
|
copy_gps_location(gpsfix, dive);
|
Change in logic while aplying gps fixes to dives
We were actually searching dives which match the dowloaded position
fixes. So we're also trying to take into account if the fix is automatic
or no based on a limited amount of predefined strings (bad idea, as the
user can change in companion app settings the predefined string).
This way, in actual implementation, if program concludes that a fix has
been manually got or, simply, the user is unlucky enough to have all the
position fixes out of the dive time, find_dive_n_near() function will
pair fix and dive in an ordered way (1st fix -> 1st dive; 2nd fix -> 2nd
dive ...) which is probably erroneous, except for manual position fixes.
BTW actual implementation can't pair the same gps position with more
than one dive, which would be the case, e.g. in repetitive dives while at
anchor in the same point.
The patch changes the logic:
- Search positions for defined dives (instead of dives for defined
positions) without care if position has manually or automatically been
set.
- Only take care of those dives that don't have a position yet.
- It makes two assumptions:
a.- If the position fix has been taken during the dive time, is
correct. If there are more than one inside the dive time, takes the
first one (closest to the DC's reported time).
b.- If not during diving time, the correct one is the nearest fix
before the dive begins (also the usual case if manually fixed from the
smartphone just before jump into the water). But will work too if there
is only one fix *in SAME_GROUP range* after the dive (another usual
case).
- Finally, as copy_gps_location() in dive.h is used only here, let it
take care of naming the dive if user hasn't named it yet.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-07-16 05:23:34 +00:00
|
|
|
changed++;
|
|
|
|
tracer = j;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* If it is not, check if there are more position fixes in SAME_GROUP range
|
|
|
|
*/
|
2015-06-25 05:38:44 +00:00
|
|
|
if ((nextgpsfix = get_dive_from_table(j + 1, &gps_location_table)) &&
|
|
|
|
time_during_dive_with_offset(dive, nextgpsfix->when, SAME_GROUP)) {
|
|
|
|
qDebug() << "look at the next gps fix @" << get_dive_date_string(nextgpsfix->when);
|
|
|
|
/* first let's test if this one is during the dive */
|
|
|
|
if (time_during_dive_with_offset(dive, nextgpsfix->when, 0)) {
|
|
|
|
qDebug() << "which is during the dive, pick that one";
|
|
|
|
copy_gps_location(nextgpsfix, dive);
|
|
|
|
changed++;
|
|
|
|
tracer = j + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* we know the gps fixes are sorted; if they are both before the dive, ignore the first,
|
|
|
|
* if theay are both after the dive, take the first,
|
|
|
|
* if the first is before and the second is after, take the closer one */
|
|
|
|
if (nextgpsfix->when < dive->when) {
|
|
|
|
qDebug() << "which is closer to the start of the dive, do continue with that";
|
|
|
|
continue;
|
|
|
|
} else if (gpsfix->when > dive->when + dive->duration.seconds) {
|
|
|
|
qDebug() << "which is even later after the end of the dive, so pick the previous one";
|
2015-02-13 15:14:30 +00:00
|
|
|
copy_gps_location(gpsfix, dive);
|
2015-06-09 21:34:37 +00:00
|
|
|
changed++;
|
Change in logic while aplying gps fixes to dives
We were actually searching dives which match the dowloaded position
fixes. So we're also trying to take into account if the fix is automatic
or no based on a limited amount of predefined strings (bad idea, as the
user can change in companion app settings the predefined string).
This way, in actual implementation, if program concludes that a fix has
been manually got or, simply, the user is unlucky enough to have all the
position fixes out of the dive time, find_dive_n_near() function will
pair fix and dive in an ordered way (1st fix -> 1st dive; 2nd fix -> 2nd
dive ...) which is probably erroneous, except for manual position fixes.
BTW actual implementation can't pair the same gps position with more
than one dive, which would be the case, e.g. in repetitive dives while at
anchor in the same point.
The patch changes the logic:
- Search positions for defined dives (instead of dives for defined
positions) without care if position has manually or automatically been
set.
- Only take care of those dives that don't have a position yet.
- It makes two assumptions:
a.- If the position fix has been taken during the dive time, is
correct. If there are more than one inside the dive time, takes the
first one (closest to the DC's reported time).
b.- If not during diving time, the correct one is the nearest fix
before the dive begins (also the usual case if manually fixed from the
smartphone just before jump into the water). But will work too if there
is only one fix *in SAME_GROUP range* after the dive (another usual
case).
- Finally, as copy_gps_location() in dive.h is used only here, let it
take care of naming the dive if user hasn't named it yet.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-07-16 05:23:34 +00:00
|
|
|
tracer = j;
|
|
|
|
break;
|
2015-06-25 05:38:44 +00:00
|
|
|
} else {
|
|
|
|
/* ok, gpsfix is before, nextgpsfix is after */
|
|
|
|
if (dive->when - gpsfix->when <= nextgpsfix->when - (dive->when + dive->duration.seconds)) {
|
|
|
|
qDebug() << "pick the one before as it's closer to the start";
|
|
|
|
copy_gps_location(gpsfix, dive);
|
|
|
|
changed++;
|
|
|
|
tracer = j;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
qDebug() << "pick the one after as it's closer to the start";
|
|
|
|
copy_gps_location(nextgpsfix, dive);
|
|
|
|
changed++;
|
|
|
|
tracer = j + 1;
|
|
|
|
break;
|
|
|
|
}
|
Change in logic while aplying gps fixes to dives
We were actually searching dives which match the dowloaded position
fixes. So we're also trying to take into account if the fix is automatic
or no based on a limited amount of predefined strings (bad idea, as the
user can change in companion app settings the predefined string).
This way, in actual implementation, if program concludes that a fix has
been manually got or, simply, the user is unlucky enough to have all the
position fixes out of the dive time, find_dive_n_near() function will
pair fix and dive in an ordered way (1st fix -> 1st dive; 2nd fix -> 2nd
dive ...) which is probably erroneous, except for manual position fixes.
BTW actual implementation can't pair the same gps position with more
than one dive, which would be the case, e.g. in repetitive dives while at
anchor in the same point.
The patch changes the logic:
- Search positions for defined dives (instead of dives for defined
positions) without care if position has manually or automatically been
set.
- Only take care of those dives that don't have a position yet.
- It makes two assumptions:
a.- If the position fix has been taken during the dive time, is
correct. If there are more than one inside the dive time, takes the
first one (closest to the DC's reported time).
b.- If not during diving time, the correct one is the nearest fix
before the dive begins (also the usual case if manually fixed from the
smartphone just before jump into the water). But will work too if there
is only one fix *in SAME_GROUP range* after the dive (another usual
case).
- Finally, as copy_gps_location() in dive.h is used only here, let it
take care of naming the dive if user hasn't named it yet.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-07-16 05:23:34 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If no more positions in range, the actual is the one. Asign, mark and end loop.
|
|
|
|
*/
|
|
|
|
} else {
|
2015-06-25 05:38:44 +00:00
|
|
|
qDebug() << "which seems to be the best one for this dive, so pick it";
|
2015-02-13 15:14:30 +00:00
|
|
|
copy_gps_location(gpsfix, dive);
|
Change in logic while aplying gps fixes to dives
We were actually searching dives which match the dowloaded position
fixes. So we're also trying to take into account if the fix is automatic
or no based on a limited amount of predefined strings (bad idea, as the
user can change in companion app settings the predefined string).
This way, in actual implementation, if program concludes that a fix has
been manually got or, simply, the user is unlucky enough to have all the
position fixes out of the dive time, find_dive_n_near() function will
pair fix and dive in an ordered way (1st fix -> 1st dive; 2nd fix -> 2nd
dive ...) which is probably erroneous, except for manual position fixes.
BTW actual implementation can't pair the same gps position with more
than one dive, which would be the case, e.g. in repetitive dives while at
anchor in the same point.
The patch changes the logic:
- Search positions for defined dives (instead of dives for defined
positions) without care if position has manually or automatically been
set.
- Only take care of those dives that don't have a position yet.
- It makes two assumptions:
a.- If the position fix has been taken during the dive time, is
correct. If there are more than one inside the dive time, takes the
first one (closest to the DC's reported time).
b.- If not during diving time, the correct one is the nearest fix
before the dive begins (also the usual case if manually fixed from the
smartphone just before jump into the water). But will work too if there
is only one fix *in SAME_GROUP range* after the dive (another usual
case).
- Finally, as copy_gps_location() in dive.h is used only here, let it
take care of naming the dive if user hasn't named it yet.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-07-16 05:23:34 +00:00
|
|
|
changed++;
|
|
|
|
tracer = j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* If position is out of SAME_GROUP range and in the future, mark position for
|
|
|
|
* next dive iteration and end the gps_location loop
|
|
|
|
*/
|
|
|
|
if (gpsfix->when >= dive->when + dive->duration.seconds + SAME_GROUP) {
|
|
|
|
tracer = j;
|
|
|
|
break;
|
|
|
|
}
|
2013-11-14 22:59:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return changed > 0;
|
|
|
|
}
|
Change in logic while aplying gps fixes to dives
We were actually searching dives which match the dowloaded position
fixes. So we're also trying to take into account if the fix is automatic
or no based on a limited amount of predefined strings (bad idea, as the
user can change in companion app settings the predefined string).
This way, in actual implementation, if program concludes that a fix has
been manually got or, simply, the user is unlucky enough to have all the
position fixes out of the dive time, find_dive_n_near() function will
pair fix and dive in an ordered way (1st fix -> 1st dive; 2nd fix -> 2nd
dive ...) which is probably erroneous, except for manual position fixes.
BTW actual implementation can't pair the same gps position with more
than one dive, which would be the case, e.g. in repetitive dives while at
anchor in the same point.
The patch changes the logic:
- Search positions for defined dives (instead of dives for defined
positions) without care if position has manually or automatically been
set.
- Only take care of those dives that don't have a position yet.
- It makes two assumptions:
a.- If the position fix has been taken during the dive time, is
correct. If there are more than one inside the dive time, takes the
first one (closest to the DC's reported time).
b.- If not during diving time, the correct one is the nearest fix
before the dive begins (also the usual case if manually fixed from the
smartphone just before jump into the water). But will work too if there
is only one fix *in SAME_GROUP range* after the dive (another usual
case).
- Finally, as copy_gps_location() in dive.h is used only here, let it
take care of naming the dive if user hasn't named it yet.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-07-16 05:23:34 +00:00
|
|
|
|
2014-04-17 02:56:42 +00:00
|
|
|
// TODO: This looks like should be ported to C code. or a big part of it.
|
2014-03-14 18:26:07 +00:00
|
|
|
bool DivelogsDeWebServices::prepare_dives_for_divelogs(const QString &tempfile, const bool selected)
|
2013-12-05 16:31:40 +00:00
|
|
|
{
|
2013-12-12 01:56:29 +00:00
|
|
|
static const char errPrefix[] = "divelog.de-upload:";
|
2013-12-12 01:56:28 +00:00
|
|
|
if (!amount_selected) {
|
2014-03-14 18:26:07 +00:00
|
|
|
report_error(tr("no dives were selected").toUtf8());
|
2013-12-20 01:03:21 +00:00
|
|
|
return false;
|
2013-12-12 01:56:28 +00:00
|
|
|
}
|
|
|
|
|
2013-12-05 16:31:40 +00:00
|
|
|
xsltStylesheetPtr xslt = NULL;
|
|
|
|
struct zip *zip;
|
|
|
|
|
2013-12-12 01:56:30 +00:00
|
|
|
xslt = get_stylesheet("divelogs-export.xslt");
|
|
|
|
if (!xslt) {
|
|
|
|
qDebug() << errPrefix << "missing stylesheet";
|
2013-12-20 01:03:21 +00:00
|
|
|
return false;
|
2013-12-12 01:56:30 +00:00
|
|
|
}
|
|
|
|
|
2013-12-05 16:31:40 +00:00
|
|
|
|
2013-12-20 01:03:23 +00:00
|
|
|
int error_code;
|
2014-08-03 17:22:48 +00:00
|
|
|
zip = zip_open(QFile::encodeName(QDir::toNativeSeparators(tempfile)), ZIP_CREATE, &error_code);
|
2013-12-07 14:43:28 +00:00
|
|
|
if (!zip) {
|
2013-12-20 01:03:23 +00:00
|
|
|
char buffer[1024];
|
|
|
|
zip_error_to_str(buffer, sizeof buffer, error_code, errno);
|
2014-03-14 18:26:07 +00:00
|
|
|
report_error(tr("failed to create zip file for upload: %s").toUtf8(), buffer);
|
2013-12-20 01:03:21 +00:00
|
|
|
return false;
|
2013-12-07 14:43:28 +00:00
|
|
|
}
|
2013-12-05 16:31:40 +00:00
|
|
|
|
|
|
|
/* walk the dive list in chronological order */
|
2014-05-19 21:37:19 +00:00
|
|
|
int i;
|
|
|
|
struct dive *dive;
|
2015-04-28 18:28:53 +00:00
|
|
|
struct membuffer mb = { 0 };
|
2014-05-22 18:40:22 +00:00
|
|
|
for_each_dive (i, dive) {
|
2013-12-20 01:03:24 +00:00
|
|
|
FILE *f;
|
|
|
|
char filename[PATH_MAX];
|
|
|
|
int streamsize;
|
2015-04-28 18:28:53 +00:00
|
|
|
const char *membuf;
|
2013-12-20 01:03:24 +00:00
|
|
|
xmlDoc *transformed;
|
2013-12-20 01:03:25 +00:00
|
|
|
struct zip_source *s;
|
2013-12-20 01:03:24 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the i'th dive in XML format so we can process it.
|
|
|
|
* We need to save to a file before we can reload it back into memory...
|
|
|
|
*/
|
2013-12-05 16:31:40 +00:00
|
|
|
if (selected && !dive->selected)
|
|
|
|
continue;
|
2015-04-28 18:28:53 +00:00
|
|
|
/* make sure the buffer is empty and add the dive */
|
|
|
|
mb.len = 0;
|
2015-09-06 18:40:15 +00:00
|
|
|
|
|
|
|
struct dive_site *ds = get_dive_site_by_uuid(dive->dive_site_uuid);
|
|
|
|
|
|
|
|
if (ds) {
|
|
|
|
put_format(&mb, "<divelog><divesites><site uuid='%8x' name='", dive->dive_site_uuid);
|
|
|
|
put_quoted(&mb, ds->name, 1, 0);
|
|
|
|
put_format(&mb, "'");
|
|
|
|
if (ds->latitude.udeg || ds->longitude.udeg) {
|
|
|
|
put_degrees(&mb, ds->latitude, " gps='", " ");
|
|
|
|
put_degrees(&mb, ds->longitude, "", "'");
|
|
|
|
}
|
|
|
|
put_format(&mb, "/>\n</divesites>\n");
|
|
|
|
}
|
|
|
|
|
2015-04-28 18:28:53 +00:00
|
|
|
save_one_dive_to_mb(&mb, dive);
|
2015-09-06 18:40:15 +00:00
|
|
|
|
|
|
|
if (ds) {
|
|
|
|
put_format(&mb, "</divelog>\n");
|
|
|
|
}
|
2015-04-28 18:28:53 +00:00
|
|
|
membuf = mb_cstring(&mb);
|
|
|
|
streamsize = strlen(membuf);
|
2013-12-05 16:31:40 +00:00
|
|
|
/*
|
|
|
|
* Parse the memory buffer into XML document and
|
|
|
|
* transform it to divelogs.de format, finally dumping
|
|
|
|
* the XML into a character buffer.
|
|
|
|
*/
|
2013-12-12 01:56:33 +00:00
|
|
|
xmlDoc *doc = xmlReadMemory(membuf, streamsize, "divelog", NULL, 0);
|
2013-12-07 14:43:28 +00:00
|
|
|
if (!doc) {
|
2013-12-20 01:03:23 +00:00
|
|
|
qWarning() << errPrefix << "could not parse back into memory the XML file we've just created!";
|
2014-03-14 18:26:07 +00:00
|
|
|
report_error(tr("internal error").toUtf8());
|
2013-12-12 01:56:32 +00:00
|
|
|
goto error_close_zip;
|
2013-12-07 14:43:28 +00:00
|
|
|
}
|
2013-12-05 16:31:40 +00:00
|
|
|
free((void *)membuf);
|
2013-12-20 01:03:24 +00:00
|
|
|
|
2013-12-05 16:31:40 +00:00
|
|
|
transformed = xsltApplyStylesheet(xslt, doc, NULL);
|
2014-02-28 04:09:57 +00:00
|
|
|
xmlDocDumpMemory(transformed, (xmlChar **)&membuf, &streamsize);
|
2013-12-05 16:31:40 +00:00
|
|
|
xmlFreeDoc(doc);
|
|
|
|
xmlFreeDoc(transformed);
|
2013-12-20 01:03:24 +00:00
|
|
|
|
2013-12-05 16:31:40 +00:00
|
|
|
/*
|
|
|
|
* Save the XML document into a zip file.
|
|
|
|
*/
|
|
|
|
snprintf(filename, PATH_MAX, "%d.xml", i + 1);
|
2013-12-20 01:03:25 +00:00
|
|
|
s = zip_source_buffer(zip, membuf, streamsize, 1);
|
|
|
|
if (s) {
|
|
|
|
int64_t ret = zip_add(zip, filename, s);
|
2013-12-05 16:31:40 +00:00
|
|
|
if (ret == -1)
|
2013-12-09 17:23:31 +00:00
|
|
|
qDebug() << errPrefix << "failed to include dive:" << i;
|
2013-12-05 16:31:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
zip_close(zip);
|
2013-12-12 01:56:30 +00:00
|
|
|
xsltFreeStylesheet(xslt);
|
2013-12-20 01:03:21 +00:00
|
|
|
return true;
|
2013-12-12 01:56:32 +00:00
|
|
|
|
|
|
|
error_close_zip:
|
|
|
|
zip_close(zip);
|
2013-12-20 01:03:21 +00:00
|
|
|
QFile::remove(tempfile);
|
2013-12-12 01:56:32 +00:00
|
|
|
xsltFreeStylesheet(xslt);
|
2013-12-20 01:03:21 +00:00
|
|
|
return false;
|
2013-12-05 16:31:40 +00:00
|
|
|
}
|
|
|
|
|
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-14 22:55:49 +00:00
|
|
|
QNetworkAccessManager *WebServices::manager()
|
|
|
|
{
|
|
|
|
static QNetworkAccessManager *manager = new QNetworkAccessManager(qApp);
|
|
|
|
return manager;
|
|
|
|
}
|
|
|
|
|
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-10-25 00:52:11 +00:00
|
|
|
// #
|
|
|
|
// #
|
|
|
|
// # Subsurface Web Service Implementation.
|
|
|
|
// #
|
|
|
|
// #
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
SubsurfaceWebServices::SubsurfaceWebServices(QWidget *parent, Qt::WindowFlags f) : WebServices(parent, f)
|
2013-10-03 18:54:25 +00:00
|
|
|
{
|
2013-06-06 14:57:12 +00:00
|
|
|
QSettings s;
|
2014-04-17 14:34:21 +00:00
|
|
|
if (!prefs.save_userid_local || !*prefs.userid)
|
2014-04-11 06:17:35 +00:00
|
|
|
ui.userID->setText(s.value("subsurface_webservice_uid").toString().toUpper());
|
|
|
|
else
|
2014-04-17 14:34:21 +00:00
|
|
|
ui.userID->setText(prefs.userid);
|
2013-10-25 00:30:21 +00:00
|
|
|
hidePassword();
|
|
|
|
hideUpload();
|
2014-07-22 17:52:56 +00:00
|
|
|
ui.progressBar->setFormat(tr("Enter User ID and click Download"));
|
2014-02-28 04:09:57 +00:00
|
|
|
ui.progressBar->setRange(0, 1);
|
2014-01-15 08:33:04 +00:00
|
|
|
ui.progressBar->setValue(-1);
|
2014-07-22 17:50:44 +00:00
|
|
|
ui.progressBar->setAlignment(Qt::AlignCenter);
|
2014-04-17 14:34:21 +00:00
|
|
|
ui.saveUidLocal->setChecked(prefs.save_userid_local);
|
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-06-06 14:57:12 +00:00
|
|
|
}
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
void SubsurfaceWebServices::buttonClicked(QAbstractButton *button)
|
2013-06-06 13:33:15 +00:00
|
|
|
{
|
2013-10-03 18:54:25 +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: {
|
2015-02-13 15:14:30 +00:00
|
|
|
int i;
|
|
|
|
struct dive *d;
|
|
|
|
struct dive_site *ds;
|
2015-06-10 14:09:23 +00:00
|
|
|
bool changed = false;
|
2013-11-14 22:39:17 +00:00
|
|
|
clear_table(&gps_location_table);
|
|
|
|
QByteArray url = tr("Webservice").toLocal8Bit();
|
2014-03-14 18:26:07 +00:00
|
|
|
parse_xml_buffer(url.data(), downloadedData.data(), downloadedData.length(), &gps_location_table, NULL);
|
2015-02-13 15:14:30 +00:00
|
|
|
// make sure we mark all the dive sites that were created
|
|
|
|
for (i = 0; i < gps_location_table.nr; i++) {
|
|
|
|
d = get_dive_from_table(i, &gps_location_table);
|
|
|
|
ds = get_dive_site_by_uuid(d->dive_site_uuid);
|
|
|
|
if (ds)
|
|
|
|
ds->notes = strdup("SubsurfaceWebservice");
|
|
|
|
}
|
2013-11-14 22:39:17 +00:00
|
|
|
/* now merge the data in the gps_location table into the dive_table */
|
|
|
|
if (merge_locations_into_dives()) {
|
2015-06-10 14:09:23 +00:00
|
|
|
changed = true;
|
2014-01-15 08:30:42 +00:00
|
|
|
mark_divelist_changed(true);
|
2014-07-02 19:58:41 +00:00
|
|
|
MainWindow::instance()->information()->updateDiveInfo();
|
2013-06-06 14:57:12 +00:00
|
|
|
}
|
2013-11-14 22:39:17 +00:00
|
|
|
|
|
|
|
/* store last entered uid in config */
|
|
|
|
QSettings s;
|
2014-04-11 06:17:35 +00:00
|
|
|
QString qDialogUid = ui.userID->text().toUpper();
|
|
|
|
bool qSaveUid = ui.saveUidLocal->checkState();
|
|
|
|
set_save_userid_local(qSaveUid);
|
|
|
|
if (qSaveUid) {
|
|
|
|
QString qSettingUid = s.value("subsurface_webservice_uid").toString();
|
2014-04-17 14:34:21 +00:00
|
|
|
QString qFileUid = QString(prefs.userid);
|
2014-04-11 06:17:35 +00:00
|
|
|
bool s_eq_d = (qSettingUid == qDialogUid);
|
|
|
|
bool d_eq_f = (qDialogUid == qFileUid);
|
|
|
|
if (!d_eq_f || s_eq_d)
|
|
|
|
s.setValue("subsurface_webservice_uid", qDialogUid);
|
|
|
|
set_userid(qDialogUid.toLocal8Bit().data());
|
|
|
|
} else {
|
|
|
|
s.setValue("subsurface_webservice_uid", qDialogUid);
|
|
|
|
}
|
2013-11-14 22:39:17 +00:00
|
|
|
s.sync();
|
|
|
|
hide();
|
|
|
|
close();
|
2013-11-15 00:50:46 +00:00
|
|
|
resetState();
|
2015-02-13 15:14:30 +00:00
|
|
|
/* and now clean up and remove all the extra dive sites that were created */
|
|
|
|
QSet<uint32_t> usedUuids;
|
|
|
|
for_each_dive(i, d) {
|
|
|
|
if (d->dive_site_uuid)
|
|
|
|
usedUuids.insert(d->dive_site_uuid);
|
|
|
|
}
|
|
|
|
for_each_dive_site(i, ds) {
|
2015-06-09 21:35:27 +00:00
|
|
|
if (!usedUuids.contains(ds->uuid) && same_string(ds->notes, "SubsurfaceWebservice")) {
|
2015-02-13 15:14:30 +00:00
|
|
|
delete_dive_site(ds->uuid);
|
2015-06-09 21:35:27 +00:00
|
|
|
i--; // otherwise we skip one site
|
|
|
|
}
|
2015-02-13 15:14:30 +00:00
|
|
|
}
|
2015-06-10 14:09:23 +00:00
|
|
|
#ifndef NO_MARBLE
|
|
|
|
// finally now that all the extra GPS fixes that weren't used have been deleted
|
|
|
|
// we can update the globe
|
|
|
|
if (changed) {
|
2015-07-31 00:51:38 +00:00
|
|
|
GlobeGPS::instance()->repopulateLabels();
|
|
|
|
GlobeGPS::instance()->centerOnDiveSite(get_dive_site_by_uuid(current_dive->dive_site_uuid));
|
2015-06-10 14:09:23 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
} break;
|
2013-11-14 22:39:17 +00:00
|
|
|
case QDialogButtonBox::RejectRole:
|
2013-12-09 15:42:06 +00:00
|
|
|
if (reply != NULL && reply->isOpen()) {
|
|
|
|
reply->abort();
|
|
|
|
delete reply;
|
|
|
|
reply = NULL;
|
|
|
|
}
|
2013-11-15 00:50:46 +00:00
|
|
|
resetState();
|
2013-11-14 22:39:17 +00:00
|
|
|
break;
|
|
|
|
case QDialogButtonBox::HelpRole:
|
|
|
|
QDesktopServices::openUrl(QUrl("http://api.hohndel.org"));
|
|
|
|
break;
|
|
|
|
default:
|
2013-06-06 14:57:12 +00:00
|
|
|
break;
|
2013-06-06 14:31:55 +00:00
|
|
|
}
|
2013-06-06 13:33:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SubsurfaceWebServices::startDownload()
|
|
|
|
{
|
|
|
|
QUrl url("http://api.hohndel.org/api/dive/get/");
|
2014-01-15 08:30:34 +00:00
|
|
|
QUrlQuery query;
|
|
|
|
query.addQueryItem("login", ui.userID->text().toUpper());
|
|
|
|
url.setQuery(query);
|
2013-06-06 14:31:55 +00:00
|
|
|
|
2013-06-06 13:33:15 +00:00
|
|
|
QNetworkRequest request;
|
|
|
|
request.setUrl(url);
|
|
|
|
request.setRawHeader("Accept", "text/xml");
|
2014-07-31 18:20:11 +00:00
|
|
|
request.setRawHeader("User-Agent", userAgent.toUtf8());
|
2013-11-14 22:55:49 +00:00
|
|
|
reply = manager()->get(request);
|
2013-11-14 23:05:24 +00:00
|
|
|
ui.status->setText(tr("Connecting..."));
|
2014-01-15 08:33:04 +00:00
|
|
|
ui.progressBar->setEnabled(true);
|
2014-02-28 04:09:57 +00:00
|
|
|
ui.progressBar->setRange(0, 0); // this makes the progressbar do an 'infinite spin'
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.download->setEnabled(false);
|
|
|
|
ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
|
2013-11-15 00:52:08 +00:00
|
|
|
connectSignalsForDownload(reply);
|
2013-06-06 13:33:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SubsurfaceWebServices::downloadFinished()
|
|
|
|
{
|
2013-11-15 00:52:08 +00:00
|
|
|
if (!reply)
|
|
|
|
return;
|
|
|
|
|
2014-02-28 04:09:57 +00:00
|
|
|
ui.progressBar->setRange(0, 1);
|
2014-01-15 08:33:04 +00:00
|
|
|
ui.progressBar->setValue(1);
|
|
|
|
ui.progressBar->setFormat("%p%");
|
2013-06-06 14:31:55 +00:00
|
|
|
downloadedData = reply->readAll();
|
|
|
|
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.download->setEnabled(true);
|
2013-11-15 02:57:09 +00:00
|
|
|
ui.status->setText(tr("Download finished"));
|
2013-06-06 14:31:55 +00:00
|
|
|
|
|
|
|
uint resultCode = download_dialog_parse_response(downloadedData);
|
|
|
|
setStatusText(resultCode);
|
2014-01-16 04:50:56 +00:00
|
|
|
if (resultCode == DD_STATUS_OK) {
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true);
|
2013-06-06 14:31:55 +00:00
|
|
|
}
|
|
|
|
reply->deleteLater();
|
2013-11-15 00:52:08 +00:00
|
|
|
reply = NULL;
|
2013-06-06 13:33:15 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 01:47:30 +00:00
|
|
|
void SubsurfaceWebServices::downloadError(QNetworkReply::NetworkError)
|
2013-06-06 13:33:15 +00:00
|
|
|
{
|
2013-11-15 00:50:46 +00:00
|
|
|
resetState();
|
|
|
|
ui.status->setText(tr("Download error: %1").arg(reply->errorString()));
|
2013-06-06 14:31:55 +00:00
|
|
|
reply->deleteLater();
|
2013-11-15 00:52:08 +00:00
|
|
|
reply = NULL;
|
2013-06-06 13:33:15 +00:00
|
|
|
}
|
|
|
|
|
2013-06-06 14:31:55 +00:00
|
|
|
void SubsurfaceWebServices::setStatusText(int status)
|
|
|
|
{
|
|
|
|
QString text;
|
2014-01-16 04:50:56 +00:00
|
|
|
switch (status) {
|
2014-02-28 04:09:57 +00:00
|
|
|
case DD_STATUS_ERROR_CONNECT:
|
2014-07-11 17:39:03 +00:00
|
|
|
text = tr("Connection error: ");
|
2014-02-28 04:09:57 +00:00
|
|
|
break;
|
|
|
|
case DD_STATUS_ERROR_ID:
|
|
|
|
text = tr("Invalid user identifier!");
|
|
|
|
break;
|
|
|
|
case DD_STATUS_ERROR_PARSE:
|
|
|
|
text = tr("Cannot parse response!");
|
|
|
|
break;
|
|
|
|
case DD_STATUS_OK:
|
2014-07-11 17:39:03 +00:00
|
|
|
text = tr("Download successful");
|
2014-02-28 04:09:57 +00:00
|
|
|
break;
|
2013-06-06 14:31:55 +00:00
|
|
|
}
|
2013-10-03 18:54:25 +00:00
|
|
|
ui.status->setText(text);
|
2013-06-06 14:31:55 +00:00
|
|
|
}
|
2013-06-06 13:33:15 +00:00
|
|
|
|
2014-04-17 02:56:42 +00:00
|
|
|
//TODO: C-Code.
|
2013-06-06 14:31:55 +00:00
|
|
|
/* requires that there is a <download> or <error> tag under the <root> tag */
|
|
|
|
void SubsurfaceWebServices::download_dialog_traverse_xml(xmlNodePtr node, unsigned int *download_status)
|
|
|
|
{
|
|
|
|
xmlNodePtr cur_node;
|
|
|
|
for (cur_node = node; cur_node; cur_node = cur_node->next) {
|
|
|
|
if ((!strcmp((const char *)cur_node->name, (const char *)"download")) &&
|
2014-02-28 04:09:57 +00:00
|
|
|
(!strcmp((const char *)xmlNodeGetContent(cur_node), (const char *)"ok"))) {
|
2013-06-06 14:31:55 +00:00
|
|
|
*download_status = DD_STATUS_OK;
|
|
|
|
return;
|
2014-02-28 04:09:57 +00:00
|
|
|
} else if (!strcmp((const char *)cur_node->name, (const char *)"error")) {
|
2013-06-06 14:31:55 +00:00
|
|
|
*download_status = DD_STATUS_ERROR_ID;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-17 02:56:42 +00:00
|
|
|
// TODO: C-Code
|
2014-02-28 04:09:57 +00:00
|
|
|
unsigned int SubsurfaceWebServices::download_dialog_parse_response(const QByteArray &xml)
|
2013-06-06 14:31:55 +00:00
|
|
|
{
|
|
|
|
xmlNodePtr root;
|
|
|
|
xmlDocPtr doc = xmlParseMemory(xml.data(), xml.length());
|
|
|
|
unsigned int status = DD_STATUS_ERROR_PARSE;
|
|
|
|
|
|
|
|
if (!doc)
|
|
|
|
return DD_STATUS_ERROR_PARSE;
|
|
|
|
root = xmlDocGetRootElement(doc);
|
|
|
|
if (!root) {
|
|
|
|
status = DD_STATUS_ERROR_PARSE;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
if (root->children)
|
|
|
|
download_dialog_traverse_xml(root->children, &status);
|
2013-11-14 22:39:17 +00:00
|
|
|
end:
|
|
|
|
xmlFreeDoc(doc);
|
|
|
|
return status;
|
2013-06-06 14:31:55 +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);
|
2014-07-15 23:27:32 +00:00
|
|
|
const QString invalidXmlError = QObject::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 =
|
2014-07-15 23:27:32 +00:00
|
|
|
QObject::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;
|
2014-07-15 23:27:32 +00:00
|
|
|
result.errorDetails = QObject::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;
|
2014-07-15 23:27:32 +00:00
|
|
|
result.errorDetails = QObject::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
|
|
|
self->setAttribute(Qt::WA_QuitOnClose, false);
|
|
|
|
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";
|
2014-05-20 16:33:32 +00:00
|
|
|
if (prepare_dives_for_divelogs(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-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
|
|
|
}
|
2015-02-27 00:57:56 +00:00
|
|
|
MainWindow::instance()->getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
|
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
|
|
|
{
|
|
|
|
QSettings s;
|
|
|
|
ui.userID->setText(s.value("divelogde_user").toString());
|
|
|
|
ui.password->setText(s.value("divelogde_pass").toString());
|
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()
|
|
|
|
{
|
2013-12-09 14:45:54 +00:00
|
|
|
QSettings s;
|
|
|
|
s.setValue("divelogde_user", ui.userID->text());
|
|
|
|
s.setValue("divelogde_pass", ui.password->text());
|
|
|
|
s.sync();
|
|
|
|
|
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());
|
|
|
|
body.addQueryItem("pass", ui.password->text());
|
|
|
|
|
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());
|
|
|
|
body.addQueryItem("pass", ui.password->text());
|
|
|
|
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"),
|
|
|
|
tr("The archive could not be opened:\n"));
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void DivelogsDeWebServices::setStatusText(int status)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
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 */
|
2014-03-14 18:26:07 +00:00
|
|
|
parse_file(QFile::encodeName(zipFile.fileName()));
|
2014-01-15 08:30:42 +00:00
|
|
|
process_dives(true, false);
|
2014-02-12 14:22:54 +00:00
|
|
|
MainWindow::instance()->refreshDisplay();
|
2013-12-07 01:10:32 +00:00
|
|
|
|
2013-12-07 12:33:43 +00:00
|
|
|
/* store last entered user/pass in config */
|
|
|
|
QSettings s;
|
|
|
|
s.setValue("divelogde_user", ui.userID->text());
|
|
|
|
s.setValue("divelogde_pass", ui.password->text());
|
|
|
|
s.sync();
|
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
|
|
|
|
|
|
|
UserSurveyServices::UserSurveyServices(QWidget *parent, Qt::WindowFlags f) : WebServices(parent, f)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-07-16 20:20:21 +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");
|
2014-07-31 18:20:11 +00:00
|
|
|
request.setRawHeader("User-Agent", userAgent.toUtf8());
|
2014-06-30 14:19:22 +00:00
|
|
|
reply = manager()->get(request);
|
2014-07-16 20:20:21 +00:00
|
|
|
return reply;
|
2014-06-30 14:19:22 +00:00
|
|
|
}
|
2015-06-05 00:26:30 +00:00
|
|
|
|
2015-06-22 13:42:02 +00:00
|
|
|
CloudStorageAuthenticate::CloudStorageAuthenticate(QObject *parent) :
|
|
|
|
QObject(parent),
|
|
|
|
reply(NULL)
|
2015-06-05 00:26:30 +00:00
|
|
|
{
|
|
|
|
userAgent = getUserAgent();
|
|
|
|
}
|
|
|
|
|
2015-06-15 13:05:00 +00:00
|
|
|
#define CLOUDURL QString(prefs.cloud_base_url)
|
|
|
|
#define CLOUDBACKENDSTORAGE CLOUDURL + "/storage"
|
|
|
|
#define CLOUDBACKENDVERIFY CLOUDURL + "/verify"
|
2015-07-22 18:10:40 +00:00
|
|
|
#define CLOUDBACKENDUPDATE CLOUDURL + "/update"
|
2015-06-05 00:26:30 +00:00
|
|
|
|
2015-07-22 18:10:40 +00:00
|
|
|
QNetworkReply* CloudStorageAuthenticate::backend(QString email, QString password, QString pin, QString newpasswd)
|
2015-06-05 00:26:30 +00:00
|
|
|
{
|
2015-06-09 18:21:46 +00:00
|
|
|
QString payload(email + " " + password);
|
|
|
|
QUrl requestUrl;
|
2015-07-22 18:10:40 +00:00
|
|
|
if (pin == "" && newpasswd == "") {
|
2015-06-09 18:21:46 +00:00
|
|
|
requestUrl = QUrl(CLOUDBACKENDSTORAGE);
|
2015-07-22 18:10:40 +00:00
|
|
|
} else if (newpasswd != "") {
|
|
|
|
requestUrl = QUrl(CLOUDBACKENDUPDATE);
|
|
|
|
payload += " " + newpasswd;
|
2015-06-09 18:21:46 +00:00
|
|
|
} else {
|
|
|
|
requestUrl = QUrl(CLOUDBACKENDVERIFY);
|
|
|
|
payload += " " + pin;
|
|
|
|
}
|
|
|
|
QNetworkRequest *request = new QNetworkRequest(requestUrl);
|
2015-06-05 00:26:30 +00:00
|
|
|
request->setRawHeader("Accept", "text/xml, text/plain");
|
|
|
|
request->setRawHeader("User-Agent", userAgent.toUtf8());
|
|
|
|
request->setHeader(QNetworkRequest::ContentTypeHeader, "text/plain");
|
2015-06-09 18:21:46 +00:00
|
|
|
reply = WebServices::manager()->post(*request, qPrintable(payload));
|
2015-06-05 00:26:30 +00:00
|
|
|
connect(reply, SIGNAL(finished()), this, SLOT(uploadFinished()));
|
|
|
|
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>)));
|
|
|
|
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
|
|
|
|
SLOT(uploadError(QNetworkReply::NetworkError)));
|
|
|
|
return reply;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CloudStorageAuthenticate::uploadFinished()
|
|
|
|
{
|
2015-06-14 21:18:51 +00:00
|
|
|
static QString myLastError;
|
|
|
|
|
2015-06-07 16:54:28 +00:00
|
|
|
QString cloudAuthReply(reply->readAll());
|
|
|
|
qDebug() << "Completed connection with cloud storage backend, response" << cloudAuthReply;
|
2015-06-14 20:50:13 +00:00
|
|
|
if (cloudAuthReply == "[VERIFIED]" || cloudAuthReply == "[OK]") {
|
|
|
|
prefs.cloud_verification_status = CS_VERIFIED;
|
2015-06-14 21:18:51 +00:00
|
|
|
NotificationWidget *nw = MainWindow::instance()->getNotificationWidget();
|
|
|
|
if (nw->getNotificationText() == myLastError)
|
|
|
|
nw->hideNotification();
|
|
|
|
myLastError.clear();
|
2015-06-09 18:21:46 +00:00
|
|
|
} else if (cloudAuthReply == "[VERIFY]") {
|
2015-06-14 20:50:13 +00:00
|
|
|
prefs.cloud_verification_status = CS_NEED_TO_VERIFY;
|
2015-07-22 22:06:57 +00:00
|
|
|
} else if (cloudAuthReply == "[PASSWDCHANGED]") {
|
|
|
|
free(prefs.cloud_storage_password);
|
|
|
|
prefs.cloud_storage_password = prefs.cloud_storage_newpassword;
|
|
|
|
prefs.cloud_storage_newpassword = NULL;
|
|
|
|
emit passwordChangeSuccessful();
|
|
|
|
return;
|
2015-06-14 20:50:13 +00:00
|
|
|
} else {
|
|
|
|
prefs.cloud_verification_status = CS_INCORRECT_USER_PASSWD;
|
2015-06-14 21:18:51 +00:00
|
|
|
myLastError = cloudAuthReply;
|
2015-06-14 20:50:13 +00:00
|
|
|
report_error("%s", qPrintable(cloudAuthReply));
|
|
|
|
MainWindow::instance()->getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error);
|
2015-06-09 18:21:46 +00:00
|
|
|
}
|
2015-06-14 21:06:44 +00:00
|
|
|
emit finishedAuthenticate();
|
2015-06-05 00:26:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CloudStorageAuthenticate::uploadError(QNetworkReply::NetworkError error)
|
|
|
|
{
|
|
|
|
qDebug() << "Received error response from cloud storage backend:" << reply->errorString();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CloudStorageAuthenticate::sslErrors(QList<QSslError> errorList)
|
|
|
|
{
|
|
|
|
qDebug() << "Received error response trying to set up https connection with cloud storage backend:";
|
|
|
|
Q_FOREACH (QSslError err, errorList) {
|
|
|
|
qDebug() << err.errorString();
|
|
|
|
}
|
|
|
|
}
|