#include "slxbrowser.h"
#include "webview.h"
#include "nam.h"
#include <QtWebKitWidgets>
#include <QWebPage>
#include <QNetworkReply>
#include <QSslConfiguration>
#include <QProgressBar>
#include <QDateTime>
static QRegularExpression urlListToRegExp(const QStringList &list);
SlxBrowser::SlxBrowser(BrowserSettings settings)
: QMainWindow(nullptr),
_settings(settings),
_unsupportedUri(false),
_blockedSite(false),
_lastPageLoad(0),
_activity(false),
_lastActivity(0),
_pageValid(false)
{
_settings.reloadInterval *= 1000;
if (_settings.fullscreen) {
this->showFullScreen();
this->setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
} else if (_settings.maximized) {
this->showMaximized();
}
//QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
QWidget *w = new QWidget;
QLayout *l = new QVBoxLayout;
_browser = new WebView;
_progress = new QProgressBar;
_progress->hide();
l->addWidget(_browser);
l->addWidget(_progress);
l->setMargin(0);
l->setSpacing(0);
l->setContentsMargins(0,0,0,0);
w->setContentsMargins(0,0,0,0);
w->setLayout(l);
this->setCentralWidget(w);
_reset.setSingleShot(true);
connect(&_reset, &QTimer::timeout, this, &SlxBrowser::reloadInitial);
connect(_browser, &WebView::loadStarted, this, &SlxBrowser::loadStarted);
connect(_browser, &WebView::loadFinished, this, &SlxBrowser::loadFinished);
connect(_browser, &WebView::loadProgress, this, &SlxBrowser::loadProgress);
//
QWebPage *page = _browser->page();
QNetworkAccessManager *nam;
if (_settings.urlList.isEmpty()) {
nam = new QNetworkAccessManager(this);
} else {
if (_settings.isWhitelist) {
// Just to be safe
_settings.urlList << _settings.url;
}
nam = new SlxNetworkAccessManager(urlListToRegExp(_settings.urlList), _settings.isWhitelist);
}
connect(nam, &QNetworkAccessManager::sslErrors, this, &SlxBrowser::sslErrors);
connect(nam, &QNetworkAccessManager::finished, this, &SlxBrowser::requestFinished);
page->setNetworkAccessManager(nam);
page->mainFrame()->load(_settings.url);
//
_browser->show();
}
SlxBrowser::~SlxBrowser()
{
}
void SlxBrowser::loadStarted()
{
_pageValid = false;
_reset.stop();
if (_settings.reloadInterval > 0) {
_reset.start(_settings.reloadInterval + 5000);
}
_normalError.clear();
_sslErrors.clear();
_progress->setValue(0);
_progress->show();
}
void SlxBrowser::loadFinished(bool ok)
{
_progress->hide();
qint64 now = QDateTime::currentMSecsSinceEpoch();
bool abortedDl = _browser->wasAbortedDownload();
if (!abortedDl && !ok) {
if (_unsupportedUri) {
QMessageBox::warning(this, QString::fromUtf8("Denied"),
QString::fromUtf8("This URL type is not supported.\n\n"
"Diese Art Link wird nicht unterstützt.\n\n"
"(z.B. Mail)"));
} else if (_blockedSite) {
int numElems = _browser->page()->mainFrame()->documentElement().findAll("*").count();
if (now - _lastPageLoad < 500 && numElems < 15) {
// Was probably a JS redirect, go back before displaying the error
_browser->page()->triggerAction(QWebPage::Back);
}
QTimer::singleShot(5, [=]() {
QMessageBox::warning(this, QString::fromUtf8("Denied"),
QString::fromUtf8("Target URL not allowed.\n\n"
"Dieser Link führt auf eine nicht erlaubte Seite."));
});
} else {
_browser->page()->mainFrame()->setHtml("<html><body style='background:blue;color:white'><br><br>"
"<center><h1>Page Load Error</h1><pre id='content'></pre></center>"
"</body></html>");
QWebElement el = _browser->page()->mainFrame()->documentElement().findFirst("#content");
QString str;
if (!_sslErrors.empty()) {
str.append("SSL Errors:\n");
for (QSslError err : _sslErrors) {
str.append(err.errorString());
str.append('\n');
}
} else if (_normalError.length() != 0) {
str.append("Load Error:\n");
str.append(_normalError);
} else {
str.append("Unknown Error");
}
str.append("\n\n\n\n" + QDateTime::currentDateTime().toString());
el.setPlainText(str);
_pageValid = false;
if (_settings.reloadInterval > 0) {
_reset.start(qMin(30000, _settings.reloadInterval));
} else {
_reset.start(30000);
}
}
_sslErrors.clear();
_normalError.clear();
} else {
_pageValid = true;
if (_settings.reloadInterval > 0) {
_reset.start(qMax(_settings.reloadInterval / 20, 1000));
}
}
_unsupportedUri = false;
_blockedSite = false;
_lastPageLoad = now;
}
void SlxBrowser::loadProgress(int progress)
{
_progress->setValue(progress);
}
void SlxBrowser::sslErrors(QNetworkReply* reply, const QList<QSslError>& errors)
{
if (_settings.ignoreSslErrors) {
reply->ignoreSslErrors();
return;
}
_sslErrors.append(errors);
}
void SlxBrowser::requestFinished(QNetworkReply *reply)
{
if (reply->error() == QNetworkReply::ProtocolUnknownError) {
_unsupportedUri = true;
} else if (reply->error() == QNetworkReply::UnknownNetworkError) {
_blockedSite = true;
} else {
//qDebug() << reply->error();
_normalError = reply->errorString();
}
}
void SlxBrowser::reloadInitial()
{
if (_pageValid) {
if (_activity) {
_lastActivity = QDateTime::currentMSecsSinceEpoch();
_activity = false;
_reset.start(qMax(_settings.reloadInterval / 20, 1000));
return;
}
qint64 now = QDateTime::currentMSecsSinceEpoch();
if (now - qMax(_lastActivity, _lastPageLoad) > _settings.reloadInterval) {
_browser->page()->mainFrame()->load(_settings.url);
} else {
_reset.start(qMax(_settings.reloadInterval / 20, 1000));
}
} else {
_browser->page()->mainFrame()->load(_settings.url);
}
}
static QRegularExpression urlListToRegExp(const QStringList &list)
{
// We search in the escaped string, so actually look for \*\* and \*
// Capture char before that because it must not be another backslash, as that
// means the star was already escaped in the list.
// Since these are C strings there are some additional backslashes here.
static const QRegularExpression STARSTAR("(^|[^\\\\])\\\\\\*\\\\\\*");
static const QRegularExpression STAR("(^|[^\\\\])\\\\\\*");
static const QRegularExpression QUEST("(^|[^\\\\])\\\\\\?");
static const QString STARSTAR_REP("\\1.*");
static const QString STAR_REP("\\1[^/]*");
static const QString QUEST_REP("\\1.?");
QStringList regexes; // All my regex's live in Regtexas
for (const QString &str : list) {
QString mangled;
if (str.contains(QLatin1String("//"))) {
mangled = str;
} else if (str.contains(QLatin1Char('/')) || str.contains(QLatin1String("**"))) {
mangled = "*//" + str;
} else {
mangled = "*//" + str + "/**";
}
mangled = QRegularExpression::escape(mangled);
mangled = mangled.replace(STARSTAR, STARSTAR_REP).replace(STAR, STAR_REP)
.replace(QUEST, QUEST_REP);
regexes << mangled;
}
qDebug() << regexes;
return QRegularExpression("^(" + regexes.join('|') + ")$");
}