summaryrefslogblamecommitdiffstats
path: root/src/pvs.cpp
blob: 2aaec8a33c7a9beac3e1311e9e77361f876d3418 (plain) (tree)





































                                                                                              


                            


                                                                                  

                                        








                                                                
                                        
                                                          
                                                 
                                                           










                                                                              
                     










                                            
                        



































































































                                                                                                                                                                                                        












                                                                                          












































































































































                                                                            


                                                               

















































































































                                                                                                  
                                                                
                    

                                                                      
                    
 
                 












































                                                                                              
                                                         

                         





                                                                                                     



                                                            














                                                            
                         










                                                             



                                                                    






                 
                 

                                                                               
                

































































                                                                                  
                         













                               


                                                                    


 











                                                    
/*
 # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
 #
 # This program is free software distributed under the GPL version 2.
 # See http://openslx.org/COPYING
 #
 # If you have any feedback please consult http://openslx.org/feedback and
 # send your suggestions, praise, or complaints to feedback@openslx.org
 #
 # General information about OpenSLX can be found at http://openslx.org/
 */

#include "pvs.h"
#include "src/util/dispatcher.h"
#include "src/net/pvsMsg.h"
#include "src/net/pvsServiceDiscovery.h"
#include "src/net/pvsDiscoveredServer.h"

// D-Bus
#include "pvsadaptor.h"

extern PVS *mainClient;

// !!STATION LOCK TESTING!!
//#define lock_test_unlock_time 3
// uncomment the following line to test locking in a local context
// it disables the lock of a station #(lock_test_unlock_time) seconds after it has been locked
//#define lock_test

PVS::PVS() :
        QObject()
{
    _pvsServerConnection = new PVSServerConnection(this);
    _locked = false;
    _vncAllowed = false;
    _vncRequested = false;
    readPolicyFiles();
    loadCommands();
    /*#ifndef __WIN32__*/
        _blankScreen = NULL;
    /*#endif*/
    _vncPort = -1;

    // add a notify to the allow file, so we get informed when the file is changed
    QString watchPath(getPolicyDir());
    watchPath.append(QString(".allow"));
    _notify = new QFileSystemWatcher(this);
    _notify->addPath(QString(watchPath.toUtf8().data()));

    connect(_notify, SIGNAL(fileChanged(const QString &)), this,
            SLOT(fileChanged(const QString &)));

    // connect to D-Bus
    new PvsAdaptor(this);
    QDBusConnection dbus = QDBusConnection::sessionBus();
    if (!dbus.registerObject("/", this))
        qDebug("[ERROR] DBus: Could not register object");
    if (!dbus.registerService("org.openslx.pvs"))
        qDebug("[ERROR] DBus: Could not register service");

    _sdClient = new PVSServiceDiscovery(this);

    _chat = new PVSChatClient();
    _chat->setServerConnection(_pvsServerConnection);
    _chat->getChatMsgHandler().addListener(this, &PVS::chat_receive);
    _chat->getChatCommandHandler().addListener(this, &PVS::UpdateChatClients);

    _timerLockTest = 0;
    _timerLockDelay = 0;

    #ifndef __WIN32__
    //add signalhandling for sigterm signals
    struct sigaction act;
    act.sa_handler = &PVS::signalHandler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

    //register signals with actions
    sigaction(SIGTERM, &act, 0);
    sigaction(SIGHUP, &act, 0);
    sigaction(SIGINT, &act, 0);
    sigaction(SIGQUIT, &act, 0);
    #endif /*__WIN32__*/
}

PVS::~PVS()
{
    // make sure we dont leave a locked computer
    if (_notify)
        disconnect(_notify, SIGNAL(fileChanged(const QString &)), this,
                   SLOT(fileChanged(const QString &)));
    unlock();
    delete _sdClient;
}

void PVS::connectToHost(PVSDiscoveredServer* server, QString passwd)
{
    _pvsServerConnection->connectToServer(server, passwd);
}

/**
 * onCommand Callback method
 * handles incoming commands
 */
