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

                   




                       
                  
                      
                
                      
                                              


                                                  

                     
                               
                         
 






                                                                                  






                                                            
                                                 



                                                  
                                   




                                        


                                                               
                                                                    




                                                       

                          



                                                  
     


































                                                                         
 

                                 
                           



                                                         






                                                         
                                                                               


                                          




                                                                 

                                                                     

 
                                           
                           


                               
                                                           




                                                                   

 
                                                                       
                                                 


                                                                                                        
                               

                                                                                     

                                 

                 

                             


                

 

















                                                                        
                             
                                      
                                                                                                          
                     


                                

















                                                                          
                                                                                                                        




                                                     
                                                                                                                      


                         
 

                                   








                                                                                                                      
         
     









                                                       
                                                 


                                
                                                
                                                               

                    
                                                                      


                     

 
                            



                                                                           
                      

                                                                                                     
 
                               
                                                                 



                                                                                             

     




                                                


                                                                       

                                                                      

                     

                                                                            
                                 
                    
 
                                                                                                                                                  
                                                                             

                                                                                        









                                                                
                                


                         
                                          
 
                                          
                          
                                                                
         
                           
     
 
                                 
                          






                                                                  

                                                                                          
             
                               


                                            
                              


                                                                             
                               

         

                                                                  


                            
            


                                               




                                                                                                                                                                           

             
     
 

                         

                                                                   

                                                    
                                   
                                           
                              


                                  

         
                       

 
                                



                                                                    

 
                                           
                               

                                         

 











                                                      
#include "config.h"

#include <QtXml>
#include <QDir>
#include <QApplication>
#include <QProcess>
#include <QDate>
#include <QThread>
#include <QStringList>
#include <QIcon>
#include <QMessageBox>
#include <QHostInfo> // available since Qt 4.7
#include <unistd.h> // for getuid()
#include <sys/types.h> // for getuid(), getpwuid()
#include <pwd.h> // for getpwuid()
#include "globals.h"
#include "vsession.h"
#include "sessionsiconholder.h"
#include "userldapdata.h"

static QProcess _process;

bool VSession::init(const QDomElement& xml) {
    QDomElement settingsNode = this->doc_.createElement("settings");
    this->doc_.appendChild(settingsNode);
    eintrag_ = this->doc_.importNode(xml, true).toElement();
    return !settingsNode.appendChild(eintrag_).isNull() && !settingsNode.isNull();
}

void VSession::addNodeWithAttribute(const QString& nodeName,
                                 const QString& value,
                                 const QString& attribute,
                                 bool replace) {
    QDomElement node =
            eintrag_.firstChildElement(nodeName);

    if (replace == false || node.isNull()) {
        // create a new node
        node = this->doc_.createElement(nodeName);
        eintrag_.appendChild(node);
    }

    node.setAttribute(attribute, value);
}

QIcon VSession::icon() const {
    QString icon(getAttribute("icon"));
    SessionsIconHolder *iconHolder = SessionsIconHolder::get();
    if (icon.startsWith("http://") || icon.startsWith("https://")) {
       // try to load icon from url
       QIcon url_icon(iconHolder->getIcon(QUrl(icon)));
       if (!url_icon.isNull()) {
           return url_icon;
       }
    }
    if (!icon.isEmpty()) {
        QIcon res_icon(iconHolder->getIcon(icon));
        if (!res_icon.isNull()) {
            return res_icon;
        }
    }
    // Everything failed, try to guess the OS
    QString os(getAttribute("os", "param").toLower());
    if (!os.isEmpty()) {
        QIcon osi = iconHolder->getIcon(os);
        if (!osi.isNull())
            return osi;
        // These match vmware guestOS keywords mostly, extend for vbox...
        if (os == "dos")
            return iconHolder->getIcon("dos");
        if (os.startsWith("windows7"))
            return iconHolder->getIcon("win7");
        if (os.startsWith("win31"))
            return iconHolder->getIcon("win311");
        if (os.startsWith("windows8"))
            return iconHolder->getIcon("win8");
        if (os.startsWith("win2000"))
            return iconHolder->getIcon("win2000");
        if (os.startsWith("winxp"))
            return iconHolder->getIcon("winxp");
        if (os.startsWith("debian"))
            return iconHolder->getIcon("debian");
        if (os.startsWith("ubuntu"))
            return iconHolder->getIcon("ubuntu");
        if (os.startsWith("win"))
            return iconHolder->getIcon("windows");
        if (os.contains("linux"))
            return iconHolder->getIcon("linux");
    }
    // TODO: Maybe parse title of entry for an OS guess?
    // Fallback to generic virtualizer icon
    if (imgtype() == VMWARE)
        return iconHolder->getIcon("vmware");
    if (imgtype() == VBOX)
        return iconHolder->getIcon("virtualbox");
    return QIcon();
}

