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


                                
                            
 
                   
                  
                   
                  
 
                   
                             
                    
                 

                         


                             
                   
 
                                                                                             









                                                                      
                






                                                       
 

                        
 







                                                                                    
 
















                                                                                            
 


                                                  
 





                                                                                        
 




                                                
 
                 
                          
 
                                                                                             

                                                                                             







                                                                    
                           










                                                               

                                                                                             


                                                          
                             




                                                                 
 
                                                                                             

                                                                                             








                                                                              
                               






















                                                                                   
 
 
                                                                                             









                                                              
                              






                                                                           

                                                                                             
                                                       
                                                                                             




                                                      
                               









                                                                       

                                                                                             









                                                                                         
                       








                                                                                    

                                                                                             



                                                                  
                                                             






                                                                           
                                      









                                                                                  
 










                                                                              
 






                                                            

                                                                                             
                                                             
                                                                                             
                                  

















                                                                                 

                                                                                             
                                  

                                                            
 













                                                                                             







                                                                              














                                                                                             







                                                                              































                                                                                             

                                                                                   


                                                                                         



                                                                                

                                    



                                                                   



                                                                                                           








                                                                       
                                    
         
 
#include "fbgui.h"
#include "sysinfo.h"
#include "loggerengine.h"
#include "downloadmanager.h"
#include "javascriptinterface.h"
#include "sysinfolibsysfs.h"

#include <iostream>
#include <QThread>
#include <QtWebKit>
#include <QxtCore>

//QThread dmThread;
QString ipConfigFilePath("");
QString binPath("");
QUrl baseURL("");
QString downloadPath("");
int updateInterval = -1;
QString fileToTriggerURL("");
QString serialLocation("");
QString sessionID("");
int debugMode = -1;

//-------------------------------------------------------------------------------------------
/**
 * A constructor.
 *
 * The constructor of the fbgui class. It initializes the main objects
 * which are needed while the program is running.
 * The appearance of the webView is here also defined.
 *
 * @see JavascriptInterface
 * @see DownloadManager
 */
fbgui::fbgui() {
	// test for libsys function
	//SysInfoLibsysfs* sil = new SysInfoLibsysfs();
	//sil->getInfoAboutNetworkInterface();
	//sil->getInfoMainboardSerial();
	//SysInfo si;
	//qxtLog->debug() << si.getInfo("mbserial");
	//si.getInfo("usb");

	setupLayout();
	createActions();

	// initialize javascript interface
	JavascriptInterface* jsi = new JavascriptInterface(
			_webView->page()->mainFrame());
	QObject::connect(jsi, SIGNAL(quitFbgui()), this, SLOT(close()));
	QObject::connect(jsi, SIGNAL(shutDownClient()), this, SLOT(
			performShutDown()));
	QObject::connect(_webView->page()->mainFrame(), SIGNAL(
			javaScriptWindowObjectCleared()), jsi, SLOT(attachToDOM()));

	// initialize download manager
	DownloadManager* dm = new DownloadManager();
	QObject::connect(dm, SIGNAL(downloadInfo(const QString&, const double&)),
			jsi, SLOT(downloadInfo(const QString&, const double&)));
	QObject::connect(dm, SIGNAL(notify(const QString&)), jsi,
			SLOT(notify(const QString&)));
	QObject::connect(jsi, SIGNAL(requestFile(const QString&)), dm,
			SLOT(downloadFile(const QString&)));
	QObject::connect(
			dm,
			SIGNAL(updateProgress(const int&, const double&, const QString&)),
			jsi,
			SLOT(updateProgressBar(const int&, const double&, const QString&)));
	QObject::connect(dm, SIGNAL(downloadQueueEmpty()), jsi, SLOT(
			callbackOnFinished()));
	QObject::connect(dm, SIGNAL(downloadQueueEmpty()), this, SLOT(
			prepareKexec()));

	// move download manager to its own thread
	//dm->moveToThread(&dmThread);
	//dmThread.start();

	//_webView->page()->networkAccessManager()->setCookieJar(new QNetworkCookieJar);
	// show page
	_webView->load(QUrl("qrc:/html/preload.html"));
	// start watching for fileToTriggerURL
	watchForTrigger();
	//if (checkHost()) loadURL();

	// set properties
	setWindowTitle("fbgui");
	setAttribute(Qt::WA_QuitOnClose, true);
	setWindowFlags(Qt::FramelessWindowHint);
	showFullScreen();
}
fbgui::~fbgui() {
	//dmThread.quit();
}
//-------------------------------------------------------------------------------------------
//                               Layout / actions setup
//-------------------------------------------------------------------------------------------
/**
 * This method sets the used Layout.
 *
 * This method sets the used Layout. Possible layout are:
 *  - browser mode: only the browser is visible
 *  - debug mode: the screen is divided into the browser and a debug
 *      out console
 */
