Revamped updater thread: Got rid of some old cruft + now using NC for connectivity test (way faster than Wget).

This commit is contained in:
LoRd_MuldeR 2016-04-23 13:25:01 +02:00
parent 35159c3d07
commit a6f6264917
2 changed files with 373 additions and 371 deletions

View File

@ -80,7 +80,7 @@ namespace MUtils
} }
update_status_t; update_status_t;
UpdateChecker(const QString &binWGet, const QString &binGnuPG, const QString &binKeys, const QString &applicationId, const quint32 &installedBuildNo, const bool betaUpdates, const bool testMode = false); UpdateChecker(const QString &binWGet, const QString &binNC, const QString &binGnuPG, const QString &binKeys, const QString &applicationId, const quint32 &installedBuildNo, const bool betaUpdates, const bool testMode = false);
~UpdateChecker(void); ~UpdateChecker(void);
const int getUpdateStatus(void) const { return m_status; } const int getUpdateStatus(void) const { return m_status; }
@ -110,6 +110,7 @@ namespace MUtils
const quint32 m_installedBuildNo; const quint32 m_installedBuildNo;
const QString m_binaryWGet; const QString m_binaryWGet;
const QString m_binaryNC;
const QString m_binaryGnuPG; const QString m_binaryGnuPG;
const QString m_binaryKeys; const QString m_binaryKeys;
@ -122,12 +123,13 @@ namespace MUtils
inline void setProgress(const int progress); inline void setProgress(const int progress);
inline void log(const QString &str1, const QString &str2 = QString(), const QString &str3 = QString(), const QString &str4 = QString()); inline void log(const QString &str1, const QString &str2 = QString(), const QString &str3 = QString(), const QString &str4 = QString());
bool getUpdateInfo(const QString &url, const QString &outFileVers, const QString &outFileSign);
bool tryContactHost(const QString &hostname);
bool parseVersionInfo(const QString &file, UpdateCheckerInfo *updateInfo);
bool getFile(const QString &url, const QString &outFile, const unsigned int maxRedir = 5U, bool *httpOk = NULL); bool getFile(const QString &url, const QString &outFile, const unsigned int maxRedir = 5U, bool *httpOk = NULL);
bool getFile(const QString &url, const bool forceIp4, const QString &outFile, const unsigned int maxRedir, bool *httpOk); bool getFile(const QString &url, const bool forceIp4, const QString &outFile, const unsigned int maxRedir, bool *httpOk);
bool getUpdateInfo(const QString &url, const QString &outFileVers, const QString &outFileSign);
int tryContactHost(const QString &url);
bool tryUpdateMirror(UpdateCheckerInfo *updateInfo, const QString &url);
bool checkSignature(const QString &file, const QString &signature); bool checkSignature(const QString &file, const QString &signature);
bool parseVersionInfo(const QString &file, UpdateCheckerInfo *updateInfo); bool tryUpdateMirror(UpdateCheckerInfo *updateInfo, const QString &url);
}; };
} }

View File

