diff options
| author | Tannin <Tannin@Miranda> | 2013-02-17 09:26:29 +0100 |
|---|---|---|
| committer | Tannin <Tannin@Miranda> | 2013-02-17 09:26:29 +0100 |
| commit | 6516a6b7c19713de28db7142612f1c095e541317 (patch) | |
| tree | 06829bf7f82e1251a9e3db27185b7df90833bbc8 /src/selfupdater.cpp | |
| parent | 5d1154c24e2475ed2b7ac248de27ab7b501a1e5e (diff) | |
- moved shared and uibase libraries to namespaces
- bugfix: the "fix mods" function was accessing the save game data incorrectly, causing a crash
Diffstat (limited to 'src/selfupdater.cpp')
| -rw-r--r-- | src/selfupdater.cpp | 876 |
1 files changed, 440 insertions, 436 deletions
diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp index 884f9647..503c2596 100644 --- a/src/selfupdater.cpp +++ b/src/selfupdater.cpp @@ -17,439 +17,443 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ -#include "selfupdater.h"
-#include "utility.h"
-#include "installationmanager.h"
-#include "report.h"
-#include "messagedialog.h"
-#include "downloadmanager.h"
-
-#include <versioninfo.h>
-#include <gameinfo.h>
-#include <skyriminfo.h>
-#include <QMessageBox>
-#include <QNetworkAccessManager>
-#include <QNetworkRequest>
-#include <QDir>
-#include <QLibrary>
-#include <QProcess>
-#include <QApplication>
-#include <util.h>
-
-
-typedef Archive* (*CreateArchiveType)();
-
-
-template <typename T> T resolveFunction(QLibrary &lib, const char *name)
-{
- T temp = reinterpret_cast<T>(lib.resolve(name));
- if (temp == NULL) {
- throw std::runtime_error(QObject::tr("invalid 7-zip32.dll: %1").arg(lib.errorString()).toLatin1().constData());
- }
- return temp;
-}
-
-
-SelfUpdater::SelfUpdater(NexusInterface *nexusInterface, QWidget *parent)
- : QObject(parent), m_Parent(parent), m_Interface(nexusInterface), m_UpdateRequestID(-1),
- m_Reply(NULL), m_Progress(parent), m_Attempts(3)
-{
- m_Progress.setMaximum(100);
-
- QLibrary archiveLib("dlls\\archive.dll");
- if (!archiveLib.load()) {
- throw MyException(tr("archive.dll not loaded: \"%1\"").arg(archiveLib.errorString()));
- }
-
- CreateArchiveType CreateArchiveFunc = resolveFunction<CreateArchiveType>(archiveLib, "CreateArchive");
-
- m_CurrentArchive = CreateArchiveFunc();
- if (!m_CurrentArchive->isValid()) {
- throw MyException(InstallationManager::getErrorString(m_CurrentArchive->getLastError()));
- }
-
- connect(&m_Progress, SIGNAL(canceled()), this, SLOT(downloadCancel()));
-
- VS_FIXEDFILEINFO version = GetFileVersion(ToWString(QApplication::applicationFilePath()));
-
- m_MOVersion = VersionInfo(version.dwFileVersionMS >> 16,
- version.dwFileVersionMS & 0xFFFF,
- version.dwFileVersionLS >> 16);
-}
-
-
-SelfUpdater::~SelfUpdater()
-{
- delete m_CurrentArchive;
-}
-
-
-void SelfUpdater::testForUpdate()
-{
-/* if (QFile::exists(QCoreApplication::applicationDirPath() + "/mo_test_update.7z")) {
- emit updateAvailable();
- return;
- }*/
-
- if (m_UpdateRequestID == -1) {
- m_UpdateRequestID = m_Interface->requestDescription(
- SkyrimInfo::getNexusModIDStatic(), this, QVariant(),
- ToQString(SkyrimInfo::getNexusInfoUrlStatic()));
- }
-}
-
-void SelfUpdater::startUpdate()
-{
-/* if (QFile::exists(QCoreApplication::applicationDirPath() + "/mo_test_update.7z")) {
- m_UpdateFile.setFileName(QCoreApplication::applicationDirPath() + "/mo_test_update.7z");
- installUpdate();
- return;
- }*/
-
- if ((m_UpdateRequestID == -1) &&
- (!m_NewestVersion.isEmpty())) {
- if (QMessageBox::question(m_Parent, tr("Update"),
- tr("An update is available (newest version: %1), do you want to install it?").arg(m_NewestVersion),
- QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
- m_UpdateRequestID = m_Interface->requestFiles(SkyrimInfo::getNexusModIDStatic(),
- this, m_NewestVersion,
- ToQString(SkyrimInfo::getNexusInfoUrlStatic()));
- }
- }
-}
-
-
-void SelfUpdater::download(const QString &downloadLink, const QString &fileName)
-{
- qDebug("download: %s", downloadLink.toUtf8().constData());
- QNetworkAccessManager *accessManager = m_Interface->getAccessManager();
- QUrl dlUrl(downloadLink);
- QNetworkRequest request(dlUrl);
- m_Canceled = false;
- m_Reply = accessManager->get(request);
- m_UpdateFile.setFileName(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory()).append("\\").append(fileName)));
- m_UpdateFile.open(QIODevice::WriteOnly);
- m_Progress.setModal(true);
- m_Progress.show();
- m_Progress.setValue(0);
- m_Progress.setWindowTitle(tr("Update"));
- m_Progress.setLabelText(tr("Download in progress"));
-
- connect(m_Reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64)));
- connect(m_Reply, SIGNAL(finished()), this, SLOT(downloadFinished()));
- connect(m_Reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead()));
-}
-
-
-void SelfUpdater::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
-{
- if (m_Reply != NULL) {
- if (m_Canceled) {
- m_Reply->abort();
- } else {
- if (bytesTotal != 0) {
- m_Progress.setValue((bytesReceived * 100) / bytesTotal);
- }
- }
- }
-}
-
-
-void SelfUpdater::downloadReadyRead()
-{
- if (m_Reply != NULL) {
- m_UpdateFile.write(m_Reply->readAll());
- }
-}
-
-
-void SelfUpdater::downloadFinished()
-{
- int error = QNetworkReply::NoError;
-
- if (m_Reply != NULL) {
- m_UpdateFile.write(m_Reply->readAll());
-
- error = m_Reply->error();
-
- if (m_Reply->header(QNetworkRequest::ContentTypeHeader).toString().startsWith("text", Qt::CaseInsensitive)) {
- m_Canceled = true;
- }
-
- m_Progress.hide();
- m_Reply->close();
- m_Reply->deleteLater();
- m_Reply = NULL;
- }
-
- m_UpdateFile.close();
-
- if ((m_UpdateFile.size() == 0) ||
- (error != QNetworkReply::NoError) ||
- m_Canceled) {
- if (!m_Canceled) {
- reportError(tr("Download failed: %1").arg(error));
- }
- m_UpdateFile.remove();
- return;
- }
-
- qDebug("download: %s", m_UpdateFile.fileName().toUtf8().constData());
-
- try {
- installUpdate();
- } catch (const std::exception &e) {
- reportError(tr("Failed to install update: %1").arg(e.what()));
- }
-}
-
-
-void SelfUpdater::downloadCancel()
-{
- m_Canceled = true;
-}
-
-
-void SelfUpdater::installUpdate()
-{
- const QString mopath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory()));
-
- QString backupPath = mopath.mid(0).append("/update_backup");
- QDir().mkdir(backupPath);
-
- // rename files that are currently open so we can unpack the update
- if (!m_CurrentArchive->open(ToWString(QDir::toNativeSeparators(m_UpdateFile.fileName())).c_str(),
- new MethodCallback<SelfUpdater, void, LPSTR>(this, &SelfUpdater::queryPassword))) {
- throw MyException(tr("failed to open archive \"%1\": %2")
- .arg(m_UpdateFile.fileName())
- .arg(InstallationManager::getErrorString(m_CurrentArchive->getLastError())));
- }
-
- // move all files contained in the archive out of the way,
- // otherwise we can't overwrite everything
- FileData* const *data;
- size_t size;
- m_CurrentArchive->getFileList(data, size);
-
- for (size_t i = 0; i < size; ++i) {
- QString outputName = ToQString(data[i]->getFileName());
- if (outputName.startsWith("ModOrganizer\\", Qt::CaseInsensitive)) {
- outputName = outputName.mid(13);
- data[i]->setOutputFileName(ToWString(outputName).c_str());
- } else if (outputName == "ModOrganizer") {
- data[i]->setSkip(true);
- }
- QFile file(mopath.mid(0).append("/").append(outputName));
- if (file.exists()) {
- file.rename(backupPath.mid(0).append("/").append(outputName));
- }
- }
-
- // now unpack the archive into the mo directory
- if (!m_CurrentArchive->extract(GameInfo::instance().getOrganizerDirectory().c_str(),
- new MethodCallback<SelfUpdater, void, float>(this, &SelfUpdater::updateProgress),
- new MethodCallback<SelfUpdater, void, LPCWSTR>(this, &SelfUpdater::updateProgressFile),
- new MethodCallback<SelfUpdater, void, LPCWSTR>(this, &SelfUpdater::report7ZipError))) {
- throw std::runtime_error("extracting failed");
- }
-
- m_CurrentArchive->close();
-
- m_UpdateFile.remove();
-
- QMessageBox::information(m_Parent, tr("Update"), tr("Update installed, Mod Organizer will now be restarted."));
-
- QProcess newProcess;
- if (QFile::exists(mopath.mid(0).append("/ModOrganizer.exe"))) {
- newProcess.startDetached(mopath.mid(0).append("/ModOrganizer.exe"), QStringList("update"));
- } else {
- newProcess.startDetached(mopath.mid(0).append("/ModOrganiser.exe"), QStringList("update"));
- }
- emit restart();
-}
-
-void SelfUpdater::queryPassword(LPSTR)
-{
- // nop
-}
-
-void SelfUpdater::updateProgress(float)
-{
- // nop
-}
-
-void SelfUpdater::updateProgressFile(LPCWSTR)
-{
- // nop
-}
-
-void SelfUpdater::report7ZipError(LPCWSTR errorMessage)
-{
- QMessageBox::critical(m_Parent, tr("Error"), ToQString(errorMessage));
-}
-
-
-QString SelfUpdater::retrieveNews(const QString &description)
-{
- QStringList temp = description.split("[s][/s]");
- if (temp.length() < 2) {
- return QString();
- } else {
- return temp.at(1);
- }
-}
-
-
-void SelfUpdater::nxmDescriptionAvailable(int, QVariant, QVariant resultData, int requestID)
-{
- if (requestID == m_UpdateRequestID) {
- m_UpdateRequestID = -1;
-
- QVariantMap result = resultData.toMap();
- QString motd = retrieveNews(result["description"].toString()).trimmed();
- if (motd.length() != 0) {
- emit motdAvailable(motd);
- }
-
- m_NewestVersion = result["version"].toString();
- if (m_NewestVersion.isEmpty()) {
- QTimer::singleShot(5000, this, SLOT(testForUpdate()));
- }
-
- VersionInfo currentVersion(m_MOVersion);
- VersionInfo newestVersion(m_NewestVersion);
-
- if (!m_NewestVersion.isEmpty() && (currentVersion < newestVersion)) {
- emit updateAvailable();
- } else if (newestVersion < currentVersion) {
- qDebug("this version is newer than the current version on nexus (%s vs %s)",
- currentVersion.canonicalString().toUtf8().constData(),
- newestVersion.canonicalString().toUtf8().constData());
- }
- }
-}
-
-
-void SelfUpdater::nxmFilesAvailable(int, QVariant userData, QVariant resultData, int requestID)
-{
- if (requestID != m_UpdateRequestID) {
- return;
- }
- QString version = userData.toString();
-
- m_UpdateRequestID = -1;
-
- if (!resultData.canConvert<QVariantList>()) {
- qCritical("invalid files result: %s", resultData.toString().toUtf8().constData());
- reportError(tr("Failed to parse response. Please report this as a bug and include the file mo_interface.log."));
- return;
- }
-
- QVariantList result = resultData.toList();
-
- QRegExp updateExpList(QString("updates version ([0-9., ]*) to %1").arg(version));
- QRegExp updateExpRange(QString("updates version ([0-9.]*) - ([0-9.]*) to %1").arg(version));
- int updateFileID = -1;
- QString updateFileName;
- int mainFileID = -1;
- QString mainFileName;
- int mainFileSize = 0;
-
- foreach(QVariant file, result) {
- QVariantMap fileInfo = file.toMap();
- if (!fileInfo["uri"].toString().endsWith(".7z")) {
- continue;
- }
-
- if (fileInfo["version"].toString() == version) {
- if (fileInfo["category_id"].toInt() == 2) {
- QString description = fileInfo["description"].toString();
- // update
- if (updateExpList.indexIn(description) != -1) {
- // there is an update for the newest version of MO, but does
- // it apply to the current version?
- QStringList supportedVersions = updateExpList.cap(1).split(QRegExp(",[ ]*"), QString::SkipEmptyParts);
- if (supportedVersions.contains(m_MOVersion.canonicalString())) {
- updateFileID = fileInfo["id"].toInt();
- updateFileName = fileInfo["uri"].toString();
- } else {
- qDebug("update not supported from %s", m_MOVersion.canonicalString().toUtf8().constData());
- }
- } else if (updateExpRange.indexIn(description) != -1) {
- VersionInfo rangeLowEnd(updateExpRange.cap(1));
- VersionInfo rangeHighEnd(updateExpRange.cap(2));
- if ((rangeLowEnd <= m_MOVersion) &&
- (m_MOVersion <= rangeHighEnd)) {
- updateFileID = fileInfo["id"].toInt();
- updateFileName = fileInfo["uri"].toString();
- break;
- } else {
- qDebug("update not supported from %s", m_MOVersion.canonicalString().toUtf8().constData());
- }
- } else {
- qWarning("invalid update description: %s",
- description.toUtf8().constData());
- }
- } else if (fileInfo["category_id"].toInt() == 1) {
- mainFileID = fileInfo["id"].toInt();
- mainFileName = fileInfo["uri"].toString();
- mainFileSize = fileInfo["size"].toInt();
- }
- }
- }
-
- if (updateFileID != -1) {
- qDebug("update available: %d", updateFileID);
- m_UpdateRequestID = m_Interface->requestDownloadURL(SkyrimInfo::getNexusModIDStatic(),
- updateFileID, this, updateFileName,
- ToQString(SkyrimInfo::getNexusInfoUrlStatic()));
- } else if (mainFileID != -1) {
- qDebug("full download required: %d", mainFileID);
- if (QMessageBox::question(m_Parent, tr("Update"),
- tr("No incremental update available for this version, "
- "the complete package needs to be downloaded (%1 kB)").arg(mainFileSize),
- QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
- m_UpdateRequestID = m_Interface->requestDownloadURL(SkyrimInfo::getNexusModIDStatic(),
- mainFileID, this, mainFileName,
- ToQString(SkyrimInfo::getNexusInfoUrlStatic()));
- }
- } else {
- qCritical("no file for update found");
- MessageDialog::showMessage(tr("no file for update found. Please update manually."), m_Parent);
- m_Progress.hide();
- }
-}
-
-
-void SelfUpdater::nxmRequestFailed(int, QVariant, int requestID, const QString &errorMessage)
-{
- if (requestID == m_UpdateRequestID) {
- m_UpdateRequestID = -1;
- if (m_Attempts > 0) {
- QTimer::singleShot(60000, this, SLOT(testForUpdate()));
- --m_Attempts;
- } else {
- MessageDialog::showMessage(tr("Failed to retrieve update information: %1").arg(errorMessage), m_Parent);
- }
- }
-}
-
-
-void SelfUpdater::nxmDownloadURLsAvailable(int, int, QVariant userData, QVariant resultData, int requestID)
-{
- if (requestID == m_UpdateRequestID) {
- m_UpdateRequestID = -1;
- QVariantList serverList = resultData.toList();
- if (serverList.count() != 0) {
- qSort(serverList.begin(), serverList.end(), DownloadManager::ServerByPreference);
-
- QVariantMap dlServer = serverList.first().toMap();
-
- download(dlServer["URI"].toString(), userData.toString());
- } else {
- MessageDialog::showMessage(tr("No download server available. Please try again later."), m_Parent);
- m_Progress.hide();
- }
- }
-}
-
+#include "selfupdater.h" +#include "utility.h" +#include "installationmanager.h" +#include "report.h" +#include "messagedialog.h" +#include "downloadmanager.h" + +#include <versioninfo.h> +#include <gameinfo.h> +#include <skyriminfo.h> +#include <QMessageBox> +#include <QNetworkAccessManager> +#include <QNetworkRequest> +#include <QDir> +#include <QLibrary> +#include <QProcess> +#include <QApplication> +#include <util.h> + + +using namespace MOBase; +using namespace MOShared; + + +typedef Archive* (*CreateArchiveType)(); + + +template <typename T> T resolveFunction(QLibrary &lib, const char *name) +{ + T temp = reinterpret_cast<T>(lib.resolve(name)); + if (temp == NULL) { + throw std::runtime_error(QObject::tr("invalid 7-zip32.dll: %1").arg(lib.errorString()).toLatin1().constData()); + } + return temp; +} + + +SelfUpdater::SelfUpdater(NexusInterface *nexusInterface, QWidget *parent) + : QObject(parent), m_Parent(parent), m_Interface(nexusInterface), m_UpdateRequestID(-1), + m_Reply(NULL), m_Progress(parent), m_Attempts(3) +{ + m_Progress.setMaximum(100); + + QLibrary archiveLib("dlls\\archive.dll"); + if (!archiveLib.load()) { + throw MyException(tr("archive.dll not loaded: \"%1\"").arg(archiveLib.errorString())); + } + + CreateArchiveType CreateArchiveFunc = resolveFunction<CreateArchiveType>(archiveLib, "CreateArchive"); + + m_CurrentArchive = CreateArchiveFunc(); + if (!m_CurrentArchive->isValid()) { + throw MyException(InstallationManager::getErrorString(m_CurrentArchive->getLastError())); + } + + connect(&m_Progress, SIGNAL(canceled()), this, SLOT(downloadCancel())); + + VS_FIXEDFILEINFO version = GetFileVersion(ToWString(QApplication::applicationFilePath())); + + m_MOVersion = VersionInfo(version.dwFileVersionMS >> 16, + version.dwFileVersionMS & 0xFFFF, + version.dwFileVersionLS >> 16); +} + + +SelfUpdater::~SelfUpdater() +{ + delete m_CurrentArchive; +} + + +void SelfUpdater::testForUpdate() +{ +/* if (QFile::exists(QCoreApplication::applicationDirPath() + "/mo_test_update.7z")) { + emit updateAvailable(); + return; + }*/ + + if (m_UpdateRequestID == -1) { + m_UpdateRequestID = m_Interface->requestDescription( + SkyrimInfo::getNexusModIDStatic(), this, QVariant(), + ToQString(SkyrimInfo::getNexusInfoUrlStatic())); + } +} + +void SelfUpdater::startUpdate() +{ +/* if (QFile::exists(QCoreApplication::applicationDirPath() + "/mo_test_update.7z")) { + m_UpdateFile.setFileName(QCoreApplication::applicationDirPath() + "/mo_test_update.7z"); + installUpdate(); + return; + }*/ + + if ((m_UpdateRequestID == -1) && + (!m_NewestVersion.isEmpty())) { + if (QMessageBox::question(m_Parent, tr("Update"), + tr("An update is available (newest version: %1), do you want to install it?").arg(m_NewestVersion), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + m_UpdateRequestID = m_Interface->requestFiles(SkyrimInfo::getNexusModIDStatic(), + this, m_NewestVersion, + ToQString(SkyrimInfo::getNexusInfoUrlStatic())); + } + } +} + + +void SelfUpdater::download(const QString &downloadLink, const QString &fileName) +{ + qDebug("download: %s", downloadLink.toUtf8().constData()); + QNetworkAccessManager *accessManager = m_Interface->getAccessManager(); + QUrl dlUrl(downloadLink); + QNetworkRequest request(dlUrl); + m_Canceled = false; + m_Reply = accessManager->get(request); + m_UpdateFile.setFileName(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory()).append("\\").append(fileName))); + m_UpdateFile.open(QIODevice::WriteOnly); + m_Progress.setModal(true); + m_Progress.show(); + m_Progress.setValue(0); + m_Progress.setWindowTitle(tr("Update")); + m_Progress.setLabelText(tr("Download in progress")); + + connect(m_Reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgress(qint64, qint64))); + connect(m_Reply, SIGNAL(finished()), this, SLOT(downloadFinished())); + connect(m_Reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead())); +} + + +void SelfUpdater::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) +{ + if (m_Reply != NULL) { + if (m_Canceled) { + m_Reply->abort(); + } else { + if (bytesTotal != 0) { + m_Progress.setValue((bytesReceived * 100) / bytesTotal); + } + } + } +} + + +void SelfUpdater::downloadReadyRead() +{ + if (m_Reply != NULL) { + m_UpdateFile.write(m_Reply->readAll()); + } +} + + +void SelfUpdater::downloadFinished() +{ + int error = QNetworkReply::NoError; + + if (m_Reply != NULL) { + m_UpdateFile.write(m_Reply->readAll()); + + error = m_Reply->error(); + + if (m_Reply->header(QNetworkRequest::ContentTypeHeader).toString().startsWith("text", Qt::CaseInsensitive)) { + m_Canceled = true; + } + + m_Progress.hide(); + m_Reply->close(); + m_Reply->deleteLater(); + m_Reply = NULL; + } + + m_UpdateFile.close(); + + if ((m_UpdateFile.size() == 0) || + (error != QNetworkReply::NoError) || + m_Canceled) { + if (!m_Canceled) { + reportError(tr("Download failed: %1").arg(error)); + } + m_UpdateFile.remove(); + return; + } + + qDebug("download: %s", m_UpdateFile.fileName().toUtf8().constData()); + + try { + installUpdate(); + } catch (const std::exception &e) { + reportError(tr("Failed to install update: %1").arg(e.what())); + } +} + + +void SelfUpdater::downloadCancel() +{ + m_Canceled = true; +} + + +void SelfUpdater::installUpdate() +{ + const QString mopath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())); + + QString backupPath = mopath.mid(0).append("/update_backup"); + QDir().mkdir(backupPath); + + // rename files that are currently open so we can unpack the update + if (!m_CurrentArchive->open(ToWString(QDir::toNativeSeparators(m_UpdateFile.fileName())).c_str(), + new MethodCallback<SelfUpdater, void, LPSTR>(this, &SelfUpdater::queryPassword))) { + throw MyException(tr("failed to open archive \"%1\": %2") + .arg(m_UpdateFile.fileName()) + .arg(InstallationManager::getErrorString(m_CurrentArchive->getLastError()))); + } + + // move all files contained in the archive out of the way, + // otherwise we can't overwrite everything + FileData* const *data; + size_t size; + m_CurrentArchive->getFileList(data, size); + + for (size_t i = 0; i < size; ++i) { + QString outputName = ToQString(data[i]->getFileName()); + if (outputName.startsWith("ModOrganizer\\", Qt::CaseInsensitive)) { + outputName = outputName.mid(13); + data[i]->setOutputFileName(ToWString(outputName).c_str()); + } else if (outputName == "ModOrganizer") { + data[i]->setSkip(true); + } + QFile file(mopath.mid(0).append("/").append(outputName)); + if (file.exists()) { + file.rename(backupPath.mid(0).append("/").append(outputName)); + } + } + + // now unpack the archive into the mo directory + if (!m_CurrentArchive->extract(GameInfo::instance().getOrganizerDirectory().c_str(), + new MethodCallback<SelfUpdater, void, float>(this, &SelfUpdater::updateProgress), + new MethodCallback<SelfUpdater, void, LPCWSTR>(this, &SelfUpdater::updateProgressFile), + new MethodCallback<SelfUpdater, void, LPCWSTR>(this, &SelfUpdater::report7ZipError))) { + throw std::runtime_error("extracting failed"); + } + + m_CurrentArchive->close(); + + m_UpdateFile.remove(); + + QMessageBox::information(m_Parent, tr("Update"), tr("Update installed, Mod Organizer will now be restarted.")); + + QProcess newProcess; + if (QFile::exists(mopath.mid(0).append("/ModOrganizer.exe"))) { + newProcess.startDetached(mopath.mid(0).append("/ModOrganizer.exe"), QStringList("update")); + } else { + newProcess.startDetached(mopath.mid(0).append("/ModOrganiser.exe"), QStringList("update")); + } + emit restart(); +} + +void SelfUpdater::queryPassword(LPSTR) +{ + // nop +} + +void SelfUpdater::updateProgress(float) +{ + // nop +} + +void SelfUpdater::updateProgressFile(LPCWSTR) +{ + // nop +} + +void SelfUpdater::report7ZipError(LPCWSTR errorMessage) +{ + QMessageBox::critical(m_Parent, tr("Error"), ToQString(errorMessage)); +} + + +QString SelfUpdater::retrieveNews(const QString &description) +{ + QStringList temp = description.split("[s][/s]"); + if (temp.length() < 2) { + return QString(); + } else { + return temp.at(1); + } +} + + +void SelfUpdater::nxmDescriptionAvailable(int, QVariant, QVariant resultData, int requestID) +{ + if (requestID == m_UpdateRequestID) { + m_UpdateRequestID = -1; + + QVariantMap result = resultData.toMap(); + QString motd = retrieveNews(result["description"].toString()).trimmed(); + if (motd.length() != 0) { + emit motdAvailable(motd); + } + + m_NewestVersion = result["version"].toString(); + if (m_NewestVersion.isEmpty()) { + QTimer::singleShot(5000, this, SLOT(testForUpdate())); + } + + VersionInfo currentVersion(m_MOVersion); + VersionInfo newestVersion(m_NewestVersion); + + if (!m_NewestVersion.isEmpty() && (currentVersion < newestVersion)) { + emit updateAvailable(); + } else if (newestVersion < currentVersion) { + qDebug("this version is newer than the current version on nexus (%s vs %s)", + currentVersion.canonicalString().toUtf8().constData(), + newestVersion.canonicalString().toUtf8().constData()); + } + } +} + + +void SelfUpdater::nxmFilesAvailable(int, QVariant userData, QVariant resultData, int requestID) +{ + if (requestID != m_UpdateRequestID) { + return; + } + QString version = userData.toString(); + + m_UpdateRequestID = -1; + + if (!resultData.canConvert<QVariantList>()) { + qCritical("invalid files result: %s", resultData.toString().toUtf8().constData()); + reportError(tr("Failed to parse response. Please report this as a bug and include the file mo_interface.log.")); + return; + } + + QVariantList result = resultData.toList(); + + QRegExp updateExpList(QString("updates version ([0-9., ]*) to %1").arg(version)); + QRegExp updateExpRange(QString("updates version ([0-9.]*) - ([0-9.]*) to %1").arg(version)); + int updateFileID = -1; + QString updateFileName; + int mainFileID = -1; + QString mainFileName; + int mainFileSize = 0; + + foreach(QVariant file, result) { + QVariantMap fileInfo = file.toMap(); + if (!fileInfo["uri"].toString().endsWith(".7z")) { + continue; + } + + if (fileInfo["version"].toString() == version) { + if (fileInfo["category_id"].toInt() == 2) { + QString description = fileInfo["description"].toString(); + // update + if (updateExpList.indexIn(description) != -1) { + // there is an update for the newest version of MO, but does + // it apply to the current version? + QStringList supportedVersions = updateExpList.cap(1).split(QRegExp(",[ ]*"), QString::SkipEmptyParts); + if (supportedVersions.contains(m_MOVersion.canonicalString())) { + updateFileID = fileInfo["id"].toInt(); + updateFileName = fileInfo["uri"].toString(); + } else { + qDebug("update not supported from %s", m_MOVersion.canonicalString().toUtf8().constData()); + } + } else if (updateExpRange.indexIn(description) != -1) { + VersionInfo rangeLowEnd(updateExpRange.cap(1)); + VersionInfo rangeHighEnd(updateExpRange.cap(2)); + if ((rangeLowEnd <= m_MOVersion) && + (m_MOVersion <= rangeHighEnd)) { + updateFileID = fileInfo["id"].toInt(); + updateFileName = fileInfo["uri"].toString(); + break; + } else { + qDebug("update not supported from %s", m_MOVersion.canonicalString().toUtf8().constData()); + } + } else { + qWarning("invalid update description: %s", + description.toUtf8().constData()); + } + } else if (fileInfo["category_id"].toInt() == 1) { + mainFileID = fileInfo["id"].toInt(); + mainFileName = fileInfo["uri"].toString(); + mainFileSize = fileInfo["size"].toInt(); + } + } + } + + if (updateFileID != -1) { + qDebug("update available: %d", updateFileID); + m_UpdateRequestID = m_Interface->requestDownloadURL(SkyrimInfo::getNexusModIDStatic(), + updateFileID, this, updateFileName, + ToQString(SkyrimInfo::getNexusInfoUrlStatic())); + } else if (mainFileID != -1) { + qDebug("full download required: %d", mainFileID); + if (QMessageBox::question(m_Parent, tr("Update"), + tr("No incremental update available for this version, " + "the complete package needs to be downloaded (%1 kB)").arg(mainFileSize), + QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { + m_UpdateRequestID = m_Interface->requestDownloadURL(SkyrimInfo::getNexusModIDStatic(), + mainFileID, this, mainFileName, + ToQString(SkyrimInfo::getNexusInfoUrlStatic())); + } + } else { + qCritical("no file for update found"); + MessageDialog::showMessage(tr("no file for update found. Please update manually."), m_Parent); + m_Progress.hide(); + } +} + + +void SelfUpdater::nxmRequestFailed(int, QVariant, int requestID, const QString &errorMessage) +{ + if (requestID == m_UpdateRequestID) { + m_UpdateRequestID = -1; + if (m_Attempts > 0) { + QTimer::singleShot(60000, this, SLOT(testForUpdate())); + --m_Attempts; + } else { + MessageDialog::showMessage(tr("Failed to retrieve update information: %1").arg(errorMessage), m_Parent); + } + } +} + + +void SelfUpdater::nxmDownloadURLsAvailable(int, int, QVariant userData, QVariant resultData, int requestID) +{ + if (requestID == m_UpdateRequestID) { + m_UpdateRequestID = -1; + QVariantList serverList = resultData.toList(); + if (serverList.count() != 0) { + qSort(serverList.begin(), serverList.end(), DownloadManager::ServerByPreference); + + QVariantMap dlServer = serverList.first().toMap(); + + download(dlServer["URI"].toString(), userData.toString()); + } else { + MessageDialog::showMessage(tr("No download server available. Please try again later."), m_Parent); + m_Progress.hide(); + } + } +} + |