void PVS::onCommand(PVSMsg cmdMessage)
{
    QString message = cmdMessage.getMessage();
    QString ident = cmdMessage.getIdent();
    if (ident.compare("LOCKSTATION") == 0)
    {
        if (_blankScreen)
        {
            return;
        }
        else
        {
            _lockMsg = message;
            //TODO:@Javier: lock it eith message.
            // Sent message.
            if(message.size() > 0) // Lock client with message.
            {
                message = message + "\n \n WARNING: Your screen will be blocked in 10 seconds.";
                emit showMessage("Lock Message", message, true);
                _timerLockDelay = startTimer(10*1000); // 10 sec.
            }
            else // lock client without message.
            {
                lock();
            }
        }

        return;
    }
    if (ident.compare("UNLOCKSTATION") == 0)
    {
        _timerLockDelay = 0;
        if (!_blankScreen)
        {
            return;
        }
        else
        {
            ConsoleLog writeLine("Unlocked.");
            unlock();
        }
        return;
    }
    if (ident.compare("VNCREQUEST") == 0)
    {
        // a vnc connection was requested, so lets check if this is against our policies
    	_vncRequested = (message.compare("YES") == 0);
    	if (!_vncRequested) return;
		getVNCAllow();
        return;
    }
    if (ident.compare("PROJECT") == 0)
    {
        std::vector<QString> connDetails;
        std::string buf;
        std::stringstream ss(message.toStdString());
        while (ss >> buf)
            connDetails.push_back(QString::fromStdString(buf));

        if(connDetails.size() == 4) {
            int port, quality;
            bool fullscreen, smooth;
            fullscreen = smooth = true;
            port = connDetails[1].toInt();
            quality = connDetails[3].toInt();
            if(port > 0) {
                emit project(connDetails[0], port, connDetails[2], fullscreen, smooth, quality);
                lock_inputs();
                ConsoleLog writeNetwork(QString("Received Projection Information: Projsrc: ").append(connDetails[0]).append( " port: ").append(connDetails[1]).append(" pass:").append(connDetails[2]));
            }
            ConsoleLog writeNetwork(QString("Received illegal port! (").append(port).append(")"));
			}
    }
    if (ident.compare("UNPROJECT") == 0)
    {
        emit unproject();
        unlock();
        return;
    }
    if (ident.compare("SHOWPROCESSES") == 0)
    {
        // do stuff to show processes
    	// to test if SHOWPROCESSES command is submitted correct uncomment following lines
    	// a messagebox will appear on the client
    	// emit showMessage("Show Processes", "", true);
        return;
    }
    if (ident.compare("KILLPROCESS") == 0)
    {
        // do stuff to kill a process
        return;
    }

#ifdef never
    // prototype
    if (command.compare(<<string>>) == 0)
    {
        // do stuff
        return;
    }
#endif
}

/**
 * onLogin Callback method
 * handles the servers login messages (see PVSListenServer)
 */
void PVS::onLogin(PVSMsg login)
{
    if (login.getIdent().compare(QString("ACCEPTED")) == 0)
    {
        ConsoleLog writeNetwork("Server accepted connection.");
        login.getMessage();
    }
    else if (login.getIdent().compare(QString("DENIED")) == 0)
    {

        ConsoleLog writeNetwork(QString("Sent Username."));
    }
}

void PVS::chat_send(QString nick_to, QString nick_from, QString msg)
{
    _chat->send(nick_to, msg);
}

void PVS::UpdateChatClients(PVSChatMsg chatCommand)
{
    if(chatCommand.getCommand().compare("clientToAdd") == 0)
    {
        _chat->addClient(chatCommand.getUsername(), chatCommand.getIp());
        emit chat_client_add(chatCommand.getUsername());
    }

    if(chatCommand.getCommand().compare("clientToRemove") == 0)
    {
        _chat->removeClient(chatCommand.getUsername());
        emit chat_client_remove(chatCommand.getUsername());
    }

    if(chatCommand.getCommand().compare("assignedName") == 0)
    {
        _chat->setSource(chatCommand.getUsername());
    }
}

void PVS::chat_receive(PVSChatMsg msg)
{
	emit chat_receive(msg.getNickFrom(), msg.getNickTo(), msg.getMsg());
}

/**
 * onDaemon Callback method
 * handles incoming UDS Communicator messages
 */
void PVS::onDaemonCommand(PVSMsg msg)
{
    if (msg.getIdent().compare(QString("stop")) == 0)
    {
        stop();
        unlock();
        exit(0);
    }
}

void PVS::onMessage(PVSMsg msg)
{
	QString ident = msg.getIdent();
	QString message = msg.getMessage();

	if (ident.compare("BROADCAST") == 0)
	{
		emit showMessage(tr("Message"), message, true);
	}
}

/**
 * load custom commands by adding callbacks to the dispatchers
 */