@ -47,7 +47,7 @@ static const char *mirror_url_postfix[] =
NULL NULL
}; };
static const char *update_mirrors_prim[] = static const char *update_mirrors[] =
{ {
"http://muldersoft.com/", "http://muldersoft.com/",
"http://mulder.bplaced.net/", //"http://mulder.cwsurf.de/", "http://mulder.bplaced.net/", //"http://mulder.cwsurf.de/",
@ -66,139 +66,133 @@ static const char *update_mirrors_prim[] =
NULL NULL
}; };
static const char *update_mirrors_back[] =
{
"http://mplayer.savedonthe.net/",
NULL
};
static const char *known_hosts[] = //Taken form: http://www.alexa.com/topsites !!! static const char *known_hosts[] = //Taken form: http://www.alexa.com/topsites !!!
{ {
"http://www.163.com/", "www.163.com",
"http://www.7-zip.org/", "www.7-zip.org",
"http://www.ac3filter.net/", "www.ac3filter.net",
"http://clbianco.altervista.org/", "clbianco.altervista.org",
"http://status.aws.amazon.com/", "status.aws.amazon.com",
"http://build.antergos.com/", "build.antergos.com",
"http://www.aol.com/", "www.aol.com",
"http://www.apache.org/", "www.apache.org",
"http://www.apple.com/", "www.apple.com",
"http://www.adobe.com/", "www.adobe.com",
"http://archive.org/web/", "archive.org",
"http://www.artlebedev.ru/", "www.artlebedev.ru",
"http://web.audacityteam.org/", "web.audacityteam.org",
"http://status.automattic.com/", "status.automattic.com",
"http://www.avidemux.org/", "www.avidemux.org",
"http://www.babylon.com/", "www.babylon.com",
"http://www.baidu.com/", "www.baidu.com",
"http://bandcamp.com/", "bandcamp.com",
"http://www.bbc.co.uk/", "www.bbc.co.uk",
"http://www.berlios.de/", "www.berlios.de",
"http://www.bing.com/", "www.bing.com",
"http://www.bingeandgrab.com/", "www.bingeandgrab.com",
"http://www.bucketheadpikes.com/", "www.bucketheadpikes.com",
"http://www.buckethead-coop.com/", "www.buckethead-coop.com",
"http://www.buzzfeed.com/", "www.buzzfeed.com",
"http://www.ccc.de/", "www.ccc.de",
"http://www.citizeninsomniac.com/WMV/", "www.citizeninsomniac.com",
"http://www.cnet.com/", "www.cnet.com",
"http://cnzz.com/", "cnzz.com",
"http://www.codeplex.com/", "www.codeplex.com",
"http://www.codeproject.com/", "www.codeproject.com",
"http://www.der-postillon.com/", "www.der-postillon.com",
"http://www.ebay.com/", "www.ebay.com",
"http://www.equation.com/", "www.equation.com",
"http://www.farbrausch.de/", "www.farbrausch.de",
"http://fc2.com/", "fc2.com",
"http://fedoraproject.org/wiki/Fedora_Project_Wiki", "fedoraproject.org",
"http://blog.fefe.de/", "blog.fefe.de",
"http://www.ffmpeg.org/", "www.ffmpeg.org",
"http://blog.flickr.net/en", "blog.flickr.net",
"http://free-codecs.com/", "free-codecs.com",
"http://git-scm.com/", "git-scm.com",
"http://doc.gitlab.com/", "doc.gitlab.com",
"http://www.gmx.net/", "www.gmx.net",
"http://news.gnome.org/", "news.gnome.org",
"http://www.gnu.org/", "www.gnu.org",
"http://go.com/", "go.com",
"http://code.google.com/", "code.google.com",
"http://haali.su/mkv/", "haali.su",
"http://www.heise.de/", "www.heise.de",
"http://www.huffingtonpost.co.uk/", "www.huffingtonpost.co.uk",
"http://www.iana.org/", "www.iana.org",
"http://www.imdb.com/", "www.imdb.com",
"http://www.imgburn.com/", "www.imgburn.com",
"http://imgur.com/", "imgur.com",
"http://www.jd.com/contact/", "www.jd.com",
"http://www.jiscdigitalmedia.ac.uk/", "www.jiscdigitalmedia.ac.uk",
"http://kannmanumdieuhrzeitschonnbierchentrinken.de/", "kannmanumdieuhrzeitschonnbierchentrinken.de",
"http://mirrors.kernel.org/", "mirrors.kernel.org",
"http://komisar.gin.by/", "komisar.gin.by",
"http://lame.sourceforge.net/", "lame.sourceforge.net",
"http://www.libav.org/", "www.libav.org",
"http://blog.linkedin.com/", "blog.linkedin.com",
"http://www.linuxmint.com/", "www.linuxmint.com",
"http://www.livedoor.com/", "www.livedoor.com",
"http://www.livejournal.com/", "www.livejournal.com",
"http://longplayer.org/", "longplayer.org",
"http://go.mail.ru/", "go.mail.ru",
"http://marknelson.us/", "marknelson.us",
"http://www.mediafire.com/about/", "www.mediafire.com",
"http://www.mod-technologies.com/", "www.mod-technologies.com",
"http://ftp.mozilla.org/", "ftp.mozilla.org",
"http://mplayerhq.hu/", "mplayerhq.hu",
"http://www.msn.com/en-us/", "www.msn.com",
"http://wiki.multimedia.cx/", "wiki.multimedia.cx",
"http://www.nch.com.au/", "www.nch.com.au",
"http://mirror.netcologne.de/", "mirror.netcologne.de",
"http://oss.netfarm.it/", "oss.netfarm.it",
"http://blog.netflix.com/", "blog.netflix.com",
"http://netrenderer.de/", "netrenderer.de",
"http://www.nytimes.com/", "www.nytimes.com",
"http://www.opera.com/", "www.opera.com",
"http://www.partha.com/", "www.partha.com",
"http://pastebin.com/", "pastebin.com",
"http://pastie.org/", "pastie.org",
"http://portableapps.com/about", "portableapps.com",
"http://www.portablefreeware.com/", "www.portablefreeware.com",
"http://support.proboards.com/", "support.proboards.com",
"http://www.qq.com/", "www.qq.com",
"http://www.qt.io/", "www.qt.io",
"http://www.quakelive.com/", "www.quakelive.com",
"http://rationalqm.us/mine.html", "rationalqm.us",
"http://www.seamonkey-project.org/", "www.seamonkey-project.org",
"http://selfhtml.org/", "selfhtml.org",
"http://www.sina.com.cn/", "www.sina.com.cn",
"http://www.sohu.com/", "www.sohu.com",
"http://help.sogou.com/", "help.sogou.com",
"http://sourceforge.net/", "sourceforge.net",
"http://www.spiegel.de/", "www.spiegel.de",
"http://www.sputnikmusic.com/", "www.sputnikmusic.com",
"http://stackoverflow.com/", "stackoverflow.com",
"http://www.t-online.de/", "www.t-online.de",
"http://www.tagesschau.de/", "www.tagesschau.de",
"http://tdm-gcc.tdragon.net/", "tdm-gcc.tdragon.net",
"http://www.tdrsmusic.com/", "www.tdrsmusic.com",
"http://www.ubuntu.com/", "www.ubuntu.com",
"http://www.uol.com.br/", "www.uol.com.br",
"http://www.videohelp.com/", "www.videohelp.com",
"http://www.videolan.org/", "www.videolan.org",
"http://virtualdub.org/", "virtualdub.org",
"http://blog.virustotal.com/", "blog.virustotal.com",
"http://www.vkgoeswild.com/", "www.vkgoeswild.com",
"http://www.warr.org/WAhere.html", "www.warr.org",
"http://www.weibo.com/login.php", "www.weibo.com",
"http://status.wikimedia.org/", "status.wikimedia.org",
"http://www.winamp.com/", "www.winamp.com",
"http://www.winhoros.de/", "www.winhoros.de",
"http://wpde.org/", "wpde.org",
"http://x265.org/", "x265.org",
"http://xhmikosr.1f0.de/", "xhmikosr.1f0.de",
"http://xiph.org/", "xiph.org",
"http://us.mail.yahoo.com/", "us.mail.yahoo.com",
"http://www.youtube.com/yt/about/", "www.youtube.com",
"http://www.zedo.com/", "www.zedo.com",
"http://ffmpeg.zeranoe.com/", "ffmpeg.zeranoe.com",
NULL NULL
}; };
@ -210,11 +204,21 @@ static char *USER_AGENT_STR = "Mozilla/5.0 (X11; Linux i686; rv:7.0.1) Gecko/201
static int getMaxProgress(void) static int getMaxProgress(void)
{ {
int counter = MIN_CONNSCORE + 2; int counter = MIN_CONNSCORE + 2;
for(int i = 0; update_mirrors_prim[i]; i++) counter++; for(int i = 0; update_mirrors[i]; i++) counter++;
for(int i = 0; update_mirrors_back[i]; i++) counter++;
return counter; return counter;
} }
static QStringList buildRandomList(const char *const values[])
{
QStringList list;
for (int index = 0; values[index]; index++)
{
const int pos = next_rand32() % (index + 1);
list.insert(pos, QString::fromLatin1(values[index]));
}
return list;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Update Info Class // Update Info Class
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -252,10 +256,11 @@ bool UpdateCheckerInfo::isComplete(void)
// Constructor & Destructor // Constructor & Destructor
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
UpdateChecker::UpdateChecker(const QString &binWGet, const QString &binGnuPG, const QString &binKeys, const QString &applicationId, const quint32 &installedBuildNo, const bool betaUpdates, const bool testMode) UpdateChecker::UpdateChecker(const QString &binWGet, const QString &binNC, const QString &binGnuPG, const QString &binKeys, const QString &applicationId, const quint32 &installedBuildNo, const bool betaUpdates, const bool testMode)
: :
m_updateInfo(new UpdateCheckerInfo()), m_updateInfo(new UpdateCheckerInfo()),
m_binaryWGet(binWGet), m_binaryWGet(binWGet),
m_binaryNC(binNC),
m_binaryGnuPG(binGnuPG), m_binaryGnuPG(binGnuPG),
m_binaryKeys(binKeys), m_binaryKeys(binKeys),
m_applicationId(applicationId), m_applicationId(applicationId),
@ -300,16 +305,13 @@ void UpdateChecker::checkForUpdates(void)
// ----- Test Internet Connection ----- // // ----- Test Internet Connection ----- //
int connectionScore = 0; log("Checking internet connection...", "");
int maxConnectTries = (3 * MIN_CONNSCORE) / 2;
log("Checking internet connection...");
setStatus(UpdateStatus_CheckingConnection); setStatus(UpdateStatus_CheckingConnection);
const int networkStatus = OS::network_status(); const int networkStatus = OS::network_status();
if(networkStatus == OS::NETWORK_TYPE_NON) if(networkStatus == OS::NETWORK_TYPE_NON)
{ {
log("", "Operating system reports that the computer is currently offline !!!"); log("Operating system reports that the computer is currently offline !!!");
setProgress(m_maxProgress); setProgress(m_maxProgress);
setStatus(UpdateStatus_ErrorNoConnection); setStatus(UpdateStatus_ErrorNoConnection);
return; return;
@ -319,19 +321,14 @@ void UpdateChecker::checkForUpdates(void)
// ----- Test Known Hosts Connectivity ----- // // ----- Test Known Hosts Connectivity ----- //
QStringList hostList; int connectionScore = 0;
for(int i = 0; known_hosts[i]; i++)
{
hostList << QString::fromLatin1(known_hosts[i]);
}
while(!(hostList.isEmpty() || (connectionScore >= MIN_CONNSCORE) || (maxConnectTries < 1))) QStringList hostList = buildRandomList(known_hosts);
while(!(hostList.isEmpty() || (connectionScore >= MIN_CONNSCORE)))
{ {
switch(tryContactHost(hostList.takeAt(next_rand32() % hostList.count()))) if(tryContactHost(hostList.takeFirst()))
{ {
case 01: connectionScore += 1; break; connectionScore += 1;
case 02: connectionScore += 2; break;
default: maxConnectTries -= 1; break;
} }
setProgress(qBound(1, connectionScore + 1, MIN_CONNSCORE + 1)); setProgress(qBound(1, connectionScore + 1, MIN_CONNSCORE + 1));
msleep(64); msleep(64);
@ -345,33 +342,12 @@ void UpdateChecker::checkForUpdates(void)
return; return;
} }
// ----- Build Mirror List ----- //
log("", "----", "", "Checking for updates online...");
setStatus(UpdateStatus_FetchingUpdates);
QStringList mirrorList;
for(int index = 0; update_mirrors_prim[index]; index++)
{
mirrorList << QString::fromLatin1(update_mirrors_prim[index]);
}
if(const int len = mirrorList.count())
{
const int rounds = len * 1097;
for(int i = 0; i < rounds; i++)
{
mirrorList.swap(i % len, next_rand32() % len);
}
}
for(int index = 0; update_mirrors_back[index]; index++)
{
mirrorList << QString::fromLatin1(update_mirrors_back[index]);
}
// ----- Fetch Update Info From Server ----- // // ----- Fetch Update Info From Server ----- //
log("----", "", "Checking for updates online...");
setStatus(UpdateStatus_FetchingUpdates);
QStringList mirrorList = buildRandomList(update_mirrors);
while(!mirrorList.isEmpty()) while(!mirrorList.isEmpty())
{ {
QString currentMirror = mirrorList.takeFirst(); QString currentMirror = mirrorList.takeFirst();
@ -385,7 +361,7 @@ void UpdateChecker::checkForUpdates(void)
} }
else else
{ {
msleep(64); msleep(25);
} }
} }
@ -429,21 +405,11 @@ void UpdateChecker::testKnownHosts(void)
QString currentHost = hostList.takeFirst(); QString currentHost = hostList.takeFirst();
qDebug("Testing: %s", currentHost.toLatin1().constData()); qDebug("Testing: %s", currentHost.toLatin1().constData());
log("", "Testing:", currentHost, ""); log("", "Testing:", currentHost, "");
QString outFile = QString("%1/%2.htm").arg(temp_folder(), rand_str()); if (!tryContactHost(currentHost))
bool httpOk = false;
if(!getFile(currentHost, outFile, 0, &httpOk))
{ {
if(httpOk) qWarning("\nConnectivity test FAILED on the following host:\n%s\n", currentHost.toLatin1().constData());
{
qWarning("\nConnectivity test was SLOW on the following site:\n%s\n", currentHost.toLatin1().constData());
}
else
{
qWarning("\nConnectivity test FAILED on the following site:\n%s\n", currentHost.toLatin1().constData());
}
} }
log("", "---"); log("", "---");
QFile::remove(outFile);
} }
} }
@ -477,35 +443,6 @@ void UpdateChecker::log(const QString &str1, const QString &str2, const QString
if(!str4.isNull()) emit messageLogged(str4); if(!str4.isNull()) emit messageLogged(str4);
} }
int UpdateChecker::tryContactHost(const QString &url)
{
int result = -1; bool httpOkay = false;
const QString outFile = QString("%1/%2.htm").arg(temp_folder(), rand_str());
log("", "Testing host:", url);
if(getFile(url, outFile, 0, &httpOkay))
{
log("Connection to host was established successfully.");
result = 2;
}
else
{
if(httpOkay)
{
log("Connection to host timed out after HTTP OK was received.");
result = 1;
}
else
{
log("Connection failed: The host could not be reached!");
result = 0;
}
}
QFile::remove(outFile);
return result;
}
bool UpdateChecker::tryUpdateMirror(UpdateCheckerInfo *updateInfo, const QString &url) bool UpdateChecker::tryUpdateMirror(UpdateCheckerInfo *updateInfo, const QString &url)
{ {
bool success = false; bool success = false;
@ -556,155 +493,6 @@ bool UpdateChecker::getUpdateInfo(const QString &url, const QString &outFileVers
return true; return true;
} }
bool UpdateChecker::getFile(const QString &url, const QString &outFile, const unsigned int maxRedir, bool *httpOk)
{
for(int i = 0; i < 2; i++)
{
if(getFile(url, (i > 0), outFile, maxRedir, httpOk))
{
return true;
}
}
return false;
}
bool UpdateChecker::getFile(const QString &url, const bool forceIp4, const QString &outFile, const unsigned int maxRedir, bool *httpOk)
{
QFileInfo output(outFile);
output.setCaching(false);
if(httpOk) *httpOk = false;
if(output.exists())
{
QFile::remove(output.canonicalFilePath());
if(output.exists())
{
return false;
}
}
QProcess process;
init_process(process, output.absolutePath());
QStringList args;
if(forceIp4)
{
args << "-4";
}
args << "-T" << "15" << "--no-cache" << "--no-dns-cache" << QString().sprintf("--max-redirect=%u", maxRedir);
args << QString("--referer=%1://%2/").arg(QUrl(url).scheme(), QUrl(url).host()) << "-U" << USER_AGENT_STR;
args << "-O" << output.fileName() << url;
QEventLoop loop;
connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), &loop, SLOT(quit()));
connect(&process, SIGNAL(readyRead()), &loop, SLOT(quit()));
QTimer timer;
timer.setSingleShot(true);
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
const QRegExp httpResponseOK("200 OK$");
process.start(m_binaryWGet, args);
if(!process.waitForStarted())
{
return false;
}
timer.start(25000);
while(process.state() != QProcess::NotRunning)
{
loop.exec();
const bool bTimeOut = (!timer.isActive());
while(process.canReadLine())
{
QString line = QString::fromLatin1(process.readLine()).simplified();
if(line.contains(httpResponseOK))
{
line.append(" [OK]");
if(httpOk) *httpOk = true;
}
log(line);
}
if(bTimeOut)
{
qWarning("WGet process timed out <-- killing!");
process.kill();
process.waitForFinished();
log("!!! TIMEOUT !!!");
return false;
}
}
timer.stop();
timer.disconnect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
log(QString().sprintf("Exited with code %d", process.exitCode()));
return (process.exitCode() == 0) && output.exists() && output.isFile();
}
bool UpdateChecker::checkSignature(const QString &file, const QString &signature)
{
if(QFileInfo(file).absolutePath().compare(QFileInfo(signature).absolutePath(), Qt::CaseInsensitive) != 0)
{
qWarning("CheckSignature: File and signature should be in same folder!");
return false;
}
QString keyRingPath(m_binaryKeys);
bool removeKeyring = false;
if(QFileInfo(file).absolutePath().compare(QFileInfo(m_binaryKeys).absolutePath(), Qt::CaseInsensitive) != 0)
{
keyRingPath = make_temp_file(QFileInfo(file).absolutePath(), "gpg");
removeKeyring = true;
if(!QFile::copy(m_binaryKeys, keyRingPath))
{
qWarning("CheckSignature: Failed to copy the key-ring file!");
return false;
}
}
QProcess process;
init_process(process, QFileInfo(file).absolutePath());
QEventLoop loop;
connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), &loop, SLOT(quit()));
connect(&process, SIGNAL(readyRead()), &loop, SLOT(quit()));
process.start(m_binaryGnuPG, QStringList() << "--homedir" << "." << "--keyring" << QFileInfo(keyRingPath).fileName() << QFileInfo(signature).fileName() << QFileInfo(file).fileName());
if(!process.waitForStarted())
{
if(removeKeyring)
{
remove_file(keyRingPath);
}
return false;
}
while(process.state() == QProcess::Running)
{
loop.exec();
while(process.canReadLine())
{
log(QString::fromLatin1(process.readLine()).simplified());
}
}
if(removeKeyring)
{
remove_file(keyRingPath);
}
log(QString().sprintf("Exited with code %d", process.exitCode()));
return (process.exitCode() == 0);
}
bool UpdateChecker::parseVersionInfo(const QString &file, UpdateCheckerInfo *updateInfo) bool UpdateChecker::parseVersionInfo(const QString &file, UpdateCheckerInfo *updateInfo)
{ {
QRegExp value("^(\\w+)=(.+)$"); QRegExp value("^(\\w+)=(.+)$");
@ -808,6 +596,218 @@ bool UpdateChecker::parseVersionInfo(const QString &file, UpdateCheckerInfo *upd
return true; return true;
} }
//----------------------------------------------------------
// EXTERNAL TOOLS
//----------------------------------------------------------
bool UpdateChecker::getFile(const QString &url, const QString &outFile, const unsigned int maxRedir, bool *httpOk)
{
for (int i = 0; i < 2; i++)
{
if (getFile(url, (i > 0), outFile, maxRedir, httpOk))
{
return true;
}
}
return false;
}
bool UpdateChecker::getFile(const QString &url, const bool forceIp4, const QString &outFile, const unsigned int maxRedir, bool *httpOk)
{
QFileInfo output(outFile);
output.setCaching(false);
if (httpOk) *httpOk = false;
if (output.exists())
{
QFile::remove(output.canonicalFilePath());
if (output.exists())
{
return false;
}
}
QProcess process;
init_process(process, output.absolutePath());
QStringList args;
if (forceIp4)
{
args << "-4";
}
args << "-T" << "15" << "--no-cache" << "--no-dns-cache" << QString().sprintf("--max-redirect=%u", maxRedir);
args << QString("--referer=%1://%2/").arg(QUrl(url).scheme(), QUrl(url).host()) << "-U" << USER_AGENT_STR;
args << "-O" << output.fileName() << url;
QEventLoop loop;
connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), &loop, SLOT(quit()));
connect(&process, SIGNAL(readyRead()), &loop, SLOT(quit()));
QTimer timer;
timer.setSingleShot(true);
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
const QRegExp httpResponseOK("200 OK$");
process.start(m_binaryWGet, args);
if (!process.waitForStarted())
{
return false;
}
timer.start(25000);
while (process.state() != QProcess::NotRunning)
{
loop.exec();
const bool bTimeOut = (!timer.isActive());
while (process.canReadLine())
{
QString line = QString::fromLatin1(process.readLine()).simplified();
if (line.contains(httpResponseOK))
{
line.append(" [OK]");
if (httpOk) *httpOk = true;
}
log(line);
}
if (bTimeOut)
{
qWarning("WGet process timed out <-- killing!");
process.kill();
process.waitForFinished();
log("!!! TIMEOUT !!!");
return false;
}
}
timer.stop();
timer.disconnect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
log(QString().sprintf("Exited with code %d", process.exitCode()));
return (process.exitCode() == 0) && output.exists() && output.isFile();
}
bool UpdateChecker::tryContactHost(const QString &hostname)
{
log(QString("Connecting to host: %1").arg(hostname));
QProcess process;
init_process(process, temp_folder());
QStringList args;
args << "-z" << hostname << QString::number(80);
QEventLoop loop;
connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), &loop, SLOT(quit()));
connect(&process, SIGNAL(readyRead()), &loop, SLOT(quit()));
QTimer timer;
timer.setSingleShot(true);
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
process.start(m_binaryNC, args);
if (!process.waitForStarted())
{
return false;
}
timer.start(25000);
while (process.state() != QProcess::NotRunning)
{
loop.exec();
const bool bTimeOut = (!timer.isActive());
while (process.canReadLine())
{
QString line = QString::fromLatin1(process.readLine()).simplified();
log(line);
}
if (bTimeOut)
{
qWarning("NC process timed out <-- killing!");
process.kill();
process.waitForFinished();
log("!!! TIMEOUT !!!");
return false;
}
}
timer.stop();
timer.disconnect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
if (process.exitCode() != 0)
{
log("Connection has failed!");
}
log(QString().sprintf("Exited with code %d", process.exitCode()), "");
return (process.exitCode() == 0);
}
bool UpdateChecker::checkSignature(const QString &file, const QString &signature)
{
if (QFileInfo(file).absolutePath().compare(QFileInfo(signature).absolutePath(), Qt::CaseInsensitive) != 0)
{
qWarning("CheckSignature: File and signature should be in same folder!");
return false;
}
QString keyRingPath(m_binaryKeys);
bool removeKeyring = false;
if (QFileInfo(file).absolutePath().compare(QFileInfo(m_binaryKeys).absolutePath(), Qt::CaseInsensitive) != 0)
{
keyRingPath = make_temp_file(QFileInfo(file).absolutePath(), "gpg");
removeKeyring = true;
if (!QFile::copy(m_binaryKeys, keyRingPath))
{
qWarning("CheckSignature: Failed to copy the key-ring file!");
return false;
}
}
QProcess process;
init_process(process, QFileInfo(file).absolutePath());
QEventLoop loop;
connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), &loop, SLOT(quit()));
connect(&process, SIGNAL(readyRead()), &loop, SLOT(quit()));
process.start(m_binaryGnuPG, QStringList() << "--homedir" << "." << "--keyring" << QFileInfo(keyRingPath).fileName() << QFileInfo(signature).fileName() << QFileInfo(file).fileName());
if (!process.waitForStarted())
{
if (removeKeyring)
{
remove_file(keyRingPath);
}
return false;
}
while (process.state() == QProcess::Running)
{
loop.exec();
while (process.canReadLine())
{
log(QString::fromLatin1(process.readLine()).simplified());
}
}
if (removeKeyring)
{
remove_file(keyRingPath);
}
log(QString().sprintf("Exited with code %d", process.exitCode()));
return (process.exitCode() == 0);
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// SLOTS // SLOTS
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////