summaryrefslogblamecommitdiffstats
path: root/src/pvs.cpp
blob: 5621c641191d106fb3a2420b3e597555d9aeadbb (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12











                                                                               



                             




                                        
                                 
                                         
                                    

                                                 
                                                 


















                                                                                              
                        

                  




                                                                                  
 

                      
 

                                                         



                                                         
                                        
                                                          
                                                 
                                                           






















                                                                              
                                   

                                                       



                                                                                                           


                                                                      
                                                            
                                              


                                                         



           



























































































                                                                                                                                                                                                        


                                         




                                                      
     




                                                  
                                                 




                                                                                     






































                                                                              




                                            

                                            
                                                                                                                                                  
                          

               

                                           
                              

                                                                               
                                                                                                                              

               

                                          
                              

                                                                                            
                                                                                                                                     

               


































































































































                                                                            




                                                                 


                                                               






































                                                                                                  


































































                                                                        
                                                                
                    

                                                                      
                    
 
                 












































                                                                                              







































                                                                                                     
                 

                                                                               
                


















                                                 




                                                          




























































                                                                                  

 

















                                                                                                                                                           

                                                                                                                    




                                                   

                 


                                                                      
                                

 

                                                 

                                                                                                   
                                        




                                                      
                                                                       
                                         
 
 





                                                                                     
                                              



                        










                                                                                     


                                                                                   


                                                
                                           
                                                           





                                                       

                                                                                                                                  









                                                                                                                                                               
                                                                              









                                                                                                  






                                      




                                                      




                                                                            








                                                                                     











                                                                                     














































                                                                                                                                                                                         
 

                                                    





                                        



                                        
                                            

 
                                  
 
                                                   
 

                             
                                                  

                           
                                                                           




                                                                                                 

                              


                                                                                              

                                          
                                                                                              









                                                                                               
                                                                                                                       
                                                                                                                                           
                                                                                                                              
                                                                                                                                            
                                          



                                                                                                                                     

                                                                      


                                                      
                                                                      
                              
                                                                      
                                  
                                                                        
                                                               
                                  


                                                                                              
                                                                                                        






                                                                                                                   

                                                                                                                                                                



                                                                                               
                                                                                                                      



                                                                                                                                                  












                                                                                                                                  
/*
 # 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 <QCryptographicHash>
#include <QDataStream>
#include <QDateTime>

#include "pvs.h"
#include "src/util/dispatcher.h"
#include "src/net/pvsMsg.h"
#include "src/net/pvsServiceDiscovery.h"
#include "src/net/pvsDiscoveredServer.h"
#include "src/input/inputEvent.h"
#include "src/input/inputHandlerChains.h"
#include "src/input/x11InputUtils.h"
#include "src/net/mcast/McastConfiguration.h"
#include "src/net/pvsOutgoingMulticastTransfer.h"
#include "src/net/pvsIncomingMulticastTransfer.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;
    _blankScreen = NULL;
    _vncPort = -1;

    QSettings tmp(QSettings::SystemScope, "openslx", "pvs");
    if (tmp.value("restricted").toBool())
        _settings = new QSettings(QSettings::SystemScope, "openslx", "pvs", this);
    else
        _settings = new QSettings(QSettings::UserScope, "openslx", "pvs", this);

    readPolicyFiles();
    loadCommands();

    _masterMcastConfig = new McastConfiguration(this);
    _masterMcastConfig->loadFrom(_settings, "multicast");

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

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

    initializeInputEventHandling();

    // Read Config and try to autoconnect to given host
    QHostAddress host(_settings->value("Connection/host").toString());
    int port = _settings->value("Connection/port").toInt();
    QByteArray fingerprint = QByteArray::fromHex(_settings->value("Connection/fingerprint").toByteArray());
    QString name = _settings->value("Connection/sessionname").toString();
    if (!host.isNull() && port > 0 && fingerprint != "" && name != "")
    {
        qDebug() << "Autoconnecting to " << host.toString();
        _sdClient->handleDiscovery(host, port, fingerprint);
        _sdClient->connectToSession(name, "");
    }
    else
        qDebug() << "No Config for autoconnection found";
}

PVS::~PVS()
{
    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("INPUTEVENT") == 0)
    {
    	InputEvent evt;
    	if(inputEventsAllowed())
    	{
			eventFromString(message, evt);
			handleInputEvent(evt);
    	}
    }
    if (ident.compare("MCASTFTRETRY") == 0)
    {
        QStringList fields = message.split(':');
        if (fields[0].compare(getUserName()) == 0)
        {
            quint64 id = fields[1].toULongLong();
            PVSOutgoingMulticastTransfer* transfer = _outgoingTransfers.value(id, 0);
            if (transfer)
                transfer->retry();
        }
    }
    if (ident.compare("MCASTFTANNOUNCE") == 0)
    {
        QStringList fields = message.split(':');
        bool ok;
        QString sender;
        qulonglong transferID;
        QString basename;
        qulonglong size;
        ushort port;

        if (!fields.size() == 5)
        {
            goto malformedAnnounce;
        }
        sender = fields[0];
        transferID = fields[1].toULongLong(&ok);
        if (!ok)
        {
            goto malformedAnnounce;
        }
        basename = fields[2];
        size = fields[3].toULongLong(&ok);
        if (!ok)
        {
            goto malformedAnnounce;
        }
        port = fields[4].toUShort(&ok);
        if (!ok)
        {
            goto malformedAnnounce;
        }

        onIncomingMulticastTransfer(sender, transferID, basename, size, port);
        return;

    malformedAnnounce:
        qDebug() << "Ignoring malformed MCASTFTANNOUNCE command: " << message;
        return;
    }
    if (ident.compare("MCASTFTCONFIG") == 0)
    {
    	loadMcastConfig(message);
    	return;
    }
    if (ident.compare("SHOWPROCESSES") == 0)
    {
    	_pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROCESSES", "SHOW clear")); //tell the client that we want to clear his process-list
    	showProc(message);
        return;
    }
    if (ident.compare("STARTPROCESS") == 0)
    {
    	processName = message;
    	QProcess *proc = new QProcess( this );
    	proc->start(message); //we try to run the process with the name message
    	connect( proc, SIGNAL( error(QProcess::ProcessError)), this, SLOT( processStartErrorOccured(QProcess::ProcessError)));
    	return;
    }
    if (ident.compare("KILLPROCESS") == 0)
    {
    	processName = message;
		QProcess *proc = new QProcess( this );
		proc->start("kill "+message); //we try to kill the process with the given ID
		connect( proc, SIGNAL( error(QProcess::ProcessError)), this, SLOT( processStopErrorOccured(QProcess::ProcessError)));
        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());
}

/**
 *  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
}

/**
 *  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());
        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
    {
        ConsoleLog writeError("VNC-Script not found.");
        return 3;
    }
}

/**
 * launch the vnc script (if present) to stop the vnc-server
 */
int PVS::stopVNCScript()
{
    if (gotVNCScript())
    {
        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
    {
        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();
}

bool PVS::isRestricted()
{
    return (_settings->scope() == QSettings::SystemScope);
}

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)));
    switch (signal) {
        case SIGHUP:
            mainClient->quit();
            break;
        case SIGTERM:
            mainClient->quit();
            break;
        case SIGINT:
            mainClient->quit();
            break;
        case SIGQUIT:
            mainClient->quit();
            break;
    }
}

