summaryrefslogblamecommitdiffstats
path: root/src/vsession.cpp
blob: 3fa385f20cfe20f62c1f2b581738982befc29be9 (plain) (tree)






































































































































































































































































































                                                                                                                                                                  
#include <QtXml>
#include <QDir>
#include <QApplication>
#include <QProcess>
#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"

bool VSession::init(const QString& xml, const QString& baseDirPath) {
    printf("VSession::init(xml, %s)\n", baseDirPath.toAscii().data());
    //printf("xml = %s\n", xml.toAscii().data());
    this->baseDirPath_ = baseDirPath;
    return this->doc_.setContent(xml);
}

void VSession::addNodeWithAttribute(const QString& nodeName,
                                 const QString& value,
                                 const QString& attribute,
                                 bool replace) {

    printf("VSession:addNodeWithAttribute(%s, %s, %s, %d)\n",
           nodeName.toUtf8().data(),
           value.toUtf8().data(),
           attribute.toUtf8().data(),
           replace);

    QDomElement node =
            this->doc_.namedItem("eintrag").namedItem(nodeName).toElement();

    if (replace == false || node.isNull()) {
        printf(" creating new node\n");
        // create a new node
        node = this->doc_.createElement(nodeName);
        this->doc_.namedItem("eintrag").appendChild(node);
    }

    printf(" setting attribute\n");
    node.setAttribute(attribute, value);
}

QString VSession::toXml() const {
    return this->doc_.toString();
}

QString VSession::getAttribute(const QString &nodeName,
                                const QString &attribute) const {
    printf ("VSession::getAttribute(%s, %s)\n", nodeName.toAscii().data(), attribute.toAscii().data());
    QDomDocument doc = this->doc_;
    //printf (" doc xml:\n%s\n", doc.toString().toAscii().data());
    QDomNode n = doc.namedItem("eintrag").namedItem(nodeName);
    if (n.isNull()) {
        printf(" failed to find node\n");
    }

    printf(" node name: %s\n", n.nodeName().toAscii().data());
    printf(" node type: %d\n", n.nodeType());
    printf(" node value: %s\n", n.nodeValue().toAscii().data());
    printf(" attribute %s=%s\n", attribute.toUtf8().data(), this->doc_.namedItem("eintrag").namedItem(nodeName).toElement().attribute(attribute).toUtf8().data());
    //printf (" --> %s\n", this->doc_.namedItem("eintrag").namedItem(nodeName).namedItem(attribute).toAttr().value());
    return this->doc_.namedItem("eintrag").namedItem(nodeName).toElement().attribute(attribute);
}

QString VSession::getNodeText(const QString& nodeName) const {
    return this->doc_.namedItem(nodeName).toText().data();
}

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 {
    // default to true
    return getAttribute("active").compare("false");
}

bool VSession::isLocked() const {
    // default to false
    return getAttribute("locked").compare("true") == 0;
}

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

        // TODO: check return values, exceptions, ...
        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() {
    printf("VSession::addUserAndHostname()\n");
    QString username(getpwuid(geteuid())->pw_name);
    this->addNodeWithAttribute("username", username);

    // Qt >= 4.7 has <QHostInfo>
    //QString hostname(QHostInfo::localHostName());
    char hname[HOST_NAME_MAX + 1];
    gethostname(hname, HOST_NAME_MAX);
    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());
}

bool VSession::run() {

    printf("VSession::run()\n");
    QString command = getAttribute("command");
    if (! command.isEmpty()) {
        if (QProcess::startDetached(command)) {
            // TODO: save session
            return true;
        }

        return false;
    }

    VSession session = *this;

    QString etcpath(VMCHOOSER_ETC_BASE_PATH);
    // TODO: put script names in (global?) constants
    session.addPrinters(etcpath + "printer.sh");
    session.addScanners(etcpath + "scanner.sh");

    session.addUserAndHostname();

    // TODO: read the group configuration XML
    //session.readGroupXml(&dat, env);

    // 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);

    // TODO: put script name in constant
    QString runVmScript(QString(VMCHOOSER_BIN_PATH) + "run-virt.sh");
    if (QProcess::startDetached(runVmScript, QStringList(tmpfile.fileName()))) {
        // TODO: save session
        return true;
    }
    return false;
}

QList<Session*> VSession::readXmlFile(const QString& filepath) {
    printf("VSession::readXmlFile(%s)\n", filepath.toAscii().data());
    QList<Session*> retval;

    QDomDocument doc;
    QFile file(filepath);
    if (!file.open(QIODevice::ReadOnly)) {
        // TODO: error message
        printf("error: cannot open file\n");
        return retval;
    }
    if (!doc.setContent(&file)) {
        // TODO: error message
        printf("error: cannot parse file\n");
        file.close();
        return retval;
    }
    file.close();

    // TODO: iterate over all <settings> child nodes?
    QString dirName(QFileInfo(filepath).dir().absolutePath());
    QDomElement settingsNode = doc.firstChildElement("settings");
    for (QDomElement el(settingsNode.firstChildElement("eintrag"));
    !el.isNull();
    el = el.nextSiblingElement("eintrag")) {
        printf("reading %s node\n", el.tagName().toAscii().data());
        QDomDocument dummy;
        dummy.appendChild(dummy.importNode(el, true));
        VSession* e = new VSession;
        if (e->init(dummy.toString(), dirName)) {
            printf("appending node\n");
            retval.append(e);
        }
    }
    return retval;
}

/**
 * - calls xmlfilter.sh to glob a folder for xmls
 *   -> if no xmlfilter.sh is available, it globs for available xmls
 * - reads all xml files and creates for each its own VSession-struct
 */
QList<Session*> VSession::readXmlDir(const QString& path) {
    printf("VSession::readXmlDir(%s)\n", path.toAscii().data());
    QList<Session*> retval;

    QDir appDir(QApplication::applicationDirPath());
    if (QFile::exists(appDir.filePath(filterscript))) {
        // run filterscript
        // treat every output line as a filename and read it
        QProcess myFilterScript;
        myFilterScript.start(appDir.filePath(filterscript), QStringList(path),
                           QIODevice::ReadOnly);
        while (! myFilterScript.atEnd()) {
            QString filename(myFilterScript.readLine());
            if (QDir::isRelativePath(filename)) {
                filename.prepend(path + "/");
            }
            retval.append(readXmlFile(filename));
        }

        myFilterScript.close();
    } else {
        // iterate over all .xml files in directory path and read them
        foreach (QFileInfo fi, QDir(path).entryInfoList(QStringList("*.xml"))) {
            retval.append(readXmlFile(fi.absoluteFilePath()));
        }
    }

    printf("VSession::readXmlDir(%s), read %d entries\n", path.toAscii().data(), retval.size());
    return retval;
}

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