516 lines
15 KiB
C++
516 lines
15 KiB
C++
/************************************************************************
|
|
MeOS - Orienteering Software
|
|
Copyright (C) 2009-2017 Melin Software HB
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Melin Software HB - software@melin.nu - www.melin.nu
|
|
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
|
|
|
|
************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "resource.h"
|
|
|
|
#include <commctrl.h>
|
|
#include <commdlg.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "oEvent.h"
|
|
#include "gdioutput.h"
|
|
|
|
#include "onlineresults.h"
|
|
#include "meos_util.h"
|
|
#include <shellapi.h>
|
|
|
|
#include "gdiconstants.h"
|
|
#include "infoserver.h"
|
|
#include "meosException.h"
|
|
#include "Download.h"
|
|
#include "xmlparser.h"
|
|
#include "progress.h"
|
|
|
|
int AutomaticCB(gdioutput *gdi, int type, void *data);
|
|
|
|
static int OnlineCB(gdioutput *gdi, int type, void *data) {
|
|
switch (type) {
|
|
case GUI_BUTTON: {
|
|
//Make a copy
|
|
ButtonInfo bu=*static_cast<ButtonInfo *>(data);
|
|
OnlineResults &ores = dynamic_cast<OnlineResults &>(*AutoMachine::getMachine(bu.getExtraInt()));
|
|
|
|
return ores.processButton(*gdi, bu);
|
|
}
|
|
case GUI_LISTBOX:{
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
OnlineResults::~OnlineResults() {
|
|
if (infoServer)
|
|
delete infoServer;
|
|
}
|
|
|
|
int OnlineResults::processButton(gdioutput &gdi, ButtonInfo &bi) {
|
|
|
|
if (bi.id == "ToURL")
|
|
enableURL(gdi, gdi.isChecked(bi.id));
|
|
else if (bi.id == "ToFile")
|
|
enableFile(gdi, gdi.isChecked(bi.id));
|
|
else if (bi.id == "BrowseFolder") {
|
|
string res = gdi.getText("FolderName");
|
|
res = gdi.browseForFolder(res, 0);
|
|
if (!res.empty())
|
|
gdi.setText("FolderName", res, true);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void OnlineResults::settings(gdioutput &gdi, oEvent &oe, bool created) {
|
|
int iv = interval;
|
|
if (created) {
|
|
iv = 10;
|
|
url = oe.getPropertyString("MOPURL", "");
|
|
file = oe.getPropertyString("MOPFolderName", "");
|
|
oe.getAllClasses(classes);
|
|
}
|
|
|
|
string time;
|
|
if (iv>0)
|
|
time = itos(iv);
|
|
|
|
settingsTitle(gdi, "Resultat online");
|
|
startCancelInterval(gdi, "Save", created, IntervalSecond, time);
|
|
|
|
int basex = gdi.getCX();
|
|
gdi.pushY();
|
|
gdi.fillRight();
|
|
gdi.addListBox("Classes", 200,300,0, "Klasser:","", true);
|
|
gdi.pushX();
|
|
vector< pair<string, size_t> > d;
|
|
gdi.addItem("Classes", oe.fillClasses(d, oEvent::extraNone, oEvent::filterNone));
|
|
gdi.setSelection("Classes", classes);
|
|
|
|
gdi.popX();
|
|
|
|
gdi.popY();
|
|
gdi.fillDown();
|
|
|
|
|
|
// gdi.dropLine();
|
|
// gdi.addInput("Interval", time, 10, 0, "Uppdateringsintervall (sekunder):");
|
|
|
|
gdi.addSelection("Format", 200, 200, 0, "Exportformat:");
|
|
gdi.addItem("Format", "MeOS Online Protocol XML", 1);
|
|
gdi.addItem("Format", "IOF XML 2.0.3", 2);
|
|
gdi.addItem("Format", "IOF XML 3.0", 3);
|
|
gdi.selectItemByData("Format", dataType);
|
|
|
|
gdi.addCheckbox("Zip", "Packa stora filer (zip)", 0, zipFile);
|
|
int cx = gdi.getCX();
|
|
gdi.fillRight();
|
|
|
|
gdi.addCheckbox("ToURL", "Skicka till webben", OnlineCB, sendToURL).setExtra(getId());
|
|
|
|
gdi.addString("", 0, "URL:");
|
|
gdi.pushX();
|
|
gdi.addInput("URL", url, 40, 0, "", "Till exempel X#http://www.results.org/online.php");
|
|
gdi.dropLine(2.5);
|
|
gdi.popX();
|
|
gdi.addInput("CmpID", itos(cmpId), 10, 0, "Tävlingens ID-nummer:");
|
|
gdi.addInput("Password", passwd, 15, 0, "Lösenord:").setPassword(true);
|
|
|
|
enableURL(gdi, sendToURL);
|
|
|
|
gdi.setCX(cx);
|
|
gdi.dropLine(5);
|
|
gdi.fillRight();
|
|
|
|
gdi.addCheckbox("ToFile", "Spara på disk", OnlineCB, sendToFile).setExtra(getId());
|
|
|
|
gdi.addString("", 0, "Mapp:");
|
|
gdi.pushX();
|
|
gdi.addInput("FolderName", file, 30);
|
|
gdi.addButton("BrowseFolder", "Bläddra...", OnlineCB).setExtra(getId());
|
|
gdi.dropLine(2.5);
|
|
gdi.popX();
|
|
|
|
gdi.addInput("Prefix", prefix, 10, 0, "Filnamnsprefix:");
|
|
gdi.dropLine(2.8);
|
|
gdi.popX();
|
|
|
|
gdi.addInput("ExportScript", exportScript, 32, 0, "Skript att köra efter export:");
|
|
gdi.dropLine(0.8);
|
|
gdi.addButton("BrowseScript", "Bläddra...", AutomaticCB);
|
|
|
|
gdi.setCY(gdi.getHeight());
|
|
gdi.setCX(basex);
|
|
|
|
gdi.fillDown();
|
|
gdi.dropLine();
|
|
gdi.addString("", fontMediumPlus, "Kontroller");
|
|
RECT rc;
|
|
rc.left = gdi.getCX();
|
|
rc.right = gdi.getWidth();
|
|
rc.top = gdi.getCY();
|
|
rc.bottom = rc.top + 3;
|
|
gdi.addRectangle(rc, colorDarkBlue, false);
|
|
gdi.dropLine();
|
|
vector<pControl> ctrl;
|
|
oe.getControls(ctrl, true);
|
|
|
|
vector< pair<pControl, int> > ctrlP;
|
|
for (size_t k = 0; k< ctrl.size(); k++) {
|
|
for (int i = 0; i < ctrl[k]->getNumberDuplicates(); i++) {
|
|
ctrlP.push_back(make_pair(ctrl[k], oControl::getCourseControlIdFromIdIndex(ctrl[k]->getId(), i)));
|
|
}
|
|
}
|
|
|
|
int width = gdi.scaleLength(130);
|
|
int height = int(gdi.getLineHeight()*1.5);
|
|
int xp = gdi.getCX();
|
|
int yp = gdi.getCY();
|
|
for (size_t k = 0; k< ctrlP.size(); k++) {
|
|
string name = "#" + (ctrlP[k].first->hasName() ? ctrlP[k].first->getName() : ctrlP[k].first->getString());
|
|
if (ctrlP[k].first->getNumberDuplicates() > 1)
|
|
name += "-" + itos(oControl::getIdIndexFromCourseControlId(ctrlP[k].second).second + 1);
|
|
gdi.addCheckbox(xp + (k % 6)*width, yp + (k / 6)*height, "C"+itos(ctrlP[k].second),
|
|
name, 0, ctrlP[k].first->isValidRadio());
|
|
}
|
|
gdi.dropLine();
|
|
|
|
rc.top = gdi.getCY();
|
|
rc.bottom = rc.top + 3;
|
|
gdi.addRectangle(rc, colorDarkBlue, false);
|
|
gdi.dropLine();
|
|
|
|
formatError(gdi);
|
|
if (errorLines.empty())
|
|
gdi.addString("", 10, "help:onlineresult");
|
|
|
|
enableFile(gdi, sendToFile);
|
|
}
|
|
|
|
void OnlineResults::enableURL(gdioutput &gdi, bool state) {
|
|
gdi.setInputStatus("URL", state);
|
|
gdi.setInputStatus("CmpID", state);
|
|
gdi.setInputStatus("Password", state);
|
|
}
|
|
|
|
void OnlineResults::enableFile(gdioutput &gdi, bool state) {
|
|
gdi.setInputStatus("FolderName", state);
|
|
gdi.setInputStatus("BrowseFolder", state);
|
|
gdi.setInputStatus("Prefix", state);
|
|
gdi.setInputStatus("ExportScript", state);
|
|
gdi.setInputStatus("BrowseScript", state);
|
|
}
|
|
|
|
void OnlineResults::save(oEvent &oe, gdioutput &gdi) {
|
|
int iv=gdi.getTextNo("Interval");
|
|
string folder=gdi.getText("FolderName");
|
|
const string &xurl=gdi.getText("URL");
|
|
|
|
if (!folder.empty())
|
|
oe.setProperty("MOPFolderName", folder);
|
|
|
|
if (!xurl.empty())
|
|
oe.setProperty("MOPURL", xurl);
|
|
|
|
sendToURL = gdi.isChecked("ToURL");
|
|
sendToFile = gdi.isChecked("ToFile");
|
|
|
|
cmpId = gdi.getTextNo("CmpID");
|
|
passwd = gdi.getText("Password");
|
|
prefix = gdi.getText("Prefix");
|
|
exportScript = gdi.getText("ExportScript");
|
|
zipFile = gdi.isChecked("Zip");
|
|
|
|
ListBoxInfo lbi;
|
|
gdi.getSelectedItem("Format", lbi);
|
|
dataType = lbi.data;
|
|
|
|
gdi.getSelection("Classes", classes);
|
|
if (sendToFile) {
|
|
if (folder.empty()) {
|
|
throw meosException("Mappnamnet får inte vara tomt.");
|
|
}
|
|
|
|
if (*folder.rbegin() == '/' || *folder.rbegin() == '\\')
|
|
folder = folder.substr(0, folder.size() - 1);
|
|
|
|
file = folder;
|
|
string exp = getExportFileName();
|
|
if (fileExist(exp.c_str()))
|
|
throw meosException(string("Filen finns redan: X#") + exp);
|
|
}
|
|
|
|
if (sendToURL) {
|
|
if (xurl.empty()) {
|
|
throw meosException("URL måste anges.");
|
|
}
|
|
url = xurl;
|
|
}
|
|
|
|
vector<pControl> ctrl;
|
|
oe.getControls(ctrl, true);
|
|
for (size_t k = 0; k< ctrl.size(); k++) {
|
|
vector<int> ids;
|
|
ctrl[k]->getCourseControls(ids);
|
|
for (size_t i = 0; i < ids.size(); i++) {
|
|
string id = "C"+itos(ids[i]);
|
|
if (gdi.hasField(id)) {
|
|
bool st = gdi.isChecked(id);
|
|
if (st != ctrl[k]->isValidRadio())
|
|
ctrl[k]->setRadio(st);
|
|
}
|
|
}
|
|
}
|
|
|
|
process(gdi, &oe, SyncNone);
|
|
|
|
interval = iv;
|
|
synchronize = true;
|
|
synchronizePunches = true;
|
|
}
|
|
|
|
void OnlineResults::status(gdioutput &gdi)
|
|
{
|
|
gdi.addString("", 1, name);
|
|
gdi.fillRight();
|
|
gdi.pushX();
|
|
if (sendToFile) {
|
|
gdi.addString("", 0, "Mapp:");
|
|
gdi.addStringUT(0, file);
|
|
gdi.popX();
|
|
gdi.dropLine(1);
|
|
}
|
|
if (sendToURL) {
|
|
gdi.addString("", 0, "URL:");
|
|
gdi.addStringUT(0, url);
|
|
gdi.popX();
|
|
gdi.dropLine(1);
|
|
}
|
|
|
|
if (sendToFile || sendToURL) {
|
|
gdi.addString("", 0, "Exporterar om: ");
|
|
gdi.addTimer(gdi.getCY(), gdi.getCX(), timerIgnoreSign, (GetTickCount()-timeout)/1000);
|
|
gdi.addString("", 0, "Antal skickade uppdateringar X (Y kb)#" +
|
|
itos(exportCounter-1) + "#" + itos(bytesExported/1024));
|
|
}
|
|
gdi.popX();
|
|
|
|
gdi.dropLine(2);
|
|
gdi.addButton("Stop", "Stoppa automaten", AutomaticCB).setExtra(getId());
|
|
gdi.fillDown();
|
|
gdi.addButton("OnlineResults", "Inställningar...", AutomaticCB).setExtra(getId());
|
|
gdi.popX();
|
|
}
|
|
|
|
void OnlineResults::process(gdioutput &gdi, oEvent *oe, AutoSyncType ast) {
|
|
errorLines.clear();
|
|
DWORD tick = GetTickCount();
|
|
if (lastSync + interval * 1000 > tick)
|
|
return;
|
|
|
|
if (!sendToFile && !sendToURL)
|
|
return;
|
|
ProgressWindow pwMain((sendToURL && ast == SyncNone) ? gdi.getHWND() : 0);
|
|
pwMain.init();
|
|
|
|
string t;
|
|
int xmlSize = 0;
|
|
InfoCompetition &ic = getInfoServer();
|
|
xmlbuffer xmlbuff;
|
|
if (dataType == 1) {
|
|
if (ic.synchronize(*oe, classes)) {
|
|
lastSync = tick; // If error, avoid to quick retry
|
|
ic.getDiffXML(xmlbuff);
|
|
}
|
|
}
|
|
else {
|
|
t = getTempFile();
|
|
if (dataType == 2)
|
|
oe->exportIOFSplits(oEvent::IOF20, t.c_str(), false, false,
|
|
classes, -1, false, true, true, false);
|
|
else if (dataType == 3)
|
|
oe->exportIOFSplits(oEvent::IOF30, t.c_str(), false, false,
|
|
classes, -1, false, true, true, false);
|
|
else
|
|
throw meosException("Internal error");
|
|
}
|
|
|
|
if (!t.empty() || xmlbuff.size() > 0) {
|
|
if (sendToFile) {
|
|
|
|
if (xmlbuff.size() > 0) {
|
|
t = getTempFile();
|
|
xmlparser xml(gdi.getEncoding() == ANSI ? 0 : &gdi);
|
|
if (sendToURL) {
|
|
xmlbuffer bcopy = xmlbuff;
|
|
bcopy.startXML(xml, t);
|
|
bcopy.commit(xml, xmlbuff.size());
|
|
}
|
|
else {
|
|
xmlbuff.startXML(xml, t);
|
|
xmlbuff.commit(xml, xmlbuff.size());
|
|
}
|
|
xml.endTag();
|
|
xmlSize = xml.closeOut();
|
|
|
|
}
|
|
string fn = getExportFileName();
|
|
|
|
if (!CopyFile(t.c_str(), fn.c_str(), false))
|
|
gdi.addInfoBox("", "Kunde inte skriva resultat till X#" + fn);
|
|
else if (!sendToURL) {
|
|
ic.commitComplete();
|
|
bytesExported +=xmlSize;
|
|
removeTempFile(t);
|
|
}
|
|
|
|
if (!exportScript.empty()) {
|
|
ShellExecute(NULL, NULL, exportScript.c_str(), fn.c_str(), NULL, SW_HIDE);
|
|
}
|
|
}
|
|
|
|
try {
|
|
if (sendToURL) {
|
|
Download dwl;
|
|
dwl.initInternet();
|
|
ProgressWindow pw(0);
|
|
vector<pair<string,string> > key;
|
|
pair<string, string> mk1("competition", itos(cmpId));
|
|
key.push_back(mk1);
|
|
pair<string, string> mk2("pwd", passwd);
|
|
key.push_back(mk2);
|
|
|
|
bool moreToWrite = true;
|
|
string tmp;
|
|
const int total = max(xmlbuff.size(), 1u);
|
|
|
|
while(moreToWrite) {
|
|
|
|
t = getTempFile();
|
|
xmlparser xmlOut(gdi.getEncoding() == ANSI ? 0 : &gdi);
|
|
xmlbuff.startXML(xmlOut, t);
|
|
moreToWrite = xmlbuff.commit(xmlOut, 250);
|
|
xmlOut.endTag();
|
|
xmlSize = xmlOut.closeOut();
|
|
string result = getTempFile();
|
|
|
|
if (zipFile && xmlSize > 1024) {
|
|
string zipped = getTempFile();
|
|
zip(zipped.c_str(), 0, vector<string>(1, t));
|
|
removeTempFile(t);
|
|
t = zipped;
|
|
|
|
struct stat st;
|
|
stat(t.c_str(), &st);
|
|
bytesExported += st.st_size;
|
|
}
|
|
else
|
|
bytesExported +=xmlSize;
|
|
|
|
dwl.postFile(url, t, result, key, pw);
|
|
removeTempFile(t);
|
|
|
|
pwMain.setProgress(1000-(1000 * xmlbuff.size())/total);
|
|
|
|
xmlparser xml(0);
|
|
xmlobject res;
|
|
try {
|
|
xml.read(result);
|
|
res = xml.getObject("MOPStatus");
|
|
}
|
|
catch(std::exception &) {
|
|
ifstream is(result.c_str());
|
|
is.seekg (0, is.end);
|
|
int length = is.tellg();
|
|
is.seekg (0, is.beg);
|
|
char * buffer = new char [length+1];
|
|
is.read (buffer,length);
|
|
is.close();
|
|
removeTempFile(result);
|
|
buffer[length] = 0;
|
|
OutputDebugString(buffer);
|
|
split(buffer, "\n", errorLines);
|
|
delete[] buffer;
|
|
formatError(gdi);
|
|
throw meosException("Onlineservern svarade felaktigt.");
|
|
}
|
|
removeTempFile(result);
|
|
|
|
if (res)
|
|
res.getObjectString("status", tmp);
|
|
if (tmp == "BADCMP")
|
|
throw meosException("Onlineservern svarade: Felaktigt tävlings-id");
|
|
if (tmp == "BADPWD")
|
|
throw meosException("Onlineservern svarade: Felaktigt lösenord");
|
|
if (tmp == "NOZIP")
|
|
throw meosException("Onlineservern svarade: ZIP stöds ej");
|
|
if (tmp == "ERROR")
|
|
throw meosException("Onlineservern svarade: Serverfel");
|
|
|
|
if (tmp != "OK")
|
|
break;
|
|
}
|
|
|
|
if (tmp == "OK")
|
|
ic.commitComplete();
|
|
else
|
|
throw meosException("Misslyckades med att ladda upp onlineresultat");
|
|
}
|
|
}
|
|
catch(std::exception &ex) {
|
|
if (ast == SyncNone)
|
|
throw;
|
|
else
|
|
gdi.addInfoBox("", string("Online Results Error X#")+ex.what(), 5000);
|
|
}
|
|
|
|
lastSync = GetTickCount();
|
|
exportCounter++;
|
|
}
|
|
}
|
|
|
|
void OnlineResults::formatError(gdioutput &gdi) {
|
|
gdi.restore("ServerError", false);
|
|
if (errorLines.empty()) {
|
|
gdi.refresh();
|
|
return;
|
|
}
|
|
gdi.setRestorePoint("ServerError");
|
|
gdi.dropLine();
|
|
gdi.fillDown();
|
|
gdi.addString("", boldText, "Server response X:#" + getLocalTime()).setColor(colorRed);
|
|
for (size_t k = 0; k < errorLines.size(); k++)
|
|
gdi.addStringUT(0, errorLines[k]);
|
|
gdi.scrollToBottom();
|
|
gdi.refresh();
|
|
}
|
|
|
|
InfoCompetition &OnlineResults::getInfoServer() const {
|
|
if (!infoServer)
|
|
infoServer = new InfoCompetition(1);
|
|
|
|
return *infoServer;
|
|
}
|
|
|
|
string OnlineResults::getExportFileName() const {
|
|
char bf[260];
|
|
sprintf_s(bf, "%s\\%s%04d.xml", file.c_str(), prefix.c_str(), exportCounter);
|
|
return bf;
|
|
} |