QString VSession::toXml() const {
    QDomDocument doc(doc_);

    QDomNode xmlNode = doc.createProcessingInstruction(
            "xml", "version=\"1.0\" encoding=\"UTF-8\"");
    doc.insertBefore(xmlNode, doc.firstChild());
    QString image(this->getAttribute("image_name"));
    QDomElement path = doc.firstChildElement("settings")
            .firstChildElement("eintrag")
            .appendChild(doc.createElement("image_path"))
            .toElement();
    if (QFileInfo(image).isRelative()) {
        // make path to image absolute
        path.setAttribute("param", Config::get(Config::BASEDIR) + "/" + image);
    } else {
        path.setAttribute("param", image);
    }
    return doc.toString();
}

QString VSession::getAttribute(const QString &nodeName,
                                const QString &attribute) const {
    QDomNode n = eintrag_.firstChildElement(nodeName);
    return eintrag_.firstChildElement(nodeName).attribute(attribute);
}

QList<QString> VSession::keywords() const {
    return this->keywords_;
}

void VSession::readKeywords() {
    QDomNode keywordsNode = eintrag_.namedItem("keywords");
    for (QDomElement el(keywordsNode.firstChildElement("keyword"));
            !el.isNull();
            el = el.nextSiblingElement("keyword")) {
        this->keywords_.append(el.text());
    }
}

bool VSession::containsKeywords(const QList<QString>& keywords) const {
    for (int j = 0; j < keywords.length(); ++j) {
        if (!this->shortDescription().contains(keywords[j], Qt::CaseInsensitive)
                && !this->description().contains(keywords[j], Qt::CaseInsensitive)
                && !this->getAttribute("creator", "param").contains(keywords[j], Qt::CaseInsensitive)) {
            bool match = false;
            for (int i = 0; i < this->keywords().length(); ++i) {
                if (this->keywords()[i].contains(keywords[j], Qt::CaseInsensitive)) {
                    match = true;
                    break;
                }
            }
            if (!match)
                return false;
        }
    }
    return true;
}

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"));
    // Is disabled completely
    if (value.compare("false") == 0) {
        if (g_debugMode) qDebug() << "'" << shortDescription() << "' not active. Reason: active == false";
        return false;
    }
    // Check for date range
    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 (g_debugMode) qDebug() << "'" << shortDescription() << "' not active. Reason: fromDate is in the future";
            return false;
        }

        if (tillDate.isValid() && tillDate < today) {
            // tillDate is in the past
            if (g_debugMode) qDebug() << "'" << shortDescription() << "' not active. Reason: tillDate is in the past";
            return false;
        }
    }

    // Filter by LDAP data
    if (!UserLdapData::isEmpty()) {
        QDomElement el(eintrag_.namedItem("filters").firstChildElement("filter"));
        if (!el.isNull()) {
            for (; !el.isNull(); el = el.nextSiblingElement("filter")) {
                if (el.attribute("type") != "LDAP")
                    continue;
                if (UserLdapData::isAllowed(el.firstChildElement("key").text(), el.firstChildElement("value").text()))
                    return true;
            }
            return false;
        }
    }

    return true;
}

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

bool VSession::isValid() const {
    return !getAttribute("image_name").isEmpty();
}

int VSession::priority() const {
    int prio = getAttribute("priority").toInt();
    if (g_templateHandling == TEMPLATES_BUMP && isTemplate()) {
        prio -= 500;
    }
    if (g_forLocationHandling != LOCATION_IGNORE && isForLocation()) {
        prio -= 1000;
    }
    return prio;
}