bool PVS::createMulticastTransfer(QString const& objectPath, quint64& transferID, QString& errorReason)
{
    transferID = generateMcastTransferID();

    PVSOutgoingMulticastTransfer* transfer = new PVSOutgoingMulticastTransfer(getUserName(), transferID, objectPath, this);
    if (transfer->isError())
    {
        errorReason = transfer->reason();
        delete transfer;
        return false;
    }

    _outgoingTransfers.insert(transferID, transfer);
    connect(transfer, SIGNAL(started(qulonglong)), SIGNAL(outgoingMulticastTransferStarted(qulonglong)));
    connect(transfer, SIGNAL(finished(qulonglong)), SIGNAL(outgoingMulticastTransferFinished(qulonglong)));
    connect(transfer, SIGNAL(failed(qulonglong, QString const)), SIGNAL(outgoingMulticastTransferFailed(qulonglong, QString const)));
    connect(transfer, SIGNAL(progress(qulonglong, qulonglong, qulonglong)), SIGNAL(outgoingMulticastTransferProgress(qulonglong, qulonglong, qulonglong)));
    connect(transfer, SIGNAL(announce(PVSMsg)), _pvsServerConnection, SLOT(sendMessage(PVSMsg)));
    connect(transfer, SIGNAL(finished(qulonglong)), SLOT(outgoingMulticastTransferDelete(qulonglong)));
    connect(transfer, SIGNAL(failed(qulonglong, QString const)), SLOT(outgoingMulticastTransferDelete(qulonglong)));
    QTimer::singleShot(0, transfer, SLOT(start()));
    errorReason = "";
    return true;
}

// Input handling

bool PVS::inputEventsAllowed()
{
	QString lecturer = getConfigValue("Permissions/vnc_lecturer");
	return lecturer == "rw";
}

void PVS::handleInputEvent(InputEvent const& evt)
{
	QString s = evt.toString();
	ConsoleLog writeLine(QString("Received input event: %1").arg(s.toLocal8Bit().constData()));
	_inputEventHandlers.handle(evt);
}

