#include #include #include #include #include #include #if 0 #include // available since Qt 4.7 #endif #include // for HOST_NAME_MAX #include // for gethostname(), getuid() #include // for getuid, getpwuid #include // 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 // 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 // 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 VSession::readXmlFile(const QString& filepath) { QList 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 VSession::readXmlDir(const QString& path) { QList 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 (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 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; }