void fbgui::setupLayout() {
	// setup layout of the gui: debug split or browser
	_webView = new QWebView(this);
	if (debugMode == 1) {
		// split main window in browser & debug console
		createDebugConsole();
		_splitter = new QSplitter(Qt::Vertical, this);
		_splitter->addWidget(_webView);
		_splitter->addWidget(_debugConsole);
		setCentralWidget(_splitter);
	} else
		setCentralWidget(_webView);
}
//-------------------------------------------------------------------------------------------
/**
 * This method enables a shortcut for closing the program.
 */
void fbgui::createActions() {
	// CTRL + X to kill the gui
	_quit = new QAction(tr("&quit"), this);
	_quit->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X));
	this->addAction(_quit);
	connect(_quit, SIGNAL(triggered()), this, SLOT(close()));
}
//-------------------------------------------------------------------------------------------
//                                 File system watching
//-------------------------------------------------------------------------------------------
/**
 * This method sets a "watchdog" to a special file.
 *
 * This method sets a "watchdog" to a special file. If needed it creates the
 * file which it has to watch over. It than connects a QFileSystemWatcher with
 * this file. If changes happen to this file, the
 * fbgui::checkForTrigger(const QString& dirname) method will be called.
 *
 */
void fbgui::watchForTrigger() {
	// check if fileToTriggerURL already exists
	QFile file(fileToTriggerURL);
	if (file.exists()) {
		qxtLog->debug() << "[watcher] " << fileToTriggerURL
				<< " exists already!";
		// try to load URL
		loadURL();
	} else {
		// create it
		if (file.open(QIODevice::WriteOnly)) {
			qxtLog->debug() << "[gui] Created: " << fileToTriggerURL;
			file.close();
		} else {
			qxtLog->debug() << "[gui] Creation of " << fileToTriggerURL
					<< " failed! Exiting...";
			exit( EXIT_FAILURE);
		}
	}
	// watch the path where trigger file is expected
	qxtLog->debug() << "[watcher] Watching " << fileToTriggerURL;
	_watcher = new QFileSystemWatcher(QStringList(fileToTriggerURL), this);
QObject::connect(_watcher, SIGNAL(fileChanged(const QString&)), this,
		SLOT(prepareURLLoad()));

}
//-------------------------------------------------------------------------------------------
/**
 * This method checks if the trigger was valid.
 *
 * This method checks if the trigger was valid. If yes,
 * we have received an IP Address an can load the main screen.
 * If not, something some error happened.
 *
 * @see fbgui::checkHost()
 * @see fbgui::loadURL()
 */
void fbgui::prepareURLLoad() {
	qxtLog->debug() << "[watcher] " << fileToTriggerURL << " changed!";
	// disconnect _watcher, his job is done
	qxtLog->debug() << "[watcher] disconnected.";
	_watcher->disconnect(this);
	_watcher->deleteLater();
	// try to load URL
	loadURL();
}
//-------------------------------------------------------------------------------------------
//                            Preparations for URL load
//-------------------------------------------------------------------------------------------
/**
 * This method checks if is connected to the internet.
 *
 * This method checks if is connected to the internet.
 */