bool VSession::run() const {
    if (_process.state() != QProcess::NotRunning) {
        qDebug() << "Cannot start vsession while old one is still running";
        return false;
    }
    if (g_debugMode) {
        qDebug() << "Sarting session " << this->getAttribute("short_description", "param") << " ...";
    }

    if (g_noVtx && is64Bit()) {
        QMessageBox::warning(nullptr, QObject::trUtf8("Warning"),
                QObject::trUtf8("The selected session is based on a 64 bit operating system,"
                        " but this computer doesn't seem to support this (VT-x/AMD-V not"
                        " supported by CPU, or disabled in BIOS). You will probably get an"
                        " error message while the virtualizer is initializing."));
    }

    QString command = getAttribute("command");
    if (!command.isEmpty()) {
        return QProcess::startDetached(command);
    }

    // write xml to temporary file
    QTemporaryFile tmpfile(QDir::tempPath() + "/vmchooser-XXXXXX.xml");
    if (!tmpfile.open() ||
        tmpfile.write(this->toXml().toUtf8()) == -1) {
        qDebug() << "Error writing xml to file" << tmpfile.fileName();
        return false;
    }
    // Docs say we should call fileName() before closing to prevent deletion
    QString tmpFileName = tmpfile.fileName();
    tmpfile.setAutoRemove(false);
    tmpfile.close();

    QObject::connect(&_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), QApplication::instance(), &QCoreApplication::quit);
    _process.start(Config::get(Config::RUNSCRIPT), QStringList(tmpFileName));
    _process.waitForStarted(10);
    if (_process.state() == QProcess::Starting || _process.state() == QProcess::Running)
        return true;
    else
        return false;
}

int VSession::type() const {
    return Session::VSESSION;
}

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

    QDomDocument doc;
    QFile file(filepath);
    QFile backup_file(TEMP_PATH_XML_LIST);

    if (!file.open(QIODevice::ReadOnly)) {
        if (g_debugMode) {
            qDebug() << "Cannot read file: " << file.fileName();
        }
        return sessionList;
    }

    if (!doc.setContent(&file)) {
        if (g_debugMode) {
            qDebug() << "XML file not valid: " << file.fileName();
        }

        file.close();

        // try to use backup file
        if (!backup_file.open(QIODevice::ReadOnly)) {
            if (g_debugMode) {
                qDebug() << "Cannot read backup file " << TEMP_PATH_XML_LIST << " either";
            }
            return sessionList;
        }

        if (!doc.setContent(&backup_file)) {
            if (g_debugMode) {
                qDebug() << "XML file not valid: " << backup_file.fileName();
            }
            backup_file.close();
            return sessionList;
        }

        if (g_debugMode) {
            qDebug() << "Used backup file " << TEMP_PATH_XML_LIST;
        }

        backup_file.close();
    } else {
        file.close();

        // file is valid --> create backup file
        QFile::remove(TEMP_PATH_XML_LIST);
        QFile::rename(filepath, TEMP_PATH_XML_LIST);
        if (!QFile::setPermissions(TEMP_PATH_XML_LIST, QFile::ReadUser | QFile::ReadGroup | QFile::ReadOther | QFile::WriteUser | QFile::WriteGroup | QFile::WriteOther)) {
            if (g_debugMode) {
                qDebug() << "Could not change permissions of file: " << TEMP_PATH_NEWS;
            }
        }
    }

    UserLdapData::init();

    QDomElement settingsNode = doc.firstChildElement("settings");
    for (QDomElement el(settingsNode.firstChildElement("eintrag"));
            !el.isNull();
            el = el.nextSiblingElement("eintrag")) {
        VSession* e = new VSession;
        if (e->init(el) && e->isActive()) {
            e->readKeywords();
            sessionList.append(e);
        } else {
            delete e;
        }
    }
    return sessionList;
}

bool VSession::is64Bit() const {
    ImgType type = imgtype();
    return (type == VMWARE && getAttribute("os").endsWith("-64"))
            || (type == VBOX && getAttribute("os").endsWith("_64"));
    // TODO: qemu-kvm, ...
}

QVariant VSession::foregroundRole() const {
    if (!g_noVtx || !is64Bit())
        return Session::foregroundRole();
    return QColor(180, 180, 180);
}

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