summaryrefslogblamecommitdiffstats
path: root/src/VSession.cpp
blob: 76e13b0a8bc660d741e607328f04e6f0cba82527 (plain) (tree)



































































































































































































































































































































































                                                                                                                    
/*
 * 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;
}