summaryrefslogtreecommitdiff
path: root/src/gui/windows/updaterwindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/windows/updaterwindow.cpp')
-rw-r--r--src/gui/windows/updaterwindow.cpp943
1 files changed, 943 insertions, 0 deletions
diff --git a/src/gui/windows/updaterwindow.cpp b/src/gui/windows/updaterwindow.cpp
new file mode 100644
index 000000000..d025f83b6
--- /dev/null
+++ b/src/gui/windows/updaterwindow.cpp
@@ -0,0 +1,943 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2004-2009 The Mana World Development Team
+ * Copyright (C) 2009-2010 The Mana Developers
+ * Copyright (C) 2011-2013 The ManaPlus Developers
+ *
+ * This file is part of The ManaPlus Client.
+ *
+ * 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 2 of the License, or
+ * 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/>.
+ */
+
+#include "gui/windows/updaterwindow.h"
+
+#include "client.h"
+#include "configuration.h"
+
+#include "input/keydata.h"
+#include "input/keyevent.h"
+
+#include "gui/widgets/browserbox.h"
+#include "gui/widgets/button.h"
+#include "gui/widgets/label.h"
+#include "gui/widgets/layout.h"
+#include "gui/widgets/progressbar.h"
+#include "gui/widgets/scrollarea.h"
+
+#include "net/logindata.h"
+
+#include "resources/resourcemanager.h"
+
+#include "utils/gettext.h"
+#include "utils/mkdir.h"
+#include "utils/paths.h"
+#include "utils/process.h"
+
+#include <fstream>
+
+#include <sys/stat.h>
+
+#include "debug.h"
+
+const std::string xmlUpdateFile("resources.xml");
+const std::string txtUpdateFile("resources2.txt");
+const std::string updateServer2
+ ("http://download.evolonline.org/manaplus/updates/");
+
+/**
+ * Load the given file into a vector of updateFiles.
+ */
+static std::vector<UpdateFile> loadXMLFile(const std::string &fileName)
+{
+ std::vector<UpdateFile> files;
+ XML::Document doc(fileName, false);
+ const XmlNodePtr rootNode = doc.rootNode();
+
+ if (!rootNode || !xmlNameEqual(rootNode, "updates"))
+ {
+ logger->log("Error loading update file: %s", fileName.c_str());
+ return files;
+ }
+
+ for_each_xml_child_node(fileNode, rootNode)
+ {
+ if (!xmlNameEqual(fileNode, "update"))
+ continue;
+
+ if (XML::getProperty(fileNode, "group", "default") != "default")
+ continue;
+
+ UpdateFile file;
+ file.name = XML::getProperty(fileNode, "file", "");
+ file.hash = XML::getProperty(fileNode, "hash", "");
+ file.type = XML::getProperty(fileNode, "type", "data");
+ file.desc = XML::getProperty(fileNode, "description", "");
+ const std::string version = XML::getProperty(
+ fileNode, "version", "");
+ if (!version.empty())
+ {
+ if (version > CHECK_VERSION)
+ continue;
+ }
+ const std::string notVersion = XML::getProperty(
+ fileNode, "notVersion", "");
+ if (!notVersion.empty())
+ {
+ if (notVersion <= CHECK_VERSION)
+ continue;
+ }
+ if (XML::getProperty(fileNode, "required", "yes") == "yes")
+ file.required = true;
+ else
+ file.required = false;
+
+ if (checkPath(file.name))
+ files.push_back(file);
+ }
+
+ return files;
+}
+
+static std::vector<UpdateFile> loadTxtFile(const std::string &fileName)
+{
+ std::vector<UpdateFile> files;
+ std::ifstream fileHandler;
+ fileHandler.open(fileName.c_str(), std::ios::in);
+
+ if (fileHandler.is_open())
+ {
+ while (fileHandler.good())
+ {
+ char name[256];
+ char hash[50];
+ fileHandler.getline(name, 256, ' ');
+ fileHandler.getline(hash, 50);
+
+ UpdateFile thisFile;
+ thisFile.name = name;
+ thisFile.hash = hash;
+ thisFile.type = "data";
+ thisFile.required = true;
+ thisFile.desc.clear();
+
+ if (!thisFile.name.empty() && checkPath(thisFile.name))
+ files.push_back(thisFile);
+ }
+ }
+ else
+ {
+ logger->log("Error loading update file: %s", fileName.c_str());
+ }
+ fileHandler.close();
+
+ return files;
+}
+
+UpdaterWindow::UpdaterWindow(const std::string &updateHost,
+ const std::string &updatesDir,
+ const bool applyUpdates,
+ const int updateType):
+ // TRANSLATORS: updater window name
+ Window(_("Updating..."), false, nullptr, "update.xml"),
+ gcn::ActionListener(),
+ gcn::KeyListener(),
+ mDownloadStatus(UPDATE_NEWS),
+ mUpdateHost(updateHost),
+ mUpdatesDir(updatesDir),
+ mUpdatesDirReal(updatesDir),
+ mCurrentFile("news.txt"),
+ mNewLabelCaption(),
+ mDownloadProgress(0.0F),
+ mDownloadMutex(),
+ mCurrentChecksum(0),
+ mStoreInMemory(true),
+ mDownloadComplete(true),
+ mUserCancel(false),
+ mDownloadedBytes(0),
+ mMemoryBuffer(nullptr),
+ mDownload(nullptr),
+ mUpdateFiles(),
+ mTempUpdateFiles(),
+ mUpdateIndex(0),
+ mUpdateIndexOffset(0),
+ mLoadUpdates(applyUpdates),
+ mUpdateType(updateType),
+ // TRANSLATORS: updater window label
+ mLabel(new Label(this, _("Connecting..."))),
+ // TRANSLATORS: updater window button
+ mCancelButton(new Button(this, _("Cancel"), "cancel", this)),
+ // TRANSLATORS: updater window button
+ mPlayButton(new Button(this, _("Play"), "play", this)),
+ mProgressBar(new ProgressBar(this, 0.0, 310, 0)),
+ mBrowserBox(new BrowserBox(this)),
+ mScrollArea(new ScrollArea(mBrowserBox, true, "update_background.xml")),
+ mUpdateServerPath(mUpdateHost)
+{
+ setWindowName("UpdaterWindow");
+ setResizable(true);
+ setDefaultSize(450, 400, ImageRect::CENTER);
+ setMinWidth(310);
+ setMinHeight(220);
+
+ mProgressBar->setSmoothProgress(false);
+ mBrowserBox->setOpaque(false);
+ mBrowserBox->setLinkHandler(this);
+ mBrowserBox->setEnableKeys(true);
+ mBrowserBox->setEnableTabs(true);
+ mPlayButton->setEnabled(false);
+
+ ContainerPlacer placer;
+ placer = getPlacer(0, 0);
+
+ placer(0, 0, mScrollArea, 5, 3).setPadding(3);
+ placer(0, 3, mLabel, 5);
+ placer(0, 4, mProgressBar, 5);
+ placer(3, 5, mCancelButton);
+ placer(4, 5, mPlayButton);
+
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
+
+ addKeyListener(this);
+
+ loadWindowState();
+ setVisible(true);
+ mCancelButton->requestFocus();
+ removeProtocol(mUpdateServerPath);
+
+ download();
+}
+
+UpdaterWindow::~UpdaterWindow()
+{
+ if (mLoadUpdates)
+ loadUpdates();
+
+ if (mDownload)
+ {
+ mDownload->cancel();
+
+ delete mDownload;
+ mDownload = nullptr;
+ }
+ free(mMemoryBuffer);
+}
+
+void UpdaterWindow::setProgress(const float p)
+{
+ // Do delayed progress bar update, since Guichan isn't thread-safe
+ MutexLocker lock(&mDownloadMutex);
+ mDownloadProgress = p;
+}
+
+void UpdaterWindow::setLabel(const std::string &str)
+{
+ // Do delayed label text update, since Guichan isn't thread-safe
+ MutexLocker lock(&mDownloadMutex);
+ mNewLabelCaption = str;
+}
+
+void UpdaterWindow::enable()
+{
+ mCancelButton->setEnabled(false);
+ mPlayButton->setEnabled(true);
+ mPlayButton->requestFocus();
+
+ if (mUpdateType & LoginData::Upd_Close)
+ client->setState(STATE_LOAD_DATA);
+}
+
+void UpdaterWindow::action(const gcn::ActionEvent &event)
+{
+ const std::string &eventId = event.getId();
+ if (eventId == "cancel")
+ {
+ // Register the user cancel
+ mUserCancel = true;
+ // Skip the updating process
+ if (mDownloadStatus != UPDATE_COMPLETE)
+ {
+ mDownload->cancel();
+ mDownloadStatus = UPDATE_ERROR;
+ }
+ }
+ else if (eventId == "play")
+ {
+ client->setState(STATE_LOAD_DATA);
+ }
+}
+
+void UpdaterWindow::keyPressed(gcn::KeyEvent &keyEvent)
+{
+ const int actionId = static_cast<KeyEvent*>(&keyEvent)->getActionId();
+ if (actionId == static_cast<int>(Input::KEY_GUI_CANCEL))
+ {
+ action(gcn::ActionEvent(nullptr, mCancelButton->getActionEventId()));
+ client->setState(STATE_LOGIN);
+ }
+ else if (actionId == static_cast<int>(Input::KEY_GUI_SELECT)
+ || actionId == static_cast<int>(Input::KEY_GUI_SELECT2))
+ {
+ if (mDownloadStatus == UPDATE_COMPLETE ||
+ mDownloadStatus == UPDATE_ERROR)
+ {
+ action(gcn::ActionEvent(nullptr, mPlayButton->getActionEventId()));
+ }
+ else
+ {
+ action(gcn::ActionEvent(nullptr,
+ mCancelButton->getActionEventId()));
+ }
+ }
+}
+
+void UpdaterWindow::loadNews()
+{
+ if (!mMemoryBuffer)
+ {
+ logger->log1("Couldn't load news");
+ return;
+ }
+
+ // Reallocate and include terminating 0 character
+ mMemoryBuffer = static_cast<char*>(realloc(
+ mMemoryBuffer, mDownloadedBytes + 1));
+
+ mMemoryBuffer[mDownloadedBytes] = '\0';
+ mBrowserBox->clearRows();
+
+ std::string newsName = mUpdatesDir + "/local/help/news.txt";
+ mkdir_r((mUpdatesDir + "/local/help/").c_str());
+ bool firstLine(true);
+ std::ofstream file;
+ std::stringstream ss(mMemoryBuffer);
+ std::string line;
+ file.open(newsName.c_str(), std::ios::out);
+ while (std::getline(ss, line, '\n'))
+ {
+ if (firstLine)
+ {
+ firstLine = false;
+ const size_t i = line.find("##9 Latest client version: ##6");
+ if (!i)
+ continue;
+
+ if (file.is_open())
+ file << line << std::endl;
+ mBrowserBox->addRow(line);
+ }
+ else
+ {
+ if (file.is_open())
+ file << line << std::endl;
+ mBrowserBox->addRow(line);
+ }
+ }
+
+ file.close();
+ // Free the memory buffer now that we don't need it anymore
+ free(mMemoryBuffer);
+ mMemoryBuffer = nullptr;
+ mDownloadedBytes = 0;
+
+ mScrollArea->setVerticalScrollAmount(0);
+}
+
+void UpdaterWindow::loadPatch()
+{
+ if (!mMemoryBuffer)
+ {
+ logger->log1("Couldn't load patch");
+ return;
+ }
+
+ // Reallocate and include terminating 0 character
+ mMemoryBuffer = static_cast<char*>(
+ realloc(mMemoryBuffer, mDownloadedBytes + 1));
+ mMemoryBuffer[mDownloadedBytes] = '\0';
+
+ std::string version;
+
+ // Tokenize and add each line separately
+ char *line = strtok(mMemoryBuffer, "\n");
+ if (line)
+ {
+ version = line;
+ if (serverVersion < 1)
+ {
+ line = strtok(nullptr, "\n");
+ if (line)
+ {
+ mBrowserBox->addRow(strprintf("##9 Latest client version: "
+ "##6ManaPlus %s##0", line), true);
+ }
+ }
+ if (version > CHECK_VERSION)
+ {
+#if defined(ANDROID)
+ mBrowserBox->addRow("", true);
+ mBrowserBox->addRow("##1You can download from [[@@"
+ "https://play.google.com/store/apps/details?id=org.evolonline"
+ ".beta.manaplus|Google Play@@]", true);
+ mBrowserBox->addRow("##1ManaPlus updated.", true);
+#elif defined(WIN32)
+ mBrowserBox->addRow("", true);
+ mBrowserBox->addRow(" ##1[@@http://download.evolonline.org/"
+ "manaplus/download/manaplus-win32.exe|download here@@]", true);
+#else
+ mBrowserBox->addRow("", true);
+ mBrowserBox->addRow(" ##1@@http://manaplus.org/|"
+ "http://manaplus.org/@@", true);
+ mBrowserBox->addRow("##1You can download it from", true);
+ mBrowserBox->addRow("##1ManaPlus updated.", true);
+#endif
+ }
+ else
+ {
+ mBrowserBox->addRow("You have latest client version.", true);
+ }
+ }
+
+ // Free the memory buffer now that we don't need it anymore
+ free(mMemoryBuffer);
+ mMemoryBuffer = nullptr;
+ mDownloadedBytes = 0;
+
+ mScrollArea->setVerticalScrollAmount(0);
+}
+
+int UpdaterWindow::updateProgress(void *ptr, DownloadStatus status,
+ size_t dt, size_t dn)
+{
+ UpdaterWindow *const uw = reinterpret_cast<UpdaterWindow *>(ptr);
+ if (!uw)
+ return -1;
+
+ if (status == DOWNLOAD_STATUS_COMPLETE)
+ {
+ uw->mDownloadComplete = true;
+ }
+ else if (status == DOWNLOAD_STATUS_ERROR ||
+ status == DOWNLOAD_STATUS_CANCELLED)
+ {
+ if (uw->mDownloadStatus == UPDATE_COMPLETE)
+ { // ignoring error in last state (was UPDATE_PATCH)
+ uw->mDownloadStatus = UPDATE_COMPLETE;
+ uw->mDownloadComplete = true;
+ free(uw->mMemoryBuffer);
+ uw->mMemoryBuffer = nullptr;
+ }
+ else
+ {
+ uw->mDownloadStatus = UPDATE_ERROR;
+ }
+ }
+
+ if (!dt)
+ dt = 1;
+
+ float progress = static_cast<float>(dn) /
+ static_cast<float>(dt);
+
+ if (progress != progress)
+ progress = 0.0F; // check for NaN
+ if (progress < 0.0F)
+ progress = 0.0F; // no idea how this could ever happen,
+ // but why not check for it anyway.
+ if (progress > 1.0F)
+ progress = 1.0F;
+
+ uw->setLabel(std::string(uw->mCurrentFile).append(" (")
+ .append(toString(static_cast<int>(progress * 100))).append("%)"));
+
+ uw->setProgress(progress);
+
+ if (client->getState() != STATE_UPDATE
+ || uw->mDownloadStatus == UPDATE_ERROR)
+ {
+ // If the action was canceled return an error code to stop the mThread
+ return -1;
+ }
+
+ return 0;
+}
+
+size_t UpdaterWindow::memoryWrite(void *ptr, size_t size,
+ size_t nmemb, void *stream)
+{
+ UpdaterWindow *const uw = reinterpret_cast<UpdaterWindow *>(stream);
+ const size_t totalMem = size * nmemb;
+ uw->mMemoryBuffer = static_cast<char*>(realloc(uw->mMemoryBuffer,
+ uw->mDownloadedBytes + totalMem));
+ if (uw->mMemoryBuffer)
+ {
+ memcpy(&(uw->mMemoryBuffer[uw->mDownloadedBytes]), ptr, totalMem);
+ uw->mDownloadedBytes += static_cast<int>(totalMem);
+ }
+
+ return totalMem;
+}
+
+void UpdaterWindow::download()
+{
+ if (mDownload)
+ {
+ mDownload->cancel();
+ delete mDownload;
+ }
+ if (mDownloadStatus == UPDATE_PATCH)
+ {
+ mDownload = new Net::Download(this,
+ "http://manaplus.org/update/" + mCurrentFile,
+ updateProgress, true);
+ }
+ else
+ {
+ mDownload = new Net::Download(this, std::string(mUpdateHost).append(
+ "/").append(mCurrentFile), updateProgress);
+ }
+
+ if (mStoreInMemory)
+ {
+ mDownload->setWriteFunction(UpdaterWindow::memoryWrite);
+ }
+ else
+ {
+ if (mDownloadStatus == UPDATE_RESOURCES)
+ {
+ mDownload->setFile(std::string(mUpdatesDir).append("/").append(
+ mCurrentFile), mCurrentChecksum);
+ }
+ else
+ {
+ mDownload->setFile(std::string(mUpdatesDir).append(
+ "/").append(mCurrentFile));
+ }
+ }
+
+ if (mDownloadStatus != UPDATE_RESOURCES)
+ mDownload->noCache();
+
+ setLabel(mCurrentFile + " (0%)");
+ mDownloadComplete = false;
+
+ mDownload->start();
+}
+
+void UpdaterWindow::loadUpdates()
+{
+ const ResourceManager *const resman = ResourceManager::getInstance();
+ if (mUpdateFiles.empty())
+ { // updates not downloaded
+ mUpdateFiles = loadXMLFile(std::string(mUpdatesDir).append(
+ "/").append(xmlUpdateFile));
+ if (mUpdateFiles.empty())
+ {
+ logger->log("Warning this server does not have a"
+ " %s file falling back to %s", xmlUpdateFile.c_str(),
+ txtUpdateFile.c_str());
+ mUpdateFiles = loadTxtFile(std::string(mUpdatesDir).append(
+ "/").append(txtUpdateFile));
+ }
+ }
+
+ std::string fixPath = mUpdatesDir + "/fix";
+ const unsigned sz = static_cast<unsigned>(mUpdateFiles.size());
+ for (mUpdateIndex = 0; mUpdateIndex < sz; mUpdateIndex++)
+ {
+ UpdaterWindow::addUpdateFile(resman, mUpdatesDir, fixPath,
+ mUpdateFiles[mUpdateIndex].name, false);
+ }
+ loadManaPlusUpdates(mUpdatesDir, resman);
+}
+
+void UpdaterWindow::loadLocalUpdates(const std::string &dir)
+{
+ const ResourceManager *const resman = ResourceManager::getInstance();
+
+ std::vector<UpdateFile> updateFiles
+ = loadXMLFile(std::string(dir).append("/").append(xmlUpdateFile));
+
+ if (updateFiles.empty())
+ {
+ logger->log("Warning this server does not have a"
+ " %s file falling back to %s", xmlUpdateFile.c_str(),
+ txtUpdateFile.c_str());
+ updateFiles = loadTxtFile(std::string(dir).append(
+ "/").append(txtUpdateFile));
+ }
+
+ const std::string fixPath = dir + "/fix";
+ for (unsigned int updateIndex = 0, sz = static_cast<unsigned int>(
+ updateFiles.size()); updateIndex < sz; updateIndex ++)
+ {
+ UpdaterWindow::addUpdateFile(resman, dir, fixPath,
+ updateFiles[updateIndex].name, false);
+ }
+ loadManaPlusUpdates(dir, resman);
+}
+
+void UpdaterWindow::unloadUpdates(const std::string &dir)
+{
+ const ResourceManager *const resman = ResourceManager::getInstance();
+ std::vector<UpdateFile> updateFiles
+ = loadXMLFile(std::string(dir).append("/").append(xmlUpdateFile));
+
+ if (updateFiles.empty())
+ {
+ updateFiles = loadTxtFile(std::string(dir).append(
+ "/").append(txtUpdateFile));
+ }
+
+ const std::string fixPath = dir + "/fix";
+ for (unsigned int updateIndex = 0, sz = static_cast<unsigned int>(
+ updateFiles.size()); updateIndex < sz; updateIndex ++)
+ {
+ UpdaterWindow::removeUpdateFile(resman, dir, fixPath,
+ updateFiles[updateIndex].name);
+ }
+ unloadManaPlusUpdates(dir, resman);
+}
+
+void UpdaterWindow::loadManaPlusUpdates(const std::string &dir,
+ const ResourceManager *const resman)
+{
+ std::string fixPath = dir + "/fix";
+ std::vector<UpdateFile> updateFiles
+ = loadXMLFile(std::string(fixPath).append("/").append(xmlUpdateFile));
+
+ for (unsigned int updateIndex = 0, sz = static_cast<unsigned int>(
+ updateFiles.size()); updateIndex < sz; updateIndex ++)
+ {
+ std::string name = updateFiles[updateIndex].name;
+ if (strStartWith(name, "manaplus_"))
+ {
+ struct stat statbuf;
+ std::string file = std::string(fixPath).append("/").append(name);
+ if (!stat(file.c_str(), &statbuf))
+ resman->addToSearchPath(file, false);
+ }
+ }
+}
+
+void UpdaterWindow::unloadManaPlusUpdates(const std::string &dir,
+ const ResourceManager *const resman)
+{
+ const std::string fixPath = dir + "/fix";
+ const std::vector<UpdateFile> updateFiles
+ = loadXMLFile(std::string(fixPath).append("/").append(xmlUpdateFile));
+
+ for (unsigned int updateIndex = 0, sz = static_cast<unsigned int>(
+ updateFiles.size()); updateIndex < sz; updateIndex ++)
+ {
+ std::string name = updateFiles[updateIndex].name;
+ if (strStartWith(name, "manaplus_"))
+ {
+ struct stat statbuf;
+ const std::string file = std::string(
+ fixPath).append("/").append(name);
+ if (!stat(file.c_str(), &statbuf))
+ resman->removeFromSearchPath(file);
+ }
+ }
+}
+
+void UpdaterWindow::addUpdateFile(const ResourceManager *const resman,
+ const std::string &path,
+ const std::string &fixPath,
+ const std::string &file,
+ const bool append)
+{
+ const std::string tmpPath = std::string(path).append("/").append(file);
+ if (!append)
+ resman->addToSearchPath(tmpPath, append);
+
+ const std::string fixFile = std::string(fixPath).append("/").append(file);
+ struct stat statbuf;
+ if (!stat(fixFile.c_str(), &statbuf))
+ resman->addToSearchPath(fixFile, append);
+
+ if (append)
+ resman->addToSearchPath(tmpPath, append);
+}
+
+void UpdaterWindow::removeUpdateFile(const ResourceManager *const resman,
+ const std::string &path,
+ const std::string &fixPath,
+ const std::string &file)
+{
+ resman->removeFromSearchPath(std::string(path).append("/").append(file));
+ const std::string fixFile = std::string(fixPath).append("/").append(file);
+ struct stat statbuf;
+ if (!stat(fixFile.c_str(), &statbuf))
+ resman->removeFromSearchPath(fixFile);
+}
+
+void UpdaterWindow::logic()
+{
+ BLOCK_START("UpdaterWindow::logic")
+ // Update Scroll logic
+ mScrollArea->logic();
+
+ // Synchronize label caption when necessary
+ {
+ MutexLocker lock(&mDownloadMutex);
+
+ if (mLabel->getCaption() != mNewLabelCaption)
+ {
+ mLabel->setCaption(mNewLabelCaption);
+ mLabel->adjustSize();
+ }
+
+ mProgressBar->setProgress(mDownloadProgress);
+ if (mUpdateFiles.size() && mUpdateIndex <= mUpdateFiles.size())
+ {
+ mProgressBar->setText(strprintf("%u/%u", mUpdateIndex
+ + mUpdateIndexOffset + 1, static_cast<unsigned>(
+ mUpdateFiles.size()) + static_cast<int>(
+ mTempUpdateFiles.size()) + 1));
+ }
+ else
+ {
+ mProgressBar->setText("");
+ }
+ }
+
+ switch (mDownloadStatus)
+ {
+ case UPDATE_ERROR:
+ mBrowserBox->addRow("");
+ // TRANSLATORS: update message
+ mBrowserBox->addRow(_("##1 The update process is incomplete."));
+ // TRANSLATORS: Continues "The update process is incomplete.".
+ mBrowserBox->addRow(_("##1 It is strongly recommended that"));
+ // TRANSLATORS: Begins "It is strongly recommended that".
+ mBrowserBox->addRow(_("##1 you try again later."));
+
+ mBrowserBox->addRow(mDownload->getError());
+ mScrollArea->setVerticalScrollAmount(
+ mScrollArea->getVerticalMaxScroll());
+ mDownloadStatus = UPDATE_COMPLETE;
+ break;
+ case UPDATE_NEWS:
+ if (mDownloadComplete)
+ {
+ // Parse current memory buffer as news and dispose of the data
+ loadNews();
+
+ mCurrentFile = xmlUpdateFile;
+ mStoreInMemory = false;
+ mDownloadStatus = UPDATE_LIST;
+ download(); // download() changes mDownloadComplete to false
+ }
+ break;
+ case UPDATE_PATCH:
+ if (mDownloadComplete)
+ {
+ // Parse current memory buffer as news and dispose of the data
+ loadPatch();
+
+ mUpdateHost = updateServer2 + mUpdateServerPath;
+ mUpdatesDir.append("/fix");
+ mCurrentFile = xmlUpdateFile;
+ mStoreInMemory = false;
+ mDownloadStatus = UPDATE_LIST2;
+ download();
+ }
+ break;
+
+ case UPDATE_LIST:
+ if (mDownloadComplete)
+ {
+ if (mCurrentFile == xmlUpdateFile)
+ {
+ mUpdateFiles = loadXMLFile(std::string(mUpdatesDir).append(
+ "/").append(xmlUpdateFile));
+
+ if (mUpdateFiles.empty())
+ {
+ logger->log("Warning this server does not have a %s"
+ " file falling back to %s",
+ xmlUpdateFile.c_str(),
+ txtUpdateFile.c_str());
+
+ // If the resources.xml file fails,
+ // fall back onto a older version
+ mCurrentFile = txtUpdateFile;
+ mStoreInMemory = false;
+ mDownloadStatus = UPDATE_LIST;
+ download();
+ break;
+ }
+ }
+ else if (mCurrentFile == txtUpdateFile)
+ {
+ mUpdateFiles = loadTxtFile(std::string(mUpdatesDir).append(
+ "/").append(txtUpdateFile));
+ }
+ mStoreInMemory = false;
+ mDownloadStatus = UPDATE_RESOURCES;
+ }
+ break;
+ case UPDATE_RESOURCES:
+ if (mDownloadComplete)
+ {
+ if (mUpdateIndex < mUpdateFiles.size())
+ {
+ UpdateFile thisFile = mUpdateFiles[mUpdateIndex];
+ if (!thisFile.required)
+ {
+ // This statement checks to see if the file type
+ // is music, and if download-music is true
+ // If it fails, this statement returns true,
+ // and results in not downloading the file
+ // Else it will ignore the break,
+ // and download the file.
+
+ if (!(thisFile.type == "music"
+ && config.getBoolValue("download-music")))
+ {
+ mUpdateIndex++;
+ break;
+ }
+ }
+ mCurrentFile = thisFile.name;
+ std::string checksum;
+ checksum = thisFile.hash;
+ std::stringstream ss(checksum);
+ ss >> std::hex >> mCurrentChecksum;
+
+ std::ifstream temp((std::string(mUpdatesDir).append(
+ "/").append(mCurrentFile)).c_str());
+
+ if (!temp.is_open() || !validateFile(std::string(
+ mUpdatesDir).append("/").append(mCurrentFile),
+ mCurrentChecksum))
+ {
+ temp.close();
+ download();
+ }
+ else
+ {
+ temp.close();
+ logger->log("%s already here", mCurrentFile.c_str());
+ }
+ mUpdateIndex++;
+ }
+ else
+ {
+ // Download of updates completed
+ mCurrentFile = "latest.txt";
+ mStoreInMemory = true;
+ mDownloadStatus = UPDATE_PATCH;
+ download(); // download() changes
+ // mDownloadComplete to false
+ }
+ }
+ break;
+ case UPDATE_LIST2:
+ if (mDownloadComplete)
+ {
+ if (mCurrentFile == xmlUpdateFile)
+ {
+ mTempUpdateFiles = loadXMLFile(std::string(
+ mUpdatesDir).append("/").append(xmlUpdateFile));
+ }
+ mUpdateIndexOffset = mUpdateIndex;
+ mUpdateIndex = 0;
+ mStoreInMemory = false;
+ mDownloadStatus = UPDATE_RESOURCES2;
+ download();
+ }
+ break;
+ case UPDATE_RESOURCES2:
+ if (mDownloadComplete)
+ {
+ if (mUpdateIndex < mTempUpdateFiles.size())
+ {
+ const UpdateFile thisFile = mTempUpdateFiles[mUpdateIndex];
+ mCurrentFile = thisFile.name;
+ std::string checksum;
+ checksum = thisFile.hash;
+ std::stringstream ss(checksum);
+ ss >> std::hex >> mCurrentChecksum;
+
+ std::ifstream temp((std::string(mUpdatesDir).append(
+ "/").append(mCurrentFile)).c_str());
+
+ if (!temp.is_open() || !validateFile(std::string(
+ mUpdatesDir).append("/").append(mCurrentFile),
+ mCurrentChecksum))
+ {
+ temp.close();
+ download();
+ }
+ else
+ {
+ temp.close();
+ logger->log("%s already here", mCurrentFile.c_str());
+ }
+ mUpdateIndex++;
+ }
+ else
+ {
+ mUpdatesDir = mUpdatesDirReal;
+ mDownloadStatus = UPDATE_COMPLETE;
+ }
+ }
+ break;
+ case UPDATE_COMPLETE:
+ mUpdatesDir = mUpdatesDirReal;
+ enable();
+ // TRANSLATORS: updater window label
+ setLabel(_("Completed"));
+ break;
+ case UPDATE_IDLE:
+ break;
+ default:
+ logger->log("UpdaterWindow::logic unknown status: "
+ + toString(static_cast<unsigned>(mDownloadStatus)));
+ break;
+ }
+ BLOCK_END("UpdaterWindow::logic")
+}
+
+bool UpdaterWindow::validateFile(const std::string &filePath,
+ const unsigned long hash)
+{
+ FILE *const file = fopen(filePath.c_str(), "rb");
+ if (!file)
+ return false;
+
+ const unsigned long adler = Net::Download::fadler32(file);
+ fclose(file);
+ return adler == hash;
+}
+
+unsigned long UpdaterWindow::getFileHash(const std::string &filePath)
+{
+ int size = 0;
+ char *const buf = static_cast<char*>(ResourceManager::loadFile(
+ filePath, size));
+ if (!buf)
+ return 0;
+ return Net::Download::adlerBuffer(buf, size);
+}
+
+void UpdaterWindow::handleLink(const std::string &link,
+ gcn::MouseEvent *event A_UNUSED)
+{
+ if (strStartWith(link, "http://") || strStartWith(link, "https://"))
+ openBrowser(link);
+}