bool fbgui::checkHost() const {
	QHostInfo hostInfo = QHostInfo::fromName(baseURL.host());
	if (hostInfo.error() != QHostInfo::NoError) {
		qxtLog->debug() << "[gui] Lookup of " << baseURL.host()
				<< "failed. Exiting...";
		return false;
	} else {
		qxtLog->debug() << "[gui] Lookup of " << baseURL.host()
				<< " succeeded.";
		return true;
	}
}
//-------------------------------------------------------------------------------------------
/**
 * This method loads the main screen.
 *
 * This method loads the main screen via an POST request. If also disconnects the watcher
 * of the file, (Watcher is set in the fbgui::watchForTrigger() method).
 * and generates the POST data body.
 *
 * @see fbgui::watchForTrigger()
 * @see fbgui::generatePOSTData()
 */
void fbgui::loadURL() {
	if (checkHost()) {
		qxtLog->debug() << "[gui] Loading URL...";
		QByteArray postData = generatePOSTData();
		QNetworkRequest req(baseURL);
		// show arrow cursor
		QWSServer::instance()->setCursorVisible(true);
		//qApp->setOverrideCursor(QCursor(Qt::ArrowCursor));
		_webView->load(req, QNetworkAccessManager::PostOperation, postData);
	}
}
//-------------------------------------------------------------------------------------------
/**
 * This method generates the POST data body.
 *
 * This method generates the POST data body. The body contains the
 * MAC address, an hardwarehash and a specific serial number.
 * The hardwarehash is a MD5 hash over the MAC address and the
 * mainboard serial number.
 * The specific serial number is set at the creation of the usb boot stick.
 *
 * @see SysInfo::getMACAddress()
 * @see SysInfo::getMainboardSerial()
 */
QByteArray fbgui::generatePOSTData() {
	qxtLog->debug() << "[gui] Generating POST data...";
	// use MAC address as base data
	SysInfo si;
	QByteArray data(si.getInfo("mac").toUtf8());
	// append mainboard serial to the mac address for more unique hardwarehash
	data.append(si.getInfo("mbserial").toUtf8());
	qxtLog->debug() << "[post] Hashing: " << data;
	// generate MD5 hash of data
	QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5);
	qxtLog->debug() << "[post] MD5 Hash: " << hash.toHex();

	// fetch serial number from usb
	QByteArray serial;
	QFile file(serialLocation);
	if (!file.open(QIODevice::ReadOnly)) {
		qxtLog->debug() << "[post] No such file: " << file.fileName();
	}
	// everything ok, read data
	serial = file.readAll();
	file.close();
	serial.chop(1); // chop EOF
	qxtLog->debug() << "[post] Serial number is: " << serial;

	// construct final byte array
	QByteArray postData("mac=");
	postData.append(si.getInfo("mac"));
	postData.append("&hardwarehash=" + hash.toHex());
	postData.append("&serialnumber=" + serial);
	qxtLog->debug() << "[post] POST data: " << postData;
	return postData;
}
//-------------------------------------------------------------------------------------------
//                              Debug console setup / control
//-------------------------------------------------------------------------------------------
void fbgui::createDebugConsole() {
	// create the debug console widget
	_debugConsole = new QTextEdit(this);
	_debugConsole->setWindowFlags(Qt::FramelessWindowHint);
	// fanciness
	QPalette pal;
	pal.setColor(QPalette::Base, Qt::black);
	_debugConsole->setPalette(pal);
	_debugConsole->setTextColor(Qt::white);
	// enable custom logger engine
	qxtLog->addLoggerEngine("fb_logger", new LoggerEngine_fb(_debugConsole));
	//qxtLog->initLoggerEngine("fb_logger");
	qxtLog->setMinimumLevel("fb_logger", QxtLogger::DebugLevel);
	// CTRL + D  toggles debug window
	_toggleDebugConsole = new QAction(tr("&toggleDebug"), this);
	_toggleDebugConsole->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D));
	addAction(_toggleDebugConsole);
	connect(_toggleDebugConsole, SIGNAL(triggered()), this, SLOT(
			toggleDebugConsole()));
}
//-------------------------------------------------------------------------------------------
void fbgui::toggleDebugConsole() {
	(_debugConsole->isVisible()) ? _debugConsole->hide()
			: _debugConsole->show();
}
//-------------------------------------------------------------------------------------------
/**
 * This method performs the shutdown of the client.
 *
 * This method performs the shutdown of the client. It is triggered by the
 * JavascriptInterface::shutDownClient() signal which will be emited in the
 * JavascriptInterface::shutDown() method.
 * This method uses an QProcess object to execute the standard linux
 * shutdown command.
 *
 * @see JavascriptInterface::shutDownClient()
 * @see JavascriptInterface::shutDown()
 */