void PVS::loadCommands()
{
    if (_pvsServerConnection)
    {
        _pvsServerConnection->addCommandHandler("*", this, &PVS::onCommand);
        _pvsServerConnection->addLoginHandler("*", this, &PVS::onLogin);
        _pvsServerConnection->addChatHandler("*", this, &PVS::onMessage);
    }
}

void PVS::quit()
{
    stop();
    unlock();
    exit(0);
}

/**
 * stops the client
 */
void PVS::stop()
{
    _pvsServerConnection->disconnectFromServer();
    stopVNCScript();
}

/**
 * used to unlock the client after 3 seconds
 * this a maintainance method
 * uncomment the define to use it
 */
void PVS::timerEvent(QTimerEvent *event)
{
#ifdef lock_test
    if (_locked && event->timerId()== _timerLockTest) unlock();
#endif
    if(_timerLockDelay == event->timerId())
    {
        if (lock()) ConsoleLog writeLine(QString("Locked."));
        _timerLockDelay = 0;
    }
    killTimer(event->timerId());
}

bool PVS::allowExists()
{
    return policyFileExists(QString(".allow"));
}

/**
 *  check whether we want to allow vnc connections to this client
 */
bool PVS::getVNCAllow()
{

    QString value = getConfigValue("Permissions/vnc_lecturer");
    _vncAllowed = (value == "rw" || value == "ro");

    if (_vncAllowed && _vncRequested)
    {
        // then boot up the vnc-server and set password and port
        int result = bootVNC();
        if (result == 0)
        {
            // now inform the server
            _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PORT", int2String(_vncPort)));
            _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PASSWORD", _vncPassword));
            _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "RWPASSWORD", _vncRwPassword));
            _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "VNC","YES"));
            ConsoleLog writeNetwork(QString("Sent password, port and granted access."));
            // show message on clientgui
            emit showMessage(tr("VNC connection"), tr("The host ")
                    .append(_pvsServerConnection->getServerName()
                            .append(tr(" requested your screen!"))));
        }
        _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "VNCSRVRESULT", int2String(result)));

    }
    else if (!_vncAllowed)
    {
    	stopVNCScript();
        _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "VNC","NO"));
    }
    return _vncAllowed;
}

/**
 *  read the policy files
 */
void PVS::readPolicyFiles()
{
    getVNCAllow();
    // Add more policyfiles here if any
}

/**
 *  callback which gets invoked when the watched file is changed
 */
void PVS::fileChanged(const QString& path)
{
    getVNCAllow();
}

/**
 *  lock the client
 */
bool PVS::lock()
{

#ifdef lock_test
    _timerLockTest = startTimer(lock_test_unlock_time * 1000);
    printf("will auto-unlock in %d secs\n", int(lock_test_unlock_time));
#endif

    if (!_blankScreen)
    {
        _blankScreen = new BlankScreen();
        if (_blankScreen)
            return _locked = _blankScreen->lock();
        else
            return false;
    }
    return true;
}

/**
 *  lock the client inputs only
 */
bool PVS::lock_inputs()
{

#ifdef lock_test
    _timerLockTest = startTimer(lock_test_unlock_time * 1000);
    printf("will auto-unlock in %d secs\n", int(lock_test_unlock_time));
#endif

    if (!_blankScreen)
    {
        _blankScreen = new BlankScreen();
        if (_blankScreen)
            return _locked = _blankScreen->lock_inputs();
        else
            return false;
    }
    return true;
}

/**
 *  unlock the client
 */
bool PVS::unlock()
{
    if (_blankScreen)
    {
        if (_blankScreen->unlock())
        {
            delete _blankScreen;
            _blankScreen = NULL;
        }
    }
    return false;
}

void PVS::setScriptPath(QString path)
{
    _vncScriptPath = path;
    _vncScriptName = getFilenameFromPath(_vncScriptPath);
}

bool PVS::gotVNCScript()
{
    if (!_vncScriptPath.isEmpty() && fileExists(_vncScriptPath))
        return true;

    if (!_vncScriptName.isEmpty() && policyFileExists(_vncScriptName))
        return true;

    return false;
}
/**
 * setup password and port
 * the local_test define is used to enable local testing modes without invoking the vnc-script
 */
