overte/interface/external/fervor/fvupdater.cpp
2013-08-15 11:12:17 -07:00

908 lines
22 KiB
C++
Executable file

#include "fvupdater.h"
#include "fvplatform.h"
#include "fvignoredversions.h"
#include "fvavailableupdate.h"
#include <QCoreApplication>
#include <QtNetwork>
#include <QDebug>
#include <QSettings>
#include "quazip.h"
#include "quazipfile.h"
#ifdef Q_OS_MAC
#include "CoreFoundation/CoreFoundation.h"
#endif
#ifdef FV_GUI
#include "fvupdatewindow.h"
#include "fvupdatedownloadprogress.h"
#include <QMessageBox>
#include <QDesktopServices>
#else
// QSettings key for automatic update installation
#define FV_NEW_VERSION_POLICY_KEY "FVNewVersionPolicy"
#endif
#ifdef FV_DEBUG
// Unit tests
# include "fvversioncomparatortest.h"
#endif
extern QSettings* settings;
FvUpdater* FvUpdater::m_Instance = 0;
FvUpdater* FvUpdater::sharedUpdater()
{
static QMutex mutex;
if (! m_Instance) {
mutex.lock();
if (! m_Instance) {
m_Instance = new FvUpdater;
}
mutex.unlock();
}
return m_Instance;
}
void FvUpdater::drop()
{
static QMutex mutex;
mutex.lock();
delete m_Instance;
m_Instance = 0;
mutex.unlock();
}
FvUpdater::FvUpdater() : QObject(0)
{
m_reply = 0;
#ifdef FV_GUI
m_updaterWindow = 0;
#endif
m_proposedUpdate = 0;
m_requiredSslFingerprint = "";
htAuthUsername = "";
htAuthPassword = "";
skipVersionAllowed = true;
remindLaterAllowed = true;
connect(&m_qnam, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)),this, SLOT(authenticationRequired(QNetworkReply*, QAuthenticator*)));
// Translation mechanism
installTranslator();
#ifdef FV_DEBUG
// Unit tests
FvVersionComparatorTest* test = new FvVersionComparatorTest();
test->runAll();
delete test;
#endif
}
FvUpdater::~FvUpdater()
{
if (m_proposedUpdate) {
delete m_proposedUpdate;
m_proposedUpdate = 0;
}
#ifdef FV_GUI
hideUpdaterWindow();
#endif
}
void FvUpdater::installTranslator()
{
QTranslator translator;
QString locale = QLocale::system().name();
translator.load(QString("fervor_") + locale);
#if QT_VERSION < 0x050000
QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8"));
#endif
qApp->installTranslator(&translator);
}
#ifdef FV_GUI
void FvUpdater::showUpdaterWindowUpdatedWithCurrentUpdateProposal()
{
// Destroy window if already exists
hideUpdaterWindow();
// Create a new window
m_updaterWindow = new FvUpdateWindow(NULL, skipVersionAllowed, remindLaterAllowed);
m_updaterWindow->UpdateWindowWithCurrentProposedUpdate();
m_updaterWindow->show();
}
void FvUpdater::hideUpdaterWindow()
{
if (m_updaterWindow) {
if (! m_updaterWindow->close()) {
qWarning() << "Update window didn't close, leaking memory from now on";
}
// not deleting because of Qt::WA_DeleteOnClose
m_updaterWindow = 0;
}
}
void FvUpdater::updaterWindowWasClosed()
{
// (Re-)nullify a pointer to a destroyed QWidget or you're going to have a bad time.
m_updaterWindow = 0;
}
#endif
void FvUpdater::SetFeedURL(QUrl feedURL)
{
m_feedURL = feedURL;
}
void FvUpdater::SetFeedURL(QString feedURL)
{
SetFeedURL(QUrl(feedURL));
}
QString FvUpdater::GetFeedURL()
{
return m_feedURL.toString();
}
FvAvailableUpdate* FvUpdater::GetProposedUpdate()
{
return m_proposedUpdate;
}
void FvUpdater::InstallUpdate()
{
if(m_proposedUpdate==NULL)
{
qWarning() << "Abort Update: No update prososed! This should not happen.";
return;
}
// Prepare download
QUrl url = m_proposedUpdate->GetEnclosureUrl();
// Check SSL Fingerprint if required
if(url.scheme()=="https" && !m_requiredSslFingerprint.isEmpty())
if( !checkSslFingerPrint(url) ) // check failed
{
qWarning() << "Update aborted.";
return;
}
// Start Download
QNetworkReply* reply = m_qnam.get(QNetworkRequest(url));
connect(reply, SIGNAL(finished()), this, SLOT(httpUpdateDownloadFinished()));
// Maybe Check request 's return value
if (reply->error() != QNetworkReply::NoError)
{
qDebug()<<"Unable to download the update: "<<reply->errorString();
return;
}
else
qDebug()<<"OK";
// Show download Window
#ifdef FV_GUI
FvUpdateDownloadProgress* dlwindow = new FvUpdateDownloadProgress(NULL);
connect(reply, SIGNAL(downloadProgress(qint64, qint64)), dlwindow, SLOT(downloadProgress(qint64, qint64) ));
connect(&m_qnam, SIGNAL(finished(QNetworkReply*)), dlwindow, SLOT(close()));
dlwindow->show();
#endif
emit (updatedFinishedSuccessfully());
#ifdef FV_GUI
hideUpdaterWindow();
#endif
}
void FvUpdater::httpUpdateDownloadFinished()
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if(reply==NULL)
{
qWarning()<<"The slot httpUpdateDownloadFinished() should only be invoked by S&S.";
return;
}
if(reply->error() == QNetworkReply::NoError)
{
int httpstatuscode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toUInt();
// no error received?
if (reply->error() == QNetworkReply::NoError)
{
if (reply->isReadable())
{
#ifdef Q_OS_MAC
CFURLRef appURLRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
char path[PATH_MAX];
if (!CFURLGetFileSystemRepresentation(appURLRef, TRUE, (UInt8 *)path, PATH_MAX)) {
// error!
}
CFRelease(appURLRef);
QString filePath = QString(path);
QString rootDirectory = filePath.left(filePath.lastIndexOf("/"));
#else
QString rootDirectory = QCoreApplication::applicationDirPath() + "/";
#endif
// Write download into File
QFileInfo fileInfo=reply->url().path();
QString fileName = rootDirectory + fileInfo.fileName();
//qDebug()<<"Writing downloaded file into "<<fileName;
QFile file(fileName);
file.open(QIODevice::WriteOnly);
file.write(reply->readAll());
file.close();
// Retrieve List of updated files (Placed in an extra scope to avoid QuaZIP handles the archive permanently and thus avoids the deletion.)
{
QuaZip zip(fileName);
if (!zip.open(QuaZip::mdUnzip)) {
qWarning("testRead(): zip.open(): %d", zip.getZipError());
return;
}
zip.setFileNameCodec("IBM866");
QList<QuaZipFileInfo> updateFiles = zip.getFileInfoList();
// Rename all current files with available update.
for (int i=0;i<updateFiles.size();i++)
{
QString sourceFilePath = rootDirectory + "\\" + updateFiles[i].name;
QDir appDir( QCoreApplication::applicationDirPath() );
QFileInfo file( sourceFilePath );
if(file.exists())
{
//qDebug()<<tr("Moving file %1 to %2").arg(sourceFilePath).arg(sourceFilePath+".oldversion");
appDir.rename( sourceFilePath, sourceFilePath+".oldversion" );
}
}
}
// Install updated Files
unzipUpdate(fileName, rootDirectory);
// Delete update archive
while(QFile::remove(fileName) )
{
};
// Restart ap to clean up and start usual business
restartApplication();
}
else qDebug()<<"Error: QNetworkReply is not readable!";
}
else
{
qDebug()<<"Download errors ocurred! HTTP Error Code:"<<httpstatuscode;
}
reply->deleteLater();
} // If !reply->error END
} // httpUpdateDownloadFinished END
bool FvUpdater::unzipUpdate(const QString & filePath, const QString & extDirPath, const QString & singleFileName )
{
QuaZip zip(filePath);
if (!zip.open(QuaZip::mdUnzip)) {
qWarning()<<tr("Error: Unable to open zip archive %1 for unzipping: %2").arg(filePath).arg(zip.getZipError());
return false;
}
zip.setFileNameCodec("IBM866");
//qWarning("Update contains %d files\n", zip.getEntriesCount());
QuaZipFileInfo info;
QuaZipFile file(&zip);
QFile out;
QString name;
QDir appDir(extDirPath);
for (bool more = zip.goToFirstFile(); more; more = zip.goToNextFile())
{
if (!zip.getCurrentFileInfo(&info)) {
qWarning()<<tr("Error: Unable to retrieve fileInfo about the file to extract: %2").arg(zip.getZipError());
return false;
}
if (!singleFileName.isEmpty())
if (!info.name.contains(singleFileName))
continue;
if (!file.open(QIODevice::ReadOnly)) {
qWarning()<<tr("Error: Unable to open file %1 for unzipping: %2").arg(filePath).arg(file.getZipError());
return false;
}
name = QString("%1/%2").arg(extDirPath).arg(file.getActualFileName());
if (file.getZipError() != UNZ_OK) {
qWarning()<<tr("Error: Unable to retrieve zipped filename to unzip from %1: %2").arg(filePath).arg(file.getZipError());
return false;
}
QFileInfo fi(name);
appDir.mkpath(fi.absolutePath() ); // Ensure that subdirectories - if required - exist
out.setFileName(name);
out.open(QIODevice::WriteOnly);
out.write( file.readAll() );
out.close();
if (file.getZipError() != UNZ_OK) {
qWarning()<<tr("Error: Unable to unzip file %1: %2").arg(name).arg(file.getZipError());
return false;
}
if (!file.atEnd()) {
qWarning()<<tr("Error: Have read all available bytes, but pointer still does not show EOF: %1").arg(file.getZipError());
return false;
}
file.close();
if (file.getZipError() != UNZ_OK) {
qWarning()<<tr("Error: Unable to close zipped file %1: %2").arg(name).arg(file.getZipError());
return false;
}
}
zip.close();
if (zip.getZipError() != UNZ_OK) {
qWarning()<<tr("Error: Unable to close zip archive file %1: %2").arg(filePath).arg(file.getZipError());
return false;
}
return true;
}
void FvUpdater::SkipUpdate()
{
qDebug() << "Skip update";
FvAvailableUpdate* proposedUpdate = GetProposedUpdate();
if (! proposedUpdate) {
qWarning() << "Proposed update is NULL (shouldn't be at this point)";
return;
}
// Start ignoring this particular version
FVIgnoredVersions::IgnoreVersion(proposedUpdate->GetEnclosureVersion());
#ifdef FV_GUI
hideUpdaterWindow();
#endif
}
void FvUpdater::RemindMeLater()
{
//qDebug() << "Remind me later";
#ifdef FV_GUI
hideUpdaterWindow();
#endif
}
bool FvUpdater::CheckForUpdates(bool silentAsMuchAsItCouldGet)
{
if (m_feedURL.isEmpty()) {
qCritical() << "Please set feed URL via setFeedURL() before calling CheckForUpdates().";
return false;
}
m_silentAsMuchAsItCouldGet = silentAsMuchAsItCouldGet;
// Check if application's organization name and domain are set, fail otherwise
// (nowhere to store QSettings to)
if (QCoreApplication::organizationName().isEmpty()) {
qCritical() << "QCoreApplication::organizationName is not set. Please do that.";
return false;
}
if (QCoreApplication::organizationDomain().isEmpty()) {
qCritical() << "QCoreApplication::organizationDomain is not set. Please do that.";
return false;
}
if(QCoreApplication::applicationName().isEmpty()) {
qCritical() << "QCoreApplication::applicationName is not set. Please do that.";
return false;
}
// Set application version is not set yet
if (QCoreApplication::applicationVersion().isEmpty()) {
qCritical() << "QCoreApplication::applicationVersion is not set. Please do that.";
return false;
}
cancelDownloadFeed();
m_httpRequestAborted = false;
startDownloadFeed(m_feedURL);
return true;
}
bool FvUpdater::CheckForUpdatesSilent()
{
return CheckForUpdates(true);
}
bool FvUpdater::CheckForUpdatesNotSilent()
{
return CheckForUpdates(false);
}
void FvUpdater::startDownloadFeed(QUrl url)
{
m_xml.clear();
// Check SSL Fingerprint if required
if(url.scheme()=="https" && !m_requiredSslFingerprint.isEmpty())
if( !checkSslFingerPrint(url) ) // check failed
{
qWarning() << "Update aborted.";
return;
}
m_reply = m_qnam.get(QNetworkRequest(url));
connect(m_reply, SIGNAL(readyRead()), this, SLOT(httpFeedReadyRead()));
connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(httpFeedUpdateDataReadProgress(qint64, qint64)));
connect(m_reply, SIGNAL(finished()), this, SLOT(httpFeedDownloadFinished()));
}
void FvUpdater::cancelDownloadFeed()
{
if (m_reply) {
m_httpRequestAborted = true;
m_reply->abort();
}
}
void FvUpdater::httpFeedReadyRead()
{
// this slot gets called every time the QNetworkReply has new data.
// We read all of its new data and write it into the file.
// That way we use less RAM than when reading it at the finished()
// signal of the QNetworkReply
m_xml.addData(m_reply->readAll());
}
void FvUpdater::httpFeedUpdateDataReadProgress(qint64 bytesRead,
qint64 totalBytes)
{
Q_UNUSED(bytesRead);
Q_UNUSED(totalBytes);
if (m_httpRequestAborted) {
return;
}
}
void FvUpdater::httpFeedDownloadFinished()
{
if (m_httpRequestAborted) {
m_reply->deleteLater();
return;
}
QVariant redirectionTarget = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (m_reply->error()) {
// Error.
showErrorDialog(tr("Feed download failed: %1.").arg(m_reply->errorString()), false);
} else if (! redirectionTarget.isNull()) {
QUrl newUrl = m_feedURL.resolved(redirectionTarget.toUrl());
m_feedURL = newUrl;
m_reply->deleteLater();
startDownloadFeed(m_feedURL);
return;
} else {
// Done.
xmlParseFeed();
}
m_reply->deleteLater();
m_reply = 0;
}
bool FvUpdater::xmlParseFeed()
{
QString currentTag, currentQualifiedTag;
QString xmlTitle, xmlLink, xmlReleaseNotesLink, xmlPubDate, xmlEnclosureUrl,
xmlEnclosureVersion, xmlEnclosurePlatform, xmlEnclosureType;
unsigned long xmlEnclosureLength;
// Parse
while (! m_xml.atEnd()) {
m_xml.readNext();
if (m_xml.isStartElement()) {
currentTag = m_xml.name().toString();
currentQualifiedTag = m_xml.qualifiedName().toString();
if (m_xml.name() == "item") {
xmlTitle.clear();
xmlLink.clear();
xmlReleaseNotesLink.clear();
xmlPubDate.clear();
xmlEnclosureUrl.clear();
xmlEnclosureVersion.clear();
xmlEnclosurePlatform.clear();
xmlEnclosureLength = 0;
xmlEnclosureType.clear();
} else if (m_xml.name() == "enclosure") {
QXmlStreamAttributes attribs = m_xml.attributes();
if (attribs.hasAttribute("fervor:platform"))
{
xmlEnclosurePlatform = attribs.value("fervor:platform").toString().trimmed();
if (FvPlatform::CurrentlyRunningOnPlatform(xmlEnclosurePlatform))
{
xmlEnclosureUrl = attribs.hasAttribute("url") ? attribs.value("url").toString().trimmed() : "";
xmlEnclosureVersion = "";
if (attribs.hasAttribute("fervor:version"))
xmlEnclosureVersion = attribs.value("fervor:version").toString().trimmed();
if (attribs.hasAttribute("sparkle:version"))
xmlEnclosureVersion = attribs.value("sparkle:version").toString().trimmed();
xmlEnclosureLength = attribs.hasAttribute("length") ? attribs.value("length").toString().toLong() : 0;
xmlEnclosureType = attribs.hasAttribute("type") ? attribs.value("type").toString().trimmed() : "";
}
} // if hasAttribute flevor:platform END
} // IF encosure END
} else if (m_xml.isEndElement()) {
if (m_xml.name() == "item") {
// That's it - we have analyzed a single <item> and we'll stop
// here (because the topmost is the most recent one, and thus
// the newest version.
return searchDownloadedFeedForUpdates(xmlTitle,
xmlLink,
xmlReleaseNotesLink,
xmlPubDate,
xmlEnclosureUrl,
xmlEnclosureVersion,
xmlEnclosurePlatform,
xmlEnclosureLength,
xmlEnclosureType);
}
} else if (m_xml.isCharacters() && ! m_xml.isWhitespace()) {
if (currentTag == "title") {
xmlTitle += m_xml.text().toString().trimmed();
} else if (currentTag == "link") {
xmlLink += m_xml.text().toString().trimmed();
} else if (currentQualifiedTag == "sparkle:releaseNotesLink") {
xmlReleaseNotesLink += m_xml.text().toString().trimmed();
} else if (currentTag == "pubDate") {
xmlPubDate += m_xml.text().toString().trimmed();
}
}
if (m_xml.error() && m_xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
showErrorDialog(tr("Feed parsing failed: %1 %2.").arg(QString::number(m_xml.lineNumber()), m_xml.errorString()), false);
return false;
}
}
return false;
}
bool FvUpdater::searchDownloadedFeedForUpdates(QString xmlTitle,
QString xmlLink,
QString xmlReleaseNotesLink,
QString xmlPubDate,
QString xmlEnclosureUrl,
QString xmlEnclosureVersion,
QString xmlEnclosurePlatform,
unsigned long xmlEnclosureLength,
QString xmlEnclosureType)
{
Q_UNUSED(xmlTitle);
Q_UNUSED(xmlPubDate);
Q_UNUSED(xmlEnclosureLength);
Q_UNUSED(xmlEnclosureType);
// Validate
if (xmlReleaseNotesLink.isEmpty()) {
if (xmlLink.isEmpty()) {
showErrorDialog(tr("Feed error: \"release notes\" link is empty"), false);
return false;
} else {
xmlReleaseNotesLink = xmlLink;
}
} else {
xmlLink = xmlReleaseNotesLink;
}
if (! (xmlLink.startsWith("http://") || xmlLink.startsWith("https://"))) {
showErrorDialog(tr("Feed error: invalid \"release notes\" link"), false);
return false;
}
if (xmlEnclosureUrl.isEmpty() || xmlEnclosureVersion.isEmpty() || xmlEnclosurePlatform.isEmpty()) {
showErrorDialog(tr("Feed error: invalid \"enclosure\" with the download link"), false);
return false;
}
// Relevant version?
if (FVIgnoredVersions::VersionIsIgnored(xmlEnclosureVersion)) {
qDebug() << "Version '" << xmlEnclosureVersion << "' is ignored, too old or something like that.";
showInformationDialog(tr("No updates were found."), false);
return true; // Things have succeeded when you think of it.
}
//
// Success! At this point, we have found an update that can be proposed
// to the user.
//
if (m_proposedUpdate) {
delete m_proposedUpdate; m_proposedUpdate = 0;
}
m_proposedUpdate = new FvAvailableUpdate();
m_proposedUpdate->SetTitle(xmlTitle);
m_proposedUpdate->SetReleaseNotesLink(xmlReleaseNotesLink);
m_proposedUpdate->SetPubDate(xmlPubDate);
m_proposedUpdate->SetEnclosureUrl(xmlEnclosureUrl);
m_proposedUpdate->SetEnclosureVersion(xmlEnclosureVersion);
m_proposedUpdate->SetEnclosurePlatform(xmlEnclosurePlatform);
m_proposedUpdate->SetEnclosureLength(xmlEnclosureLength);
m_proposedUpdate->SetEnclosureType(xmlEnclosureType);
#ifdef FV_GUI
// Show "look, there's an update" window
showUpdaterWindowUpdatedWithCurrentUpdateProposal();
#else
// Decide ourselves what to do
decideWhatToDoWithCurrentUpdateProposal();
#endif
return true;
}
void FvUpdater::showErrorDialog(QString message, bool showEvenInSilentMode)
{
if (m_silentAsMuchAsItCouldGet) {
if (! showEvenInSilentMode) {
// Don't show errors in the silent mode
return;
}
}
#ifdef FV_GUI
QMessageBox dlFailedMsgBox;
dlFailedMsgBox.setIcon(QMessageBox::Critical);
dlFailedMsgBox.setText(tr("Error"));
dlFailedMsgBox.setInformativeText(message);
dlFailedMsgBox.exec();
#else
qCritical() << message;
#endif
}
void FvUpdater::showInformationDialog(QString message, bool showEvenInSilentMode)
{
if (m_silentAsMuchAsItCouldGet) {
if (! showEvenInSilentMode) {
// Don't show information dialogs in the silent mode
return;
}
}
#ifdef FV_GUI
QMessageBox dlInformationMsgBox;
dlInformationMsgBox.setIcon(QMessageBox::Information);
dlInformationMsgBox.setText(tr("Information"));
dlInformationMsgBox.setInformativeText(message);
dlInformationMsgBox.exec();
#else
qDebug() << message;
#endif
}
void FvUpdater::finishUpdate(QString pathToFinish)
{
pathToFinish = pathToFinish.isEmpty() ? QCoreApplication::applicationDirPath() : pathToFinish;
QDir appDir(pathToFinish);
appDir.setFilter( QDir::Files | QDir::Dirs );
QFileInfoList dirEntries = appDir.entryInfoList();
foreach (QFileInfo fi, dirEntries)
{
if ( fi.isDir() )
{
QString dirname = fi.fileName();
if ((dirname==".") || (dirname == ".."))
continue;
// recursive clean up subdirectory
finishUpdate(fi.filePath());
}
else
{
if(fi.suffix()=="oldversion")
if( !appDir.remove( fi.absoluteFilePath() ) )
qDebug()<<"Error: Unable to clean up file: "<<fi.absoluteFilePath();
}
} // For each dir entry END
}
void FvUpdater::restartApplication()
{
// Spawn a new instance of myApplication:
QString app = QApplication::applicationFilePath();
QStringList arguments = QApplication::arguments();
QString wd = QDir::currentPath();
qDebug() << app << arguments << wd;
QProcess::startDetached(app, arguments, wd);
QApplication::exit();
}
void FvUpdater::setRequiredSslFingerPrint(QString md5)
{
m_requiredSslFingerprint = md5.remove(":");
}
QString FvUpdater::getRequiredSslFingerPrint()
{
return m_requiredSslFingerprint;
}
bool FvUpdater::checkSslFingerPrint(QUrl urltoCheck)
{
if(urltoCheck.scheme()!="https")
{
qWarning()<<tr("SSL fingerprint check: The url %1 is not a ssl connection!").arg(urltoCheck.toString());
return false;
}
QSslSocket *socket = new QSslSocket(this);
socket->connectToHostEncrypted(urltoCheck.host(), 443);
if( !socket->waitForEncrypted(1000)) // waits until ssl emits encrypted(), max 1000msecs
{
qWarning()<<"SSL fingerprint check: Unable to connect SSL server: "<<socket->sslErrors();
return false;
}
QSslCertificate cert = socket->peerCertificate();
if(cert.isNull())
{
qWarning()<<"SSL fingerprint check: Unable to retrieve SSL server certificate.";
return false;
}
// COmpare digests
if(cert.digest().toHex() != m_requiredSslFingerprint)
{
qWarning()<<"SSL fingerprint check: FINGERPRINT MISMATCH! Server digest="<<cert.digest().toHex()<<", requiered ssl digest="<<m_requiredSslFingerprint;
return false;
}
return true;
}
void FvUpdater::authenticationRequired ( QNetworkReply * reply, QAuthenticator * authenticator )
{
if(reply==NULL || authenticator==NULL)
return;
if(!authenticator->user().isEmpty()) // If there is already a login user set but an authentication is still required: credentials must be wrong -> abort
{
reply->abort();
qWarning()<<"Http authentication: Wrong credentials!";
return;
}
authenticator->setUser(htAuthUsername);
authenticator->setPassword(htAuthPassword);
}
void FvUpdater::setHtAuthCredentials(QString user, QString pass)
{
htAuthUsername = user;
htAuthPassword = pass;
}
void FvUpdater::setHtAuthUsername(QString user)
{
htAuthUsername = user;
}
void FvUpdater::setHtAuthPassword(QString pass)
{
htAuthPassword = pass;
}
void FvUpdater::setSkipVersionAllowed(bool allowed)
{
skipVersionAllowed = allowed;
}
void FvUpdater::setRemindLaterAllowed(bool allowed)
{
remindLaterAllowed = allowed;
}
bool FvUpdater::getSkipVersionAllowed()
{
return skipVersionAllowed;
}
bool FvUpdater::getRemindLaterAllowed()
{
return remindLaterAllowed;
}
#ifndef FV_GUI
void FvUpdater::decideWhatToDoWithCurrentUpdateProposal()
{
QString policy = settings->value(FV_NEW_VERSION_POLICY_KEY).toString();
if(policy == "install")
InstallUpdate();
else if(policy == "skip")
SkipUpdate();
else
RemindMeLater();
}
#endif