void fbgui::performShutDown() {
	QFile file("/proc/sysrq-trigger");
	if (file.open(QIODevice::WriteOnly)) {
		file.write("o");
		file.close();
	}
	else {
		qxtLog->debug() << "[gui] Could not open /proc/sysrq-trigger";
	}
}
//-------------------------------------------------------------------------------------------
/**
 * This method performs the reboot of the client.
 *
 * This method performs the reboot of the client. It is triggered by the
 * JavascriptInterface::rebootClient() signal which will be emited in the
 * JavascriptInterface::reboot() method.
 * This method uses an QProcess object to execute the standard linux
 * shutdown command.
 *
 * @see JavascriptInterface::rebootClient()
 * @see JavascriptInterface::reboot()
 */
void fbgui::performReboot() {
	QFile file("/proc/sysrq-trigger");
	if (file.open(QIODevice::WriteOnly)) {
		file.write("b");
		file.close();
	}
	else {
		qxtLog->debug() << "[gui] Could not open /proc/sysrq-trigger";
	}
}
//-------------------------------------------------------------------------------------------
/**
 * This method performs kexec.
 *
 */
void fbgui::prepareKexec() {

	// TODO read kcl file
	QFile file(downloadPath + "/kcl");
	if (!file.open(QIODevice::ReadOnly)) {
		qxtLog->debug() << "[gui] No such file: " << file.fileName();
	}
	// everything ok, read data
	QString kcl = file.readAll();
	file.close();
	qxtLog->debug() << "[gui] KCL from PBS: " << kcl;

	// TODO read IP config file
	file.setFileName("/tmp/ip_config_fbgui");
	if (!file.open(QIODevice::ReadOnly)) {
		qxtLog->debug() << "[gui] No such file: " << file.fileName();
	}
	QString ipConfig = file.readAll();
	file.close();
	qxtLog->debug() << "[gui] IP config: " << ipConfig;

	kcl.append(" ip=");
	kcl.append(ipConfig);

	qxtLog->debug() << "[gui] Complete KCL: " << kcl;

	QProcess *process = new QProcess(this);
	QString cmdline = "kexec -l " + downloadPath.toUtf8() + "/kernel --initrd="
			+ downloadPath.toUtf8() + "/initramfs --append=\"" + kcl.toUtf8()
			+ "\"";
	qxtLog->debug() << "[gui] kexec cmdline: " << cmdline;
	process->start(cmdline);
	bool ret = process->waitForFinished();
	if (!ret) {
		qxtLog->debug() << "[sysinfo] Failed to load kexec! Exiting...";
		exit( EXIT_FAILURE);
	} else {
		qxtLog->debug() << "[gui] Kexec load successfull.";
		if (debugMode < 0) {
			runKexec();
		} else {
			qxtLog->debug()
					<< "[gui] Skipping execution of kexec - open debug shell.";
			qxtLog->debug()
					<< "[gui] To start the system execute \"kexec -e\" in your shell.";
			close();
		}
	}
}
void fbgui::runKexec() {
	QProcess *process = new QProcess(this);
	process->startDetached("kexec -e");
	if (!process->waitForStarted()) {
		qxtLog->debug() << "[gui] Failed to execute: kexec -e";
		exit( EXIT_FAILURE);
	}
}