int PVS::bootVNC()
{
    //    #define local_test

    stopVNCScript(); // just to be sure
#ifndef local_test
    _vncPassword = int2String(getRandom(0, 99999999));
    do {
    	_vncRwPassword = int2String(getRandom(0, 99999999));
    } while (_vncRwPassword == _vncPassword);

    _vncPort = getRandom(5901, 6000);
    return startVNCScript(_vncPort, _vncPassword, _vncRwPassword);
#else
    _vncPassword = QString("1234");
    _vncPort = 5901;
    return startVNCScript(_vncPort, _vncPassword);
#endif
    //#undef local_test
}

/**
 * launch the vnc script (if present) to start the vnc-server
 */
int PVS::startVNCScript(int port, QString pass, QString rwpass)
{
    if (gotVNCScript())
    {
        ConsoleLog writeLine("Starting VNC-Script");
        QString commandLine(_vncScriptPath);
        commandLine.append(" ");
        commandLine.append("start");
        commandLine.append(" ");
        commandLine.append(int2String(port));
        commandLine.append(" ");
        commandLine.append(pass);
        commandLine.append(" ");
        commandLine.append(rwpass);
        if (!system(NULL))
            ConsoleLog writeError("No Command processor available");
        int result = system(commandLine.toUtf8().data());
        #ifndef __WIN32__
//TODO Win32
        result = WEXITSTATUS(result);
        if (result != 0)
            ConsoleLog writeError(QString("VNC-Server is not running, code: ") + int2String(result));
        else
            ConsoleLog writeLine("VNC-Server should be running");
        return result;
        #else
            /*Code fuer VNC-Aufruf unter Windows einfuegen*/
            return 0;
        #endif /*__WIN32__*/
    }
    else
    {
        ConsoleLog writeError("VNC-Script not found.");
        return 3;
    }
}

/**
 * launch the vnc script (if present) to stop the vnc-server
 */
int PVS::stopVNCScript()
{
    if (gotVNCScript())
    {
        #ifndef __WIN32__
        ConsoleLog writeLine("Stopping VNC-Script");
        QString commandLine(_vncScriptPath);
        commandLine.append(" ");
        commandLine.append("stop");
        commandLine.append(" ");
        commandLine.append("dummy");
        commandLine.append(" ");
        commandLine.append("dummy");
        ConsoleLog writeLine("VNC-Server should be stopped");
        int result = system(commandLine.toUtf8().data());
        return WEXITSTATUS(result);
        #else
            /*Code fuer VNC-Server stoppen unter Windows einfuegen*/
            return 0;
        #endif /*__WIN32__*/
    }
    else
    {
        return 3;
    }
}

bool PVS::start()
{
    _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROJECTING", "YES"));
    return true;
}

void PVS::onConnected(QString name)
{
    emit connected(name);
}

void PVS::onDisconnected()
{
	emit disconnected();
	_chat->clearClients();
	stopVNCScript();
}

QString PVS::isConnected()
{
    return _pvsServerConnection->getServerName();
}

QString PVS::chat_getNickname()
{
    return _chat->getSource();
}

QStringList PVS::chat_getNicknames()
{
	return _chat->getClients();
}

void PVS::pvsConnect(QString host, QString passwd)
{
	_pvsServerConnection->disconnectFromServer();
    _sdClient->connectToSession(host, passwd);
}
void PVS::pvsDisconnect()
{
	_chat->clearClients();
	_sdClient->connectToSession("", "");
	stop();
}


QStringList PVS::getAvailableHosts()
{
    return _sdClient->getAllServers();
}

void PVS::guiAddHost(QString host)
{
	emit addHost(host);
}

void PVS::guiDelHost(QString host)
{
	emit delHost(host);
}

QString PVS::getIpByNick(QString nick)
{
    return _chat->getIPFromUsername(nick);
}

//Handles signals (SIGTERM and SIGHUP)
void PVS::signalHandler(int signal)
{
    ConsoleLog writeLine(QString("Received Signal ").append (int2String(signal)));
	#ifndef __WIN32__
    switch (signal) {
        case SIGHUP:
            mainClient->quit();
            break;
        case SIGTERM:
            mainClient->quit();
            break;
        case SIGINT:
            mainClient->quit();
            break;
        case SIGQUIT:
            mainClient->quit();
            break;
    }
    #else
        ConsoleLog writeLine("Abfang nicht definiert fuer Windows");
    #endif /*__WIN32__*/

}

void PVS::setConfigValue(QString key, QString value)
{
    _settings.setValue(key, value);
    _settings.sync();
    getVNCAllow();
}

QString PVS::getConfigValue(QString key)
{
    return _settings.value(key).toString();
}