/*
* Copyright (c) 2010,2011 - RZ Uni Freiburg
* Copyright (c) 2010,2011 - OpenSLX Project
*
* This program/file is free software distributed under the GPL version 2.
* See http://gpl.openslx.org/
*
* If you have any feedback please consult http://feedback.openslx.org/ and
* send your feedback to feedback@openslx.org
*
* General information about OpenSLX - libChooser can be found under
* http://openslx.org
*
*/
#include <QtXml>
#include <QDir>
#include <QApplication>
#include <QProcess>
#include <QDate>
#include <QStringList>
#include <QTextStream>
#if 0
#include <QHostInfo> // available since Qt 4.7
#endif
#include <limits> // for HOST_NAME_MAX
#include <unistd.h> // for gethostname(), getuid()
#include <sys/types.h> // for getuid, getpwuid
#include <pwd.h> // for getpwuid
//#include "globals.h"
#include "VSession.h"
#include "VSessionHandler.h"
bool VSession::debugMode = false;
VSession::VSession(VSessionHandler *parent) {
sessionHandler = parent;
}
bool VSession::init(const QString& xml, const QString& baseDirPath) {
this->baseDirPath_ = baseDirPath;
_process = new QProcess();
return this->doc_.setContent(xml);
}
void VSession::addNodeWithAttribute(const QString& nodeName,
const QString& value,
const QString& attribute,
bool replace) {
QDomElement node =
this->doc_.namedItem("eintrag").namedItem(nodeName).toElement();
if (replace == false || node.isNull()) {
// create a new node
node = this->doc_.createElement(nodeName);
this->doc_.namedItem("eintrag").appendChild(node);
}
node.setAttribute(attribute, value);
}
QString VSession::icon() const {
QString icon(getAttribute("icon"));
if (icon.isEmpty()) {
if (imgtype() == VMWARE) icon = "vmware";
else if (imgtype() == VBOX) icon = "virtualbox";
else icon = "unknown";
} else if (icon.contains(".") && QDir::isRelativePath(icon)) {
// non-built-in icon with relative path
icon.prepend(baseDirPath_ + "/");
}
return icon;
}
QString VSession::screenshot() const {
QString ret;
ret = getAttribute("screenshot");
// qDebug() << ret;
if (ret.size() > 0) {
ret.prepend(baseDirPath_ + "/");
ret.prepend("file://");
return ret;
}
return QString("qrc:/img/noscreenshot");
};
QString VSession::toXml() const {
QDomDocument doc;
doc.appendChild(doc.createElement("settings"));
doc.firstChild().appendChild(doc.importNode(doc_.documentElement(), true));
QDomNode xmlNode = doc.createProcessingInstruction(
"xml", "version=\"1.0\" encoding=\"UTF-8\"");
doc.insertBefore(xmlNode, doc.firstChild());
return doc.toString();
}
QString VSession::getAttribute(const QString &nodeName,
const QString &attribute) const {
QDomDocument doc = this->doc_;
QDomNode n = doc.namedItem("eintrag").namedItem(nodeName);
return this->doc_.namedItem("eintrag").namedItem(nodeName).toElement()
.attribute(attribute);
}
QString VSession::getNodeText(const QString& nodeName) const {
QString str;
QTextStream stream(&str);
QDomNode node = this->doc_.namedItem("eintrag").namedItem(nodeName).toElement();
node.save(stream, 4);
// return this->doc_.namedItem("eintrag").namedItem(nodeName).toElement().text();
return str;
}
ImgType VSession::imgtype() const {
QString s(getAttribute("virtualmachine"));
if (s.compare("vmware") == 0) {
return VMWARE;
} else if (s.compare("virtualbox") == 0 || s.compare("vbox") == 0) {
return VBOX;
} else {
return OTHER;
}
}
bool VSession::isActive() const {
QString value(getAttribute("active"));
if (value.compare("false") == 0) {
return false;
} else if (value.count("/") == 1) {
// try to interpret value as date range
// [YYYY-MM-DD]/[YYYY-MM-DD]
// eg. "1970-01-01/1971-01-01" from Jan 1st 1970 till Jan 1st 1971
// "/1971-01-01" till Jan 1st 1971
// "1970-01-01/" from Jan 1st 1970
// "/" allways
// note: invalid dates are treated as empty dates
QStringList list(value.split("/"));
QString from(list.value(0));
QString till(list.value(1));
QDate fromDate(QDate::fromString(from, Qt::ISODate));
QDate tillDate(QDate::fromString(till, Qt::ISODate));
QDate today(QDate::currentDate());
if (fromDate.isValid() && fromDate > today) {
// fromDate is in the future
if (debugMode) qDebug() << "Not active. Reason: fromDate is in the future";
return false;
}
if (tillDate.isValid() && tillDate < today) {
// tillDate is in the past
if (debugMode) qDebug() << "Not active. Reason: tillDate is in the past";
return false;
}
}
if (sessionHandler->hasEnv()) {
QStringList pools = getAttribute("pools").split("\\s*,\\s*");
if (!pools.isEmpty() && !pools.contains(sessionHandler->getEnv())) {
// pools does not contain pool
if (debugMode) qDebug() << "Not active. Reason: vsession is not part of active env";
return false;
}
}
return true;
}
bool VSession::isLocked() const {
// default to false
return getAttribute("locked").compare("true") == 0;
}
bool VSession::isValid() const {
// default to false
return QFile::exists(QString(this->baseDirPath_).append("/").append(getAttribute("image_name")));
}
int VSession::priority() const {
return getAttribute("priority").toInt();
}
void VSession::addPrinters(const QString& script, const QString& type) {
QDomElement printersNode =
this->doc_.namedItem("eintrag").namedItem(type + "s").toElement();
if (printersNode.isNull()) {
// create new printers node
printersNode = this->doc_.createElement(type + "s");
this->doc_.namedItem("eintrag").appendChild(printersNode);
}
QProcess addPrintersScript;
addPrintersScript.start(script, QIODevice::ReadOnly);
while (!addPrintersScript.atEnd()) {
QString line(addPrintersScript.readLine());
QStringList tokens(line.split("\t"));
if (tokens.size() < 2 or tokens.size() > 3) {
// TODO error message
// invalid output of printerScript
// printserver\tprinter\tprinter description
continue;
}
QDomElement printerNode(doc_.createElement(type));
printerNode.setAttribute("name", tokens.at(1));
printerNode.setAttribute("path",
"\\\\" + tokens.at(0) + "\\" + tokens.at(1));
if (tokens.size() == 3) {
QDomText printerDescriptionNode(doc_.createTextNode(tokens.at(3)));
printerNode.appendChild(printerDescriptionNode);
}
printersNode.appendChild(printerNode);
}
addPrintersScript.close();
return;
}
void VSession::addScanners(const QString& script) {
addPrinters(script, "scanner");
}
void VSession::addUserAndHostname() {
QString username(getpwuid(geteuid())->pw_name);
this->addNodeWithAttribute("username", username);
// Qt >= 4.7 has <QHostInfo>
// QString hostname(QHostInfo::localHostName());
char hname[255];
gethostname(hname, sizeof(hname));
QString hostname(hname);
this->addNodeWithAttribute("hostname", hostname);
QString image(this->getAttribute("image_name"));
if (QFileInfo(image).isRelative()) {
// make path to image absolute
this->addNodeWithAttribute("image_name",
this->baseDirPath_ + "/" + image);
}
// insert computername as the first child of <eintrag>
// bootpgm needs computername within the first 500 bytes
QDomElement computername(doc_.createElement("computername"));
computername.setAttribute("param", hostname);
this->doc_.namedItem("eintrag").insertBefore(computername, QDomNode());
}
void VSession::mergePoolXml() {
QDomDocument doc;
QString poolXmlFile = sessionHandler->getConfPath() + "/vmchooser-" + sessionHandler->getEnv() + ".xml";
QFile file(poolXmlFile);
if (!file.open(QIODevice::ReadOnly)) {
return;
}
if (!doc.setContent(&file)) {
file.close();
return;
}
file.close();
for (QDomElement envNode(doc.firstChildElement("environment"));
!envNode.isNull();
envNode = envNode.nextSiblingElement()) {
if (envNode.attribute("param") != sessionHandler->getEnv()) continue;
for (QDomElement typeNode(envNode.firstChildElement());
!typeNode.isNull();
typeNode = typeNode.nextSiblingElement()) {
QString type = typeNode.nodeName();
if (type != "shared_folders" &&
type != "printers" &&
type != "scanners") continue;
QDomElement destinationNode =
this->doc_.namedItem("eintrag").namedItem(type).toElement();
if (destinationNode.isNull()) {
// create new node
destinationNode = this->doc_.createElement(type);
this->doc_.namedItem("eintrag").appendChild(destinationNode);
}
for (QDomElement el(typeNode.firstChildElement());
!el.isNull();
el = el.nextSiblingElement()) {
destinationNode.appendChild(this->doc_.importNode(el, true));
}
}
}
}
bool VSession::run() const {
QString command = getAttribute("command");
if (!command.isEmpty()) {
return QProcess::startDetached(command);
}
VSession session = *this;
session.addPrinters(sessionHandler->getPrinterScript());
session.addScanners(sessionHandler->getScannerScript());
session.addUserAndHostname();
session.mergePoolXml();
// write xml to temporary file
QTemporaryFile tmpfile(QDir::tempPath() + "/vmchooser-XXXXXX.xml");
if (!tmpfile.open() ||
tmpfile.write(session.toXml().toUtf8()) == -1) {
return false;
}
tmpfile.close();
tmpfile.setAutoRemove(false);
_process->start(sessionHandler->getRunVmScript(), QStringList(tmpfile.fileName()));
qDebug() << sessionHandler->getRunVmScript();
QObject::connect(_process, SIGNAL(finished(int, QProcess::ExitStatus)), QApplication::instance(), SLOT(quit()));
if (_process->state() == QProcess::Starting || QProcess::Running)
return true;
else
return false;
}
int VSession::type() const {
return Session::VSESSION;
}
bool VSession::operator<(const Session& other) const {
int p0 = this->priority();
int p1 = other.priority();
if (p0 < p1) return true;
if (p0 == p1) {
QString d0 = this->shortDescription();
QString d1 = other.shortDescription();
return d0.localeAwareCompare(d1) < 0;
}
return false;
}