void PVS::initializeInputEventHandling()
{
	X11InputUtils::setDisplay(X11Info::display());
	_inputEventHandlers = makeUnprivilegedInputEventHandlerChain();
	_inputEventHandlers.initialize();
}

void PVS::cancelOutgoingMulticastTransfer(quint64 transferID)
{
    PVSOutgoingMulticastTransfer* transfer = _outgoingTransfers.value(transferID, 0);

    if (transfer)
    {
        _outgoingTransfers.remove(transferID);
        delete transfer;
    }
}

void PVS::cancelIncomingMulticastTransfer(qulonglong transferID)
{
    PVSIncomingMulticastTransfer* transfer = _incomingTransfers.value(transferID, 0);

    if(transfer)
    {
        _incomingTransfers.remove(transferID);
        delete transfer;
    }
}

void PVS::onIncomingMulticastTransfer(QString const& sender, qulonglong transferID,
        QString const& basename, qulonglong size, ushort port)
{
    if (_outgoingTransfers.contains(transferID))
        return;

    PVSIncomingMulticastTransfer* transfer;
    if (transfer = _incomingTransfers.value(transferID, 0))
    {
        transfer->updatePort(port);
        QTimer::singleShot(0, transfer, SLOT(start()));
    }
    else
    {
        QString filename = QFileInfo(QDir::home(), QString("%1.part.%2").arg(basename).arg(transferID, 0, 16)).absoluteFilePath();
        transfer = new PVSIncomingMulticastTransfer(sender, transferID, size, filename, port, _masterMcastConfig, this);
        _incomingTransfers.insert(transferID, transfer);

        connect(transfer, SIGNAL(retry(QString const&, qulonglong)), SLOT(onIncomingMulticastTransferRetry(QString const&, qulonglong)));
        connect(transfer, SIGNAL(started(qulonglong)), SIGNAL(incomingMulticastTransferStarted(qulonglong)));
        connect(transfer, SIGNAL(progress(qulonglong, qulonglong, qulonglong)), SIGNAL(incomingMulticastTransferProgress(qulonglong, qulonglong, qulonglong)));
        connect(transfer, SIGNAL(finished(qulonglong)), SIGNAL(incomingMulticastTransferFinished(qulonglong)));
        connect(transfer, SIGNAL(failed(qulonglong, QString const&)), SIGNAL(incomingMulticastTransferFailed(qulonglong, QString)));
        connect(transfer, SIGNAL(finished(qulonglong)), SLOT(incomingMulticastTransferDelete(qulonglong)));
        connect(transfer, SIGNAL(failed(qulonglong, QString const&)), SLOT(incomingMulticastTransferDelete(qulonglong)));

        emit incomingMulticastTransferNew(transferID, sender, filename, size);
        QTimer::singleShot(0, transfer, SLOT(start()));
    }
}

void PVS::onIncomingMulticastTransferRetry(QString const& sender, qulonglong transferID)
{
    PVSMsg retryMessage(PVSCOMMAND, "MCASTFTRETRY", QString("%1:%2").arg(sender).arg(transferID));
    _pvsServerConnection->sendMessage(retryMessage);
}

quint64 PVS::generateMcastTransferID()
{
    static quint64 nodeID = 0;
    static quint16 counter = 0;

    if (!nodeID)
    {
    	QDateTime t = QDateTime::currentDateTime();
    	QCryptographicHash h(QCryptographicHash::Md5);
    	h.addData(getUserName().toLocal8Bit());
    	h.addData(t.toString().toLocal8Bit());
        QDataStream(h.result()) >> nodeID;
    }

    return (nodeID & Q_UINT64_C(0xffffffffffff0000)) | (quint64)(++counter);
}

void PVS::outgoingMulticastTransferDelete(qulonglong transferID)
{
    PVSOutgoingMulticastTransfer* transfer = _outgoingTransfers.value(transferID, 0);
    if (!transfer)
        return;

    _outgoingTransfers.remove(transferID);
    transfer->deleteLater();
}

void PVS::incomingMulticastTransferDelete(qulonglong transferID)
{
    PVSIncomingMulticastTransfer* transfer = _incomingTransfers.value(transferID, 0);
    if (!transfer)
    {
        return;
    }

    _incomingTransfers.remove(transferID);
    transfer->deleteLater();
}

