summaryrefslogblamecommitdiffstats
path: root/src/slxbrowser.cpp
blob: 9c7eb03959743a86921183a3fc8c029bc8673b5b (plain) (tree)
1
2
3
4
5
6
7
8
9

                       
                




                            
                    
 

                                                                   
                                                
                           
                              
                            
                              



                           
 

                                         

                                                                               

                                         
















                                                                                                   
                                                                             
 


                                                                                   

                                          









                                                                                                             

                                                                                           
                                           
                                               



                         
                         


 
                              
 
                           
                      
                                           
                                                              
         





                               
                                      

                          
                                                         

                                                        









                                                                                                             
                         




                                                                                                                      
                        


















                                                                                                                                                                      





                                                                                    
                 

                                     




                                                                                
         
 
                            

                             

 
                                           



                                      
                                                                                
 
                                        





                                         
                                                      
 
                                                                    
                               

                                                                          
            
                                             



                                                    
                                
 















                                                                                          

















                                                                                     
                                      











                                                                                                 
 
#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('|') + ")$");
}