/* # 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 #include #include #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 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(<>) == 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")).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;isendMessage(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 = ""; }