summaryrefslogblamecommitdiffstats
path: root/src/vsession.cpp
blob: e9059f29f29f8a961bf562cd3b3b15c6a38fac0c (plain) (tree)
1
2
3
4
5
6



                       

                      










                                                                     
                                     
                              






                                                            



                                                                            




                                                          


                                        


                                          


                                                           






                                                                     
                                 









                                                                               



                                                                 
                                  
                                                              

                                                                          


















                                                                        

                                          
                                      



















                                                                          
                                                                                           




                                                     
                                                                                         



                         



                                                                     
                                                                                                    

                         

     
                






                                                       




                                                                                                     
















                                                                              
                                        





                                                     
                                                        


                     

                                                          

                                                                              
















                                                                               



                                                     
                                                    







                                                     

                                                                     








                                                                           






                                                                  


                                 







                                                                   




                                                               
















                                                                                





                                                                             
                            
                                              
                             
                                                



                             

                                       


                                 
                           









                                                                       





                                                                                                                    

 



                             
                                                                





                                          



                                 




                      




                                                                   



                                                      











                                                                     

                           

                                      

                                                            
                                                             
                                                
                                         
                                         
                                                        
                                          







                                                 




                                                                                
                              
                                                      





                                                                                                                                          

                                                                                        




                                                                                                                                










                                                                                                                     

         














                                                      
#include <QtXml>
#include <QDir>
#include <QApplication>
#include <QProcess>
#include <QDate>
#include <QStringList>
#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) {
    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::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 {
    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 {
    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 (!pool.isEmpty()) {
        QStringList pools = getAttribute("pools").split("\\s*,\\s*");
        if (!pools.isEmpty() && !pools.contains(pool)) {
            // 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[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());
}

void VSession::mergePoolXml() {
    QDomDocument doc;

    QString poolXmlFile = etcPath + "/vmchooser-" + pool + ".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") != pool) 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(printerScript);
    session.addScanners(scannerScript);

    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(runVmScript, QStringList(tmpfile.fileName()));
    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;
}

QList<Session*> VSession::readXmlFile(const QString& filepath) {
    QList<Session*> retval;

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

    QString dirName(QFileInfo(filepath).dir().absolutePath());
    QDomElement settingsNode = doc.firstChildElement("settings");
    for (QDomElement el(settingsNode.firstChildElement("eintrag"));
    !el.isNull();
    el = el.nextSiblingElement("eintrag")) {
        QDomDocument dummy;
        dummy.appendChild(dummy.importNode(el, true));
        VSession* e = new VSession;
        if (e->init(dummy.toString(), dirName)) {
            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) {
    QList<Session*> retval;

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

        myFilterScript.close();
    } else {
        // iterate over all .xml files in directory <path> (and sub-directories)
        // and read them
        QDirIterator di(path,
                        QDirIterator::Subdirectories |
                        QDirIterator::FollowSymlinks);
        while (di.hasNext()) {
            if (!di.next().endsWith(".xml")) continue;

            if (!di.fileInfo().isReadable()) {
            	if (debugMode) qDebug() << "skip" << di.fileInfo().absoluteFilePath() << ": xml not readable, incorrect file permissions";
            	continue;
            }

            QList<Session*> vsessionTmp = readXmlFile(di.fileInfo().absoluteFilePath());

            if (vsessionTmp.isEmpty()) {
            	if (debugMode) qDebug() << "skip" << di.fileInfo().absoluteFilePath() << ": reading xml failed for some reason";
            	continue;
            }

            if (!vsessionTmp.first()->isValid()) {
            	if (debugMode) qDebug() << "skip" << vsessionTmp.first()->shortDescription() << ": vdi/vmdk missing";
            	continue;
            }

            if (!vsessionTmp.first()->isActive()) {
            	if (debugMode) qDebug() << "skip" << vsessionTmp.first()->shortDescription() << ": not active";
            	continue;
            }

            retval.append(vsessionTmp);
        }
    }
    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;
}