mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-01 07:53:25 +00:00
Merge branch 'web' of github.com:neolit123/subsurface
This commit is contained in:
commit
8ac58181f7
4 changed files with 186 additions and 20 deletions
|
@ -8,6 +8,7 @@
|
||||||
#include "models.h"
|
#include "models.h"
|
||||||
#include "modeldelegates.h"
|
#include "modeldelegates.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
#include "subsurfacewebservices.h"
|
||||||
#include "../display.h"
|
#include "../display.h"
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
|
@ -726,6 +727,8 @@ void DiveListView::contextMenuEvent(QContextMenuEvent *event)
|
||||||
popup.addAction(tr("export As UDDF"), this, SLOT(exportSelectedDivesAsUDDF()));
|
popup.addAction(tr("export As UDDF"), this, SLOT(exportSelectedDivesAsUDDF()));
|
||||||
popup.addAction(tr("shift times"), this, SLOT(shiftTimes()));
|
popup.addAction(tr("shift times"), this, SLOT(shiftTimes()));
|
||||||
}
|
}
|
||||||
|
if (d)
|
||||||
|
popup.addAction(tr("upload dive(s) to divelogs.de"), this, SLOT(uploadToDivelogsDE()));
|
||||||
// "collapse all" really closes all trips,
|
// "collapse all" really closes all trips,
|
||||||
// "collapse" keeps the trip with the selected dive open
|
// "collapse" keeps the trip with the selected dive open
|
||||||
QAction * actionTaken = popup.exec(event->globalPos());
|
QAction * actionTaken = popup.exec(event->globalPos());
|
||||||
|
@ -781,3 +784,8 @@ void DiveListView::shiftTimes()
|
||||||
{
|
{
|
||||||
ShiftTimesDialog::instance()->show();
|
ShiftTimesDialog::instance()->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DiveListView::uploadToDivelogsDE()
|
||||||
|
{
|
||||||
|
DivelogsDeWebServices::instance()->prepareDivesForUpload();
|
||||||
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ public slots:
|
||||||
void saveSelectedDivesAs();
|
void saveSelectedDivesAs();
|
||||||
void exportSelectedDivesAsUDDF();
|
void exportSelectedDivesAsUDDF();
|
||||||
void shiftTimes();
|
void shiftTimes();
|
||||||
|
void uploadToDivelogsDE();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void currentDiveChanged(int divenr);
|
void currentDiveChanged(int divenr);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include "subsurfacewebservices.h"
|
#include "subsurfacewebservices.h"
|
||||||
#include "../webservice.h"
|
#include "../webservice.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
||||||
#include <libxml/parser.h>
|
#include <libxml/parser.h>
|
||||||
#include <zip.h>
|
#include <zip.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -99,6 +98,97 @@ static void clear_table(struct dive_table *table)
|
||||||
table->nr = 0;
|
table->nr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *prepare_dives_for_divelogs(const bool selected)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct dive *dive;
|
||||||
|
FILE *f;
|
||||||
|
char filename[PATH_MAX], *tempfile;
|
||||||
|
size_t streamsize;
|
||||||
|
char *membuf;
|
||||||
|
xmlDoc *doc;
|
||||||
|
xsltStylesheetPtr xslt = NULL;
|
||||||
|
xmlDoc *transformed;
|
||||||
|
struct zip_source *s[dive_table.nr];
|
||||||
|
struct zip *zip;
|
||||||
|
char *error = NULL;
|
||||||
|
|
||||||
|
/* generate a random filename and create/open that file with zip_open */
|
||||||
|
QString tempfileQ = QDir::tempPath() + "/import-" + QString::number(qrand() % 99999999) + ".dld";
|
||||||
|
tempfile = tempfileQ.toLocal8Bit().data();
|
||||||
|
zip = zip_open(tempfile, ZIP_CREATE, NULL);
|
||||||
|
|
||||||
|
if (!zip) {
|
||||||
|
fprintf(stderr, "divelog.de-upload: cannot open file as zip\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!amount_selected) {
|
||||||
|
fprintf(stderr, "divelog.de-upload: no dives selected\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* walk the dive list in chronological order */
|
||||||
|
for (i = 0; i < dive_table.nr; i++) {
|
||||||
|
dive = get_dive(i);
|
||||||
|
if (!dive)
|
||||||
|
continue;
|
||||||
|
if (selected && !dive->selected)
|
||||||
|
continue;
|
||||||
|
f = tmpfile();
|
||||||
|
if (!f) {
|
||||||
|
fprintf(stderr, "divelog.de-upload: cannot create temp file\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
save_dive(f, dive);
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
streamsize = ftell(f);
|
||||||
|
rewind(f);
|
||||||
|
membuf = (char *)malloc(streamsize + 1);
|
||||||
|
if (!membuf || !fread(membuf, streamsize, 1, f)) {
|
||||||
|
fprintf(stderr, "divelog.de-upload: memory error\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
membuf[streamsize] = 0;
|
||||||
|
fclose(f);
|
||||||
|
/*
|
||||||
|
* Parse the memory buffer into XML document and
|
||||||
|
* transform it to divelogs.de format, finally dumping
|
||||||
|
* the XML into a character buffer.
|
||||||
|
*/
|
||||||
|
doc = xmlReadMemory(membuf, strlen(membuf), "divelog", NULL, 0);
|
||||||
|
if (!doc) {
|
||||||
|
fprintf(stderr, "divelog.de-upload: xml error\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
free((void *)membuf);
|
||||||
|
// this call is overriding our local variable tempfile! not a good sign!
|
||||||
|
xslt = get_stylesheet("divelogs-export.xslt");
|
||||||
|
if (!xslt) {
|
||||||
|
fprintf(stderr, "divelog.de-upload: missing stylesheet\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
transformed = xsltApplyStylesheet(xslt, doc, NULL);
|
||||||
|
xsltFreeStylesheet(xslt);
|
||||||
|
xmlDocDumpMemory(transformed, (xmlChar **) &membuf, (int *)&streamsize);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
xmlFreeDoc(transformed);
|
||||||
|
/*
|
||||||
|
* Save the XML document into a zip file.
|
||||||
|
*/
|
||||||
|
snprintf(filename, PATH_MAX, "%d.xml", i + 1);
|
||||||
|
s[i] = zip_source_buffer(zip, membuf, streamsize, 1);
|
||||||
|
if (s[i]) {
|
||||||
|
int64_t ret = zip_add(zip, filename, s[i]);
|
||||||
|
if (ret == -1)
|
||||||
|
fprintf(stderr, "divelog.de-upload: failed to include dive %d\n", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zip_close(zip);
|
||||||
|
/* let's call this again */
|
||||||
|
tempfile = tempfileQ.toLocal8Bit().data();
|
||||||
|
return tempfile;
|
||||||
|
}
|
||||||
|
|
||||||
WebServices::WebServices(QWidget* parent, Qt::WindowFlags f): QDialog(parent, f)
|
WebServices::WebServices(QWidget* parent, Qt::WindowFlags f): QDialog(parent, f)
|
||||||
, reply(0)
|
, reply(0)
|
||||||
{
|
{
|
||||||
|
@ -237,9 +327,11 @@ void SubsurfaceWebServices::buttonClicked(QAbstractButton* button)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QDialogButtonBox::RejectRole:
|
case QDialogButtonBox::RejectRole:
|
||||||
// we may want to clean up after ourselves
|
if (reply != NULL && reply->isOpen()) {
|
||||||
// reply->deleteLater();
|
reply->abort();
|
||||||
|
delete reply;
|
||||||
reply = NULL;
|
reply = NULL;
|
||||||
|
}
|
||||||
resetState();
|
resetState();
|
||||||
break;
|
break;
|
||||||
case QDialogButtonBox::HelpRole:
|
case QDialogButtonBox::HelpRole:
|
||||||
|
@ -447,20 +539,47 @@ void DivelogsDeWebServices::downloadDives()
|
||||||
exec();
|
exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivelogsDeWebServices::prepareDivesForUpload()
|
||||||
|
{
|
||||||
|
QString errorText(tr("Cannot create DLD file"));
|
||||||
|
char *filename = prepare_dives_for_divelogs(true);
|
||||||
|
if (filename) {
|
||||||
|
QFile f(filename);
|
||||||
|
if (f.exists()) {
|
||||||
|
f.open(QIODevice::ReadOnly);
|
||||||
|
uploadDives((QIODevice *)&f);
|
||||||
|
f.close();
|
||||||
|
f.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mainWindow()->showError(errorText.append(": ").append(filename));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mainWindow()->showError(errorText.append("!"));
|
||||||
|
}
|
||||||
|
|
||||||
void DivelogsDeWebServices::uploadDives(QIODevice *dldContent)
|
void DivelogsDeWebServices::uploadDives(QIODevice *dldContent)
|
||||||
{
|
{
|
||||||
QHttpMultiPart mp(QHttpMultiPart::FormDataType);
|
QHttpMultiPart mp(QHttpMultiPart::FormDataType);
|
||||||
QHttpPart part;
|
QHttpPart part;
|
||||||
part.setRawHeader("Content-Disposition", "form-data; name=\"userfile\"");
|
QFile *f = (QFile *)dldContent;
|
||||||
|
QFileInfo fi(*f);
|
||||||
|
QString args("form-data; name=\"userfile\"; filename=\"" + fi.absoluteFilePath() + "\"");
|
||||||
|
part.setRawHeader("Content-Disposition", args.toLatin1());
|
||||||
part.setBodyDevice(dldContent);
|
part.setBodyDevice(dldContent);
|
||||||
mp.append(part);
|
mp.append(part);
|
||||||
|
|
||||||
multipart = ∓
|
multipart = ∓
|
||||||
hideDownload();
|
hideDownload();
|
||||||
|
resetState();
|
||||||
exec();
|
exec();
|
||||||
multipart = NULL;
|
|
||||||
|
|
||||||
delete reply; // we need to ensure it has stopped using our QHttpMultiPart
|
multipart = NULL;
|
||||||
|
if (reply != NULL && reply->isOpen()) {
|
||||||
|
reply->abort();
|
||||||
|
delete reply;
|
||||||
|
reply = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DivelogsDeWebServices::DivelogsDeWebServices(QWidget* parent, Qt::WindowFlags f): WebServices(parent, f)
|
DivelogsDeWebServices::DivelogsDeWebServices(QWidget* parent, Qt::WindowFlags f): WebServices(parent, f)
|
||||||
|
@ -473,6 +592,11 @@ DivelogsDeWebServices::DivelogsDeWebServices(QWidget* parent, Qt::WindowFlags f)
|
||||||
|
|
||||||
void DivelogsDeWebServices::startUpload()
|
void DivelogsDeWebServices::startUpload()
|
||||||
{
|
{
|
||||||
|
QSettings s;
|
||||||
|
s.setValue("divelogde_user", ui.userID->text());
|
||||||
|
s.setValue("divelogde_pass", ui.password->text());
|
||||||
|
s.sync();
|
||||||
|
|
||||||
ui.status->setText(tr("Uploading dive list..."));
|
ui.status->setText(tr("Uploading dive list..."));
|
||||||
ui.progressBar->setRange(0,0); // this makes the progressbar do an 'infinite spin'
|
ui.progressBar->setRange(0,0); // this makes the progressbar do an 'infinite spin'
|
||||||
ui.upload->setEnabled(false);
|
ui.upload->setEnabled(false);
|
||||||
|
@ -638,8 +762,25 @@ void DivelogsDeWebServices::uploadFinished()
|
||||||
// check what the server sent us: it might contain
|
// check what the server sent us: it might contain
|
||||||
// an error condition, such as a failed login
|
// an error condition, such as a failed login
|
||||||
QByteArray xmlData = reply->readAll();
|
QByteArray xmlData = reply->readAll();
|
||||||
|
reply->deleteLater();
|
||||||
// ### FIXME: what's the format?
|
reply = NULL;
|
||||||
|
char *resp = xmlData.data();
|
||||||
|
if (resp) {
|
||||||
|
char *parsed = strstr(resp, "<Login>");
|
||||||
|
if (parsed) {
|
||||||
|
if (strstr(resp, "<Login>succeeded</Login>")) {
|
||||||
|
if (strstr(resp, "<FileCopy>failed</FileCopy>")) {
|
||||||
|
ui.status->setText(tr("Upload failed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ui.status->setText(tr("Upload successful"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ui.status->setText(tr("Login failed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ui.status->setText(tr("Cannot parse response"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivelogsDeWebServices::setStatusText(int status)
|
void DivelogsDeWebServices::setStatusText(int status)
|
||||||
|
@ -650,7 +791,7 @@ void DivelogsDeWebServices::setStatusText(int status)
|
||||||
void DivelogsDeWebServices::downloadError(QNetworkReply::NetworkError)
|
void DivelogsDeWebServices::downloadError(QNetworkReply::NetworkError)
|
||||||
{
|
{
|
||||||
resetState();
|
resetState();
|
||||||
ui.status->setText(tr("Download error: %1").arg(reply->errorString()));
|
ui.status->setText(tr("Error: %1").arg(reply->errorString()));
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
reply = NULL;
|
reply = NULL;
|
||||||
}
|
}
|
||||||
|
@ -663,22 +804,37 @@ void DivelogsDeWebServices::uploadError(QNetworkReply::NetworkError error)
|
||||||
void DivelogsDeWebServices::buttonClicked(QAbstractButton* button)
|
void DivelogsDeWebServices::buttonClicked(QAbstractButton* button)
|
||||||
{
|
{
|
||||||
ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
|
ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
|
||||||
|
|
||||||
switch(ui.buttonBox->buttonRole(button)){
|
switch(ui.buttonBox->buttonRole(button)){
|
||||||
case QDialogButtonBox::ApplyRole:{
|
case QDialogButtonBox::ApplyRole:{
|
||||||
char *errorptr = NULL;
|
/* parse file and import dives */
|
||||||
parse_file(zipFile.fileName().toUtf8().constData(), &errorptr);
|
char *error = NULL;
|
||||||
|
parse_file(zipFile.fileName().toLocal8Bit().data(), &error);
|
||||||
|
if (error != NULL) {
|
||||||
|
mainWindow()->showError(error);
|
||||||
|
free(error);
|
||||||
|
}
|
||||||
process_dives(TRUE, FALSE);
|
process_dives(TRUE, FALSE);
|
||||||
// ### FIXME: do something useful with the error - but there shouldn't be one, right?
|
mainWindow()->refreshDisplay();
|
||||||
if (errorptr)
|
|
||||||
qDebug() << errorptr;
|
|
||||||
|
|
||||||
|
/* 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();
|
||||||
hide();
|
hide();
|
||||||
close();
|
close();
|
||||||
resetState();
|
resetState();
|
||||||
mark_divelist_changed(TRUE);
|
|
||||||
mainWindow()->refreshDisplay();
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ class DivelogsDeWebServices : public WebServices {
|
||||||
public:
|
public:
|
||||||
static DivelogsDeWebServices * instance();
|
static DivelogsDeWebServices * instance();
|
||||||
void downloadDives();
|
void downloadDives();
|
||||||
void uploadDives(QIODevice *dldContent);
|
void prepareDivesForUpload();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void startDownload();
|
void startDownload();
|
||||||
|
@ -79,6 +79,7 @@ private slots:
|
||||||
void uploadError(QNetworkReply::NetworkError error);
|
void uploadError(QNetworkReply::NetworkError error);
|
||||||
void startUpload();
|
void startUpload();
|
||||||
private:
|
private:
|
||||||
|
void uploadDives(QIODevice *dldContent);
|
||||||
explicit DivelogsDeWebServices (QWidget* parent = 0, Qt::WindowFlags f = 0);
|
explicit DivelogsDeWebServices (QWidget* parent = 0, Qt::WindowFlags f = 0);
|
||||||
void setStatusText(int status);
|
void setStatusText(int status);
|
||||||
void download_dialog_traverse_xml(xmlNodePtr node, unsigned int *download_status);
|
void download_dialog_traverse_xml(xmlNodePtr node, unsigned int *download_status);
|
||||||
|
|
Loading…
Add table
Reference in a new issue