Merge branch 'web' of github.com:neolit123/subsurface

This commit is contained in:
Dirk Hohndel 2013-12-09 17:22:33 +01:00
commit 8ac58181f7
4 changed files with 186 additions and 20 deletions

View file

@ -8,6 +8,7 @@
#include "models.h"
#include "modeldelegates.h"
#include "mainwindow.h"
#include "subsurfacewebservices.h"
#include "../display.h"
#include <QApplication>
#include <QHeaderView>
@ -726,6 +727,8 @@ void DiveListView::contextMenuEvent(QContextMenuEvent *event)
popup.addAction(tr("export As UDDF"), this, SLOT(exportSelectedDivesAsUDDF()));
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" keeps the trip with the selected dive open
QAction * actionTaken = popup.exec(event->globalPos());
@ -781,3 +784,8 @@ void DiveListView::shiftTimes()
{
ShiftTimesDialog::instance()->show();
}
void DiveListView::uploadToDivelogsDE()
{
DivelogsDeWebServices::instance()->prepareDivesForUpload();
}

View file

@ -49,6 +49,7 @@ public slots:
void saveSelectedDivesAs();
void exportSelectedDivesAsUDDF();
void shiftTimes();
void uploadToDivelogsDE();
signals:
void currentDiveChanged(int divenr);

View file

@ -1,7 +1,6 @@
#include "subsurfacewebservices.h"
#include "../webservice.h"
#include "mainwindow.h"
#include <libxml/parser.h>
#include <zip.h>
#include <errno.h>
@ -99,6 +98,97 @@ static void clear_table(struct dive_table *table)
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)
, reply(0)
{
@ -237,9 +327,11 @@ void SubsurfaceWebServices::buttonClicked(QAbstractButton* button)
}
break;
case QDialogButtonBox::RejectRole:
// we may want to clean up after ourselves
// reply->deleteLater();
reply = NULL;
if (reply != NULL && reply->isOpen()) {
reply->abort();
delete reply;
reply = NULL;
}
resetState();
break;
case QDialogButtonBox::HelpRole:
@ -447,20 +539,47 @@ void DivelogsDeWebServices::downloadDives()
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)
{
QHttpMultiPart mp(QHttpMultiPart::FormDataType);
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);
mp.append(part);
multipart = &mp;
hideDownload();
resetState();
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)
@ -473,6 +592,11 @@ DivelogsDeWebServices::DivelogsDeWebServices(QWidget* parent, Qt::WindowFlags f)
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.progressBar->setRange(0,0); // this makes the progressbar do an 'infinite spin'
ui.upload->setEnabled(false);
@ -638,8 +762,25 @@ void DivelogsDeWebServices::uploadFinished()
// check what the server sent us: it might contain
// an error condition, such as a failed login
QByteArray xmlData = reply->readAll();
// ### FIXME: what's the format?
reply->deleteLater();
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)
@ -650,7 +791,7 @@ void DivelogsDeWebServices::setStatusText(int status)
void DivelogsDeWebServices::downloadError(QNetworkReply::NetworkError)
{
resetState();
ui.status->setText(tr("Download error: %1").arg(reply->errorString()));
ui.status->setText(tr("Error: %1").arg(reply->errorString()));
reply->deleteLater();
reply = NULL;
}
@ -663,22 +804,37 @@ void DivelogsDeWebServices::uploadError(QNetworkReply::NetworkError error)
void DivelogsDeWebServices::buttonClicked(QAbstractButton* button)
{
ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
switch(ui.buttonBox->buttonRole(button)){
case QDialogButtonBox::ApplyRole:{
char *errorptr = NULL;
parse_file(zipFile.fileName().toUtf8().constData(), &errorptr);
/* parse file and import dives */
char *error = NULL;
parse_file(zipFile.fileName().toLocal8Bit().data(), &error);
if (error != NULL) {
mainWindow()->showError(error);
free(error);
}
process_dives(TRUE, FALSE);
// ### FIXME: do something useful with the error - but there shouldn't be one, right?
if (errorptr)
qDebug() << errorptr;
mainWindow()->refreshDisplay();
/* 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();
close();
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;
}
}

View file

@ -66,7 +66,7 @@ class DivelogsDeWebServices : public WebServices {
public:
static DivelogsDeWebServices * instance();
void downloadDives();
void uploadDives(QIODevice *dldContent);
void prepareDivesForUpload();
private slots:
void startDownload();
@ -79,6 +79,7 @@ private slots:
void uploadError(QNetworkReply::NetworkError error);
void startUpload();
private:
void uploadDives(QIODevice *dldContent);
explicit DivelogsDeWebServices (QWidget* parent = 0, Qt::WindowFlags f = 0);
void setStatusText(int status);
void download_dialog_traverse_xml(xmlNodePtr node, unsigned int *download_status);