/*
# 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 = "";
}