void PVS::loadMcastConfig(QString const& message)
{
	QByteArray ba = QByteArray::fromBase64(message.toAscii());
	QDataStream d(&ba, QIODevice::ReadOnly);
	quint16 ver, udpp, dp, sp, mtu, wsz;
	quint32 rate;
	QString addr;
	bool useudp;

	d >> ver;
	if(ver != 1)
	{
		ConsoleLog writeLine(QString("Unable to decode multicast configuration message: Unknown version %1").arg(ver));
		return;
	}

	d >> addr
		>> udpp
		>> dp
		>> sp
		>> mtu
		>> wsz
		>> rate
		>> useudp;
	if(d.status() != QDataStream::Ok)
	{
		ConsoleLog writeLine(QString("Unable to decode multicast configuration message: There was an error reading"));
		return;
	}

	_masterMcastConfig->multicastUDPPortBase(udpp);
	_masterMcastConfig->multicastDPort(dp);
	_masterMcastConfig->multicastSPort(sp);
	_masterMcastConfig->multicastMTU(mtu);
	_masterMcastConfig->multicastWinSize(wsz);
	_masterMcastConfig->multicastRate(rate);
	_masterMcastConfig->multicastAddress(addr);
	_masterMcastConfig->multicastUseUDP(useudp);

	QSettings settings;
	_masterMcastConfig->writeTo(&settings, "multicast");
	settings.sync();

	ConsoleLog writeLine(QString("Reconfigured multicast filetransfer to IP %1, UDP port base %2, destination port %3, source port %4, MTU %5, Window Size %6, rate %7, %8using UDP")
			.arg(addr).arg(udpp).arg(dp).arg(sp).arg(mtu).arg(wsz).arg(rate).arg(useudp ? "" : "not "));
}

void PVS::setConfigValue(QString key, QString value)
{
    if (!isRestricted())
    {
        _settings->setValue(key, value);
        _settings->sync();
        getVNCAllow();
    }
}

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

void PVS::showProc(QString filter)
{
	QStringList filterList = filter.split(" ");

	//look at procfs
	QDir procfs("/proc");
	QStringList procList = procfs.entryList();
	int uid = getuid();
	bool write;
	if (procList.length() < 1) //if we can't read procfs for any reason
	{
		_pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROCESSES", "SHOW ERROR"));
		return;
	}
	for (int i=0;i<procList.length();i++) //every directory in /proc is checked
	{
		write = false;
		QString tempFolder = procList.at(i);
		QString tempSend = "";
		if (!tempFolder.contains(QRegExp("\\D"))) //we have to check if name is number
		{
			QString name = "";
			QFile file("/proc/"+tempFolder+QString("/status")); //read status file
			     if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
			         return;

			     QTextStream in(&file);
			     QString line = in.readLine();
			     while (!line.isNull())
			     {
			    	 if (line.startsWith("Name:")) //to get the name of our process
					 {
			    		 name = line.remove(0,6);
			    		 tempSend.append(tempFolder).append(QString("<#>")).append(line).append("<#>");
			    		 //lets check if the process belongs to our PVS. better not to show it if we dont want to crash PVS
					 } else if (line.startsWith("Uid:")) //and to check that the process is a user process
														 //we had to read name first
					 {
						 line.remove(QRegExp("\\D")); //remove all non-digit characters (letters+whitespaces)
						 int llength = line.size();
						 line.remove(llength/4,llength);
						 if (line == QString::number(uid))
							 write = true;
						 else break;
					 }
			         line = in.readLine();
			     }
			     if (write) //check if user belongs to pvs
			     {
			    	 for (int i=0;i<filterList.size();i++)
			    	 {
			    		 if (name == (filterList.at(i)))
			    			 write = false;
			    	 }
			     }
			     if (write) //if process belongs to user (and not to PVS) we go on
			     {
			    	 QFile file("/proc/"+tempFolder+QString("/cmdline")); //and read cmdline
			    	 			     if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
			    	 			         return;

			    	 			     QTextStream in(&file);
			    	 			     QString line = in.readLine();
			    	 			     while (!line.isNull())
			    	 			     {
			    	 			    	 int templength = tempSend.length()+3;
			    	 			    	 tempSend.append(line.left(150+templength)); //but only up to a length of 150-name-id-seperators
			    	 			    	 break;
			    	 			     }
			     }
			     if (write) //if process belongs to user we send the line to client
			    	 _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROCESSES", "SHOW "+tempSend));
		}
	}
	_pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROCESSES", "SHOW finished")); //at the end we send that every process has been sent
}

//tell connectionManager that error occured
void PVS::processStartErrorOccured(QProcess::ProcessError error)
{
	_pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROCESSES", "START ERROR "+QString::number(error)+" "+processName));
	processName = "";
}

void PVS::processStopErrorOccured(QProcess::ProcessError error)
{
	_pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROCESSES", "STOP ERROR "+QString::number(error)+" "+processName));
	processName = "";
}