diff options
| author | Sebastian | 2010-05-12 19:42:27 +0200 |
|---|---|---|
| committer | Sebastian | 2010-05-12 19:42:27 +0200 |
| commit | ce3329047d378a14006ce74ec273ac59e3375303 (patch) | |
| tree | 782430f270b4c7aca1b35d5b7813518e3797c555 /src | |
| download | pvs-ce3329047d378a14006ce74ec273ac59e3375303.tar.gz pvs-ce3329047d378a14006ce74ec273ac59e3375303.tar.xz pvs-ce3329047d378a14006ce74ec273ac59e3375303.zip | |
initial import of latest svn version
Diffstat (limited to 'src')
110 files changed, 19008 insertions, 0 deletions
diff --git a/src/core/pvsChatClient.cpp b/src/core/pvsChatClient.cpp new file mode 100644 index 0000000..6717e34 --- /dev/null +++ b/src/core/pvsChatClient.cpp @@ -0,0 +1,151 @@ +/* +# Copyright (c) 2009,2010 - 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/ +# ----------------------------------------------------------------------------- +# pvsChatClient.cpp +# - Methods of the chat service. +# ----------------------------------------------------------------------------- +*/ + +#include "pvsChatClient.h" + +using namespace std; + +// Constructor +PVSChatClient::PVSChatClient() +{ + _chatServerConnection = NULL; + _source = getFullUsername(); + _registered = true; +} + +PVSChatClient::~PVSChatClient() +{ + +} + +// Get Chat login name. +QString PVSChatClient::getSource() +{ + return _source; +} + +// Set (from server) assigned username. +void PVSChatClient::setSource(QString name) +{ + _source = name; + _registered = true; +} + +bool PVSChatClient::isRegistered() +{ + return _registered; +} + +// Set PVSServerConnection +void PVSChatClient::setServerConnection(PVSServerConnection* sc) +{ + if (sc) + { + _chatServerConnection = sc; + _chatServerConnection->addChatHandler("*", this, &PVSChatClient::receive); + } +} + +// Send a message to Server. +void PVSChatClient::send(QString tar, QString msg) +{ + // Append username to msg. + QString username = _source; + username.append(":"); + msg = username.append(msg) ; + + // Create a Msg. + PVSMsg myMsg(PVSMESSAGE, tar, msg, 0); + + // Send the message. + if (_chatServerConnection) + _chatServerConnection->sendMessage(myMsg); + else + ConsoleLog writeError("[CHAT] Chat get no server connection"); // no ServerConnection + +} + +// Handle messages from server. +void PVSChatClient::receive(PVSMsg recv) +{ + PVSChatMsg chatMsg(recv); + + if(chatMsg.isCommand()) // command message for update of the client list. + { + _chatCommandDispatcher.fire(chatMsg); + } + else // conversation message. + { + if(chatMsg.getMsg().size()) + _chatMessageDispatcher.fire(chatMsg); + } +} + +// Return the current list of logged Clients. +QStringList PVSChatClient::getClients() +{ + return _clients; +} + +// Return the ip of the username. +QString PVSChatClient::getIPFromUsername(QString username) +{ + if(_clientsData.contains(username)) + { + return _clientsData.value(username); + } + else + { + ConsoleLog writeError("[CHAT] Wanted key was not found in clients hash table."); + return QString("ip not found"); + } +} + +// Add the name and ip of a new client. +void PVSChatClient::addClient(QString name, QString ip) +{ + if(!_clients.contains(name)) + { + _clients.append(name); + _clientsData[name] = ip; + } + else + { + ConsoleLog writeError("[CHAT] The new client wasn't added, because exists allready."); + } +} + +// Remove the name and ip of a removed client. +void PVSChatClient::removeClient(QString name) +{ + if(_clients.contains(name)) + { + _clients.removeOne(name); + _clientsData.remove(name); + } + else + { + ConsoleLog writeError("[CHAT] The new client can not be removed, because doesn't exist."); + } +} + +// Delete all infomation about client. +void PVSChatClient::clearClients() +{ + _clients.clear(); + _clientsData.clear(); +} diff --git a/src/core/pvsChatClient.h b/src/core/pvsChatClient.h new file mode 100644 index 0000000..2cb5d9f --- /dev/null +++ b/src/core/pvsChatClient.h @@ -0,0 +1,71 @@ +/* +# 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/ +*/ + +// pvsChatClient.h + +#ifndef PVSCHATCLIENT_H_ +#define PVSCHATCLIENT_H_ + +#include <iostream> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sstream> +#include <fstream> +#include <QStringList> +#include <QHash> +#include "src/net/pvsMsg.h" +#include "src/core/pvsChatMsg.h" +#include "src/net/pvsServerConnection.h" +#include "src/util/consoleLogger.h" +#include "src/util/util.h" + +class PVS; // forward declaration. + +class PVSChatClient +{ + +public: + + PVSChatClient(); + ~PVSChatClient(); + void setServerConnection(PVSServerConnection* sc); + void setSource(QString name); + QString getSource(); + QStringList getClients(); + QString getIPFromUsername(QString username); + void addClient(QString name, QString ip); + void removeClient(QString name); + void clearClients(); + void send(QString tar, QString msg); + void receive(PVSMsg recv); + bool isRegistered(); + EventDispatcher<PVSChatMsg>& getChatMsgHandler() + { + return _chatMessageDispatcher; + }; + EventDispatcher<PVSChatMsg>& getChatCommandHandler() + { + return _chatCommandDispatcher; + }; + +private: + + QString _source; + bool _registered; + QStringList _clients; + QHash<QString, QString> _clientsData; + PVSServerConnection *_chatServerConnection; + EventDispatcher<PVSChatMsg> _chatMessageDispatcher; + EventDispatcher<PVSChatMsg> _chatCommandDispatcher; +}; +#endif diff --git a/src/core/pvsChatMsg.cpp b/src/core/pvsChatMsg.cpp new file mode 100644 index 0000000..7a2d755 --- /dev/null +++ b/src/core/pvsChatMsg.cpp @@ -0,0 +1,108 @@ +/* +# 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/ +*/ + +// pvsChatMsg.cpp + +#include "src/core/pvsChatMsg.h" +#include <QStringList> + +PVSChatMsg::PVSChatMsg(PVSMsg pvsMsg) +{ + QStringList l = pvsMsg.getMessage().split(":"); + + if(l[0] == "") + { + _command = pvsMsg.getIdent(); + _nickFrom = "unseted"; + _nickTo = "unseted"; + _msg = "unseted"; + + if(l[2] == "local") + { + _username = l[1]; + _ip = pvsMsg.getRemoteIp(); + } + else + { + _username = l[1]; + _ip = l[2]; + } + } + else + { + _nickFrom = l[0]; + _msg = pvsMsg.getMessage().remove(0, l[0].size()+1); + _nickTo = pvsMsg.getIdent(); + _command = "unseted"; + _username = "unseted"; + _ip = "unseted"; + } +} + +PVSChatMsg::~PVSChatMsg(){}; + +void PVSChatMsg::setNickFrom(QString nick) +{ + _nickFrom = nick; +} + +void PVSChatMsg::setNickTo(QString nick) +{ + _nickTo = nick; +} + +void PVSChatMsg::setMsg(QString msg) +{ + _msg = msg; +} + +QString PVSChatMsg::getNickFrom() +{ + return _nickFrom; +} + +QString PVSChatMsg::getNickTo() +{ + return _nickTo; +} + +QString PVSChatMsg::getMsg() +{ + return _msg; +} + +QString PVSChatMsg::getCommand() +{ + return _command; +} + +QString PVSChatMsg::getUsername() +{ + return _username; +} + +QString PVSChatMsg::getIp() +{ + return _ip; +} + +bool PVSChatMsg::isCommand() +{ + if(_command == "unseted") + { + return false; + } + else + { + return true; + } +} diff --git a/src/core/pvsChatMsg.h b/src/core/pvsChatMsg.h new file mode 100644 index 0000000..0a9793e --- /dev/null +++ b/src/core/pvsChatMsg.h @@ -0,0 +1,48 @@ +/* +# 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/ +*/ + +// pvsChatMsg.h + +#include "src/net/pvsMsg.h" + +#ifndef PVSCHATMSG_H_ +#define PVSCHATMSG_H_ + +class PVSChatMsg +{ +public: + + PVSChatMsg(PVSMsg pvsMsg); + ~PVSChatMsg(); + + void setNickFrom(QString nick); + void setNickTo(QString nick); + void setMsg(QString msg); + QString getNickFrom(); + QString getNickTo(); + QString getMsg(); + QString getCommand(); + QString getUsername(); + QString getIp(); + bool isCommand(); + + +private: + QString _msg; + QString _nickFrom; + QString _nickTo; + QString _command; + QString _username; + QString _ip; +}; + +#endif /* PVSCHATMSG_H_ */ diff --git a/src/core/pvsClient.cpp b/src/core/pvsClient.cpp new file mode 100644 index 0000000..0d08b1d --- /dev/null +++ b/src/core/pvsClient.cpp @@ -0,0 +1,301 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/core/pvsConnection.cpp +# - ... +# ----------------------------------------------------------------------------- +*/ + +#include "pvsClient.h" +#include "pvsServer.h" +#include "pvsConnectionManager.h" +#include "src/util/consoleLogger.h" +#include "src/core/vncConnection.h" +#include "src/gui/mainWindow.h" + +#define CONST_PASS "" + +PVSClient::PVSClient(PVSClientConnection *newClient) +{ + newClient->setParent(this); // so the object will be deleted when this object dies + _pvsClientConnection = newClient; + _vncConnection = NULL; + _vncRwPasswordReceived = _vncPasswordReceived = _vncAllowed = false; + _vncInitMutex = false; + _hostString = newClient->getAddress(); + _hostName = _hostString; // for now + //_gotFrame = false; + _vncPort = -1; + _vncProject = false; + _connectionFrame = NULL; + _loginName = "unseted"; +} + +PVSClient::~PVSClient() +{ + if (_vncConnection) + { + disconnect(_vncConnection, SIGNAL(finished()), this, SLOT(vncFinished())); + _vncConnection->clear(); + delete _vncConnection; + _vncConnection = NULL; + } +} + +/* TODO: Call this method from an extra thread. + * Imo there should be one thread (probably in ConnectionManager) that does this job. + * Also, this function should just receive the data etc, but the actual drawing has to happen + * in the Qt main thread (the thread the window belongs to) + * Right now with GTK it would, but pay attention when switching to Qt + * */ + +void PVSClient::tick() +{ + if (_vncInitMutex) return; + if (_vncPasswordReceived && _vncAllowed && _vncRequested && _vncConnection == NULL) + { + vncProbe(); + } +} + +QString PVSClient::getIp() +{ + return _hostString; +} + +QString PVSClient::getDesktopName() +{ + if (_vncConnection) + { + return _vncConnection->getDesktopName(); + } + + return _hostName; +} + +QString PVSClient::getUserName() +{ + return _userName; +} + +QString PVSClient::getLoginName() +{ + return _loginName; +} + +//Returns Port +int PVSClient::getPort(){ + return _vncPort; +} + + +bool PVSClient::getVNCAllowed() +{ + return _vncAllowed; +} + +void PVSClient::requestVNCConnect() +{ + _vncRequested = true; + _pvsClientConnection->push_back_send(PVSMsg(PVSCOMMAND, "VNCREQUEST", "YES")); +} + +void PVSClient::setVncPassword(QString password) +{ + _vncPassword = password; + _vncPasswordReceived = true; +} + +void PVSClient::setVncRwPassword(QString password) +{ + _vncRwPassword = password; + _vncRwPasswordReceived = true; +} + +QString PVSClient::getPassword() +{ + return _vncPassword; +} + +QString PVSClient::getRWPassword() +{ + return _vncRwPassword; +} + +void PVSClient::setProject(bool value) +{ + _vncProject = value; + +} + +void PVSClient::setVncPort(int newPort) +{ + if (newPort < 1) + { + ConsoleLog writeNetwork("Client sent invalid vnc-port."); + return; + } + _vncPort = newPort; + ConsoleLog writeNetwork(QString("Received new vnc-port: ").append(int2String(newPort))); +} +void PVSClient::setAllowed(bool allow) +{ + _vncAllowed = allow; + + if (allow) + { + ConsoleLog writeLine(QString("VNCConnection was granted by the Client.")); + _vncRequested = true; + } + else + { + ConsoleLog writeLine(QString("VNCConnection was denied by the Client.")); + _vncPort = 0; + _vncPasswordReceived = false; + } + + if(_vncProject){ + if(allow){ + MainWindow::getConnectionWindow()->projectStations(_hostString); + } + else{ + _vncProject = false; + } + } +} + +void PVSClient::shutDownVNC() +{ + if (_vncConnection) + { + disconnect(_vncConnection, SIGNAL(finished()), this, SLOT(vncFinished())); + _vncConnection->clear(); + delete _vncConnection; + _vncConnection = NULL; + } +} + +void PVSClient::shutDownClient() +{ + if (_pvsClientConnection) + { + _pvsClientConnection->closeConnection(); + } +} + +void PVSClient::onClientDisconnected() +{ + _pvsClientConnection = NULL; + +} + +bool PVSClient::getLocked() +{ + // TODO: Implement! + // Previously "_pvsClientConnection->isLocked()" war returned, + // but that method always returned "false" and was removed now. + // It really didn't make any sense to put that there anyways, it has + // to be taken care of in this class. + return false; +} + + +bool PVSClient::sendMessage(PVSMsgType type, QString ident, QString message) +{ + if (_pvsClientConnection) + { + _pvsClientConnection->push_back_send(PVSMsg(type, (char*)ident.toUtf8().data(), message)); + return true; + } + return false; +} + +bool PVSClient::sendMessage(PVSMsg message) +{ + if (_pvsClientConnection) + { + _pvsClientConnection->push_back_send(message); + return true; + } + return false; +} + +void PVSClient::vncProbe() +{ + _vncInitMutex = true; + if (_vncPasswordReceived && _vncAllowed && _vncRequested) + { +#ifndef local_test + QString portString; + if (_vncPort > 0) + { + portString = int2String(_vncPort); + } + else + { + portString = int2String(5900); //std port + ConsoleLog writeError("WARNING: Using default vnc-port 5900"); + } +#else + QString portString; + portString = int2String(5900); +#endif + + if (_hostString.length() > 0) + { + char ** args = new char*[1]; + QString fullstring(_hostString); + fullstring.append(":"); + fullstring.append(portString); + args[0] = new char[fullstring.length()+1]; + std::cout << "[pvsC]connecting to: " << fullstring.toStdString() << std::endl; + ConsoleLog writeNetwork(QString("connecting to: ").append(fullstring)); + //strcpy(args[0], host); + strcpy(args[0], fullstring.toUtf8().data()); + VNCConnectInfo tmpInfo(1, args, _vncPassword); + + VNCConnection* newConnection = new VNCConnection(tmpInfo.getPassword()); + if (newConnection) + { + if (newConnection->initClient(&tmpInfo)) + { + _vncProject = false; + if (_vncConnection) _vncConnection->setDead(); + _vncConnection = newConnection; + connect(_vncConnection, SIGNAL(finished()), this, SLOT(vncFinished())); + //TODO: comment beachten !!!!! + //vncAllowed = false; // to make sure we recheck if the allowance wasnt revoked in the meantime to prevent + // another connection + ConsoleLog writeLine(QString("VNC connection attempt succeeded.")); + MainWindow::getWindow()->getConnectionWindow()->onVNCAdd(this); + } + else + { + delete newConnection; + // TODO: post on the log console + ConsoleLog writeError(QString("VNC connection attempt failed.")); + _vncRequested = false; // otherwise loop of death + } + } + } + } + _vncInitMutex = false; +} + +void PVSClient::vncFinished() +{ + disconnect(_vncConnection, SIGNAL(finished()), this, SLOT(vncFinished())); + delete _vncConnection; + _vncConnection = NULL; + _vncPort = 0; + _vncPasswordReceived = false; +} + diff --git a/src/core/pvsClient.h b/src/core/pvsClient.h new file mode 100644 index 0000000..180995a --- /dev/null +++ b/src/core/pvsClient.h @@ -0,0 +1,129 @@ +/** + * PVSConnection + * + * the representation of a connection from a PVSClient to the PVSServer + * it holds a pointer the PVSClientConnection we got from a PVS(Listen)Server + * and (if present) a pointer to a VNCConnection to the same host as the PVSClientConnection + */ + + + + +#ifndef _PVSCONNECTION_H_ +#define _PVSCONNECTION_H_ +#include "vncConnection.h" +#include "src/net/pvsClientConnection.h" +#include "src/gui/frame.h" +#include <QtCore/QThread> + +class PVSServer; +class VNCConnection; +class PVSClient; +class ConnectionFrame; +class Frame; + +class PVSClient : public QObject +{ + Q_OBJECT + friend class PVSServer; + friend class VNCConnection; + +public: + // C'Tor and D'Tor + PVSClient(PVSClientConnection *newClient); + ~PVSClient(); + + // heartbeat + void tick(); + + + //general stuff + char* getHost(); + QString getIp(); + QString getDesktopName(); + QString getUserName(); + QString getLoginName(); + bool getVNCAllowed(); + int getPort(); + void setUsername(QString name) + { + _userName = name; + }; + void setLoginName(QString ln) + { + _loginName = ln; + }; + + // methods for/from vnConnection + void requestVNCConnect(); + void setVncPassword(QString password); + void setVncRwPassword(QString password); + + QString getPassword(); + QString getRWPassword(); + + void setProject(bool value); + void setAllowed(bool allow); + void setVncPort(int newPort); + void shutDownVNC(); + void shutDownClient(); + /*bool gotFrame(){return _gotFrame;}; + void setFrame(bool gotFrame){_gotFrame = gotFrame;};*/ + ConnectionFrame* getConnectionFrame() + { + return _connectionFrame; + }; + void setConnectionFrame(ConnectionFrame* nFrame) + { + _connectionFrame = nFrame; + }; + void setFrame(Frame *f) + { + _vncFrame = f; + }; + Frame* getFrame() + { + return _vncFrame; + }; + VNCConnection* getVNCConnection() + { + return _vncConnection; + }; + PVSClientConnection* getPVSClientConnection() + { + return _pvsClientConnection; + }; + + // methods for/from PVSClientConnection + void onClientDisconnected(); + bool getLocked(); + bool sendMessage(PVSMsgType type, QString ident, QString message); + bool sendMessage(PVSMsg message); + + void setClientindex(int ind) { _clientIndex = ind; } + int getClientindex() { return _clientIndex; } + int getConnectionId() { return _pvsClientConnection->getID(); } + +private Q_SLOTS: + void vncFinished(); + +private: + + void vncProbe(); + Frame* _vncFrame; + VNCConnection* _vncConnection; + PVSClientConnection *_pvsClientConnection; + ConnectionFrame* _connectionFrame; + int _vncPort; + bool _gotFrame; + QString _hostString; + QString _hostName; + QString _userName; + QString _loginName; + QString _vncPassword; + QString _vncRwPassword; + int _clientIndex; + bool _vncAllowed, _vncRequested, _vncPasswordReceived, _vncRwPasswordReceived, _vncInitMutex, _vncProject; +}; + +#endif diff --git a/src/core/pvsConnectionManager.cpp b/src/core/pvsConnectionManager.cpp new file mode 100644 index 0000000..8a35ca9 --- /dev/null +++ b/src/core/pvsConnectionManager.cpp @@ -0,0 +1,483 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/core/pvsConnectionManager.cpp +# ----------------------------------------------------------------------------- +*/ + +#include "pvsConnectionManager.h" +#include "src/gui/mainWindow.h" +#include <QApplication> +#include "src/setup.h" +#include "src/util/CertManager.h" +#include "src/util/serviceDiscoveryUtil.h" + +PVSConnectionManager* PVSConnectionManager::singleCM; + + +PVSConnectionManager* PVSConnectionManager::getManager() +{ + if (!singleCM) + singleCM = new PVSConnectionManager(); + return singleCM; +} + +PVSConnectionManager::PVSConnectionManager() +{ + _busy = false; + _needPassword = false; + loadCommands(); + ConsoleLog writeLine(QString("Connection Manager created.")); + ConsoleLog writeChat("Log for chat is now running"); + + if (!(_pvsServer.startListen(SERVER_PORT_INT))) + ConsoleLog writeError(QString("Server listening failed!")); + setUpdateRate(500); + _sdBroadcaster.setFingerprint( + CertManager::getCertificate("manager").digest(QCryptographicHash::Sha1) + ); + _timerId = startTimer(1000); +} + +PVSConnectionManager::~PVSConnectionManager() +{ + killTimer(_timerId); +} + +void PVSConnectionManager::setUpdateRate(int newRate) +{ + // TODO: Iterate over list of clients and set the updateRate on each vncConnection + // Object. The timer does not influence the update rate of the thumbs, thus the code + // here was removed. +} + +void PVSConnectionManager::timerEvent(QTimerEvent *event) +{ + update(); +} + +void PVSConnectionManager::onClientNew(PVSClientConnection* newConnection) +{ + PVSClient* tmp = getClientFromConnection(newConnection); + if (tmp == NULL) + { + PVSClient* newCon = new PVSClient(newConnection); + _listClients.push_back(newCon); + sendEventToClients(QString("addedConnection"), newConnection, ""); + } + else + { + // already got that one... strange, eh? + } +} + +void PVSConnectionManager::onClientRemove(PVSClientConnection* removedConnection) +{ + PVSClient* tmp = getClientFromConnection(removedConnection); + if (tmp == NULL) return; + MainWindow::getWindow()->removeConnection(tmp); + removeConnection(tmp); + if(tmp->getUserName().length() > 0) + { + ConsoleLog writeChat(tmp->getUserName()+" has left the chat."); + sendEventToClients("removedClient", removedConnection , tmp->getUserName()+":"+tmp->getIp()); + } +} + +// Inform all chat clients about a new event. +void PVSConnectionManager::sendEventToClients(QString event, PVSClientConnection* connection, QString clientName) +{ + if(event.compare("addedConnection") == 0) + { + // send the client list to new Connection. + for (std::list<PVSClient*>::iterator it = _listClients.begin(); it != _listClients.end(); it++) + { + QString name = (**it).getUserName(); + QString ip = (**it).getIp(); + if (name.length() == 0) continue; + connection->push_back_send(PVSMsg(PVSMESSAGE, "clientToAdd", ":" + name + ":" + ip, 0)); + } + } + if(event.compare("addedClient") == 0) + { + // send name to everybody to all connected clients. + _pvsServer.sendToAll(PVSMsg(PVSMESSAGE, "clientToAdd", ":" + clientName, 0)); + connection->push_back_send(PVSMsg(PVSMESSAGE, "assignedName", ":" + clientName, 0)); + connection->push_back_send(PVSMsg(PVSMESSAGE, "clientToAdd", ":PVSMGR:local", 0)); + } + if(event.compare("removedClient") == 0) + { + // send name of removed client to connected clients. + _pvsServer.sendToAll(PVSMsg(PVSMESSAGE, "clientToRemove", ":"+ clientName, 0)); + } +} + +PVSClient* PVSConnectionManager::getClientFromConnection(PVSClientConnection* client) +{ + if (!_listClients.empty()) + { + + for (std::list<PVSClient*>::iterator it = _listClients.begin(); it != _listClients.end(); it++) + { + if ((*it)->getPVSClientConnection()) + { + if ((*it)->getPVSClientConnection() == client) + { + return (*it); + } + } + } + } + return NULL; +} + +PVSClient* PVSConnectionManager::getClientFromConnectionId(int id) +{ + if (_listClients.empty()) return NULL; + for (std::list<PVSClient*>::iterator it = _listClients.begin(); it != _listClients.end(); it++) + { + if ((*it)->getConnectionId() == id) return (*it); + } + return NULL; +} + +PVSClient* PVSConnectionManager::getClientFromVNCConnection(VNCConnection* client) +{ + if (!_listClients.empty()) + { + + for (std::list<PVSClient*>::iterator it = _listClients.begin(); it != _listClients.end(); it++) + { + if ((*it)->getVNCConnection()) + { + if ((*it)->getVNCConnection() == client) + { + return (*it); + } + } + } + } + return NULL; +} + +PVSClient* PVSConnectionManager::getClientFromIp(QString ip) +{ + if (!_listClients.empty()) + { + for (std::list<PVSClient*>::iterator it = _listClients.begin(); it != _listClients.end(); it++) + { + // ok, probably this could be handled better inside the PVSConnection itself + // but makeshift for now + if ((*it)->getPVSClientConnection()) + { + if ((*it)->getIp() == ip) + { + return (*it); + } + } + } + } + return NULL; +} + +void PVSConnectionManager::onCommand(PVSMsg command) +{ + QString message = command.getMessage(); + QString ident = command.getIdent(); + if (ident.compare("VNCSRVRESULT") == 0) + { + int e = string2Int(message); + QString id = int2String(command.getSndID()); + switch (e) + { + case 0: + ConsoleLog writeLine("[Client: " + id + ", VNCSRV] Server should be running"); + break; + case 1: + ConsoleLog writeError("[Client: " + id + ", VNCSRV] Server returned general error"); + break; + case 2: + ConsoleLog writeError("[Client: " + id + ", VNCSRV] ~/.pvs/vncpasswd not found"); + break; + case 3: + ConsoleLog writeError("[Client: " + id + ", VNCSRV] VNC-Script not found"); + break; + case 127: + ConsoleLog writeError("[Client: " + id + ", VNCSRV] command not found (vnc-server installed?)"); + break; + default: + ConsoleLog writeError("[Client: " + id + ", VNCSRV] unknown error"); + break; + } + } +} +void PVSConnectionManager::onChat(PVSMsg chatMsg) +{ + + QString nick_to = chatMsg.getIdent(); + int sndID = chatMsg.getSndID(); + PVSClientConnection* clientConnection = NULL; + PVSClient* client; + QStringList l = chatMsg.getMessage().split(":"); + QString nick_from = l[0]; + QString msg = chatMsg.getMessage().remove(0, l[0].size()+1); + + if (nick_to == "@all") // public message. + { + _pvsServer.sendToAll(chatMsg); + MainWindow::getWindow()->receiveChatMsg(nick_from, nick_to, msg);// get Msg on PVSMgr's Chat-GUI. + ConsoleLog writeChat(nick_from +" wrote '"+msg+"' in @all-Channel."); + } + else // private message. + { + if(nick_from == "PVSMGR") //Msg from Server + { + MainWindow::getWindow()->receiveChatMsg(nick_from, nick_to, msg); // get Msg on PVSMgr's Chat-GUI. + ConsoleLog writeChat(nick_from+" wrote '" + msg + "' to " + nick_to); // write the event to the chat log. + } + else + { + clientConnection = _pvsServer.getConnectionFromId(sndID); // become your own message. + if (clientConnection) + { + clientConnection->push_back_send(chatMsg); + } + else + { + ConsoleLog writeError("Got Chat Message from unknown ID"); + } + } + if(nick_to == "PVSMGR") //Msg to Server + { + MainWindow::getWindow()->receiveChatMsg(nick_from, nick_to, msg); // get Msg on PVSMgr's Chat-GUI. + ConsoleLog writeChat(nick_from+" wrote '" + msg + "' to " + nick_to);// write the event to the chat log. + } + else + { + client = getClientFromUsername(nick_to); // private receiver become the message. + if (client) + { + client->sendMessage(chatMsg); + ConsoleLog writeChat(nick_from+" wrote '" + msg + "' to " + nick_to);// write the event to the chat log. + } + else + { + ConsoleLog writeError("[CHAT] There is no client with username: " + nick_to); + } + } + + } +} + +PVSClient* PVSConnectionManager::getClientFromUsername(QString name) +{ + if (!(_listClients.empty())) + { + // Check for ping timeout + for (std::list<PVSClient*>::iterator it = _listClients.begin(); it!= _listClients.end(); it++) + { + PVSClient *client = *it; + if (client) + if (client->getUserName() == name) + return client; + } + } + return NULL; +} + +void PVSConnectionManager::onLoginPassword(PVSMsg command) +{ + if (!_needPassword) return; // No password required + if (_password == command.getMessage()) return; // No password set + PVSClient* tmp = getClientFromConnectionId(command.getSndID()); + tmp->sendMessage( + PVSMsg(PVSLOGIN, "FAILED", "Wrong password.") + ); + tmp->shutDownClient(); +} + +// Set usernamen and loginname a client. +void PVSConnectionManager::onLoginUsername(PVSMsg command) +{ + QStringList l = command.getMessage().split(","); + PVSClient* tmp = getClientFromConnectionId(command.getSndID()); + if (tmp->getUserName().length() > 0) return; + ConsoleLog writeError("(PVSConnectionManager::onUsername) was fired."); + if(l[0] == "PVSMGR") + { + l[0] = "fake_PVSMGR"; + } + int counter = 0; + QString uname = l[0]; + while (getClientFromUsername(uname) != NULL) + { + uname = l[0].append(QString::number(counter++, 16)); + } + if (tmp) + { + tmp->setUsername(uname); + tmp->setLoginName(l[1]); + MainWindow::getWindow()->addConnection(tmp); + ConsoleLog writeChat(tmp->getUserName()+" has joined the chat."); + sendEventToClients(QString("addedClient"), tmp->getPVSClientConnection(), tmp->getUserName() +":"+ tmp->getIp()); + } + else + ConsoleLog writeError("(PVSConnectionManager::onUsername) Couldnt find connection to user-id"); +} + +void PVSConnectionManager::onVncPassword(PVSMsg command) +{ + PVSClient* tmp = getClientFromConnectionId(command.getSndID()); + + if (tmp) + { + tmp->setVncPassword(command.getMessage()); + return; + } + else + ConsoleLog writeError("couldnt find matching connection to id!"); +} + +void PVSConnectionManager::onVncRwPassword(PVSMsg command) +{ + PVSClient* tmp = getClientFromConnectionId(command.getSndID()); + + if (tmp) + { + tmp->setVncRwPassword(command.getMessage()); + return; + } + else + ConsoleLog writeError("couldnt find matching connection to id!"); +} + +void PVSConnectionManager::onVncAllow(PVSMsg command) +{ + PVSClient* tmp = getClientFromConnectionId(command.getSndID()); + + if (tmp) + { + if (command.getMessage().compare("YES") == 0) + { + tmp->setAllowed(true); + return; + } + tmp->setAllowed(false); + } +} + +void PVSConnectionManager::onVncPort(PVSMsg command) +{ + PVSClient* tmp = getClientFromConnectionId(command.getSndID()); + if (tmp) + { + int port = string2Int(command.getMessage()); + if (port > 0) + tmp->setVncPort(port); + } + +} + +void PVSConnectionManager::onVncProjection(PVSMsg command) +{ + if (command.getMessage().compare(QString("YES")) == 0) + ConsoleLog writeLine("Client is watching.(connected via vnc)"); + if (command.getMessage().compare(QString("NO")) == 0) + ConsoleLog writeLine("Client failed to connect via vnc."); +} + +void PVSConnectionManager::removeConnection(PVSClient* newConnection) +{ + if (newConnection != NULL) + { + for (std::list<PVSClient*>::iterator it = _listClients.begin(); it != _listClients.end(); it++) + { + if (newConnection == (*it)) + { + // remove it from the list to keep this method from causing trouble when being called more than + // once in the process + _listClients.remove(newConnection); + + // it is important to tell the GUI that the vnc is gone (or ... will be) + // before we really shut it down, since the removal procedure of the + // frames shouldnt be messed with from here. + MainWindow::getWindow()->onConnectionRemoved(newConnection); // to kill vncConnection + + // now that the gui nows about it and does no longer call the vnc-stuff + newConnection->shutDownVNC(); + // and its gone... + + // clean up on the connection + newConnection->shutDownClient(); // just to be sure + newConnection->onClientDisconnected(); + + + newConnection->deleteLater(); + return; + } + } + } + else + { + // well, not our problem obviously + } +} + +bool PVSConnectionManager::update() +{ + if (_busy) return true; // already ongoing, so scrap that. + + _busy = true; // lock method + + if (!_listClients.empty()) + { + // now update the rest and check if they are alive + // otherwise mark dead connections + for (std::list<PVSClient*>::iterator it = _listClients.begin(); it != _listClients.end(); it++) + { + PVSClient* current = (*it); + current->tick(); + } + } + + //QApplication::processEvents(QEventLoop::AllEvents, 5); + + _busy = false; // we're done, so unlock + return true; +} + +void PVSConnectionManager::loadCommands() +{ + _pvsServer.addLoginHandler("USERNAME", this, &PVSConnectionManager::onLoginUsername); + _pvsServer.addLoginHandler("PASSWORD", this, &PVSConnectionManager::onLoginPassword); + _pvsServer.addCommandHandler("*", this, &PVSConnectionManager::onCommand); + _pvsServer.addCommandHandler("VNC", this, &PVSConnectionManager::onVncAllow); + _pvsServer.addCommandHandler("PORT", this, &PVSConnectionManager::onVncPort); + _pvsServer.addCommandHandler("PASSWORD", this, &PVSConnectionManager::onVncPassword); + _pvsServer.addCommandHandler("RWPASSWORD", this, &PVSConnectionManager::onVncRwPassword); + _pvsServer.addCommandHandler("PROJECTING", this, &PVSConnectionManager::onVncProjection); + _pvsServer.addChatHandler("*", this, &PVSConnectionManager::onChat); +} + +QString PVSConnectionManager::setNeedPassword(bool enabled) +{ + _needPassword = enabled; + if (enabled && _password.isEmpty()) + { + _password = QString::number(getRandom(1000, 9999), 10); + } + return _password; +} + +QString PVSConnectionManager::getSessionName() +{ + return sha1ToReadable(CertManager::getCertificate("manager").digest(QCryptographicHash::Sha1)); +} diff --git a/src/core/pvsConnectionManager.h b/src/core/pvsConnectionManager.h new file mode 100644 index 0000000..5f5fcca --- /dev/null +++ b/src/core/pvsConnectionManager.h @@ -0,0 +1,118 @@ +/** + * The PVSConnection Manager is the heart and core of the PVS. He creates, updates, delivers and deletes the connections. + * + */ + + + +// TODO: +// make it look good ;-) + + + +#include <QtGui> +#include <iostream> +#include <fstream> +#include <list> +#include <src/core/pvsClient.h> +#include <src/gui/mainWindow.h> +#include <src/core/pvsServer.h> +#ifndef _PVSCONNECTIONMANAGER_H_ +#define _PVSCONNECTIONMANAGER_H_ +#ifndef RFBCLIENT_H +extern "C" +{ +#include <rfb/rfbclient.h> +} +#endif + +#define PROFILE +#include <src/util/timeUtil.h> +#include <src/util/consoleLogger.h> +#include "src/net/pvsServiceBroadcast.h" + + + +class PVSConnectionManager; //forward declaration +class PVSClient; +class PVSListenSever; +class MainWindow; + +class PVSConnectionManager : public QObject +{ +public: + // singleton getter + static PVSConnectionManager* getManager(); + + ~PVSConnectionManager(); + + // PVSServer control/get/set methods + PVSServer* getServer() + { + return &_pvsServer; + }; + + // VNCConnection related static method + //static void onFBUpdate(rfbClient* client, int x, int y, int w, int h); + + + // gui update frequency + void setUpdateRate(int newRate); + + + // PVSConnection control/get/set methods + std::list<PVSClient*> getConnections() + { + return _listClients; + }; + void onClientNew(PVSClientConnection* newConnection); // called by the server when a new client connects + void onClientRemove(PVSClientConnection* removedConnection); // called by the server when a new client disconnects (on its own) + PVSClient* getClientFromConnection(PVSClientConnection* client); + PVSClient* getClientFromConnectionId(int id); + PVSClient* getClientFromVNCConnection(VNCConnection* client); + PVSClient* getClientFromIp(QString ip); // returns connection with hostname 'host' + PVSClient* getClientFromUsername(QString name); // returns connection with username 'name' + // these methods are called by the PVSServer which forwards the command/etc handling to the CM + void onCommand(PVSMsg command); + void onChat(PVSMsg chatMsg); + void onVncPassword(PVSMsg command); + void onVncRwPassword(PVSMsg command); + void onLoginUsername(PVSMsg command); + void onLoginPassword(PVSMsg command); + void onVncAllow(PVSMsg command); + void onVncPort(PVSMsg command); + void onVncProjection(PVSMsg command); + + void sendEventToClients(QString event, PVSClientConnection* newConnection, QString newClientName); // informs every connected clients about a new client or a removed client. + + void removeConnection(PVSClient* removedConnection); // removes and deletes the connection !DOES NOT DISCONNECT DIRECTLY! + PVSClient* getNewConnection(VNCConnectInfo* newConInfo); // returns a new connection object based on the VNCConnectInfo or NULL + + bool isBusy() { return _busy; } + + QString setNeedPassword(bool enabled); + QString getSessionName(); + +protected: + void timerEvent(QTimerEvent *event); + +private: + // C'Tor + PVSConnectionManager(); // private due to singleton pattern + // internal control methods + bool update(); // does the update and cleaning routines and makes sure the framebuffers in the connection objects are up to date + void loadCommands(); + + // Member + std::list<PVSClient*> _listClients; // list of all verified clients + PVSServer _pvsServer; // the server that handles the pvsConnections + static PVSConnectionManager* singleCM; // the CM itself + bool _busy; // to keep timed calls from starting another update before the old one is thru. + PVSServiceBroadcast _sdBroadcaster; ///< Service discovery handling + + QString _password; ///< Password required to connect (can be empty) + bool _needPassword; + int _timerId; +}; + +#endif diff --git a/src/core/pvsServer.cpp b/src/core/pvsServer.cpp new file mode 100644 index 0000000..916ad89 --- /dev/null +++ b/src/core/pvsServer.cpp @@ -0,0 +1,22 @@ +#include "pvsConnectionManager.h" +#undef Q_FOREACH +#include "pvsServer.h" + + +PVSServer::PVSServer(int port) + :PVSListenServer(port,0) +{ +} + + +void PVSServer::onClientConnected(PVSClientConnection* connected) +{ + PVSListenServer::onClientConnected(connected); + PVSConnectionManager::getManager()->onClientNew(connected); +} +void PVSServer::onClientDisconnected(PVSClientConnection* disconnected) +{ + PVSConnectionManager::getManager()->onClientRemove(disconnected); + PVSListenServer::onClientDisconnected(disconnected); +} + diff --git a/src/core/pvsServer.h b/src/core/pvsServer.h new file mode 100644 index 0000000..acd9c61 --- /dev/null +++ b/src/core/pvsServer.h @@ -0,0 +1,24 @@ +/** + * A derivate of PVSListenServer and used by the PVSConnectionManager to handle incoming connections + * which then return pointers to their PVSClientConnections to the manager to handle + * in and outgoing messsages/commands + * + */ + + + +#include <src/net/pvsListenServer.h> + +#ifndef _PVSSERVER_H_ +#define _PVSSERVER_H_ + +class PVSServer : public PVSListenServer +{ +public: + PVSServer(int port = 0); +private: + virtual void onClientConnected(PVSClientConnection* connected); + virtual void onClientDisconnected(PVSClientConnection* disconnected); +}; + +#endif diff --git a/src/core/vncConnection.cpp b/src/core/vncConnection.cpp new file mode 100644 index 0000000..1864e77 --- /dev/null +++ b/src/core/vncConnection.cpp @@ -0,0 +1,261 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/core/vncConnection.cpp +# ----------------------------------------------------------------------------- +*/ + + +#include "vncConnection.h" +#include <iostream> +#include <src/core/pvsConnectionManager.h> +#include <src/core/pvsClient.h> +#include <src/gui/connectionFrame.h> + + +//***********************************************************************************// +// VNCConnection // +//***********************************************************************************// + + + +VNCConnection::VNCConnection(QString newPass) +{ + thread = NULL; + pwSet = false; + if (newPass != "") + { + password = newPass; + pwSet = true; + } + else + password = ""; + first = true; + view_only = true; + locked = false; + myFrame = NULL; +} + +VNCConnection::~VNCConnection() +{ + setDead(); +} + +bool VNCConnection::initClient(VNCConnectInfo* newConInfo) +{ + int argc = newConInfo->getCount(); + char** argv = newConInfo->getArguments(); + + if (argc > 0) + { + + stringHost = QString(argv[0]); + + /*QString cropHost = colonSplitter(stringHost, true); + QString cropPort = colonSplitter(stringHost, false);*/ + _host = colonSplitter(stringHost, true); + _port = colonSplitter(stringHost, false); + /*if (!(cropHost.size())) + cropHost = stringHost; + if (!(cropPort.size())) + _port = 5900; + password = newConInfo->getPassword(); + _host = cropHost; + thread = new VNCClientThread(_host, 5900, password , 0, 500);*/ + if (!(_host.size())) + _host = stringHost; + if (!(_port.size())) + _port = QString("5900"); + thread = new VNCClientThread(_host, string2Int(_port), newConInfo->getPassword(), 0, 500); + connect(thread, SIGNAL(finished()), this, SIGNAL(finished())); + + return true; + } + + rfbClientLog("init failed\n"); + emit finished(); + return false; +} + +/* + * disconnect and terminate the current connection and set a new one. + */ +void VNCConnection::reInitClientWithQuality(int quality) +{ + disconnect(thread, SIGNAL(finished()), this, SIGNAL(finished())); + thread->terminate = true; + thread = new VNCClientThread(_host, string2Int(_port), password , quality, 500); + connect(thread, SIGNAL(finished()), this, SIGNAL(finished())); +} + +bool VNCConnection::isOK() +{ + return thread != NULL && thread->isRunning(); +} + +bool VNCConnection::viewOnly() +{ + return view_only; +} + +void VNCConnection::setDead() +{ + if (thread != NULL) + { + disconnect(thread, SIGNAL(finished()), this, SIGNAL(finished())); + if (thread->isRunning()) + { + thread->terminate = true; + thread->wait(2000); + } + delete thread; + thread = NULL; + } +} + +void VNCConnection::clear() +{ + setDead(); + + if (myFrame) + { + myFrame = NULL; + } +} + +void VNCConnection::setFrame(ConnectionFrame* newFrame) +{ + if (newFrame) + { + if (myFrame) + { + // TODO: Tell it that we left? + } + myFrame = newFrame; + if (thread != NULL) myFrame->setToolTip(thread->getDesktopName()); + myFrame->setRatio(ratio); + myFrame->setOversized(overSized); + } +} + +ConnectionFrame* VNCConnection::getFrame() +{ + return myFrame; +} + +char* VNCConnection::getPassword(rfbClient* myClient) +{ + // better off somewhere else? + + QString tmpPassword; + QString serverHost(myClient->serverHost); + QString cropHost = colonSplitter(serverHost, true); + if (!(cropHost.size())) + cropHost = serverHost; + if (PVSClient* selfConnection = PVSConnectionManager::getManager()->getClientFromIp(cropHost)) // no candidate means false call anyway + { + tmpPassword = selfConnection->getPassword(); + } + else + { + tmpPassword = ""; + ConsoleLog writeError("Couldn't find a matching connection to retrieve a password from!"); + } + if (tmpPassword.length() > 8) // shorten if pw is too long + { + std::cout << "VNCConnection::getPassword() given password too long, cutting it down to 8 chars!" << std::endl; + tmpPassword = tmpPassword.mid(0,8); + } + + + char* pw = new char[9]; + strcpy(pw, tmpPassword.toUtf8().data()); + return pw; +} + +QString VNCConnection::getPassword() +{ + return password; +} + +bool VNCConnection::getPWSet() +{ + return pwSet; +} + +QString VNCConnection::getDesktopName() +{ + if (_desktopName.isNull() && thread != NULL && thread->isRunning()) _desktopName = thread->getDesktopName(); + return _desktopName; +} + +VNCClientThread* VNCConnection::getVNCClientThread() +{ + if (thread) + return thread; + return NULL; +} + + + +//***********************************************************************************// +// VNCConnectInfo // +//***********************************************************************************// + + + +VNCConnectInfo::VNCConnectInfo() +{ + count = 0; + arguments = NULL; + password = ""; + passwordSupplied = false; +} + +VNCConnectInfo::VNCConnectInfo(int newCount, char** newArgs, QString pass) +{ + if (pass == "") + setArguments(newCount, newArgs); + else + setArguments(newCount, newArgs, pass); +} + +VNCConnectInfo::~VNCConnectInfo() +{ + if (arguments) + delete[] arguments; +} + +void VNCConnectInfo::setArguments(int newCount, char** newArgs, QString pass) +{ + count = newCount; + arguments = newArgs; + if (pass != "") + { + password = pass; + passwordSupplied = true; + } +} + +int VNCConnectInfo::getCount() +{ + return count; +} + +char** VNCConnectInfo::getArguments() +{ + return arguments; +} + +QString VNCConnectInfo::getPassword() +{ + return password; +} diff --git a/src/core/vncConnection.h b/src/core/vncConnection.h new file mode 100644 index 0000000..6893135 --- /dev/null +++ b/src/core/vncConnection.h @@ -0,0 +1,99 @@ +/** + * + * VNCConnection + * + * The VNCConnection and the VNCConnectInfo are the Classes containing the information about the vnc-connections. + * While the VNCConnectInfo just holds the information about the token and password / parameters given on + * create time of a new connection, the connection itself contains the C-Object from the vnc library and is + * maintained by the PVSConnectionManger. + */ + + +#ifndef _VNCCONNECTION_H_ +#define _VNCCONNECTION_H_ +extern "C" +{ +#include <rfb/rfbclient.h> +} + +#include <QtGui> +#include "../util/vncClientThread.h" +#include <src/gui/connectionFrame.h> +#include <iostream> +#include <QtCore/QObject> + +#define PROFILE +#include <src/util/timeUtil.h> + + +class VNCConnection; // forward declaration +class ConnectionFrame; +class PVSConnectionManager; +class VNCConnectInfo +{ + //Q_OBJECT +public: + VNCConnectInfo(); //Constructor + VNCConnectInfo(int newCount, char** newArgs, QString pass = ""); // Constructor with instant information feed + ~VNCConnectInfo(); + void setArguments(int newCount, char** newArgs, QString pass = ""); // (re)feed of information + int getCount(); // returns count + bool pwSet() + { + return passwordSupplied; + }; // returns wether a password was set or not + char ** getArguments(); // returns pointer to an array of char arrays holding the given arguments + QString getPassword(); // returns (if given) the password + +private: + char** arguments; + bool passwordSupplied; + QString password; + int count; +}; + +class VNCConnection : public QObject +{ + Q_OBJECT +public: + VNCConnection(QString newPass = ""); // Constructor + ~VNCConnection(); + bool initClient(VNCConnectInfo* newConInfo); // initiates the connection based on the information given with the VNCConnectInfo object + void reInitClientWithQuality(int quality); + bool isOK(); // returns true if not dead, false otherwise + bool viewOnly(); + void setDead(); // marks the connection for removal + void clear(); // does internal cleanup + void setFrame(ConnectionFrame* newFrame); // sets the given frame as its own + ConnectionFrame* getFrame(); // if present, returns the frame + static char* getPassword(rfbClient* client); // is called if a rfbclient-object asks for a password and starts the upward chain to ask for a password + QString getPassword(); // bad overload, since it returns the stored password (if any was given) + QString getHost() + { + return _host; + } + bool getPWSet(); // returns true if a password was given, false otherwise + //Glib::RefPtr<Gdk::Pixbuf> getBuffer(); + bool getBusy() { return busy; } + QString getDesktopName(); + VNCClientThread* getVNCClientThread(); + +Q_SIGNALS: + void finished(); + +private: + VNCClientThread *thread; + ConnectionFrame* myFrame; + QImage img; + QString password, stringHost, _host, _port; + bool pwSet; + bool first; + bool view_only; + bool overSized; + float ratio; + bool busy; + bool locked; + QString _desktopName; +}; + +#endif diff --git a/src/gui/aboutDialog.cpp b/src/gui/aboutDialog.cpp new file mode 100644 index 0000000..a52f70b --- /dev/null +++ b/src/gui/aboutDialog.cpp @@ -0,0 +1,58 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + # ----------------------------------------------------------------------------- + # aboutDialog.cpp + # - shows about dialog + # ----------------------------------------------------------------------------- + */ + +#include "aboutDialog.h" +#include "src/version.h" + +AboutDialog::AboutDialog(QWidget *parent) : + QDialog(parent) +{ + setupUi(this); + + // set version + QString version = tr("Version: ") + (VERSION_STRING); + label_version->setText(version); + + // read authors and write to textEdit + QString authors = ""; + QFile f1(":/AUTHORS"); + if (f1.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QTextStream in(&f1); + authors = in.readAll(); + f1.close(); + } + plainTextEdit_authors->insertPlainText(authors); + plainTextEdit_authors->moveCursor(QTextCursor::Start); + + // read translation and write to textEdit + QString translation = ""; + QFile f2(":/TRANSLATION"); + if (f2.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QTextStream in(&f2); + translation = in.readAll(); + f2.close(); + } + plainTextEdit_translation->insertPlainText(translation); + plainTextEdit_translation->moveCursor(QTextCursor::Start); + +} + +AboutDialog::~AboutDialog() +{ +} diff --git a/src/gui/aboutDialog.h b/src/gui/aboutDialog.h new file mode 100644 index 0000000..5f0489a --- /dev/null +++ b/src/gui/aboutDialog.h @@ -0,0 +1,30 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + */ + +#ifndef ABOUTDIALOG_H_ +#define ABOUTDIALOG_H_ + +#include <QtGui> +#include "ui_aboutDialog.h" + +class AboutDialog: public QDialog, private Ui::AboutDialogClass +{ +Q_OBJECT + +public: + AboutDialog(QWidget *parent = 0); + ~AboutDialog(); + +}; + +#endif /* ABOUTDIALOG_H_ */ diff --git a/src/gui/clientChatDialog.cpp b/src/gui/clientChatDialog.cpp new file mode 100644 index 0000000..7c32790 --- /dev/null +++ b/src/gui/clientChatDialog.cpp @@ -0,0 +1,298 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + # ----------------------------------------------------------------------------- + # clientChatDialog.cpp + # - graphical chat interface + # ----------------------------------------------------------------------------- + */ + +#include "clientChatDialog.h" + +ClientChatDialog::ClientChatDialog(QWidget *parent) : + QDialog(parent) +{ + _trayIcon = NULL; + _nickname = ""; + + setupUi(this); + setAcceptDrops(true); + connect(pushButton, SIGNAL(clicked()), this, SLOT(send())); + + // connect to D-Bus and get interface + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.registerObject("/chat", this); + dbus.registerService("org.openslx.pvsgui"); + _ifaceDBus = new OrgOpenslxPvsInterface("org.openslx.pvs", "/", dbus, this); + connect(_ifaceDBus, SIGNAL(chat_receive(QString, QString, QString)), this, + SLOT(receive(QString, QString, QString))); + + // add first tab for public messages + tabWidget->clear(); + QTextEdit *t = new QTextEdit(); + t->setReadOnly(true); + tabWidget->addTab(t, "@all"); + _hash = new QHash<QString, QTextEdit*> (); + _hash->insert(tabWidget->tabText(0), t); + + // already connected? + QDBusPendingReply<QString> reply = _ifaceDBus->isConnected(); + reply.waitForFinished(); + if (reply.isValid() && reply.value() != "") + { + // get available nicknames if already connected + QDBusPendingReply<QStringList> reply1 = _ifaceDBus->chat_getNicknames(); + reply1.waitForFinished(); + QStringList nicknames = reply1.value(); + if (reply1.isValid() && !nicknames.isEmpty()) + listWidget->addItems(nicknames); + + connected(); + } + else + disconnected(); + + // setup menu + _menu = new QMenu(); + _sendFileAction = new QAction(tr("&Send File..."), this); + _menu->addAction(_sendFileAction); + + connect(listWidget, SIGNAL(doubleClicked(QModelIndex)), this, + SLOT(addTab(QModelIndex))); + connect(tabWidget, SIGNAL(tabCloseRequested(int)), this, + SLOT(removeTab(int))); + connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(removeIcon(int))); + connect(listWidget, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(showMenu(QPoint))); + connect(_sendFileAction, SIGNAL(triggered()), this, + SLOT(sendFile())); + + connect(_ifaceDBus, SIGNAL(chat_client_add(QString)), this, + SLOT(addClient(QString))); + connect(_ifaceDBus, SIGNAL(chat_client_remove(QString)), this, + SLOT(removeClient(QString))); + connect(_ifaceDBus, SIGNAL(disconnected()), listWidget, + SLOT(clear())); + connect(_ifaceDBus, SIGNAL(connected(QString)), this, + SLOT(connected())); + connect(_ifaceDBus, SIGNAL(disconnected()), this, + SLOT(disconnected())); + + lineEdit->setFocus(); +} + +ClientChatDialog::~ClientChatDialog() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// Public + +void ClientChatDialog::setTrayIcon(QSystemTrayIcon *trayIcon) +{ + _trayIcon = trayIcon; + // FIXME: messageClicked() is always emitted, not only on chat msg + //connect(_trayIcon, SIGNAL(messageClicked()), this, SLOT(open())); +} + +//////////////////////////////////////////////////////////////////////////////// +// Protected + +void ClientChatDialog::dragEnterEvent(QDragEnterEvent *event) +{ + if (event->mimeData()->hasUrls()) + event->accept(); +} + +void ClientChatDialog::dropEvent(QDropEvent *event) +{ + event->accept(); + sendFile(event->mimeData()->urls().first().toLocalFile()); +} + +//////////////////////////////////////////////////////////////////////////////// +// Private + +void ClientChatDialog::send() +{ + QString msg = lineEdit->text(); + if (msg != "") + { + QString nick_to = tabWidget->tabText(tabWidget->currentIndex()); + _ifaceDBus->chat_send(nick_to, _nickname, msg); + lineEdit->clear(); + lineEdit->setFocus(); + + qDebug("[%s] S %s -> %s : %s", metaObject()->className(), + qPrintable(_nickname), qPrintable(nick_to), qPrintable(msg)); + } +} + +void ClientChatDialog::receive(QString nick_from, QString nick_to, QString msg) +{ + qDebug("[%s] R %s <- %s : %s", metaObject()->className(), + qPrintable(nick_to), qPrintable(nick_from), qPrintable(msg)); + + if (nick_to == tabWidget->tabText(0) || nick_from == _nickname) + printMsg(nick_from, msg, getTab(nick_to)); // public message or own msg + else + printMsg(nick_from, msg, getTab(nick_from)); // private message +} + +void ClientChatDialog::addTab(QModelIndex i) +{ + QString text = i.data().toString(); + if (_hash->contains(text)) + tabWidget->setCurrentWidget(_hash->value(text)); + else + { + QTextEdit *t = new QTextEdit(); + t->setReadOnly(true); + tabWidget->setCurrentIndex(tabWidget->addTab(t, text)); + _hash->insert(text, t); + } + lineEdit->setFocus(); +} + +void ClientChatDialog::removeTab(int i) +{ + if (i != 0) + { + _hash->remove(tabWidget->tabText(i)); + tabWidget->removeTab(i); + lineEdit->setFocus(); + } +} + +void ClientChatDialog::addClient(QString nick) +{ + listWidget->addItem(nick); + printEvent("-> " + nick + tr(" has joined the chat.")); +} + +void ClientChatDialog::removeClient(QString nick) +{ + delete listWidget->findItems(nick, Qt::MatchExactly).first(); + printEvent("<- " + nick + tr(" has left the chat.")); +} + +void ClientChatDialog::removeIcon(int i) +{ + tabWidget->setTabIcon(i, QIcon()); +} + +void ClientChatDialog::showMenu(QPoint p) +{ + _menu->popup(listWidget->mapToGlobal(p)); +} + +void ClientChatDialog::sendFile() +{ + ClientFileSendDialog *d = new ClientFileSendDialog(this); + d->open(listWidget->currentItem()->text()); +} + +void ClientChatDialog::sendFile(QString filename) +{ + if (tabWidget->currentIndex() == 0 || filename == "") + return; + + // ask user + QString nick = tabWidget->tabText(tabWidget->currentIndex()); + QMessageBox::StandardButton result = QMessageBox::question(0, + tr("PVS File Transfer"), + tr("Send file '") + filename + tr("' to ") + nick + "?", + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); + + if (result != QMessageBox::Ok) + return; + + ClientFileSendDialog *d = new ClientFileSendDialog(this); + d->open(nick, filename); +} + +void ClientChatDialog::connected() +{ + // get current users name from backend + QDBusPendingReply<QString> reply = _ifaceDBus->chat_getNickname(); + reply.waitForFinished(); + if (reply.isValid()) + { + _nickname = reply.value(); + pushButton->setEnabled(true); + printEvent("!!! " + tr("Connected.")); + } + + qDebug("[%s] Nickname: '%s'", metaObject()->className(), + qPrintable(_nickname)); +} + +void ClientChatDialog::disconnected() +{ + pushButton->setEnabled(false); + printEvent("!!! " + tr("Disconnected.")); +} + +QTextEdit* ClientChatDialog::getTab(QString text) +{ + if (!_hash->contains(text)) + { + QTextEdit *t = new QTextEdit(); + t->setReadOnly(true); + tabWidget->addTab(t, text); + _hash->insert(text, t); + } + lineEdit->setFocus(); + return _hash->value(text); +} + +void ClientChatDialog::printMsg(QString nick_from, QString msg, QTextEdit *t) +{ + // move cursor at the end + t->moveCursor(QTextCursor::End); + + // print time + t->setTextColor(QColor(0, 100, 0)); + t->append("[" + QTime::currentTime().toString("hh:mm") + "] "); + + // print nickname + t->setTextColor(QColor(0, 0, 255)); + t->insertPlainText("<" + nick_from + "> "); + + // print message + t->setTextColor(QColor(0, 0, 0)); + t->insertPlainText(msg); + + // show icon if not current tab + if (tabWidget->currentIndex() != tabWidget->indexOf(t)) + tabWidget->setTabIcon(tabWidget->indexOf(t), QIcon(":chat_msg16.svg")); + + // show balloon message if supported and chat-dialog is not visible + if (!isVisible() && _trayIcon && QSystemTrayIcon::supportsMessages()) + _trayIcon->showMessage(tr("Message from <") + nick_from + ">", msg, + QSystemTrayIcon::Information, 20000); +} + +void ClientChatDialog::printEvent(QString msg) +{ + QTextEdit *t = _hash->value(tabWidget->tabText(0)); + + // move cursor at the end + t->moveCursor(QTextCursor::End); + + t->setTextColor(QColor(150, 150, 150)); + + // print time + t->append("[" + QTime::currentTime().toString("hh:mm") + "] "); + + // print message + t->insertPlainText(msg); +} diff --git a/src/gui/clientChatDialog.h b/src/gui/clientChatDialog.h new file mode 100644 index 0000000..42bbb75 --- /dev/null +++ b/src/gui/clientChatDialog.h @@ -0,0 +1,63 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + */ + +#ifndef CLIENTCHATDIALOG_H_ +#define CLIENTCHATDIALOG_H_ + +#include <QtGui> +#include "pvsinterface.h" +#include "clientFileSendDialog.h" +#include "ui_clientChatDialog.h" + +class ClientChatDialog: public QDialog, private Ui::ClientChatDialogClass +{ +Q_OBJECT + +public: + ClientChatDialog(QWidget *parent = 0); + ~ClientChatDialog(); + void setTrayIcon(QSystemTrayIcon *trayIcon); + +private Q_SLOTS: + void send(); + void receive(QString nick_from, QString nick_to, QString msg); + void addTab(QModelIndex i); + void removeTab(int i); + void addClient(QString nick); + void removeClient(QString nick); + void showMenu(QPoint p); + void removeIcon(int i); + void sendFile(); + void sendFile(QString filename); + void connected(); + void disconnected(); + +protected: + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent *event); + +private: + QTextEdit* getTab(QString text); + void printMsg(QString nick_from, QString msg, QTextEdit *t); + void printEvent(QString msg); + + OrgOpenslxPvsInterface *_ifaceDBus; + QHash<QString, QTextEdit*> *_hash; + QSystemTrayIcon *_trayIcon; + QString _nickname; + QMenu *_menu; + QAction *_sendFileAction; + +}; + +#endif /* CLIENTCHATDIALOG_H_ */ diff --git a/src/gui/clientConfigDialog.cpp b/src/gui/clientConfigDialog.cpp new file mode 100644 index 0000000..76b4f5e --- /dev/null +++ b/src/gui/clientConfigDialog.cpp @@ -0,0 +1,105 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + # ----------------------------------------------------------------------------- + # clientConfigDialog.cpp + # - graphical interface + # - all configuration used by pvs/pvsgui is done here + # ----------------------------------------------------------------------------- + */ + +#include "clientConfigDialog.h" + +ClientConfigDialog::ClientConfigDialog(QWidget *parent) : + QDialog(parent) +{ + setupUi(this); + connect(this, SIGNAL(accepted()), this, SLOT(writeSettings())); + connect(radioButtonOtherRO, SIGNAL(clicked()), this, + SLOT(checkPermissions())); + +} + +ClientConfigDialog::~ClientConfigDialog() +{ + +} + +//////////////////////////////////////////////////////////////////////////////// +// Public + +void ClientConfigDialog::open() +{ + readSettings(); + setVisible(true); +} + +void ClientConfigDialog::readSettings() +{ + if (_settings.value("Display/location").isNull()) + comboBox->setCurrentIndex(1); + else + comboBox->setCurrentIndex(_settings.value("Display/location").toInt()); + + if (_settings.value("Permissions/vnc_lecturer").toString() == "rw") + radioButtonLecturerRW->setChecked(true); + else if (_settings.value("Permissions/vnc_lecturer").toString() == "ro") + radioButtonLecturerRO->setChecked(true); + else + radioButtonLecturerNO->setChecked(true); + if (_settings.value("Permissions/vnc_other").toString() == "rw") + radioButtonOtherRW->setChecked(true); + else if (_settings.value("Permissions/vnc_other").toString() == "ro") + radioButtonOtherRO->setChecked(true); + else + radioButtonOtherNO->setChecked(true); + checkBoxAllowChat->setChecked( + _settings.value("Permissions/allow_chat").toBool()); + checkBoxAllowFiletransfer->setChecked(_settings.value( + "Permissions/allow_filetransfer").toBool()); + + qDebug("[%s] Setting read from: '%s'", metaObject()->className(), + qPrintable(_settings.fileName())); +} + +void ClientConfigDialog::writeSettings() +{ + _settings.setValue("Display/location", comboBox->currentIndex()); + if (radioButtonLecturerRW->isChecked()) + _settings.setValue("Permissions/vnc_lecturer", "rw"); + else if (radioButtonLecturerRO->isChecked()) + _settings.setValue("Permissions/vnc_lecturer", "ro"); + else + _settings.setValue("Permissions/vnc_lecturer", "no"); + if (radioButtonOtherRW->isChecked()) + _settings.setValue("Permissions/vnc_other", "rw"); + else if (radioButtonOtherRO->isChecked()) + _settings.setValue("Permissions/vnc_other", "ro"); + else + _settings.setValue("Permissions/vnc_other", "no"); + _settings.setValue("Permissions/allow_chat", checkBoxAllowChat->isChecked()); + _settings.setValue("Permissions/allow_filetransfer", + checkBoxAllowFiletransfer->isChecked()); + _settings.sync(); + emit configChanged(); + + qDebug("[%s] Settings written to: '%s'.", metaObject()->className(), + qPrintable(_settings.fileName())); +} + +//////////////////////////////////////////////////////////////////////////////// +// Private + +void ClientConfigDialog::checkPermissions() +{ + if (radioButtonLecturerNO->isChecked() && radioButtonOtherRO->isChecked()) + radioButtonLecturerRO->setChecked(true); +} diff --git a/src/gui/clientConfigDialog.h b/src/gui/clientConfigDialog.h new file mode 100644 index 0000000..706bd8a --- /dev/null +++ b/src/gui/clientConfigDialog.h @@ -0,0 +1,44 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + */ + +#ifndef CLIENTCONFIGDIALOG_H_ +#define CLIENTCONFIGDIALOG_H_ + +#include <QtGui> +#include "ui_clientConfigDialog.h" + +class ClientConfigDialog: public QDialog, private Ui::ClientConfigDialogClass +{ +Q_OBJECT + +public: + ClientConfigDialog(QWidget *parent = 0); + ~ClientConfigDialog(); + +public Q_SLOTS: + void open(); + void readSettings(); + void writeSettings(); + +Q_SIGNALS: + void configChanged(); + +private Q_SLOTS: + void checkPermissions(); + +private: + QSettings _settings; + +}; + +#endif /* CLIENTCONFIGDIALOG_H_ */ diff --git a/src/gui/clientFileReceiveDialog.cpp b/src/gui/clientFileReceiveDialog.cpp new file mode 100644 index 0000000..669ca81 --- /dev/null +++ b/src/gui/clientFileReceiveDialog.cpp @@ -0,0 +1,181 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + # ----------------------------------------------------------------------------- + # clientFileReceiveDialog.cpp + # - filechooser and progress dialog + # ----------------------------------------------------------------------------- + */ + +#include "clientFileReceiveDialog.h" + +ClientFileReceiveDialog::ClientFileReceiveDialog(QTcpSocket *socket, QWidget *parent) : + QDialog(parent) +{ + setupUi(this); + + _file = NULL; + _bytesToRead = 0; + _socket = socket; + + connect(_socket, SIGNAL(readyRead()), this, SLOT(receiveHeader())); + connect(_socket, SIGNAL(disconnected()), this, SLOT(close())); + connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(error(QAbstractSocket::SocketError))); + + qDebug("[%s] New Connection: %s", metaObject()->className(), + qPrintable(_socket->peerAddress().toString())); + + connect(this, SIGNAL(finished(int)), this, SLOT(deleteLater())); +} + +ClientFileReceiveDialog::~ClientFileReceiveDialog() +{ + _socket->deleteLater(); + qDebug("[%s] Deleted!", metaObject()->className()); +} + +//////////////////////////////////////////////////////////////////////////////// +// Private + +void ClientFileReceiveDialog::receiveHeader() +{ + // parse header + QString header = QString::fromUtf8(_socket->readLine()); + QStringList args = header.split(";"); + QString nick = args[0]; + QString filename = args[1]; + _bytesToRead = args[2].toLongLong(); + div = 1 + _bytesToRead / 1000000000; // bc. progressBar supports only int + + qDebug("[%s] Received header.", metaObject()->className()); + + // ask user + QMessageBox::StandardButton result = QMessageBox::question(0, + tr("PVS File Transfer"),tr("User '") + nick + + tr("' would like to send you a file: ") + filename + + " (" + formatSize(_bytesToRead) + ").", + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); + + if (result != QMessageBox::Ok) + { + sendAck(false); + return; + } + + // open file + QString saveAs = QFileDialog::getSaveFileName(this, tr("Open File"), + QDir::homePath() + QDir::separator() + filename, ""); + if (saveAs == "") + { + sendAck(false); + return; + } + _file = new QFile(saveAs); + _file->open(QIODevice::WriteOnly); + + // gui + filenameLabel->setText(saveAs); + progressBar->setValue(0); + progressBar->setMaximum(_bytesToRead/div); + labelNick->setText(nick); + labelB->setText(formatSize(_bytesToRead)); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); + + sendAck(true); + show(); +} + +void ClientFileReceiveDialog::sendAck(bool b) +{ + disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveHeader())); + + if (b) + { + QString ack = QString("ok\n"); + _socket->write(ack.toUtf8()); + qDebug("[%s] Sending ack...", metaObject()->className()); + connect(_socket, SIGNAL(readyRead()), this, SLOT(receiveFile())); + } + else + { + QString ack = QString("no\n"); + _socket->write(ack.toUtf8()); + qDebug("[%s] Sending nack!!!", metaObject()->className()); + close(); + } +} + +void ClientFileReceiveDialog::receiveFile() +{ + qint64 bytesRead = _file->write(_socket->readAll()); + _bytesToRead -= bytesRead; + progressBar->setValue(progressBar->value() + bytesRead/div); + labelA->setText(formatSize(progressBar->value()*div)); +} + +void ClientFileReceiveDialog::close() +{ + if (_file && _file->isOpen()) + { + _file->flush(); + _file->close(); + qDebug("[%s] File closed.", metaObject()->className()); + } + + if (_socket && _socket->isOpen()) + { + disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveHeader())); + disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveFile())); + disconnect(_socket, SIGNAL(disconnected()), this, SLOT(close())); + disconnect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(error(QAbstractSocket::SocketError))); + _socket->disconnectFromHost(); + qDebug("[%s] Connection closed.", metaObject()->className()); + } + + disconnect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); + + if (_bytesToRead == 0) + { + accept(); + QMessageBox::information(0, tr("PVS - File Transfer"), + tr("File Transfer complete.")); + } + else + { + reject(); + QMessageBox::warning(0, tr("PVS - File Transfer"), + tr("File Transfer canceled!")); + } +} + +void ClientFileReceiveDialog::error(QAbstractSocket::SocketError error) +{ + if (error == QAbstractSocket::RemoteHostClosedError) + qDebug("[%s] Socket closed by remote host.", metaObject()->className()); + else + qDebug("[%s] Socket error: %i", metaObject()->className(), error); + + close(); +} + +QString ClientFileReceiveDialog::formatSize(qint64 size) +{ + if (size >= 1000000000) // GB + return QString("%1GB").arg((qreal)size / 1000000000, 0, 'f',1); + else if (size >= 1000000) // MB + return QString("%1MB").arg((qreal)size / 1000000, 0, 'f',1); + else if (size >= 1000) // KB + return QString("%1KB").arg((qreal)size / 1000, 0, 'f',1); + else // B + return QString("%1B").arg((qreal)size, 0, 'f',1); +} diff --git a/src/gui/clientFileReceiveDialog.h b/src/gui/clientFileReceiveDialog.h new file mode 100644 index 0000000..c13d7b7 --- /dev/null +++ b/src/gui/clientFileReceiveDialog.h @@ -0,0 +1,47 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + */ + +#ifndef CLIENTFILERECEIVEDIALOG_H_ +#define CLIENTFILERECEIVEDIALOG_H_ + +#include <QtGui> +#include <QtNetwork> +#include "ui_clientFileReceiveDialog.h" + +class ClientFileReceiveDialog: public QDialog, + private Ui::ClientFileReceiveDialogClass +{ +Q_OBJECT + +public: + ClientFileReceiveDialog(QTcpSocket *socket, QWidget *parent = 0); + ~ClientFileReceiveDialog(); + +private Q_SLOTS: + void receiveHeader(); + void receiveFile(); + void close(); + void error(QAbstractSocket::SocketError error); + +private: + void sendAck(bool b); + QString formatSize(qint64 size); + + QTcpSocket *_socket; + QFile *_file; + qint64 _bytesToRead; + int div; + +}; + +#endif /* CLIENTFILERECEIVEDIALOG_H_ */ diff --git a/src/gui/clientFileSendDialog.cpp b/src/gui/clientFileSendDialog.cpp new file mode 100644 index 0000000..ccb44b3 --- /dev/null +++ b/src/gui/clientFileSendDialog.cpp @@ -0,0 +1,248 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + # ----------------------------------------------------------------------------- + # clientFileSendDialog.cpp + # - filechooser and progress dialog + # ----------------------------------------------------------------------------- + */ + +#include "clientFileSendDialog.h" + +ClientFileSendDialog::ClientFileSendDialog(QWidget *parent) : + QDialog(parent) +{ + setupUi(this); + + _file = NULL; + _socket = NULL; + _clientNicklistDialog = new ClientNicklistDialog(this); + + // connect to D-Bus and get interface + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.registerObject("/filesend", this); + dbus.registerService("org.openslx.pvsgui"); + _ifaceDBus = new OrgOpenslxPvsInterface("org.openslx.pvs", "/", dbus, this); + + // get current users name from backend + QDBusPendingReply<QString> reply = _ifaceDBus->chat_getNickname(); + reply.waitForFinished(); + if (reply.isValid()) + _nickname = reply.value(); + else + _nickname = "unknown"; + + connect(this, SIGNAL(finished(int)), this, SLOT(deleteLater())); +} + +ClientFileSendDialog::~ClientFileSendDialog() +{ + qDebug("[%s] Deleted!", metaObject()->className()); +} + +//////////////////////////////////////////////////////////////////////////////// +// Public + +void ClientFileSendDialog::open() +{ + // get nick of remote user + int result = _clientNicklistDialog->exec(); + if (result == 0) // User canceled + { + reject(); + return; + } + open(_clientNicklistDialog->getNick()); +} + +void ClientFileSendDialog::open(QString nick) +{ + QString filename = QFileDialog::getOpenFileName(this, tr("Open File"), + QDir::homePath(), ""); + if (filename == "") + { + reject(); + return; + } + open(nick, filename); +} + +void ClientFileSendDialog::open(QString nick, QString filename) +{ + // open file + _file = new QFile(filename); + _file->open(QIODevice::ReadOnly); + _bytesToWrite = _file->size(); + div = 1 + _bytesToWrite / 1000000000; // bc. progressBar supports only int + + // get host from backend + QString host = ""; + QDBusPendingReply<QString> reply = _ifaceDBus->getIpByNick(nick); + reply.waitForFinished(); + if (reply.isValid()) + host = reply.value(); + else // DBus Error, hostname + qDebug("[%s] D-Bus ERROR, no hostname available!", metaObject()->className()); + + // gui + filenameLabel->setText(filename); + progressBar->setValue(0); + progressBar->setMaximum(_bytesToWrite/div); + labelNick->setText(nick); + labelB->setText(formatSize(_bytesToWrite)); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); + + // open socket + _socket = new QTcpSocket(); + _socket->connectToHost(host, 29481); + qDebug("[%s] Remote host: %s", metaObject()->className(), qPrintable(host)); + + connect(_socket, SIGNAL(connected()), this, SLOT(sendHeader())); + connect(_socket, SIGNAL(disconnected()), this, SLOT(close())); + connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(error(QAbstractSocket::SocketError))); +} + +//////////////////////////////////////////////////////////////////////////////// +// Private + +void ClientFileSendDialog::sendHeader() +{ + QFileInfo info(_file->fileName()); + QString size = QString::number(_bytesToWrite); + QString header = _nickname + ";" + info.fileName() + ";" + size + "\n"; + _socket->write(header.toLocal8Bit()); + connect(_socket, SIGNAL(readyRead()), this, SLOT(receiveAck())); + qDebug("[%s] Sending header...", metaObject()->className()); +} + +void ClientFileSendDialog::receiveAck() +{ + QString ack = QString::fromUtf8(_socket->readLine()); + if (ack != "ok\n") + { + qDebug("[%s] Received nack!", metaObject()->className()); + close(); + return; + } + qDebug("[%s] Received ack.", metaObject()->className()); + + disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveAck())); + connect(_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(sendFile())); + show(); + qDebug("[%s] Sending file...", metaObject()->className()); + sendFile(); +} + +void ClientFileSendDialog::sendFile() +{ + if (_bytesToWrite == 0) + { + qDebug("[%s] Transfer completed.", metaObject()->className()); + close(); // finished + } + else + { + qint64 bytesWritten = _socket->write(_file->read(1024)); // data left + _bytesToWrite -= bytesWritten; + progressBar->setValue(progressBar->value() + bytesWritten/div); + labelA->setText(formatSize(progressBar->value()*div)); + } +} + +void ClientFileSendDialog::close() +{ + if (_file && _file->isOpen()) + { + _file->close(); + qDebug("[%s] File closed.", metaObject()->className()); + } + + if (_socket && _socket->isOpen()) + { + disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveAck())); + disconnect(_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(sendFile())); + disconnect(_socket, SIGNAL(disconnected()), this, SLOT(close())); + disconnect(_socket, SIGNAL(connected()), this, SLOT(sendHeader())); + disconnect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(error(QAbstractSocket::SocketError))); + _socket->disconnectFromHost(); + qDebug("[%s] Connection closed.", metaObject()->className()); + } + + disconnect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); + + if (_bytesToWrite == 0) + { + accept(); + QMessageBox::information(0, tr("PVS - File Transfer"), + tr("File Transfer complete.")); + } + else + { + reject(); + QMessageBox::warning(0, tr("PVS - File Transfer"), + tr("File Transfer canceled!")); + } +} + +void ClientFileSendDialog::error(QAbstractSocket::SocketError error) +{ + qDebug("[%s] Socket error: %i", metaObject()->className(), error); + close(); +} + +QString ClientFileSendDialog::formatSize(qint64 size) +{ + if (size >= 1000000000) // GB + return QString("%1GB").arg((qreal)size / 1000000000, 0, 'f',1); + else if (size >= 1000000) // MB + return QString("%1MB").arg((qreal)size / 1000000, 0, 'f',1); + else if (size >= 1000) // KB + return QString("%1KB").arg((qreal)size / 1000, 0, 'f',1); + else // B + return QString("%1B").arg((qreal)size, 0, 'f',1); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +ClientNicklistDialog::ClientNicklistDialog(QWidget *parent) : + QDialog(parent) +{ + setupUi(this); + + // connect to D-Bus and get interface + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.registerObject("/nicklist", this); + dbus.registerService("org.openslx.pvsgui"); + _ifaceDBus = new OrgOpenslxPvsInterface("org.openslx.pvs", "/", dbus, this); + + // get available nicknames + QDBusPendingReply<QStringList> reply = _ifaceDBus->chat_getNicknames(); + reply.waitForFinished(); + QStringList nicknames = reply.value(); + if (!reply.isValid() || nicknames.isEmpty()) // DBus Error, nicknames + qDebug("[%s] D-Bus ERROR, no nicknames available!", metaObject()->className()); + + listWidget->addItems(nicknames); + listWidget->setCurrentRow(0); +} + +ClientNicklistDialog::~ClientNicklistDialog() +{ + +} + +QString ClientNicklistDialog::getNick() +{ + return listWidget->currentItem()->text(); +} diff --git a/src/gui/clientFileSendDialog.h b/src/gui/clientFileSendDialog.h new file mode 100644 index 0000000..d8afc3a --- /dev/null +++ b/src/gui/clientFileSendDialog.h @@ -0,0 +1,76 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + */ + +#ifndef CLIENTFILESENDDIALOG_H_ +#define CLIENTFILESENDDIALOG_H_ + +#include <QtGui> +#include <QtNetwork> +#include "pvsinterface.h" +#include "ui_clientFileSendDialog.h" +#include "ui_clientNicklistDialog.h" + +class ClientNicklistDialog: public QDialog, + private Ui::ClientNicklistDialogClass +{ +Q_OBJECT + +public: + ClientNicklistDialog(QWidget *parent = 0); + ~ClientNicklistDialog(); + + QString getNick(); + +private: + OrgOpenslxPvsInterface *_ifaceDBus; + +}; + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +class ClientFileSendDialog: public QDialog, + private Ui::ClientFileSendDialogClass +{ +Q_OBJECT + +public: + ClientFileSendDialog(QWidget *parent = 0); + ~ClientFileSendDialog(); + + void open(); + void open(QString nick); + void open(QString nick, QString filename); + +private Q_SLOTS: + void sendHeader(); + void receiveAck(); + void sendFile(); + void close(); + void error(QAbstractSocket::SocketError error); + +private: + QString formatSize(qint64 size); + + QTcpSocket *_socket; + QFile *_file; + qint64 _bytesToWrite; + int div; + + ClientNicklistDialog *_clientNicklistDialog; + OrgOpenslxPvsInterface *_ifaceDBus; + QString _nickname; + +}; + +#endif /* CLIENTFILESENDDIALOG_H_ */ diff --git a/src/gui/clientInfoDialog.cpp b/src/gui/clientInfoDialog.cpp new file mode 100644 index 0000000..02a6fd8 --- /dev/null +++ b/src/gui/clientInfoDialog.cpp @@ -0,0 +1,60 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + # ----------------------------------------------------------------------------- + # clientInfoDialog.cpp + # - shows big info dialog (connected host and passwd) + # ----------------------------------------------------------------------------- + */ + +#include "clientInfoDialog.h" + +ClientInfoDialog::ClientInfoDialog(QWidget *parent) : + QDialog(parent) +{ + setupUi(this); +} + +ClientInfoDialog::~ClientInfoDialog() +{ + +} + +//////////////////////////////////////////////////////////////////////////////// +// Public + +void ClientInfoDialog::setHost(QString host) +{ + hostLabel->setText("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " + "\"http://www.w3.org/TR/REC-html40/strict.dtd\"><html>" + "<head><meta name=\"qrichtext\" content=\"1\" />" + "<style type=\"text/css\">p, li { white-space: pre-wrap; }</style>" + "</head><body style=\" font-family:'DejaVu Sans'; font-size:9pt; " + "font-weight:400; font-style:normal;\"><p style=\" margin-top:0px; " + "margin-bottom:0px; margin-left:0px; margin-right:0px; " + "-qt-block-indent:0; text-indent:0px;\"><span style=\" " + "font-size:72pt; font-weight:600; color:#0000ff;\">" + + host + "</span></p></body></html>"); +} + +void ClientInfoDialog::setPasswd(QString passwd) +{ + passwdLabel->setText("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " + "\"http://www.w3.org/TR/REC-html40/strict.dtd\"><html>" + "<head><meta name=\"qrichtext\" content=\"1\" />" + "<style type=\"text/css\">p, li { white-space: pre-wrap; }</style>" + "</head><body style=\" font-family:'DejaVu Sans'; font-size:9pt; " + "font-weight:400; font-style:normal;\"><p style=\" margin-top:0px; " + "margin-bottom:0px; margin-left:0px; margin-right:0px; " + "-qt-block-indent:0; text-indent:0px;\"><span style=\" " + "font-size:48pt; font-weight:600; color:#ff0000;\">" + + passwd + "</span></p></body></html>"); +} diff --git a/src/gui/clientInfoDialog.h b/src/gui/clientInfoDialog.h new file mode 100644 index 0000000..770b5b7 --- /dev/null +++ b/src/gui/clientInfoDialog.h @@ -0,0 +1,32 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + */ + +#ifndef CLIENTINFODIALOG_H_ +#define CLIENTINFODIALOG_H_ + +#include <QtGui> +#include "ui_clientInfoDialog.h" + +class ClientInfoDialog: public QDialog, private Ui::InfoDialogClass +{ +Q_OBJECT + +public: + ClientInfoDialog(QWidget *parent = 0); + ~ClientInfoDialog(); + + void setHost(QString host); + void setPasswd(QString passwd); +}; + +#endif /* CLIENTINFODIALOG_H_ */ diff --git a/src/gui/clientVNCViewer.cpp b/src/gui/clientVNCViewer.cpp new file mode 100644 index 0000000..d6a218b --- /dev/null +++ b/src/gui/clientVNCViewer.cpp @@ -0,0 +1,273 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + # ----------------------------------------------------------------------------- + # clientVNCViewer.cpp + # - connetct to vnc server and show remote screen (window/full) + # ----------------------------------------------------------------------------- + */ + +#include "clientVNCViewer.h" + +ClientVNCViewer::ClientVNCViewer(QWidget *parent) : + QDialog(parent), _thread(0), _viewOnly(true), _buttonMask(0) +{ + // connect to D-Bus and get interface + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.registerObject("/vnc", this); + dbus.registerService("org.openslx.pvsgui"); + _ifaceDBus = new OrgOpenslxPvsInterface("org.openslx.pvs", "/", dbus, this); + connect(_ifaceDBus, SIGNAL(project(QString, int, QString, bool, bool, int)), + this, SLOT(open(QString, int, QString, bool, bool, int))); + connect(_ifaceDBus, SIGNAL(unproject()), this, SLOT(close())); +} + +ClientVNCViewer::~ClientVNCViewer() +{ + close(); +} + +//////////////////////////////////////////////////////////////////////////////// +// Public + +void ClientVNCViewer::open(QString host, int port, QString passwd, bool fs, + bool mode, int quality) +{ + // start thread for vnc-updates + _thread = new VNCClientThread(host, port, passwd, quality); + _thread->start(); + //_rfbclient = _thread->getRfbClient(); + //installEventFilter(this); + setMouseTracking(true); // get mouse events even when there is no mousebutton pressed + setFocusPolicy(Qt::WheelFocus); //needed?!? + + setAttribute(Qt::WA_OpaquePaintEvent); + + // smooth transformation? + if (mode) + _mode = Qt::SmoothTransformation; + else + _mode = Qt::FastTransformation; + + // fullscreen? + if (fs) + { + setWindowFlags(Qt::WindowStaysOnTopHint); + showFullScreen(); + activateWindow(); + raise(); + } + else + showNormal(); + + connect(this, SIGNAL(rejected()), this, SLOT(close())); + connect(_thread, SIGNAL(imageUpdated(int,int,int,int)), this, + SLOT(updateImage(int,int,int,int)), Qt::BlockingQueuedConnection); +} + +void ClientVNCViewer::close() +{ + setVisible(false); + if (_thread) + { + disconnect(_thread, SIGNAL(imageUpdated(int,int,int,int)), this, + SLOT(updateImage(int,int,int,int))); + + _thread->terminate = true; + _thread->wait(1000); + delete _thread; + _thread = NULL; + } + disconnect(this, SIGNAL(rejected()), this, SLOT(close())); +} + +void ClientVNCViewer::updateImage(int x, int y, int w, int h) +{ + if (_thread->getSize() != size()) // scaling needed? + { + // grow the update rectangle to avoid artifacts + x -= 1; + y -= 1; + w += 2; + h += 2; + + _img = _thread->getImage().copy(x, y, w, h); + + qreal sx = qreal(width()) / qreal(_thread->getSize().width()); + qreal sy = qreal(height()) / qreal(_thread->getSize().height()); + + x = qRound(qreal(x) * sx); + y = qRound(qreal(y) * sy); + w = qRound(qreal(w) * sx); + h = qRound(qreal(h) * sy); + } + else + { + _img = _thread->getImage().copy(x, y, w, h); + } + + repaint(x, y, w, h); +} + +//////////////////////////////////////////////////////////////////////////////// +// Protected + +void ClientVNCViewer::paintEvent(QPaintEvent *event) +{ + if (_img.isNull()) + return; + + QPainter painter(this); + QRect r = event->rect(); + + if (r == rect()) + _img = _thread->getImage(); // redraw complete image (e.g. on resize) + + if (_thread->getSize() == size()) + { + painter.drawImage(r.topLeft(), _img); // don't scale + } + else + { + QImage i = _img.scaled(r.size(), Qt::IgnoreAspectRatio, _mode); + painter.drawImage(r.topLeft(), i); + } + event->accept(); +} +//returns true if event was processed +/*bool ClientVNCViewer::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: + + keyEventHandler(static_cast<QKeyEvent*>(event)); + return true; + break; + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + mouseEventHandler(static_cast<QMouseEvent*>(event)); + return true; + break; + case QEvent::Wheel: + wheelEventHandler(static_cast<QWheelEvent*>(event)); + return true; + break; + default: + return false; + } +}*/ + +//handles mouseevents +void ClientVNCViewer::mouseEventHandler(QMouseEvent *e) +{ + if (e->type() != QEvent::MouseMove) { + if ((e->type() == QEvent::MouseButtonPress) || + (e->type() == QEvent::MouseButtonDblClick)) { + if (e->button() & Qt::LeftButton) + _buttonMask |= 0x01; + if (e->button() & Qt::MidButton) + _buttonMask |= 0x02; + if (e->button() & Qt::RightButton) + _buttonMask |= 0x04; + } else if (e->type() == QEvent::MouseButtonRelease) { + if (e->button() & Qt::LeftButton) + _buttonMask &= 0xfe; + if (e->button() & Qt::MidButton) + _buttonMask &= 0xfd; + if (e->button() & Qt::RightButton) + _buttonMask &= 0xfb; + } + } + qreal sx = qreal(width()) / qreal(_thread->getSize().width()); + qreal sy = qreal(height()) / qreal(_thread->getSize().height()); + _thread->mouseEvent(qRound(e->x() / sx), qRound(e->y() / sy), _buttonMask); +} + +//handles mousewheel +void ClientVNCViewer::wheelEventHandler(QWheelEvent *event) +{ + int eb = 0; + if (event->delta() < 0) + eb |= 0x10; + else + eb |= 0x8; + + qreal sx = qreal(width()) / qreal(_thread->getSize().width()); + qreal sy = qreal(height()) / qreal(_thread->getSize().height()); + const int x = qRound(event->x() / sx); + const int y = qRound(event->y() / sy); + + _thread->mouseEvent(x, y, eb | _buttonMask); + _thread->mouseEvent(x, y, _buttonMask); +} + +//Handles keypress +void ClientVNCViewer::keyEventHandler(QKeyEvent *e) +{ + rfbKeySym k = e->nativeVirtualKey(); + + // do not handle Key_Backtab separately because the Shift-modifier + // is already enabled + if (e->key() == Qt::Key_Backtab) { + k = XK_Tab; + } + + const bool pressed = (e->type() == QEvent::KeyPress); + + // handle modifiers + if (k == XK_Shift_L || k == XK_Control_L || k == XK_Meta_L || k == XK_Alt_L) { + if (pressed) { + _modkeys[k] = true; + } else if (_modkeys.contains(k)) { + _modkeys.remove(k); + } else { + unpressModifiers(); + } + } + + if (k) { + _thread->keyEvent(k, pressed); + } +} + +//removes modifier keys which have been pressed +void ClientVNCViewer::unpressModifiers() +{ + const QList<unsigned int> keys = _modkeys.keys(); + QList<unsigned int>::const_iterator it = keys.constBegin(); + while (it != keys.end()) { + _thread->keyEvent(*it, false); + it++; + } + _modkeys.clear(); +} + +//(QT Function) Filters events, if _viewOnly is set, true is returned and the event is ignored +//TODO use this function when implementing viewonly switch +bool ClientVNCViewer::eventFilter(QObject *obj, QEvent *event) +{ + if (_viewOnly) { + if (event->type() == QEvent::KeyPress || + event->type() == QEvent::KeyRelease || + event->type() == QEvent::MouseButtonDblClick || + event->type() == QEvent::MouseButtonPress || + event->type() == QEvent::MouseButtonRelease || + event->type() == QEvent::Wheel || + event->type() == QEvent::MouseMove) + return true; + } + + return false; + //return RemoteView::eventFilter(obj, event); +} diff --git a/src/gui/clientVNCViewer.h b/src/gui/clientVNCViewer.h new file mode 100644 index 0000000..6ff9c33 --- /dev/null +++ b/src/gui/clientVNCViewer.h @@ -0,0 +1,67 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + */ + +#ifndef CLIENTVNCVIEWER_H_ +#define CLIENTVNCVIEWER_H_ + +#include <QtGui> +#include <QMouseEvent> +#include "pvsinterface.h" +#include "../util/vncClientThread.h" + +// Definition of key modifier mask constants +#define KMOD_Alt_R 0x01 +#define KMOD_Alt_L 0x02 +#define KMOD_Meta_L 0x04 +#define KMOD_Control_L 0x08 +#define KMOD_Shift_L 0x10 + +class ClientVNCViewer: public QDialog +{ +Q_OBJECT + +public: + ClientVNCViewer(QWidget *parent = 0); + virtual ~ClientVNCViewer(); + +public Q_SLOTS: + void open(QString host, int port, QString passwd, bool fullscreen = false, + bool smoothTransformation = false, int quality = 0); + void close(); + void updateImage(int x, int y, int w, int h); + +protected: + void paintEvent(QPaintEvent *event); + //bool event(QEvent *event); + //bool eventFilter(QObject *obj, QEvent *event); + +private: + VNCClientThread *_thread; + //rfbClient *_rfbclient; + QImage _img; + bool _viewOnly; + int _buttonMask; + QMap<unsigned int, bool> _modkeys; + bool eventFilter(QObject *obj, QEvent *event); + void keyEventHandler(QKeyEvent *e); + void unpressModifiers(); + void wheelEventHandler(QWheelEvent *event); + void mouseEventHandler(QMouseEvent *event); + + + Qt::TransformationMode _mode; + + OrgOpenslxPvsInterface *_ifaceDBus; +}; + +#endif /* CLIENTVNCVIEWER_H_ */ diff --git a/src/gui/connectionDialog.cpp b/src/gui/connectionDialog.cpp new file mode 100644 index 0000000..8c5b743 --- /dev/null +++ b/src/gui/connectionDialog.cpp @@ -0,0 +1,216 @@ +#include "connectionDialog.h" + +ConnectionDialog::ConnectionDialog(MainWindow* newParent, const Glib::ustring& title) + : buttonOK("OK"), + buttonCancel("Cancel") + +{ + set_default_size(300, 100); + if (newParent) + myParent = newParent; + else + ; // handle errors + + set_title(title); + buttonOK.signal_clicked().connect(sigc::mem_fun(*this, &ConnectionDialog::on_button_ok_click)); + buttonCancel.signal_clicked().connect(sigc::mem_fun(*this, &ConnectionDialog::on_button_cancel_click)); + + + windowBox.pack_start(contentBox, Gtk::PACK_SHRINK); + windowBox.pack_start(buttonBox, Gtk::PACK_SHRINK); + buttonBox.pack_end(buttonOK, Gtk::PACK_SHRINK); + buttonBox.pack_end(buttonCancel, Gtk::PACK_SHRINK); + + + add(windowBox); + show_all_children(); +} + +ConnectionDialog::~ConnectionDialog() +{} + +void ConnectionDialog::on_button_ok_click() +{ + hide(); +} + +void ConnectionDialog::on_button_cancel_click() +{ + hide(); +} + + + +PasswordDialog::PasswordDialog(MainWindow* newParent, const Glib::ustring& title, QString* newTargetPW) + : ConnectionDialog(newParent, title), + frameIP(*newTargetPW), + targetPW(newTargetPW) + +{ + *newTargetPW = ""; + entryPW.signal_activate().connect(sigc::mem_fun(*this, &PasswordDialog::on_enter_password)); + + frameIP.add(entryPW); + contentBox.add(frameIP); + + show_all_children(); + +} + +PasswordDialog::~PasswordDialog() +{} + +void PasswordDialog::on_button_ok_click() +{ + if (password != "") // there was a password set by pressing enter in the pw-entry + { + *targetPW = password; + ConnectionDialog::on_button_ok_click(); + } + else // it was just typed or not supplied + { + *targetPW = entryPW.get_text(); + if (*targetPW != "") + ConnectionDialog::on_button_ok_click(); + + } + +} + +void PasswordDialog::on_button_cancel_click() +{ + *targetPW = ""; + ConnectionDialog::on_button_cancel_click(); +} + +void PasswordDialog::on_enter_password() +{ + password = entryPW.get_text(); + if (password != "") + on_button_ok_click(); +} + +NewConDialog::NewConDialog(MainWindow* newParent, const Glib::ustring& title) + : ConnectionDialog(newParent, title), + frameIP("Host"), + framePW("Password"), + buttonFromFile("From File") +{ + entryIP.signal_activate().connect(sigc::mem_fun(*this, &NewConDialog::on_enter_IP)); + entryPW.signal_activate().connect(sigc::mem_fun(*this, &NewConDialog::on_enter_password)); + buttonFromFile.signal_clicked().connect(sigc::mem_fun(*this, &NewConDialog::on_button_fromFile_click)); + + frameIP.add(entryIP); + framePW.add(entryPW); + contentBox.add(frameIP); + contentBox.add(framePW); + contentBox.add(buttonFromFile); + show_all_children(); +} + +NewConDialog::~NewConDialog() +{} + +void NewConDialog::on_enter_password() +{ + if (entryIP.get_text() != "") // if the IP/hostname was already supplied, we proceed without putting the focus + // back on the IP field. + // we also proceed if theres no password given, because theres either no password + // needed or the password dialog will take care of that later on + on_button_ok_click(); + else + entryIP.grab_focus(); +} + +void NewConDialog::on_enter_IP() +{ + if (entryIP.get_text() != "") + { + if (entryPW.get_text() == "") // if no password was supplied we put the focus on the password + entryPW.grab_focus(); + else + on_button_ok_click(); + } + else + return; +} + + +void NewConDialog::on_button_ok_click() +{ + connection_IP = entryIP.get_text(); + if (connection_IP != "") // we only proceed if the IP/hostname field isnt empty + { + connection_password = entryPW.get_text(); + QString infoLine; + infoLine = connection_IP; + if (connection_password.length() > 0) // if the password was supplied, we assemble the string + // with the necessary information + { + infoLine.append(" "); + infoLine.append(connection_password); + } + + // VNCConnectInfo* newCon = getConInfo(infoLine); + +// myParent->addConnection(newCon); + + ConnectionDialog::on_button_ok_click(); + } +} + +void NewConDialog::on_button_fromFile_click() +{ +// myParent->readClientsFromFile(); + ConnectionDialog::on_button_ok_click(); +} + + + + + + + + + + + + + + + +MessageDialog::MessageDialog(MainWindow* newParent, const Glib::ustring& title, QString* newMessage) + : ConnectionDialog(newParent, title), + frameMsg("Message") +{ + message = newMessage; + entryMsg.signal_activate().connect(sigc::mem_fun(*this, &MessageDialog::on_enter_message)); + + frameMsg.add(entryMsg); + + contentBox.add(frameMsg); + + show_all_children(); +} + +MessageDialog::~MessageDialog() +{} + +void MessageDialog::on_enter_message() +{ + if (entryMsg.get_text() != "") + { + on_button_ok_click(); + } +} + + +void MessageDialog::on_button_ok_click() +{ + if (entryMsg.get_text().empty()) + return; + + *message = entryMsg.get_text(); + + ConnectionDialog::on_button_ok_click(); +} diff --git a/src/gui/connectionDialog.h b/src/gui/connectionDialog.h new file mode 100644 index 0000000..8f268d4 --- /dev/null +++ b/src/gui/connectionDialog.h @@ -0,0 +1,123 @@ +#ifndef _CONNECTIONDIALOG_H_ +#define _CONNECTIONDIALOG_H_ +#include <src/gui/mainWindow.h> +//#include <src/core/pvsCore.h> +//#include <src/util/pvsUtil.h> + + +class MainWindow; + +/** ConnectionDialog + * Abstract base class for dialogs + */ + +class ConnectionDialog : public Gtk::Window +{ + +public: + ConnectionDialog(MainWindow* newParent, const Glib::ustring& title); + ~ConnectionDialog(); + +protected: + + virtual void on_button_ok_click(); // callback for ok button + virtual void on_button_cancel_click(); // callback for cancel button + + Gtk::VBox contentBox; // box containing the individual content of the dialogs + Gtk::HBox buttonBox; // box containing the shared buttons (ok & cancel) of the dialogs + Gtk::VBox windowBox; // box containing content and button boxes + Gtk::Button buttonOK; // the ok button + Gtk::Button buttonCancel; // the cancel button + MainWindow* myParent; // pointer to the parenting window + +}; + + +/** PasswordDialog + * dialog with the sole purpose to ask for a password (if requested) + */ + + +class PasswordDialog : public ConnectionDialog +{ + +public: + + PasswordDialog(MainWindow* newParent, const Glib::ustring& title, QString* newTargetPW); // the PasswordDialog constructor takes a pointer to a string for the sole + // reason that it is not connected to the connection that asks for a password and therefore cannot tell the user to which + // connection it belongs. So the connection puts the hostname in the string which the pointer is pointing to for the password + // dialog to read out and show to the user. The string is then overwritten with the password the user entered and then used + // inside the connection to feed the password request. + ~PasswordDialog(); + +protected: + + void on_enter_password(); + void on_button_ok_click(); + void on_button_cancel_click(); + + Gtk::Frame frameIP; + Gtk::Entry entryPW; + +private: + QString password, *targetPW; +}; + +/** NewConDialog + * dialog to open up a new connection to a vnc server + * offers the options + * * to enter a password to not come up + * with a password dialog later + * * to read prefab connections from a file + */ + + +class NewConDialog : public ConnectionDialog +{ + +public: + NewConDialog(MainWindow* newParent, const Glib::ustring& title); + ~NewConDialog(); + +protected: + + void on_enter_password(); // callback when enter was hit in the password text field. + void on_enter_IP(); // callback when enter was hit in the IP/Host text field + + void on_button_ok_click(); // ok button callback + void on_button_fromFile_click();// read-from-file button callback + + Gtk::Frame frameIP; // just a frame around the IP text field + Gtk::Frame framePW; // the same for the pw field + Gtk::Button buttonFromFile; // button to read out a file + Gtk::Entry entryIP; // text field for the IP/Hostname + Gtk::Entry entryPW; // text field for the password (optional) + +private: + QString connection_password; + QString connection_IP; +}; + +class MessageDialog : public ConnectionDialog +{ + +public: + MessageDialog(MainWindow* newParent, const Glib::ustring& title, QString* newMessage); + ~MessageDialog(); + +protected: + + void on_enter_message(); // callback when enter was hit in the text field. + + void on_button_ok_click(); // ok button callback + void on_button_fromFile_click();// read-from-file button callback + + Gtk::Frame frameMsg; // just a frame around the text + Gtk::Entry entryMsg; // text field for the message + +private: + QString * message; +}; + + +#endif diff --git a/src/gui/connectionFrame.cpp b/src/gui/connectionFrame.cpp new file mode 100644 index 0000000..e889991 --- /dev/null +++ b/src/gui/connectionFrame.cpp @@ -0,0 +1,557 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/gui/connectionFrame.cpp +# ----------------------------------------------------------------------------- +*/ + + +#include <src/gui/connectionFrame.h> +#include <src/gui/dialog.h> +#include <src/gui/mainWindow.h> +#include <iostream> +extern "C" +{ +#include <rfb/rfbclient.h> +} +#include <src/core/pvsConnectionManager.h> + + +ConnectionFrame::ConnectionFrame(QWidget *parent) : + QGroupBox(parent) +{ + + //defines the ui-stuff + + _gL = new QGridLayout(this); + _gL->setSpacing(6); + _gL->setMargin(1); + + _split = new QSplitter(this); + _split->setOrientation(Qt::Vertical); + + _frame = new Frame("", _split); + _frame->setConFrame(this); + _split->addWidget(_frame); + + _conFrameTaskbar = new QWidget(_split); + _conFrameTaskbar->setMaximumHeight(30); + + _gLayout = new QGridLayout(_conFrameTaskbar); + _gLayout->setMargin(0); + _gLayout->setSpacing(0); + + _hLayoutInCfTaskbar = new QHBoxLayout(); + + _username = new QLabel(_conFrameTaskbar); + _username->setStyleSheet(QString::fromUtf8("background-color: rgb(150, 150, 168);")); + _username->setAlignment(Qt::AlignLeft); + + _hLayoutInCfTaskbar->addWidget(_username); + + _dozentContaimner = new QLabel(_conFrameTaskbar); + _dozentContaimner->setStyleSheet(QString::fromUtf8("background-color: rgb(150, 150, 168);")); + _dozentContaimner->setAlignment(Qt::AlignRight); + _dozentContaimner->setMaximumSize(QSize(20, 20)); + _dozentContaimner->setScaledContents(true); + + _hLayoutInCfTaskbar->addWidget(_dozentContaimner); + + _dozentContaimner->setDisabled(true); + + _status = new QLabel(_conFrameTaskbar); + _status->setStyleSheet(QString::fromUtf8("background-color: rgb(150, 150, 168);")); + _status->setAlignment(Qt::AlignRight); + _status->setMaximumSize(QSize(22, 21)); + + _hLayoutInCfTaskbar->addWidget(_status); + + _gLayout->addLayout(_hLayoutInCfTaskbar, 0, 0, 1, 1); + _split->addWidget(_conFrameTaskbar); + + _gL->addWidget(_split, 0, 0, 1, 1); + + this->setLayout(_gL); + + setInitSize(190,168); + + initFrame(); + + nat_height = 0; + nat_width = 0; + _ratio = 100; + overSized = false; + _fullscreen = false; + _closeup = false; + active = false; + _isOnProjekt = false; + isClientOnline = true; + + //slots and signals + + DelDummy = new QAction(tr("&Remove dummy..."),this); + connect(DelDummy, SIGNAL(triggered()), this, SLOT(delDummy())); + lockClient = new QAction(tr("&Lock Client(s)"),this); + connect(lockClient, SIGNAL(triggered()), this, SLOT(on_lock())); + uLockClient = new QAction(tr("&Unlock Client(s)"),this); + connect(uLockClient, SIGNAL(triggered()), this, SLOT(on_unlock())); + /*invertlockClient = new QAction(tr("&Invertlock Client(s)"),this); + connect(invertlockClient, SIGNAL(triggered()), this, SLOT(on_lock_invert())); + LockAllClient = new QAction(tr("&Lock all Client(s)"),this); + connect(LockAllClient, SIGNAL(triggered()), this, SLOT(on_lock_all())); + uLockAllClient = new QAction(tr("&Unlock all Client(s)"),this); + connect(uLockAllClient, SIGNAL(triggered()), this, SLOT(on_unlock_all()));*/ + msgLockClient = new QAction(tr("&MsgLock Client(s)"),this); + connect(msgLockClient, SIGNAL(triggered()), this, SLOT(on_lock_with_message())); + msgLockAllClient = new QAction(tr("&MsgLock all Client(s)"),this); + connect(msgLockAllClient, SIGNAL(triggered()), this, SLOT(on_lock_all_with_message())); + msgClient = new QAction(tr("&Message Client(s)"),this); + connect(msgClient, SIGNAL(triggered()), this, SLOT(on_message())); + project = new QAction(tr("&Projection"),this); + connect(project, SIGNAL(triggered()), this, SLOT(on_projection())); + uproject = new QAction(tr("&Unprojection"),this); + connect(uproject, SIGNAL(triggered()), this, SLOT(on_unprojection())); + /*rHelp = new QAction(tr("&Remote Help"),this); + connect(rHelp, SIGNAL(triggered()), this, SLOT(on_remoteHelp()));*/ + + //connect(_frame, SIGNAL(clicked()), this, SLOT(on_click())); + + //menu entries + + menu = new QMenu(this); + menu->addAction(DelDummy); + menu->addSeparator(); + menu->addAction(lockClient); + menu->addAction(uLockClient); + /*menu->addAction(invertlockClient); + menu->addAction(LockAllClient); + menu->addAction(uLockAllClient);*/ + menu->addAction(msgLockClient); + menu->addAction(msgLockAllClient); + menu->addAction(msgClient); + menu->addAction(project); + menu->addAction(uproject); + //menu->addAction(rHelp); + + this->show(); +} + +ConnectionFrame::~ConnectionFrame() +{ + +} + +QString ConnectionFrame::getTitle() // get frame title +{ + return title(); +} + +void ConnectionFrame::setTheTitle(QString title) // set frame title +{ + if (title.isNull()) return; + setTitle(title); +} + +QString ConnectionFrame::getTaskbarTitle() // get taskbar title +{ + if (!_username->text().isNull()) + return _username->text(); + else + return _myConnection->getIp(); +} + +void ConnectionFrame::setTaskbarTitle(QString title) // set taskbar title +{ + _username->setText(title); + _frame->ip = title; +} + +void ConnectionFrame::setInitSize(int w, int h) +{ + resize(w, h); + _frame->resize(w, h); + _conFrameTaskbar->resize(w, h); + prev_height = h; + prev_width = w; + init_w = w; + init_h = h; +} + +void ConnectionFrame::Resize(int w, int h) +{ + resize(w, h); + _frame->resize(w, h); +} + +void ConnectionFrame::initFrame() +{ + _clientStatus = QPixmap(":/offline"); + _clientDozent = QPixmap(":/dozent2"); + _dozentContaimner->setPixmap(_clientDozent.scaled(3*_dozentContaimner->size()/4, + Qt::KeepAspectRatio, Qt::SmoothTransformation)); +} + + +void ConnectionFrame::setConnection(PVSClient* newConnection) +{ + if (newConnection) + { + _myConnection = newConnection; + _myConnection->setConnectionFrame(this); + const QString userName = QString( + _myConnection->getUserName().toUtf8().data()); + if (_myConnection->getVNCConnection() && _myConnection->getVNCConnection()->getVNCClientThread()) + { + _myConnection->getVNCConnection()->setFrame(this); + _frame->setVNCThreadConnection(_myConnection->getVNCConnection()->getVNCClientThread()); + setActive(true); + setToolTip(userName); + setTitle(userName); + } + else + { + setToolTip(userName); + setTitle(userName); + } + } + +} + +/* + * We set a new VNCConnection to the pvsmgr with a new quality. + * To do this, that is very easy. At this point we have already a ruuning + * Connection between the server an the client. This connection is controlled in a thread. + * So we disconnect all Qt-Signals on this thread and we terminate the thread. + * After do this we have to set a new thread(VNCClientThread) and connect the signals again. + * + * When you want to read about this, please check the developper's book. + */ +void ConnectionFrame::resetConnectionWithQuality(int quality) +{ + if (getFrame()) + { + _myConnection->getVNCConnection()->reInitClientWithQuality(quality); + getFrame()->stopVNCThreadConnection(); + getFrame()->setVNCThreadConnection(_myConnection->getVNCConnection()->getVNCClientThread()); + getFrame()->update(); + } +} + +void ConnectionFrame::delDummy() +{ + MainWindow::getConnectionWindow()->removeFromList(this); +} + +void ConnectionFrame::on_projection() +{ + MainWindow::getConnectionList()->on_projection(); +} + +void ConnectionFrame::on_unprojection() +{ + MainWindow::getConnectionList()->on_unprojection(); +} + +void ConnectionFrame::on_lock() +{ + if (_myConnection->getVNCConnection()) + MainWindow::getConnectionWindow()->lockStation(_myConnection); +} + +void ConnectionFrame::on_unlock() +{ + if (_myConnection->getVNCConnection()) + MainWindow::getConnectionWindow()->unlockStation(_myConnection); +} + +void ConnectionFrame::on_message() +{ + Dialog msgD; + QString myString = NULL; + int result = msgD.exec(); + + if (result == 1) + { + myString = MainWindow::getWindow()->getMsgDialog(); + if(!myString.isEmpty()) + MainWindow::getConnectionWindow()->messageStations("BROADCAST",myString); + } +} + +void ConnectionFrame::on_lock_with_message() +{ + Dialog msgD; + QString myString = NULL; + int result = msgD.exec(); + + if(result == 1) + { + myString = MainWindow::getWindow()->getMsgDialog(); + if(!myString.isEmpty()) + { + MainWindow::getConnectionWindow()->lockStationsWithMessage(myString); + } + } +} + +void ConnectionFrame::on_lock_all_with_message() +{ + QString myString = NULL; + Dialog msgD; + int result = msgD.exec(); + + if(result == 1) + { + myString = MainWindow::getWindow()->getMsgDialog(); + if(!myString.isEmpty()) + { + MainWindow::getConnectionWindow()->lockAllStationsWithMessage(myString); + } + } +} + +void ConnectionFrame::on_lock_all() +{ + MainWindow::getConnectionWindow()->lockAllStations(); +} + +void ConnectionFrame::on_unlock_all() +{ + MainWindow::getConnectionWindow()->unlockAllStations(); +} + +void ConnectionFrame::on_lock_invert() +{ + //MainWindow::getConnectionWindow()->lockInvertStations(); +} + +void ConnectionFrame::on_remoteHelp() +{ + +} + +void ConnectionFrame::setIgnoreRatio(bool ignore) +{ + ignore_ratio = ignore; +} + +void ConnectionFrame::setFullscreen(bool fs) +{ + _fullscreen = fs; + setIgnoreRatio(!fs); +} + +void ConnectionFrame::setCloseup(bool cu) +{ + _closeup = cu; + setIgnoreRatio(false); +} + +void ConnectionFrame::setInteractive(bool doit) +{ + viewOnly = !doit; +} + +void ConnectionFrame::setActive(bool activate) +{ + active = activate; +} + +void ConnectionFrame::setDummy(bool dummy) +{ + _dummy = dummy; + if (_dummy) + { + _clientStatus = QPixmap(0, 0); //ein leeres Pixmap erstellen + _clientStatus.fill(Qt::white); // benöigt bevor man drin zeichen + _clientStatus = QPixmap(":/offline"); + _status->setMaximumSize(QSize(30, 30)); + _status->setPixmap(_clientStatus.scaled(29,27, + Qt::KeepAspectRatio, Qt::SmoothTransformation)); + //_status->setPixmap(clientStatus.scaled(3*_status->size()/4, + // Qt::KeepAspectRatio, Qt::SmoothTransformation)); + //setConnection(NULL); + } + else + { + _clientStatus = QPixmap(0, 0); //ein leeres Pixmap erstellen + _clientStatus.fill(Qt::white); // benöigt bevor man drin zeichen + _clientStatus = QPixmap(":/online"); + _status->setMaximumSize(QSize(30, 30)); + _status->setPixmap(_clientStatus.scaled(29,27, + Qt::KeepAspectRatio, Qt::SmoothTransformation)); + //_status->setPixmap(clientStatus.scaled(3*_status->size()/4, + // Qt::KeepAspectRatio, Qt::SmoothTransformation)); + } + // } +} + +void ConnectionFrame::setFrameRate(int newRate) +{ + //newRate = 5000; +} + +void ConnectionFrame::mouseReleaseEvent ( QMouseEvent * e ) +{ + if (e->button() == Qt::LeftButton) + { + QPoint relPoint = mapToParent(e->pos()); + QRect r = MainWindow::getConnectionWindow()->frameGeometry(); + /* + * We don't want to move the client in a position where we can't catch it again! + */ + if (relPoint.x() > r.width() || relPoint.y() > r.height() || + relPoint.x() < 0 || relPoint.y() < 0) + move(_previousPoint); + QApplication::setOverrideCursor(QCursor(Qt::OpenHandCursor)); + } +} + +void ConnectionFrame::enterEvent ( QEvent * event ) +{ + update(); + QApplication::setOverrideCursor(QCursor(Qt::OpenHandCursor)); + if (!_dummy) + _frame->setToolButtonListVisible(true); +} + +void ConnectionFrame::leaveEvent ( QEvent * event ) +{ + QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); + if (!_dummy) + _frame->setToolButtonListVisible(false); +} + +void ConnectionFrame::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::RightButton) + { + if (!_dummy) + { + DelDummy->setDisabled(true); + menu->exec(QCursor::pos()); + } + else + { + foreach (QAction* a, menu->actions()) + a->setDisabled(true); + DelDummy->setDisabled(false); + menu->exec(QCursor::pos()); + } + } + else + { + _clickPoint = event->pos(); + _previousPoint = pos(); + QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor)); + } + /* + * On click, the window have to be on the top-level. + */ + activateWindow(); + raise(); + update(); +} + +void ConnectionFrame::mouseMoveEvent(QMouseEvent *event) +{ + QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor)); + move(mapToParent(event->pos()-_clickPoint)); +} + +void ConnectionFrame::paintCloseUp(int w, int h) +{ + + + if (!_frame->image().isNull()) + { + /*this->setFixedWidth(w); + _conFrameTaskbar->setMaximumWidth(w); + resize(w, h);*/ + resizeComponent(w, h); + setMaximumSize(w,h); + resize(w, h); + } + else + { + std::cout << "pixel is NULL" << std::endl; + } + +} + +void ConnectionFrame::resizeComponent(int w, int h) +{ + int th = (h*_conFrameTaskbar->width())/w; + int uh = (h*_username->width())/w; + _conFrameTaskbar->setMaximumSize(w, th); + _conFrameTaskbar->resize(w, th); + _username->setMaximumSize(w, uh); + _username->resize(w,uh); +} + +void ConnectionFrame::setSource() +{ + _clientStatus = QPixmap(0, 0); //ein leeres Pixmap erstellen + _clientStatus.fill(Qt::white); // benöigt bevor man drin zeichen + _clientStatus = QPixmap(":/source"); + _status->setMaximumSize(QSize(62, 30)); + _status->setPixmap(_clientStatus.scaled(61,29, + Qt::KeepAspectRatio, Qt::SmoothTransformation)); + _isOnProjekt = true; +} + +void ConnectionFrame::setTarget() +{ + _clientStatus = QPixmap(0, 0); //ein leeres Pixmap erstellen + _clientStatus.fill(Qt::white); // benöigt bevor man drin zeichen + _clientStatus = QPixmap(":/target"); + _status->setMaximumSize(QSize(62, 30)); + _status->setPixmap(_clientStatus.scaled(61,29, + Qt::KeepAspectRatio, Qt::SmoothTransformation)); +} + +void ConnectionFrame::setUnproject() +{ + _clientStatus = QPixmap(0, 0); //ein leeres Pixmap erstellen + _clientStatus.fill(Qt::white); // benöigt bevor man drin zeichen + _clientStatus = QPixmap(":/online"); + _status->setMaximumSize(QSize(30, 30)); + _status->setPixmap(_clientStatus.scaled(29,27, + Qt::KeepAspectRatio, Qt::SmoothTransformation)); + _isOnProjekt = false; +} + +void ConnectionFrame::setDozent(bool isDozent) +{ + if (isDozent) + _dozentContaimner->setDisabled(false); + else + _dozentContaimner->setDisabled(true); +} + +void ConnectionFrame::on_click() +{ + //std::cout << "HALLO! WAS?" << std::endl; +} + +const QPixmap* ConnectionFrame::getFramePixmap() +{ + if (_frame == NULL) return NULL; + return _frame->pixmap(); +} + +Frame* ConnectionFrame::getFrame() +{ + if(_myConnection && _myConnection->getVNCConnection()) return _frame; + return NULL; +}; + +//Frame* ConnectionFrame::_frame = NULL; diff --git a/src/gui/connectionFrame.h b/src/gui/connectionFrame.h new file mode 100644 index 0000000..a199102 --- /dev/null +++ b/src/gui/connectionFrame.h @@ -0,0 +1,199 @@ +#ifndef _CONNECTIONFRAME_H_ +#define _CONNECTIONFRAME_H_ +#include <QtGui> +#include <fstream> +#include <iostream> +#include <QImage> +#include <QPixmap> +#include <QLabel> +#include <src/core/pvsClient.h> +#include <src/gui/frame.h> +//#include <src/gui/mainWindow.h> +#include <src/gui/dialog.h> +extern "C" +{ +#include <rfb/rfbclient.h> +} + +#define PROFILE +#include <src/util/timeUtil.h> + +/** + * Container for the drawable area that shows the corresponding servers desktop + * + */ + +class PVSClient; +class VNCConnection; +class ConnectionWindow; +class Frame; +class Dialog; +class MainWindow; + +class ConnectionFrame : public QGroupBox +{ + + Q_OBJECT + +public: + ConnectionFrame(QWidget* parent=0); // on width and height being zero, defaults values are used + virtual ~ConnectionFrame(); + + QString getTitle(); + void setTheTitle(QString title); + QString getTaskbarTitle(); + void setTaskbarTitle(QString title); + void setInitSize(int w, int h); + void Resize(int w, int h); + void initFrame(); + + int getPrevWidth(){return prev_width;}; + void setPrevWidth(int w){prev_width = w;} + int getPrevHeight(){return prev_height;}; + void setPrevHeight(int h){prev_height = h;} + + void setConnection(PVSClient* newConnection); + void resetConnectionWithQuality(int quality); + PVSClient* getConnection() + { + return _myConnection; + } + ; + //bool drawFrame(); // call to ask for a redraw of the frames content + void setIgnoreRatio(bool ignore); // sets wether it should force square on the content or not + void setFullscreen(bool fs); // toggles wether this frame is requested to shown fullscreen or not + bool getFullscreen() + { + return _fullscreen; + } + ; // returns wether the frame is fullscreen (or requested to be) or not + void setCloseup(bool cu); // toggles wether this frame is requested to shown fullscreen or not + bool getCloseup() + { + return _closeup; + } + ; // returns wether the frame is fullscreen (or requested to be) or not + + void setInteractive(bool doit); + float getRatio() + { + return _ratio; + } + ; // returns the native ratio of the source buffer (h/w) + void setRatio(int newRatio) + { + _ratio = newRatio; + } + ; + bool getOversized() + { + return overSized; + } + ; // returns wether the frame is reasonably wider than other frames (e.g. dual screen displays) + void setOversized(bool over) + { + overSized = over; + } + ; + void setActive(bool activate); + bool getActive() + { + return active; + } + ; + void setDummy(bool dummy); + bool isDummy() + { + return _dummy; + } + ; + bool isOnProjekt() + { + return _isOnProjekt; + } + ; + void setFrameRate(int newRate); + bool isClientOnline; + void paintCloseUp(int w, int h); + void resizeComponent(int w, int h); + void setSource(); + void setTarget(); + void setUnproject(); + void setDozent(bool isDozent); + const QPixmap* getFramePixmap(); + Frame* getFrame(); + int init_w, init_h; + +public Q_SLOTS: + virtual void delDummy(); + virtual void on_projection(); + virtual void on_unprojection(); + virtual void on_lock(); + virtual void on_unlock(); + virtual void on_message(); + virtual void on_lock_with_message(); + virtual void on_lock_all_with_message(); + virtual void on_lock_all(); + virtual void on_unlock_all(); + virtual void on_lock_invert(); + virtual void on_remoteHelp(); + virtual void on_click(); + +protected: + //virtual void paintEvent(QPaintEvent *event); + void mouseReleaseEvent ( QMouseEvent * e ); + virtual void enterEvent ( QEvent * event ); + virtual void leaveEvent ( QEvent * event ); + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + //void mouseReleaseEvent ( QMouseEvent * event ); + +private: + + Frame *_frame; + //clickableLabel *frame; + QSplitter *_split; + QGridLayout* _gL; + QLabel* _username; + QLabel* _status; + QLabel* _dozentContaimner; + QWidget* _conFrameTaskbar; + QGridLayout* _gLayout; + QHBoxLayout* _hLayoutInCfTaskbar; + + PVSClient* _myConnection; + QPixmap _clientPix; + QPixmap _clientStatus; + QPixmap _clientDozent; + int nat_height, nat_width; // native height and width of the source buffer + int cu_height, cu_width; + int prev_height, prev_width; + // uint8_t prev_buttonMask; /* bits 0-7 are buttons 1-8, 0=up, 1=down */ + int _ratio; + bool _dummy; + bool ignore_ratio, overSized, first; + bool _fullscreen, _closeup, _isOnProjekt; + + bool viewOnly, active; + rfbClient* myClient; + + QMenu *menu; + QAction *DelDummy; + QAction *lockClient ; + QAction *uLockClient ; + /*QAction *invertlockClient ; + QAction *LockAllClient ; + QAction *uLockAllClient ;*/ + QAction *msgLockAllClient ; + QAction *msgClient ; + QAction *msgLockClient ; + QAction *project ; + QAction *uproject ; + //QAction *rHelp ; + + + QPoint _clickPoint; + QPoint _previousPoint; +}; + +#endif diff --git a/src/gui/connectionList.cpp b/src/gui/connectionList.cpp new file mode 100644 index 0000000..2f9829e --- /dev/null +++ b/src/gui/connectionList.cpp @@ -0,0 +1,603 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/gui/connectionList.cpp +# ----------------------------------------------------------------------------- +*/ + +#include <QtGui> +#include <iostream> +#include "connectionList.h" +#include <src/gui/dialog.h> +//#include <src/gui/projectionDialog.h> +//#include "mainWindow.h" +#define COL_FULLNAME 0 +#define COL_IP 1 +#define COL_USERNAME 2 + +ConnectionList::ConnectionList(QWidget *parent): + QTableView(parent) +{ + /*Das Modelfestlegen, wo die Clientname angezeigt werden.*/ + model = new QStandardItemModel(0,3,this); //Leere Tabelle mit einer Spalte erstellen + model->setHeaderData(0, Qt::Horizontal, tr("Name")); //Spalte name definieren + model->setHeaderData(1, Qt::Horizontal, tr("IP")); //IP-column will be hide + model->setHeaderData(2, Qt::Horizontal, tr("Username")); + setModel(model); + this->setColumnHidden(1, true); + this->setColumnHidden(2, true); + + QItemSelectionModel *selectionModel = new QItemSelectionModel(model); + setSelectionModel(selectionModel); + QHeaderView *headerView = horizontalHeader(); + headerView->setStretchLastSection(true); + /*Das popup einstellen*/ + preparePopup(); + + _useUserName = true; + + setEditTriggers(QAbstractItemView::NoEditTriggers); //Die Einträge in der Tabelle werden nicht editierbar. + setSelectionMode(QAbstractItemView::ExtendedSelection); //Damit mehere Einträge selektierbar werden. + + resizeColumnToContents(0); + clientindex = 0; + isOnProjection = false; //No projection on progress now! + projSourceName = ""; //The projection source name is empty. +} + +ConnectionList::~ConnectionList() +{ +} + +void ConnectionList::preparePopup() +{ + + /*Aktion definieren*/ + /* a1 = new QAction(tr("&Remove Clients (debug)"),model); + connect(a1, SIGNAL(triggered()), this, SLOT(on_removeClient())); + a2 = new QAction(tr("&Request VNC-Window"),model); + connect(a2, SIGNAL(triggered()), this, SLOT(on_vnc_add())); + a3 = new QAction(tr("&Remove VNC-Window"),model); + connect(a3, SIGNAL(triggered()), this, SLOT(on_vnc_remove()));*/ + _lockClient = new QAction(tr("&Lock Client(s)"),model); + connect(_lockClient, SIGNAL(triggered()), this, SLOT(on_lock())); + _uLockClient = new QAction(tr("&Unlock Client(s)"),model); + connect(_uLockClient, SIGNAL(triggered()), this, SLOT(on_unlock())); + /* invertlockClient = new QAction(tr("&Invertlock Client(s)"),model); + connect(invertlockClient, SIGNAL(triggered()), this, SLOT(on_lock_invert())); + LockAllClient = new QAction(tr("&Lock all Client(s)"),model); + connect(LockAllClient, SIGNAL(triggered()), this, SLOT(on_lock_all())); + uLockAllClient = new QAction(tr("&Unlock all Client(s)"),model); + connect(uLockAllClient, SIGNAL(triggered()), this, SLOT(on_unlock_all()));*/ + _msgLockClient = new QAction(tr("&MsgLock Client(s)"),model); + connect(_msgLockClient, SIGNAL(triggered()), this, SLOT(on_lock_with_message())); + _msgLockAllClient = new QAction(tr("&MsgLock all Client(s)"),model); + connect(_msgLockAllClient, SIGNAL(triggered()), this, SLOT(on_lock_all_with_message())); + _msgClient = new QAction(tr("&Message Client(s)"),model); + connect(_msgClient, SIGNAL(triggered()), this, SLOT(on_message())); + //msgClient = createToolbarButton(tr("&Message Client(s)"), SLOT(on_message())); + _project = new QAction(tr("&Projection"),model); + connect(_project, SIGNAL(triggered()), this, SLOT(on_projection())); + _uproject = new QAction(tr("&Unprojection"),model); + connect(_uproject, SIGNAL(triggered()), this, SLOT(on_unprojection())); + /* rHelp = new QAction(tr("&Remote Help"),model); + connect(rHelp, SIGNAL(triggered()), this, SLOT(on_remoteHelp()));*/ + + /*Menü definieren*/ + _popupMenu = new QMenu(this); + + /*Aktionen in Menü aufnehmen*/ + /* menu->addAction(a1); + menu->addAction(a2); + menu->addAction(a3);*/ + _popupMenu->addAction(_lockClient); + _popupMenu->addAction(_uLockClient); + /* menu->addAction(invertlockClient); + menu->addAction(LockAllClient); + menu->addAction(uLockAllClient);*/ + _popupMenu->addAction(_msgLockClient); + _popupMenu->addAction(_msgLockAllClient); + _popupMenu->addAction(_msgClient); + _popupMenu->addAction(_project); + _popupMenu->addAction(_uproject); + // menu->addAction(rHelp); + +} + +QAction* ConnectionList::createToolbarButton(const QString &name, const char *slot) +{ + QAction *action = new QAction(name, model); + connect(action, SIGNAL(triggered()), this, slot); + _popupMenu->addAction(action); + + return action; +} + +void ConnectionList::mouseReleaseEvent(QMouseEvent * e ) +{ + // setCurrentIndex ( currentIndex () ); + if (e->button() == Qt::RightButton) + { + if (model->rowCount(QModelIndex()) > 0) + foreach (QAction *a, _popupMenu->actions()) + { + a->setDisabled(false); + } + else + foreach (QAction *a, _popupMenu->actions()) + { + a->setDisabled(true); + } + _popupMenu->exec(QCursor::pos()); + } +} + +void ConnectionList::onAddClient(PVSClient* newConnection) +{ + if (newConnection) + { + //clientindex = model->rowCount(QModelIndex())+1; + model->insertRow(clientindex, QModelIndex()); + //QString uname = newConnection->getPVSClientConnection()->getNameUser(); + QString uname = newConnection->getLoginName(); + if (_useUserName) + { + QString username = newConnection->getUserName(); + QString ip = newConnection->getIp(); + model->setData(model->index(clientindex, COL_FULLNAME, QModelIndex()),username); + model->setData(model->index(clientindex, COL_IP, QModelIndex()),ip); + model->setData(model->index(clientindex, COL_USERNAME, QModelIndex()),uname); + newConnection->getConnectionFrame()->setTaskbarTitle(ip); + addClientToList(username); + } + else + { + QString desktopname = QString(newConnection->getDesktopName().toUtf8().data()); + QString ip = newConnection->getIp(); + model->setData(model->index(clientindex, COL_FULLNAME, QModelIndex()),desktopname); + model->setData(model->index(clientindex, COL_IP, QModelIndex()),ip); + model->setData(model->index(clientindex, COL_USERNAME, QModelIndex()),uname); + } + setCurrentIndex(model->index(clientindex, 0)); + on_vnc_add(); // triggert the automatic vnc request! + setCurrentIndex(model->index(-1, 0)); + newConnection->setClientindex(clientindex); + clientindex++; + } +} + +void ConnectionList::onRemoveClient(PVSClient* newCon) +{ + if (newCon && model->rowCount(QModelIndex()) > 0) + { + QString host = newCon->getIp(); + for (int i=0; i<model->rowCount(QModelIndex()); i++) + { + if (model->index(i, 1, QModelIndex()).data(Qt::DisplayRole).toString() + .compare(host) == 0) + { + removeClientToList(model->index(i, 1, QModelIndex()).data(Qt::DisplayRole).toString()); + model->removeRow(i, QModelIndex()); + clientindex--; + break; + } + } + /* + * We have to check, if this disconnected client is involved in a projection process. + * If true, we have to unproject it, this will unproject the others clients that becomme + * the projection. + */ + if (targetList.contains(host) || sourceList.contains(host)) + unproject(host); + + + } +} + +void ConnectionList::addClientToList(QString clientname) +{ + if (!_clientNames.contains(clientname)) + _clientNames.append(clientname); +} + +void ConnectionList::removeClientToList(QString clientname) +{ + if (_clientNames.contains(clientname)) + { + _clientNames.removeOne(clientname); + } +} + +void ConnectionList::onUpdateClient(PVSClient* newConnection) +{ + + if (model->rowCount(QModelIndex()) > 0) + { + for (int i=0; i<model->rowCount(QModelIndex()); i++) + { + if (model->index(i, 1, QModelIndex()).data(Qt::DisplayRole).toString() + .compare(newConnection->getIp()) == 0) + { + if (_useUserName) + { + newConnection->getConnectionFrame()->setTheTitle(newConnection->getUserName()); + model->setData(model->index(i, COL_FULLNAME, QModelIndex()),newConnection->getUserName()); + } + else + { + newConnection->getConnectionFrame()->setTheTitle(newConnection->getDesktopName()); + model->setData(model->index(i, COL_FULLNAME, QModelIndex()),newConnection->getDesktopName()); + } + break; + } + } + } + else + { + // something went awfully wrong! + } +} + +bool ConnectionList::useUserName() +{ + return _useUserName; +} + +bool ConnectionList::useUserName(bool use) +{ + + if (use != _useUserName) + { + _useUserName = use; + } + return useUserName(); +} + +void ConnectionList::on_vnc_add() +{ + MainWindow::getConnectionWindow()->addVNC(); +} + +void ConnectionList::on_vnc_remove() +{ + MainWindow::getConnectionWindow()->removeVNC(); +} + +void ConnectionList::unproject(QString source) +{ + if (sourceList.contains(source)) + { + QList<QString> target; + if (sourceMap.contains(source)) + { + QString item; + foreach (item, sourceMap.value(source)) + { + MainWindow::getConnectionWindow()->unprojectStations(item); //Nur target must be unproject + targetList.removeOne(item); + } + sourceMap.take(source); + } + MainWindow::getConnectionWindow()->unprojectStations(source); //the source schould be too unprojected. + sourceList.removeOne(source); + } + else + { + MainWindow::getConnectionWindow()->unprojectStations(source); //unproject a target + targetList.removeOne(source); + } + /*if (targetList.size() == 1) + targetList.clear();*/ +} + +void ConnectionList::on_projection() +{ + if(model->rowCount(QModelIndex())>1) + { + std::list<QString>* cuList = getSelectedClients(); + + if (targetList.size() == (model->rowCount(QModelIndex())-1)) + { + QString message = QString(tr("No Target is available for a projection!\nPerform an unprojection to get a target.")); + QMessageBox::information(this, "PVS", message); + } + else if(cuList->size() == 1) + { + QString source = cuList->front(); + if (targetList.contains(source)) + { + QString message = QString(tr("This source is already in a projection process involved.\n You can perform a unprojection on it to get it free.")); + QMessageBox::information(this, "PVS", message); + } + else + { + ProjectionDialog projDialog; + int result = projDialog.exec(); + + if(result == 1) + { + if(projectList.size()>0) + { + QList<QString> list; + QString item; + foreach(item, projectList) + { + list.append(item); + } + sourceMap.insert(projSourceName, list); + if (!sourceList.contains(source)) + sourceList.append(source); + MainWindow::getConnectionWindow()->projectStations(projSourceName); + } + else + ConsoleLog writeError( "Strange...the selected target aren't be transmitted to the MainWindow."); + } + else + ; // :( + } + } + else if(cuList->size() > 1) + { + QString message = QString(tr("To perform a projection you have to select only one source in a list with more than one index!")); + QMessageBox::information(this, "PVS", message); + } + } + else + { + QString message = QString(tr("To perform a projection you have to select only one source in a list with more than one index!")); + QMessageBox::information(this, "PVS", message); + } +} + +void ConnectionList::on_unprojection() +{ + if(model->rowCount(QModelIndex())>1) + { + std::list<QString>* cuList = getSelectedClients(); + if(cuList->size() == 1) + { + QString source = cuList->front(); + unproject(source); + } + else + { + QString message = QString(tr("An unprojection is only possible on a selected source that is involved in a projection process, in a list with more than one index!")); + QMessageBox::information(this, "PVS", message); + } + } + else + { + QString message = QString(tr("An unprojection is only possible on a selected source that is involved in a projection process, in a list with more than one index!")); + QMessageBox::information(this, "PVS", message); + } +} + +void ConnectionList::on_remoteHelp() +{ + if(model->rowCount(QModelIndex())>1) + { + std::list<QString>* cuList = getSelectedClients(); + + if (targetList.size() == (model->rowCount(QModelIndex())-1)) + { + QString message = QString(tr("No Target is available for remote Help!\nPerform an unprojection or remove remote help to get a target.")); + QMessageBox::information(this, "PVS", message); + } + else if(cuList->size() == 1) + { + QString source = cuList->front(); + if (targetList.contains(source)) + { + QString message = QString(tr("This source is already in a projection or remote Help process involved.\n You can perform a unprojection or remove remote Help on it to get it free.")); + QMessageBox::information(this, "PVS", message); + } + else + { + ProjectionDialog projDialog; + int result = projDialog.exec(); + + if(result == 1) + { + if(projectList.size() > 0 && projectList.size() < 2) + { + QList<QString> list; + QString item; + foreach(item, projectList) + { + list.append(item); + } + sourceMap.insert(projSourceName, list); + MainWindow::getConnectionWindow()->remoteHelp(projSourceName); + } + else + ConsoleLog writeError( "Strange...the selected targets aren't be transmitted to the MainWindow."); + } + else + ; // :( + } + } + } + else + { + QString message = QString(tr("To perform a projection you have to select only one source in a list with more than one index!")); + QMessageBox::information(this, "PVS", message); + } +} + +void ConnectionList::on_lock() +{ + MainWindow::getConnectionWindow()->lockStations(); +} + +void ConnectionList::on_unlock() +{ + MainWindow::getConnectionWindow()->unlockStations(); +} + +void ConnectionList::on_message() +{ + Dialog msgD; + QString myString = NULL; + int result = msgD.exec(); + + if (result == 1) + { + myString = MainWindow::getWindow()->getMsgDialog(); + if(!myString.isEmpty()) + MainWindow::getConnectionWindow()->messageStations("BROADCAST",myString); + } + +} + +void ConnectionList::on_lock_with_message() +{ + Dialog msgD; + QString myString = NULL; + int result = msgD.exec(); + + if(result == 1) + { + myString = MainWindow::getWindow()->getMsgDialog(); + if(!myString.isEmpty()) + { + MainWindow::getConnectionWindow()->lockStationsWithMessage(myString); + } + } +} + +void ConnectionList::on_lock_all_with_message() +{ + QString myString = NULL; + Dialog msgD; + int result = msgD.exec(); + + if(result == 1) + { + myString = MainWindow::getWindow()->getMsgDialog(); + if(!myString.isEmpty()) + { + MainWindow::getConnectionWindow()->lockAllStationsWithMessage(myString); + } + } +} + + +void ConnectionList::on_lock_all() +{ + MainWindow::getConnectionWindow()->lockAllStations(); +} +void ConnectionList::on_unlock_all() +{ + MainWindow::getConnectionWindow()->unlockAllStations(); +} + +void ConnectionList::on_unproject_all() +{ + MainWindow::getConnectionWindow()->unprojectAllStations(); +} + + +void ConnectionList::on_lock_invert() +{ + MainWindow::getConnectionWindow()->lockInvertStations(); +} + + +void ConnectionList::on_removeClient() +{ + QTableView *temp = static_cast<QTableView*>(this); + QItemSelectionModel *selectionModel = temp->selectionModel(); + + QModelIndexList indexes = selectionModel->selectedRows(); + removeClient(indexes); +} + +void ConnectionList::removeClient(QModelIndexList indexes) +{ + + QModelIndex index; + + foreach(index, indexes) + { + int row = currentIndex().row(); + QString current = model->index(row, 0).data(Qt::DisplayRole).toString(); + removeClientToList(current); + model->removeRow(row, QModelIndex()); + } +} + +std::list<QString>* ConnectionList::getSelectedClients(bool isClickOnWindow) +{ + + std::list<QString>* currentList = new std::list<QString>; + + + QTableView *temp = static_cast<QTableView*>(this); + QItemSelectionModel *selectionModel = temp->selectionModel(); + QModelIndexList indexes = selectionModel->selectedIndexes(); + QModelIndex index; + if (indexes.size() > 0) + { + foreach (index, indexes) + { + QString current = model->index(index.row(), 1).data(Qt::DisplayRole).toString(); + currentList->push_back(current); + } + } + + return currentList; +} + +void ConnectionList::setProjectProporties(QString source) +{ + projSourceName = source; // The source for this projection + sourceList.append(source); // The list for all source in pvsmgr +} + +QList<QString> ConnectionList::getTargetToDisplay(QString source) +{ + displayList.clear(); + projectList.clear(); + + for (int i=0; i<model->rowCount(QModelIndex()); i++) + { + QString item = model->index(i, 1, QModelIndex()).data(Qt::DisplayRole).toString(); + if (item.compare(source) != 0 && !targetList.contains(item) && !sourceList.contains(item)) + { + displayList.append(item); + } + } + + return displayList; + +} + +void ConnectionList::addTargetToProjectList(QString name) +{ + if (!targetList.contains(name)) + { + projectList.append(name); + targetList .append(name); + } +} + +QList<QString> ConnectionList::getTargetForTheProject(QString source) +{ + QList<QString> target; + if(sourceMap.contains(source)){ + target = sourceMap.value(source); + } + return target; +} + + + +bool ConnectionList::isOnProjection = false; diff --git a/src/gui/connectionList.h b/src/gui/connectionList.h new file mode 100644 index 0000000..50d8924 --- /dev/null +++ b/src/gui/connectionList.h @@ -0,0 +1,134 @@ +#ifndef _CONNECTIONLIST_H_ +#define _CONNECTIONLIST_H_ + +#include <QtGui> +#include <src/core/pvsClient.h> +#include <QTableView> +#include <QObject> +#include <QMap> +#include <QItemSelection> +#include <src/gui/mainWindow.h> +#include <src/gui/dialog.h> +#include <src/gui/projectionDialog.h> + +class PVSClient; + +//class QAbstractItemView; + + +/** + * The Sidebar showing the connected servers + * also used to determine to which connection + * contextual actions should be applied + */ + +class QVBoxLayout; +class QSortFilterProxyModel; +class QAbstractItemModel; +class QAbstractItemView; +class QItemSelectionModel; +class MainWindow; +class Dialog; +class ProjectionDialog; +//class ConnectionList; + +class ConnectionList: public QTableView +{ + Q_OBJECT + +public: + ConnectionList(QWidget *parent=0); + ~ ConnectionList(); + + void onAddClient(PVSClient* newConnection); // called if a new connection is added + void onUpdateClient(PVSClient* newConnection); // update the username*/ + void addClientToList(QString clientname); + void onRemoveClient(PVSClient* newCon); + void removeClientToList(QString clientname); + QList<QString> getClientist() + { + return _clientNames; + }; + // void updateAllClients(); + bool useUserName(); + bool useUserName(bool use); + QList<QString> projectList; + QList<QString> targetList; + QList<QString> displayList; + QList<QString> sourceList; + QMap<QString, QList<QString> > sourceMap; + QString projSourceName; + std::list<QString>* getSelectedClients(bool isClickOnWindow=false); // returns the currently selected clients + //void setTargetToDisplay(QString source); // return the list for the projection + void setProjectProporties(QString source); + QList<QString> getTargetToDisplay(QString source); + void addTargetToProjectList(QString name); + QList<QString> getTargetForTheProject(QString source); + QList<QString>getTargetToProject() + { + return projectList; + } + // void removeFromList(PVSConnection* newConnection); // called if a connection is removed + // void setMultipleSelection(bool on); + + QAbstractItemModel *model; + +private: + QItemSelectionModel *_selectionModel; + QList<QString> _clientNames; + + int clientindex; //Index of clientname in the list. + + static bool isOnProjection; + + QMenu *_popupMenu; // in der PopupMenu + /*Die Aktionen in der PopupMenu*/ + /* QAction *a1 ; + QAction *a2 ; + QAction *a3 ;*/ + QAction *_lockClient ; + QAction *_uLockClient ; + /*QAction *invertlockClient ; + QAction *LockAllClient ; + QAction *uLockAllClient ;*/ + QAction *_msgLockClient ; + QAction *_msgLockAllClient ; + QAction *_msgClient ; + QAction *_project ; + QAction *_uproject ; + // QAction *rHelp ; + + void preparePopup(); + void unproject(QString source); + QAction* createToolbarButton(const QString &name, const char *slot); + +public slots: + //Signal handlers: + + virtual void on_projection(); + virtual void on_unprojection(); + virtual void on_lock(); + virtual void on_unlock(); + virtual void on_message(); + virtual void on_lock_with_message(); + virtual void on_lock_all_with_message(); + virtual void on_lock_all(); + virtual void on_unlock_all(); + virtual void on_unproject_all(); + virtual void on_lock_invert(); + virtual void on_remoteHelp(); + void on_vnc_add(); + void on_vnc_remove(); + void on_removeClient(); + void removeClient(QModelIndexList indexes); + /*virtual void on_menu_file_remove_connection();*/ + +signals: + void selectionChanged (const QItemSelection &selected); + +protected: + bool _useUserName; + virtual void mouseReleaseEvent (QMouseEvent * e ); +}; + +#endif diff --git a/src/gui/connectionWindow.cpp b/src/gui/connectionWindow.cpp new file mode 100644 index 0000000..cf51051 --- /dev/null +++ b/src/gui/connectionWindow.cpp @@ -0,0 +1,763 @@ +/* + # 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/ + # ----------------------------------------------------------------------------- + # src/gui/connectionWindow.cpp + # ----------------------------------------------------------------------------- + */ + +#include "connectionWindow.h" +#include <src/core/pvsConnectionManager.h> +#include <src/gui/mainWindow.h> + +ConnectionWindow::ConnectionWindow(QWidget *parent) : + QWidget(parent) { + + //initialize the position for the frame in the clientView + posX = 4; + posY = 4; + + _closeupFrame = NULL; + hasDozent = false; // at the begin we don't have a dozent machine + + QPalette newPalette = palette(); + newPalette.setColor(QPalette::Window, Qt::white); + setPalette(newPalette); + + newDummy = new QAction(tr("&Add a dummy..."), this); // set a dummy + connect(newDummy, SIGNAL(triggered()), this, SLOT(addDummy())); + + menu = new QMenu(this); + menu->addAction(newDummy); + + setAcceptDrops(true); //drag&drop should be enabled +} + +ConnectionWindow::~ConnectionWindow() { + // +} + +void ConnectionWindow::addFrame(ConnectionFrame *cF) { + bool found = false; + foreach (ConnectionFrame* cFr, AllFrameOnWindow) + { + if (QString::compare(cF->getTaskbarTitle(), cFr->getTaskbarTitle(), Qt::CaseInsensitive) == 0) + { + QPoint cuP = currentPosition(cFr); + cF->move(cuP); + AllFrameOnWindow.append(cF); + AllFrameOnWindow.removeOne(cFr); //we don't need this dummy any more + cFr->deleteLater(); + found = true; + return; + } + } + + /* If the Frame don't belong to the profile + * we have to move it at the default position for now. + * The user can move this later to his favorite position. + */ + if (!found) + { + foreach (clientLocation cur, ClientLocationList) + { + if (QString::compare(cF->getTaskbarTitle(), cur.first, Qt::CaseInsensitive) == 0) + { + cF->move(cur.second); + found = true; + return; + } + } + } + + if (!found) + cF->move(10, 10); +} + +void ConnectionWindow::addFrameBySettings(QString client, QPoint pos) { + clientLocation cur(client, pos); + ClientLocationList.append(cur); +} + +void ConnectionWindow::showFrameFromSettings() { + foreach (clientLocation cur, ClientLocationList) + { + ConnectionFrame* dummy = new ConnectionFrame( + MainWindow::getConnectionWindow()); + AllFrameOnWindow.append(dummy); + dummy->setTheTitle("[No name]"); + dummy->setTaskbarTitle(cur.first); + dummy->setDummy(true); + dummy->move(cur.second); + } +} + +void ConnectionWindow::addDummy() { //function to add a dummy + ConnectionFrame* dummy = new ConnectionFrame( + MainWindow::getConnectionWindow()); + dummy->setTheTitle("[No name]"); + dummy->setTaskbarTitle("[0.0.0.0]"); + QPoint p = QPoint(10, 10);//the default move position, when created a dummy screen + AllFrameOnWindow.append(dummy); + clientLocation cur("[No name]", p); + ClientLocationList.append(cur); + dummy->setDummy(true); + dummy->move(p); + dummy->setStyleSheet(QString::fromUtf8( + "background-color: rgb(150, 150, 168);")); +} + +void ConnectionWindow::mousePressEvent(QMouseEvent *event) { //catch the mouse press event + if (event->button() == Qt::RightButton) + menu->exec(QCursor::pos()); +} + +QPoint ConnectionWindow::currentPosition(ConnectionFrame* cF) { + QPoint pos = QPoint(10, 10); + clientLocation cur; + foreach (cur, ClientLocationList) + { + if (QString::compare(cF->getTaskbarTitle(), cur.first, Qt::CaseInsensitive) == 0) + return cur.second; + } + return pos; +} + +int ConnectionWindow::itemAt(ConnectionFrame* cf) +{ + for (int i = AllFrameOnWindow.size() - 1; i >= 0; --i) + { + ConnectionFrame* item = AllFrameOnWindow.at(i); + if (cf->pos().x() == item->pos().x() && cf->pos().y() == item->pos().y()) + return i; + } + return -1; +} + +void ConnectionWindow::removeFromList(ConnectionFrame* cF) { + //dummyList.removeOne(cF); + if(AllFrameOnWindow.contains(cF)) + AllFrameOnWindow.removeOne(cF); + cF->deleteLater(); +} + +void ConnectionWindow::onChangeConnections() { + + //clear the view + if (!frameList.empty()) { + ConnectionFrame* tmpIt; + foreach (tmpIt, frameList) + { + if (tmpIt != currentSingleFrame) + tmpIt->setActive(false); + tmpIt->hide(); + } + } + +} + +bool ConnectionWindow::projectStations(QString sname) { + QString password, hostname; + int port, quality; + ConsoleLog writeLine(QString("Projecting from: ").append(sname)); + //TODO add method parameter for this + quality = 0; + + QList<QString> projectList = + MainWindow::getConnectionList()->getTargetForTheProject(sname); + + if (!projectList.isEmpty()) { + PVSClient* tmpSrcConnection = + PVSConnectionManager::getManager()->getClientFromIp(sname); + if (tmpSrcConnection) { + if (!tmpSrcConnection->getVNCAllowed()) { + ConsoleLog writeError(QString("VNC is not allowed on Projection Source: ").append(sname)); + ConsoleLog writeError(QString("Trying to start VNC-Server on Client: ").append(sname)); + tmpSrcConnection->setProject(true); + return false; + } + password = tmpSrcConnection->getPassword(); + port = tmpSrcConnection->getPort(); + hostname = sname; + tmpSrcConnection->getConnectionFrame()->setSource(); + ConsoleLog writeError (QString("port: ").append(int2String(port))); + ConsoleLog writeError (QString("passwort: ").append(password)); + ConsoleLog writeError (QString("pr-sourcename: ").append(sname)); + + } + else + { + return false; + } + + ConsoleLog writeError (QString("port as int: ").append(port)); + ConsoleLog writeError (QString("port as String: ").append(int2String(port))); + + QString item; + foreach (item, projectList) + { + PVSClient* tmpConnection = PVSConnectionManager::getManager()->getClientFromIp(item); + if (tmpConnection) + { + ConsoleLog writeError (QString("sending vnc data to: ").append(tmpConnection->getIp())); + tmpConnection->sendMessage(PVSCOMMAND,"PROJECT", hostname + " " + int2String(port) + " " + password + " " + int2String(quality)); + tmpConnection->getConnectionFrame()->setTarget(); + } + else + { + // scream in agony + } + } + } + return true; +} + +bool ConnectionWindow::remoteHelp(QString sname) { + + //TODO Finish this... + QString password, hostname; + int port; + + PVSClient* tmpSrcConnection = + PVSConnectionManager::getManager()->getClientFromIp(sname); + QList<QString> projectList = + MainWindow::getConnectionList()->getTargetForTheProject(sname); + if (tmpSrcConnection) { + if (!tmpSrcConnection->getVNCAllowed()) { + tmpSrcConnection->requestVNCConnect(); + tmpSrcConnection->setProject(true); + return false; + } + password = tmpSrcConnection->getRWPassword(); + port = tmpSrcConnection->getPort(); + hostname = sname; + tmpSrcConnection->getConnectionFrame()->setSource(); + } else { + return false; + } + + QString item; + foreach (item, projectList) + { + PVSClient + * tmpConnection = + PVSConnectionManager::getManager()->getClientFromIp(item); + if (tmpConnection) { + ConsoleLog writeError(QString("sending vnc data to: ").append( + tmpConnection->getIp())); + tmpConnection->sendMessage(PVSCOMMAND, "PROJECT", hostname + + " " + int2String(port) + " " + password); + tmpConnection->getConnectionFrame()->setTarget(); + } else { + // scream in agony + } + } + return true; + +} + + + +bool ConnectionWindow::lockStations() { + if (std::list<QString>* lockList = MainWindow::getConnectionList()->getSelectedClients()) { + if (!lockList->empty()) { + for (std::list<QString>::iterator tmpIt = lockList->begin(); tmpIt + != lockList->end(); tmpIt++) { + PVSClient + * tmpConnection = + PVSConnectionManager::getManager()->getClientFromIp( + (*tmpIt).toUtf8().data()); + if (tmpConnection->getConnectionFrame()->getFrame()) + { + // we don't want to lock the dozent machine + if (tmpConnection && !tmpConnection->getConnectionFrame()->getFrame()->isDozent() + && !tmpConnection->getConnectionFrame()->isOnProjekt()) + lockStation(tmpConnection); + else { + // scream in agony + } + } + } + } + delete lockList; + } + return true; +} + +void ConnectionWindow::lockStation(PVSClient* pvsCon) { + if (pvsCon->getVNCConnection()) + { + pvsCon->getConnectionFrame()->getFrame()->setLockStatus(true); + // we call the update to force Qt to paint the lockicon on the frame + pvsCon->getConnectionFrame()->getFrame()->update(); + pvsCon->sendMessage(PVSCOMMAND, "LOCKSTATION", ""); + } +} + +bool ConnectionWindow::unlockStations() { + if (std::list<QString>* unlockList = MainWindow::getConnectionList()->getSelectedClients()) { + if (!unlockList->empty()) { + for (std::list<QString>::iterator tmpIt = unlockList->begin(); tmpIt + != unlockList->end(); tmpIt++) { + PVSClient + * tmpConnection = + PVSConnectionManager::getManager()->getClientFromIp( + (*tmpIt).toUtf8().data()); + if (tmpConnection && tmpConnection->getConnectionFrame()->getFrame() && + tmpConnection->getVNCConnection()) { + tmpConnection->getConnectionFrame()->getFrame()->setLockStatus(false); + tmpConnection->getConnectionFrame()->getFrame()->update(); // we call the update to force Qt to paint the lock on the frame + tmpConnection->sendMessage(PVSCOMMAND, "UNLOCKSTATION", ""); + } else { + // scream in agony + } + } + } + delete unlockList; + } + return true; +} + +void ConnectionWindow::unlockStation(PVSClient* pvsCon) { + if (pvsCon->getVNCConnection()) + { + pvsCon->getConnectionFrame()->getFrame()->setLockStatus(false); + // we call the update to force Qt to paint the lockicon on the frame + pvsCon->getConnectionFrame()->getFrame()->update(); + pvsCon->sendMessage(PVSCOMMAND, "UNLOCKSTATION", ""); + } +} + +bool ConnectionWindow::lockAllStations() +{ + if (!hasDozent) + { + QString message = QString(tr("You have to set a Superclient-machine before performing this action.")); + QMessageBox::information(this, "PVS", message); + return false; + } + std::list<PVSClient*> listAll = + PVSConnectionManager::getManager()->getConnections(); + for (std::list<PVSClient*>::iterator it = listAll.begin(); it + != listAll.end(); it++) + { + if (*it == NULL || (*it)->getConnectionFrame() == NULL) continue; + // we don't want to lock the superclient machine + if ((*it)->getConnectionFrame()->getFrame() && + !(*it)->getConnectionFrame()->getFrame()->isDozent() && + (*it)->getVNCConnection()) + (*it)->sendMessage(PVSCOMMAND, "LOCKSTATION", ""); + else if (!(*it)->getConnectionFrame()->getFrame()) + ConsoleLog writeError(QString("The Frame connection from client: "). + append((*it)->getConnectionFrame()->getTaskbarTitle()). + append(QString(" is corrupted. Reconned the client it again."))); + } + return true; +} + +bool ConnectionWindow::unlockAllStations() { + std::list<PVSClient*> listAll = + PVSConnectionManager::getManager()->getConnections(); + for (std::list<PVSClient*>::iterator it = listAll.begin(); it + != listAll.end(); it++) + { + if ((*it)->getVNCConnection()) + { + (*it)->getConnectionFrame()->getFrame()->setLockStatus(false); + (*it)->getConnectionFrame()->getFrame()->update(); // we call the update to force Qt to repaint the frame + (*it)->sendMessage(PVSCOMMAND, "UNLOCKSTATION", ""); + } + // otherwise this will get scattered all over the place + } + return true; +} + +bool ConnectionWindow::unprojectStations(QString sname) { + PVSClient* tmpConnection = + PVSConnectionManager::getManager()->getClientFromIp(sname); + if (tmpConnection && tmpConnection->getVNCConnection()) { + tmpConnection->sendMessage(PVSCOMMAND, "UNPROJECT", ""); + tmpConnection->getConnectionFrame()->setUnproject(); + } else { + // scream in agony + } + + return true; +} + +bool ConnectionWindow::unprojectAllStations() { + std::list<PVSClient*> listAll = + PVSConnectionManager::getManager()->getConnections(); + for (std::list<PVSClient*>::iterator it = listAll.begin(); it + != listAll.end(); it++) + { + if ((*it)->getVNCConnection()) + { + (*it)->sendMessage(PVSCOMMAND, "UNPROJECT", ""); + (*it)->getConnectionFrame()->setUnproject(); + } + } + return true; +} + +bool ConnectionWindow::lockInvertStations() { + // ok, this method is highly imperformant i guess + // we're going thru all existing connections, and if they dont equal one of the selected (another loop) + // we lock them... + if (std::list<QString>* lockList = MainWindow::getConnectionList()->getSelectedClients()) { + std::list<PVSClient*> listAll = + PVSConnectionManager::getManager()->getConnections(); + bool skip = false; + for (std::list<PVSClient*>::iterator it = listAll.begin(); it + != listAll.end(); it++) { + if (!lockList->empty()) { + for (std::list<QString>::iterator tmpIt = lockList->begin(); tmpIt + != lockList->end(); tmpIt++) { + PVSClient + * tmpConnection = + PVSConnectionManager::getManager()->getClientFromIp( + (*tmpIt).toUtf8().data()); + if (tmpConnection == (*it)) { + skip = true; + break; + } + } + } + if (!skip) + (*it)->sendMessage(PVSCOMMAND, "LOCKSTATION", "");//TODO define some standard to grab this from... + // otherwise this will get scattered all over the place + } + delete lockList; + } + return true; +} + +void ConnectionWindow::lockInvertStation(PVSClient* pvsCon) { + pvsCon->sendMessage(PVSCOMMAND, "LOCKSTATION", ""); +} + +bool ConnectionWindow::messageStations(QString ident, QString message) { + if (std::list<QString>* messageList = MainWindow::getConnectionList()->getSelectedClients()) { + if (!messageList->empty()) { + for (std::list<QString>::iterator tmpIt = messageList->begin(); tmpIt + != messageList->end(); tmpIt++) { + PVSClient + * tmpConnection = + PVSConnectionManager::getManager()->getClientFromIp( + (*tmpIt).toUtf8().data()); + // we don't want to lock the dozent machine + if (tmpConnection && tmpConnection->getConnectionFrame()->getFrame() && + !tmpConnection->getConnectionFrame()->getFrame()->isDozent()) + { + messageStation(ident, message, tmpConnection); + } else { + // scream in agony + } + } + } + delete messageList; + } + return true; +} + +void ConnectionWindow::messageStation(QString ident, QString message, + PVSClient* pvsCon) { + pvsCon->sendMessage(PVSMESSAGE, ident, message); +} + +bool ConnectionWindow::lockStationsWithMessage(QString message) +{ + if (!hasDozent) + { + QString message = QString(tr("You have to set a Superclient-machine before performing this action.")); + QMessageBox::information(this, "PVS", message); + return false; + } + if (std::list<QString>* messageList = MainWindow::getConnectionList()->getSelectedClients()) { + if (!messageList->empty()) { + for (std::list<QString>::iterator tmpIt = messageList->begin(); tmpIt + != messageList->end(); tmpIt++) { + PVSClient + * tmpConnection = + PVSConnectionManager::getManager()->getClientFromIp( + (*tmpIt).toUtf8().data()); + // we don't want to lock the dozent machine + if (tmpConnection && !tmpConnection->getConnectionFrame()->getFrame()->isDozent()) + { + lockStationsWithMessage(message, tmpConnection); + + } else { + // scream in agony + } + } + } + delete messageList; + } + return true; +} + +void ConnectionWindow::lockStationsWithMessage(QString message, + PVSClient* pvsCon) +{ + pvsCon->sendMessage(PVSCOMMAND, "LOCKSTATION", message); +} + +bool ConnectionWindow::lockAllStationsWithMessage(QString message) { + + if (!hasDozent) + { + QString message = QString(tr("You have to set a Superclient-machine before performing this action.")); + QMessageBox::information(this, "PVS", message); + return false; + } + std::list<PVSClient*> listAll = + PVSConnectionManager::getManager()->getConnections(); + for (std::list<PVSClient*>::iterator it = listAll.begin(); it + != listAll.end(); it++) + { + if ((*it) && !(*it)->getConnectionFrame()->getFrame()->isDozent()) // we don't want to lock the dozent machine + (*it)->sendMessage(PVSCOMMAND, "LOCKSTATION", message); + } + return true; +} + +void ConnectionWindow::addConnection(PVSClient* newCon) { + if (newCon) { + // QList<QString> ClientList= MainWindow::getConnectionList()->getClientist(); + + //Check if this client already in the list, before we add it. + //We don't want to have two clients with the same names. + //We comments it for test. + /*if (!ClientList.contains(newCon->getHostString())) + {*/ + onVNCAdd(newCon); + MainWindow::getConnectionList()->onAddClient(newCon); + /* + * We check if the pvsmgr run a lockAll on the already connected + * clients. If yes, we lock the new conencted client too. + */ + if (MainWindow::getWindow()->isLockAllStatus() && newCon->getConnectionFrame()->getFrame()) + { + newCon->getConnectionFrame()->getFrame()->setLockStatus(true); + // we call the update to force Qt to paint the lockicon on the frame + newCon->getConnectionFrame()->getFrame()->update(); + lockStation(newCon); + } + //} + } +} + +void ConnectionWindow::removeConnection(PVSClient* newCon) { + if (newCon == NULL) return; + ConnectionFrame* frame = newCon->getConnectionFrame(); + if (frame != NULL) + { + removeFromList(frame); + //frame->deleteLater(); + } + MainWindow::getConnectionList()->onRemoveClient(newCon); +} + +void ConnectionWindow::onView() { + if (std::list<QString>* selectedClient = MainWindow::getConnectionList()->getSelectedClients()) { + if (!selectedClient->empty()) { + if (selectedClient->size() == 1) + ;//TODO + + } + } +} + +void ConnectionWindow::updateConnection(PVSClient* newCon) { + if (newCon) { + MainWindow::getConnectionList()->onUpdateClient(newCon); + } +} + +void ConnectionWindow::addVNC() { + if (std::list<QString>* vncAddList = MainWindow::getConnectionList()->getSelectedClients()) { + if (!vncAddList->empty()) { + for (std::list<QString>::iterator tmpIt = vncAddList->begin(); tmpIt + != vncAddList->end(); tmpIt++) { + PVSClient + * tmpConnection = + PVSConnectionManager::getManager()->getClientFromIp( + (*tmpIt).toUtf8().data()); + if (tmpConnection) { + tmpConnection->requestVNCConnect(); + } else { + // scream in agony + } + } + } + } +} + +void ConnectionWindow::onVNCAdd(PVSClient* newCon) { + + if (!newCon->getConnectionFrame()) { + ConnectionFrame* newFrame = newConFrame(newCon); + newFrame->setConnection(newCon); + newFrame->setTaskbarTitle(newFrame->getTaskbarTitle()); + newFrame->setDummy(false); + newFrame->setFrameRate(500); + addFrame(newFrame); + if (!frameList.contains(newFrame)) + frameList.append(newFrame); + if (!AllFrameOnWindow.contains(newFrame)) + AllFrameOnWindow.append(newFrame); + newFrame->show(); + } else + // now we have already a pvsconnection, we should set the existing vncconnection to it + newCon->getConnectionFrame()->setConnection(newCon); + // addFrame(newFrame); +} + +void ConnectionWindow::removeVNC() { + std::list<QString>* vncRemoveList = + MainWindow::getConnectionList()->getSelectedClients(); + + // if(!vncRemoveList->empty()) + // { + for (std::list<QString>::iterator tmpIt = vncRemoveList->begin(); tmpIt + != vncRemoveList->end(); tmpIt++) { + PVSClient* tmpConnection = + PVSConnectionManager::getManager()->getClientFromIp( + (*tmpIt).toUtf8().data()); + if (tmpConnection) { + if (tmpConnection->getVNCConnection()) { + ConnectionFrame* tmpFrame = + tmpConnection->getVNCConnection()->getFrame(); + if (tmpFrame) { + frameList.removeOne(tmpFrame); + onChangeConnections(); + tmpFrame->setConnection(NULL); + tmpFrame->initFrame(); + //delete tmpFrame; + } + tmpConnection->shutDownVNC(); + } + } else { + // scream in agony + } + } + // + // } +} + +void ConnectionWindow::onRemoveConnection() { + if (std::list<QString>* removeList = MainWindow::getConnectionList()->getSelectedClients()) { + if (!removeList->empty()) { + for (std::list<QString>::iterator tmpIt = removeList->begin(); tmpIt + != removeList->end(); tmpIt++) { + PVSClient + * tmpConnection = + PVSConnectionManager::getManager()->getClientFromIp( + (*tmpIt).toUtf8().data()); + if (tmpConnection) { + // removal should start from the CM, so hes linking back to the ConnectionWindow::onConnectionRemoved() method + // to finish the removal procedure here + PVSConnectionManager::getManager()->removeConnection( + tmpConnection); + } else { + // scream in agony + } + } + // onChangeConnections(); + } + delete removeList; + return; + } +} + +void ConnectionWindow::onConnectionRemoved(PVSClient* newConnection) { + + + if (newConnection->getVNCConnection()) + + // check for associated frames! + if (newConnection->getVNCConnection()) { + ConnectionFrame* tmpFrame = + newConnection->getVNCConnection()->getFrame(); + // now handle the case that the client disconnects while we are in fullscreen mode + // the vncconnection would be cut nevertheless, so this: + if (tmpFrame) { + frameList.removeOne(tmpFrame); + // now handle the case that the client disconnects while we are in fullscreen mode + // the vncconnection would be cut nevertheless, so this: + if (tmpFrame == currentSingleFrame) { + currentSingleFrame = NULL; + } + + // no longer needed + delete tmpFrame; + newConnection->getVNCConnection()->setFrame(NULL); + } + } +} + +void ConnectionWindow::setSize(int width, int height, bool forceSquare) { + if (height >= 100 && width >= 100) { + MainWindow::getWindow()->setPrevWidth(width); + MainWindow::getWindow()->setPrevHeight(height); + } + + ignoreRatio = forceSquare; + + if (!frameList.empty()) { + ConnectionFrame* item; + foreach (item, frameList) + { + item->setIgnoreRatio(ignoreRatio); + } + } +} + +void ConnectionWindow::getCloseupSize(int &width, int &height) { + if (!onCloseup) { + width = height = 0; + return; + } + + width = 150; + height = 150; +} + +bool ConnectionWindow::getShowDummies() { + return _showDummies; +} + +void ConnectionWindow::setShowDummies(bool show) { + +} + +ConnectionFrame* ConnectionWindow::newConFrame(PVSClient* newConnection) { + if (newConnection->getConnectionFrame()) { + return NULL; + } + ConnectionFrame* temp = new ConnectionFrame( + MainWindow::getConnectionWindow()); + if (!temp) { + return NULL; + } + return temp; +} + +void ConnectionWindow::setCloseupFrame(ConnectionFrame* cFrame) { + _closeupFrame = cFrame; +} + +ConnectionFrame* ConnectionWindow::getCloseupFrame() { + if (_closeupFrame) + return _closeupFrame; + + return NULL; +} + diff --git a/src/gui/connectionWindow.h b/src/gui/connectionWindow.h new file mode 100644 index 0000000..81b5033 --- /dev/null +++ b/src/gui/connectionWindow.h @@ -0,0 +1,125 @@ +#ifndef _CONNECTIONWINDOW_H_ +#define _CONNECTIONWINDOW_H_ + +#include <QtGui> +#include <src/gui/connectionFrame.h> +#include <src/gui/connectionList.h> +#include <src/gui/mainWindow.h> +#include <list> +#include <iostream> +#include <math.h> +#include <QSettings> +#define FRAME_DELAY 1000 // to comply with the standard value in the gui + + +typedef std::pair<QString, QPoint> clientLocation; +typedef QList<clientLocation> clientLocationList; + +class ConnectionList; +class PVSClient; +class PVSConnectionManager; +class MainWindow; +class ConnectionFrame; +class QDragEnterEvent; +class QDropEvent; + + +class ConnectionWindow : public QWidget +{ + Q_OBJECT +public: + enum FILLORDER + { + ROW, + COLUMN, + SQUARE, + }; + + enum VIEWSTYLE + { + FULLSCREEN, + TABLE, + }; + + + + ConnectionWindow(QWidget *parent=0); + ~ConnectionWindow(); + void addFrame(ConnectionFrame *conFrame); + void addFrameBySettings(QString client, QPoint pos); + void showFrameFromSettings(); + void onChangeConnections(); // if connections are added or removed, this method makes sure the window changes accordingly + void addConnection(PVSClient* newCon); // handle newly connected clients (forward to con-list) + void removeConnection(PVSClient* newCon); // Remove client on disconnect + void onView(); + void updateConnection(PVSClient* newCon); // update stuff like username etc on a present connection + void addVNC(); + void onVNCAdd(PVSClient* newCon); + void removeVNC(); + void onRemoveConnection(); // tells the PVSConnectionManager to remove the connections that are marked in the sidebar + void onConnectionRemoved(PVSClient* newConnection); // does some cleanup and tells the gui elements that this connection is removed + void setSize(int width, int height, bool forceSquare); // tell the frames to use this size settings + void getCloseupSize(int &width, int &height); + bool getShowDummies(); + void setShowDummies(bool show); + QList<ConnectionFrame*> dummyList; + QList<ConnectionFrame*> AllFrameOnWindow; + QList<ConnectionFrame*> getAllFrameOnWindow() + { + return AllFrameOnWindow; + } + void removeFromList(ConnectionFrame* cF); + + bool remoteHelp(QString sname); + bool projectStations(QString sname); + bool unprojectStations(QString sname); + bool lockStations(); + void lockStation(PVSClient* pvsCon); + bool unlockStations(); + void unlockStation(PVSClient* pvsCon); + bool lockAllStations(); + bool unlockAllStations(); + bool unprojectAllStations(); + bool lockInvertStations(); + void lockInvertStation(PVSClient* pvsCon); + bool messageStations(QString ident, QString message); + void messageStation(QString ident, QString message, PVSClient* pvsCon); + bool lockStationsWithMessage(QString message); + void lockStationsWithMessage(QString message, PVSClient* pvsCon); + bool lockAllStationsWithMessage(QString message); + + void setCloseupFrame(ConnectionFrame* cFrame); + int itemAt(ConnectionFrame* cf); + ConnectionFrame* getCloseupFrame(); + QList<ConnectionFrame*> getFrameList(){ return frameList; }; + clientLocationList ClientLocationList; + bool hasDozent; //if a Dozent machine is available this will be set to true else false + //Frame position in the window + int posX; + int posY; + +public Q_SLOTS: + void addDummy(); + + +protected: + QList<ConnectionFrame*> frameList; // list of all connected frames + void mousePressEvent(QMouseEvent *event); + +private: + ConnectionFrame* newConFrame(PVSClient* newConnection); // returns a new frame for the given connection + ConnectionFrame* currentSingleFrame; // pointer to the frame thats currently in FullScreen + ConnectionFrame* _closeupFrame; + QPoint currentPosition (ConnectionFrame* cF); + QMenu *menu; + QAction *newDummy; + bool ignoreRatio; // wether the native ratio should be ignored or not + bool onFullscreen; // wether on fullscreen or not + bool onCloseup; // wether on closeup or not + int defaultWidth, defaultHeight; // obvious + unsigned int frameRate; // also obvious*/ + bool _showDummies; + +}; + +#endif diff --git a/src/gui/dialog.cpp b/src/gui/dialog.cpp new file mode 100644 index 0000000..3c9b7a2 --- /dev/null +++ b/src/gui/dialog.cpp @@ -0,0 +1,74 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# dialog.cpp + Dialog to get message to send to client +# ----------------------------------------------------------------------------- +*/ + +#include "dialog.h" +#include "ui_dialog.h" +#include <src/gui/mainWindow.h> + +Dialog::Dialog(QWidget *parent) : + QDialog(parent), + dui(new Ui::MsgDialog) +{ + dui->setupUi(this); + + dui->send->setDisabled(true); + + setWindowTitle(tr("Enter the Text for the client(s)")); + + connect( dui->send, SIGNAL( clicked()), this, SLOT( send())); + connect( dui->cancel, SIGNAL( clicked()), this, SLOT( NotSend())); + connect(dui->message, SIGNAL(textChanged()), this, SLOT(textchange())); +} + +Dialog::~Dialog() +{ + delete dui; +} + +void Dialog::send() +{ + QString mesge = dui->message->toPlainText(); + MainWindow::getWindow()->setMsgDialog(mesge); + dui->message->clear(); + emit accept(); +} + +void Dialog::NotSend() +{ + dui->message->clear(); + emit reject(); +} + +void Dialog::textchange() +{ + QString message = dui->message->toPlainText(); + if(message.length()>0) + dui->send->setDisabled(false); + else + dui->send->setDisabled(true); +} + +void Dialog::changeEvent(QEvent *e) +{ + QDialog::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + dui->retranslateUi(this); + break; + default: + break; + } +} diff --git a/src/gui/dialog.h b/src/gui/dialog.h new file mode 100644 index 0000000..689cbb4 --- /dev/null +++ b/src/gui/dialog.h @@ -0,0 +1,33 @@ +#ifndef DIALOG_H +#define DIALOG_H + +#include <QDialog> +#include <QtGui> +//#include <src/gui/mainWindow.h> + + +namespace Ui { + class MsgDialog; +} + +class MainWindow; + +class Dialog : public QDialog { + Q_OBJECT +public: + Dialog(QWidget *parent = 0); + ~Dialog(); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::MsgDialog *dui; + +private slots: + void send(); + void NotSend(); + void textchange(); +}; + +#endif // DIALOG_H diff --git a/src/gui/frame.cpp b/src/gui/frame.cpp new file mode 100644 index 0000000..cb79643 --- /dev/null +++ b/src/gui/frame.cpp @@ -0,0 +1,332 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/gui/frame.cpp +# This is the drawingarea, it will be set to the suitable ConnectionFrame. +# Each instance of this class has is own VNCThread, this way is more simple +# to show, update and scale the image from the suitable client. Only the point +# on the image that need to be drawed or scaled will be processed. Thus the CPU +# performance will not be affected. The pvsmgr can manage in this way a lot of clients. +# ----------------------------------------------------------------------------- +*/ + +#include "frame.h" +#include <src/gui/mainWindow.h> +#include <iostream> +#include <QPixmap> + +Frame::Frame(const QString & text, QWidget * parent) : + QLabel(parent), _clientVNCThread(0) +{ + _clientVNCThread = NULL; + + X = 0; + Y = 0; + setBackgroundRole(QPalette::Base); + + setStyleSheet(QString::fromUtf8("QLabel{border-radius:10px;\n" + "background-color: rgb(150,150,150);}")); + + setAlignment(Qt::AlignCenter); + + setAutoFillBackground(true); + setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); + + _isLocked = false; + _dozent = false; + _uy = _ux = 0; + + //QIcon icon; + //icon.addFile(QString::fromUtf8(), QSize(), QIcon::Normal, QIcon::Off); + button_closeUp = createToolButton(tr("View"), QIcon(":/restore"),SLOT(closeUp())); + button_foto = createToolButton(tr("Foto"), QIcon(":/photos"),SLOT(foto())); + button_lock = createToolButton(tr("Lock this client"), QIcon(":/lock"),SLOT(setLock())); + //button_unlock = createToolButton(tr("Unlock this client"), QIcon(":/lock"),SLOT(setLock())); + button_dozent = createToolButton(tr("Set as Superclient"), QIcon(":/dozent2"),SLOT(setDozent())); + + connect(this, SIGNAL(clicked()), this, SLOT(slotClicked())); + ip = ""; + setToolButtonListVisible(false); +} + +Frame::~Frame() +{ + if (_clientVNCThread) + { + disconnect(_clientVNCThread, SIGNAL(imageUpdated(int,int,int,int)), this, + SLOT(updateImage(int,int,int,int))); + disconnect(_clientVNCThread, SIGNAL(finished()), this, + SLOT(iamDown())); + if (_clientVNCThread->isRunning()) + { + _clientVNCThread->terminate = true; + _clientVNCThread->wait(_clientVNCThread->getUpdatefreq()+2000); + } + } +} + + +void Frame::setVNCThreadConnection(VNCClientThread * vncClientThread) +{ + // initialize the vncthread for this connection + //printf("Starting VNC thread for %s\n", ip.toUtf8().data()); + _clientVNCThread = vncClientThread; + + connect(_clientVNCThread, SIGNAL(imageUpdated(int,int,int,int)), this, + SLOT(updateImage(int,int,int,int)), Qt::BlockingQueuedConnection); + connect(_clientVNCThread, SIGNAL(finished()), this, + SLOT(iamDown())); + + // start the thread + if(!_clientVNCThread->terminate) + _clientVNCThread->start(); +} + +/* + * To stop the vncThreadConnection, we only disconnect all connected signals on _clientVNCThread + * We don't need here to terminate the thread, this will appear in vncconnection, because + * we have set this thread there (in vncconnection). + */ +void Frame::stopVNCThreadConnection() +{ + disconnect(_clientVNCThread, SIGNAL(imageUpdated(int,int,int,int)), this, + SLOT(updateImage(int,int,int,int))); + disconnect(_clientVNCThread, SIGNAL(finished()), this, + SLOT(iamDown())); +} + +void Frame::updateImage(int x, int y, int w, int h) +{ + if (_clientVNCThread == NULL) + return; + + if (_clientVNCThread->getSize() != size()) + { + // grow the update rectangle to avoid artifacts + x -= 3; + y -= 3; + w += 6; + h += 6; + + _clientImg = _clientVNCThread->getImage().copy(x, y, w, h); + + qreal sx = qreal(width()) / qreal(_clientVNCThread->getSize().width()); + qreal sy = qreal(height()) / qreal(_clientVNCThread->getSize().height()); + + x = qRound(qreal(x) * sx); + y = qRound(qreal(y) * sy); + w = qRound(qreal(w) * sx); + h = qRound(qreal(h) * sy); + } + else + { + _clientImg = _clientVNCThread->getImage().copy(x, y, w, h); + } + + _ux = w; + _uy = h; + repaint(x, y, w, h); // this will trigger the PaintEvent +} + +void Frame::iamDown() +{ + if (_clientVNCThread == NULL) return; + _clientVNCThread = NULL; + update(); +} + +void Frame::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + QRect r = event->rect(); + event->accept(); + + if (_clientImg.isNull()) + { + _clientImg = QImage(":/terminal"); + painter.drawImage(28,0, _clientImg.scaled(145,123, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + setAlignment(Qt::AlignCenter); + return; + } + + if(_isLocked) + { + _clientImg = QImage(":/lock"); + painter.drawImage(28,0, _clientImg.scaled(145,123, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + setAlignment(Qt::AlignCenter); + return; + } + + if (_clientVNCThread != NULL) + { + if (r.width() != _ux || r.height() != _uy) + { + _clientImg = _clientVNCThread->getImage(); // redraw complete image (e.g. on resize) + r = rect(); + } + else + { + _ux = -1; + } + + if (_clientVNCThread->getSize() == size()) + { + + painter.drawImage(r.topLeft(), _clientImg); // don't scale + } + else + { + QImage i = _clientImg.scaled(r.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + painter.drawImage(r.topLeft(), i); + } + } + else + { + _clientImg = QImage(":/terminal"); + painter.drawImage(28,0, _clientImg.scaled(145,123, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + setAlignment(Qt::AlignCenter); + } +} + +void Frame::slotClicked() +{ + //qDebug() << "clickableLabel :: Clicked, searching for" << ip; + + if (ip != "") { + for (int i=0; i<MainWindow::getConnectionList()->model->rowCount(QModelIndex()); i++) + { + if (MainWindow::getConnectionList()->model->index(i, 1, QModelIndex()).data(Qt::DisplayRole).toString() + .compare(ip) == 0) + { + MainWindow::getConnectionList()->selectRow(i); + MainWindow::getConnectionList()->setCurrentIndex(MainWindow::getConnectionList()->currentIndex()); + break; + } + } + } +} + +void Frame::mousePressEvent(QMouseEvent* event) +{ + emit clicked(); + if (event->button() == Qt::RightButton) + { + /*if (!_dummy) + DelDummy->setDisabled(true); + menu->exec(QCursor::pos());*/ + } + else + { + + } + QLabel::mousePressEvent(event); +} + +void Frame::mouseReleaseEvent ( QMouseEvent * event ) +{ + QLabel::mouseReleaseEvent(event); +} + +QToolButton* Frame::createToolButton(const QString &toolTip, const QIcon &icon, const char *member) + { + QToolButton *button = new QToolButton(this); + button->setToolTip(toolTip); + button->setIcon(icon); + button->setIconSize(QSize(15, 15)); + button->setStyleSheet(QString::fromUtf8("background-color: rgb(230, 230, 230);")); + addButton(button); + toolButtonList.append(button); + connect(button, SIGNAL(clicked()), this, member); + + return button; +} + +void Frame::addButton(QToolButton *button) +{ + button->move(X,Y); + Y += button->size().height()-5; +} + +void Frame::setToolButtonListVisible(bool visible) +{ + foreach (QToolButton* tb, toolButtonList) + tb->setVisible(visible); + if (visible && MainWindow::getConnectionWindow()->hasDozent && !_dozent) + button_dozent->setVisible(false);//At this time this button should only be visible on the dozent machine (the superclient). + +} + +void Frame::setLockStatus(bool lock) +{ + if (lock) + { + button_lock->setToolTip(tr("Unlock this client")); + //button_lock->setIcon() TODO + } + else + { + button_lock->setToolTip(tr("Lock this client")); + //button_lock->setIcon() TODO + } + _isLocked = lock; +} + +QImage Frame::getImageForFoto() +{ + return _clientVNCThread->getImage(); +} + +void Frame::closeUp() +{ + emit clicked(); + MainWindow::getWindow()->closeUp(); +} + +void Frame::foto() +{ + emit clicked(); + MainWindow::getWindow()->foto(); +} + +void Frame::setLock() +{ + if (!_dozent) + { + emit clicked(); + if (_isLocked) + MainWindow::getConnectionWindow()->unlockStations(); + else + MainWindow::getConnectionWindow()->lockStations(); + } + else + { + QString message = QString(tr("You can't lock a Superclient-machine.")); + QMessageBox::information(this, "PVS", message); + } +} + +void Frame::setDozent() +{ + if (_dozent) + { + button_dozent->setToolTip(tr("Set client as Superclient")); + _dozent = false; + MainWindow::getConnectionWindow()->hasDozent = false; + getConFrame()->setDozent(false); + } + else + { + button_dozent->setToolTip(tr("Unset client as Superclient")); + _dozent = true; + MainWindow::getConnectionWindow()->hasDozent = true; + getConFrame()->setDozent(true); + } +} diff --git a/src/gui/frame.h b/src/gui/frame.h new file mode 100644 index 0000000..3004e0c --- /dev/null +++ b/src/gui/frame.h @@ -0,0 +1,90 @@ +#ifndef FRAME_H_ +#define FRAME_H_ + +#include <QtGui> +#include "../util/vncClientThread.h" + +class VNCClientThread; +class ConnectionWindow; +class ConnectionFrame; +class MainWindow; + +class Frame: public QLabel +{ + Q_OBJECT + +public: + Frame(const QString & text, QWidget * parent = 0 ); + virtual ~Frame(); + void setVNCThreadConnection(VNCClientThread * VNCclientThread); + void stopVNCThreadConnection(); + VNCClientThread * getVNCClientThread() + { + return _clientVNCThread; + } + void setConFrame (ConnectionFrame* cf) + { + _cFrame = cf; + } + ConnectionFrame* getConFrame() + { + return _cFrame; + } + void setToolButtonListVisible(bool visible); + void setLockStatus(bool lock); + bool getLockStatus() + { + return _isLocked; + } + bool isDozent() + { + return _dozent; + } + int X,Y; + + QString ip; + QToolButton* button_closeUp; + QToolButton* button_foto; + QToolButton* button_lock; + QToolButton* button_unlock; + QToolButton* button_dozent; + QList<QToolButton*> toolButtonList; + +public Q_SLOTS: + void updateImage(int x, int y, int w, int h); + void iamDown(); + void slotClicked(); + QImage image() + { + return _clientImg; + }; + void setImage(QImage img) + { + _clientImg = img; + }; + QImage getImageForFoto(); + void closeUp(); + void foto(); + void setLock(); + //void unlock(); + void setDozent(); + +signals: + void clicked(); +protected: + void paintEvent(QPaintEvent *event); + void mousePressEvent ( QMouseEvent * event ); + void mouseReleaseEvent ( QMouseEvent * event ); + +private: + QToolButton* createToolButton(const QString &toolTip, const QIcon &icon, const char *member); + void addButton(QToolButton *button); + VNCClientThread *_clientVNCThread; + ConnectionFrame *_cFrame; + QImage _clientImg; + bool _isLocked; + bool _dozent; + int _ux, _uy; +}; + +#endif /* FRAME_H_ */ diff --git a/src/gui/mainWindow.cpp b/src/gui/mainWindow.cpp new file mode 100644 index 0000000..eb15e82 --- /dev/null +++ b/src/gui/mainWindow.cpp @@ -0,0 +1,1205 @@ +/* + # 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/ + # ----------------------------------------------------------------------------- + # mainWindow.cpp + This is the Main class for the pvsManager. The GUI is contructed here. + # ----------------------------------------------------------------------------- + */ + +#include <QtGui> +#include <QFileDialog> +#include <src/gui/mainWindow.h> +using namespace std; + +// setting the IF-DEF Block for the touchgui and the normal gui, for later use + +#ifdef MAINWINDOW_USE_TOUCHGUI +#include "ui_mainwindowtouch.h" +#endif + +#ifdef MAINWINDOW_USE_NORMALGUI +#include "ui_mainwindow.h" +#endif + +#include <src/gui/connectionList.h> +#include <src/gui/connectionWindow.h> +#include <src/gui/profileDialog.h> +//#include <src/gui/dialog.h> +#include <src/core/pvsConnectionManager.h> +#include <iostream> + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), ui(new Ui::MainWindow) + +{ + + ui->setupUi(this); + + ui->horizontalSlider->setValue(100); + ui->label_2->setText("100"); + + ui->separator->setVisible(false); + + myself = this; + conWin = new ConnectionWindow(ui->widget); + ui->VconWinLayout->addWidget(conWin); + conList = new ConnectionList(ui->ClWidget); + ui->ClientGLayout->addWidget(conList); + + bgimage = false; + + _aboutDialog = new AboutDialog(this); + + PVSConnectionManager::getManager(); + + //set the maximum width for list content + ui->ClWidget->setMaximumWidth(160); + + ui->pvsLog->setReadOnly(true); + ui->pvsLog->hide(); + + onToggleLog(false); + // add ourself to the log listeners, so we can output them too + ConsoleLog addListener(this, &MainWindow::on_log_line); + + _firstResize = 1; + _oldRatio = "100"; + _isThumbnailrate = false; + is_closeup = false; + is_fullscreen = false; + _isLockAll = false; + locked = false; + + /* + * _sessionName: The session name for this Connection + * _pwdCon: Password needed to connect to the session with the name _sessionName + */ + _pwdCon = PVSConnectionManager::getManager()->setNeedPassword(false); + _sessionName = PVSConnectionManager::getManager()->getSessionName(); + + ui->setPassword->setCheckState(Qt::Checked); + +#ifdef MAINWINDOW_USE_TOUCHGUI //only used for the touchgui + + // define the slots we want to use + connect(ui->comboBox_touch1, SIGNAL(currentIndexChanged(int)), this, SLOT(combobox1(int))); // Combobox 1 verknüpfen mit IndexChangend Signal + connect(ui->comboBox_touch1, SIGNAL(currentIndexChanged(int)), this, SLOT(setindexback())); + + + connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(createProfile())); // profile button + connect(ui->pushButton_2, SIGNAL(clicked()), this, SLOT(clientlisthide())); // clienlist button + + // toolbar slots + connect(ui->actionresetall, SIGNAL(triggered()), this, SLOT(resetall())); + connect(ui->actionLocksingle, SIGNAL(triggered()), this, SLOT(locksingle())); + connect(ui->actionUnlocksingle, SIGNAL(triggered()), this, SLOT(unlocksingle())); + connect(ui->actionProjection, SIGNAL(triggered()), this, SLOT(projecttoolbar())); + connect(ui->actionUnprojection, SIGNAL(triggered()), this, SLOT(unprojecttoolbar())); + connect(ui->actionDozent, SIGNAL(triggered()), this, SLOT(setdozenttoolbar())); + + // Ui specific settings + + ui->ClWidget->hide(); + ui->progressBar->hide(); + ui->pvsLog->hide(); + + +#endif + + + // toolbar and actions in pvsmgr + connect(ui->action_Exit, SIGNAL(triggered()), this, SLOT(close())); + ui->action_Exit->setStatusTip(tr("Exit")); + connect(ui->action_Disconnect, SIGNAL(triggered()), this, SLOT(disconnect())); + ui->action_Disconnect->setStatusTip(tr("Remove the vnc-Connection for the selected client(s)")); + ui->action_Disconnect->setVisible(false);//we need it only for debug + connect(ui->actionView, SIGNAL(triggered()), this, SLOT(closeUp())); + ui->actionView->setStatusTip(tr("Show the selected client in the whole window")); + connect(ui->actionFoto, SIGNAL(triggered()), this, SLOT(foto())); + connect(ui->actionLock, SIGNAL(triggered()), this, SLOT(lockalltoolbar())); + connect(ui->actionChat, SIGNAL(triggered()), this, SLOT(startChatDialog())); + ui->actionFoto->setStatusTip(tr("Make a screenshot for the selected client(s)")); + ui->actionLock->setStatusTip(tr("Lock or Unlock all Clients")); + connect(ui->actionCreate_profile, SIGNAL(triggered()), this, SLOT(createProfile())); + + connect(ui->actionShow_Username, SIGNAL(triggered()), this, SLOT(showusername())); + connect(ui->actionShow_Hostname_IP, SIGNAL(triggered()), this, SLOT(showip())); + connect(ui->actionShow_Fullname, SIGNAL(triggered()), this, SLOT(showname())); + connect(ui->horizontalSlider, SIGNAL(valueChanged (int)), this, SLOT(changeRatio(int))); + connect(ui->setPassword, SIGNAL(stateChanged (int)), this, SLOT(setPasswordForConnection(int))); + connect(ui->vncQuality, SIGNAL(currentIndexChanged (int)), this, SLOT(setVNCQuality(int))); + connect(ui->thumbStatus, SIGNAL(currentIndexChanged(int)), this, SLOT(changeStatus(int))); + connect(ui->actionShow_Log, SIGNAL(toggled(bool)), this, SLOT(setLogConsoleDisabled(bool))); + connect(ui->actionShow_Network, SIGNAL(toggled(bool)), this, SLOT(onToggleLog(bool))); + connect(ui->actionShow_Chat, SIGNAL(toggled(bool)), this, SLOT(onToggleLog(bool))); + connect(ui->actionShow_Terminal, SIGNAL(toggled(bool)), this, SLOT(onToggleLog(bool))); + connect(ui->actionShow_Normal, SIGNAL(toggled(bool)), this, SLOT(onToggleLog(bool))); + connect(ui->actionShow_Error, SIGNAL(toggled(bool)), this, SLOT(onToggleLog(bool))); + connect(ui->actionAbout_pvs, SIGNAL(triggered()), _aboutDialog, SLOT(open())); + + loadSettings(); //we load the appliocation settings + + setUnifiedTitleAndToolBarOnMac(true); + statusBar()->showMessage(tr("The pvs manager")); + this->showMaximized(); // show the Mainwindow maximized + + // listen on port 29481 for incoming file transfers + _serverSocket = new QTcpServer(); + _serverSocket->listen(QHostAddress::Any, 29481); + connect(_serverSocket, SIGNAL(newConnection()), this, SLOT(incomingFile())); + + +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +/* + * This signal is received when the mainwindow is going to be closed. + * We have to check if the the chat-dialog is open. In this case we close + * this dialog and accept the event, the rest will be execute from Qt. + * Qt will be call the destroyer ~MainWindow(). + */ +void MainWindow::closeEvent(QCloseEvent *e) +{ + if (sChatDialog.isVisible()) + sChatDialog.close(); + e->accept(); +} + +MainWindow* MainWindow::getWindow() // catches the window +{ + + if (myself) + { + return myself; + } + else + { + return myself = new MainWindow; + } +} + +ConnectionWindow* MainWindow::getConnectionWindow() // catches the ConnectionWindow +{ + if (conWin) + { + return conWin; + } + else + { + conWin = new ConnectionWindow; + return conWin; + } +} + +ConnectionList* MainWindow::getConnectionList() // catches the ConnectionList +{ + if (conList) + return conList; + else + { + conList = new ConnectionList; + return conList; + } +} + +int MainWindow::getConnectionWindowWidth() // returns the width of the ConnectionWindow +{ + return ui->widget->width(); +} + +int MainWindow::getConnectionWindowHeight() // returns the height of the CoonectionWindow +{ + return ui->widget->height(); +} + +QStringList MainWindow::getProfilList() // loads the profile list +{ + QSettings settings("openslx", "pvsmgr"); + profilList = settings.childGroups(); + return profilList; +} + +#ifdef MAINWINDOW_USE_NORMALGUI +void MainWindow::addProfileInMenu(QString name) +{ + QAction* action = new QAction(name,this); + ui->menuLoad_profile->addAction(action); + connect(ui->menuLoad_profile, SIGNAL(triggered(QAction*)), this, SLOT(loadProfile(QAction*))); + _mapProfileToAction.insert(name, action); +} + +void MainWindow::removeProfileInMenu(QString name) +{ + if (_mapProfileToAction.contains(name)) + { + QAction* action = _mapProfileToAction.value(name); + ui->menuLoad_profile->removeAction(action); + _mapProfileToAction.take(name); + } + +} + +#endif +void MainWindow::loadSettings() +{ + QSettings settings("openslx", "pvsmgr"); + QString current = settings.value("current", "default").toString(); + currentProfi = current; + _profilName = current; + + //When no profile is available, we define a default one whith 9 dummy screens + if (current.compare("default") == 0) + { + setWindowTitle("PVSmgr - Default"); + QPoint pos1 = settings.value("default/1", QPoint(0, 0)).toPoint(); + MainWindow::getConnectionWindow()->addFrameBySettings("1", pos1); + QPoint pos2 = + settings.value("default/2", QPoint(194, 0)).toPoint(); + MainWindow::getConnectionWindow()->addFrameBySettings("2", pos2); + QPoint pos3 = + settings.value("default/3", QPoint(388, 0)).toPoint(); + MainWindow::getConnectionWindow()->addFrameBySettings("3", pos3); + QPoint pos4 = + settings.value("default/4", QPoint(582, 0)).toPoint(); + MainWindow::getConnectionWindow()->addFrameBySettings("4", pos4); + QPoint pos5 = + settings.value("default/5", QPoint(0, 173)).toPoint(); + MainWindow::getConnectionWindow()->addFrameBySettings("5", pos5); + QPoint pos6 = + settings.value("default/6", QPoint(194, 173)).toPoint(); + MainWindow::getConnectionWindow()->addFrameBySettings("6", pos6); + QPoint pos7 = + settings.value("default/7", QPoint(388, 173)).toPoint(); + MainWindow::getConnectionWindow()->addFrameBySettings("7", pos7); + QPoint pos8 = + settings.value("default/8", QPoint(582, 173)).toPoint(); + MainWindow::getConnectionWindow()->addFrameBySettings("8", pos8); + QPoint pos9 = + settings.value("default/9", QPoint(293, 346)).toPoint(); + MainWindow::getConnectionWindow()->addFrameBySettings("9", pos9); + + QString title = "PVSmgr - "; + title.append(_profilName); + title.append(" ["+_sessionName + " : "); + title.append(_pwdCon+"]"); + setWindowTitle(title); + } + else + { + QString title = "PVSmgr - "; + title.append(_profilName); + title.append(" ["+_sessionName + " : "); + title.append(_pwdCon+"]"); + setWindowTitle(title); + settings.beginGroup(current); + QStringList keys = settings.childKeys(); + for (int i=0; i<keys.size(); i++) + { + QString profil = current; + profil = profil.append("/").append(keys.at(i)); + QPoint pos = settings.value(keys.at(i)).toPoint(); + MainWindow::getConnectionWindow()->addFrameBySettings(keys.at(i), pos); + } + } + + MainWindow::getConnectionWindow()->showFrameFromSettings(); +#ifdef MAINWINDOW_USE_NORMALGUI + foreach (QString profile, getProfilList()) + addProfileInMenu(profile); +#endif +} + +void MainWindow::loadProfile(QAction* actiontriggered) +{ + QString profilename = actiontriggered->text(); + loadSettings(profilename); +} + +void MainWindow::loadSettings(QString profilname) // loads the current profile +{ + QList<ConnectionFrame*> AllFrameOnWindow = + MainWindow::getConnectionWindow()->getAllFrameOnWindow(); + + if (AllFrameOnWindow.size() > 0) + { + _profilName = profilname; + MainWindow::getConnectionWindow()->ClientLocationList.clear(); + QSettings settings("openslx", "pvsmgr"); + settings.setValue("current", _profilName); + ConnectionFrame* cFrame; + foreach (cFrame, AllFrameOnWindow) + { + if (cFrame->isDummy()) + { + AllFrameOnWindow.removeOne(cFrame); + MainWindow::getConnectionWindow()->removeFromList(cFrame); + cFrame->deleteLater(); + } + } + settings.beginGroup(_profilName); + QStringList keys = settings.childKeys(); + int rest = AllFrameOnWindow.size(); + int init = 1; + for (int i = 0; i < keys.size(); i++) + { + if (init <= rest) + { + ConnectionFrame* cF = AllFrameOnWindow.at(i); + QString profil = _profilName; + profil = profil.append("/").append(cF->getTaskbarTitle()); + if (!cF->isDummy()) + cF->move(settings.value(keys.at(i)).toPoint()); + else + cF->move(settings.value(profil, QPoint(10,(10+(5*i)))).toPoint()); + + init += 1; + } + else + { + MainWindow::getConnectionWindow()->addFrameBySettings( + keys.at(i), settings.value(keys.at(i)).toPoint()); + } + } + + MainWindow::getConnectionWindow()->showFrameFromSettings(); + + QString title = "PVSmgr - "; + title.append(_profilName); + title.append(" ["+_sessionName + " : "); + title.append(_pwdCon+"]"); + setWindowTitle(title); + } +} + +void MainWindow::saveSettings(QString profilname) +{ + QList<ConnectionFrame*> AllFrameOnWindow = + MainWindow::getConnectionWindow()->getAllFrameOnWindow(); + QSettings settings("openslx", "pvsmgr"); + settings.setValue("current", profilname); + settings.setValue("size", QString("%1").arg(AllFrameOnWindow.size())); + + for (int i = 0; i < AllFrameOnWindow.size(); i++) + { + ConnectionFrame* current = AllFrameOnWindow.at(i); + QString profil = ""; + profil = settings.value("current").toString().append("/"); + if (!current->isDummy()) + profil.append(QString(current->getTaskbarTitle())); + else + profil.append(QString("%1").arg(i + 1)); + settings.setValue(profil, current->pos()); + } +#ifdef MAINWINDOW_USE_NORMALGUI +addProfileInMenu(profilname); +#endif +} + +void MainWindow::removeProfil(QString profilname) +{ + QSettings settings("openslx", "pvsmgr"); + settings.remove(profilname); +#ifdef MAINWINDOW_USE_NORMALGUI +removeProfileInMenu(profilname); +#endif +} + +void MainWindow::addConnection(PVSClient* newCon) +{ + conWin->addConnection(newCon); + if (!_chatListClients.contains(newCon->getUserName())) + { + _chatListClients.append(newCon->getUserName()); + sChatDialog.chat_client_add(newCon->getUserName()); + sChatDialog.chat_nicklist_update(); + } + // sChatDialog->chat_nicklist_update(newCon->getUserName()); +} + +void MainWindow::removeConnection(PVSClient* newCon) +{ + conWin->removeConnection(newCon); + if (_chatListClients.contains(newCon->getUserName())) + { + _chatListClients.removeOne(newCon->getUserName()); + sChatDialog.chat_client_remove(newCon->getUserName()); + sChatDialog.chat_nicklist_update(); + } +} + +void MainWindow::onConnectionFailed(QString host) +{ +#ifdef never + // code is voided because the info-management will be overhauled sometime + + if (pwDiag) // assume this thing failed after the pw-question... so a wrong password, ey? + + { + onPasswordFailed(host); + return; + } + + QString caption, secondary; + if (host != "") + { + caption = ("PVSConnection with hostname \""); + caption.append(host); + caption.append("\" failed."); + secondary = "PVSConnection attempt for this hostname failed.Maybe the host is not prepared to accept vnc connections. Please make sure hostname and (if needed) password are correct."; + } + else + { + caption = "No IP given"; + secondary = "PVSConnection attempt for this host failed. There was either no or an errorous Hostname given."; + } + QMessageBox::information(*this, caption, secondary); + /* Gtk::MessageDialog dialog(*this, Glib::ustring(caption)); + dialog.set_secondary_text(secondary); + dialog.run();*/ +#endif +} + +void MainWindow::onConnectionTerminated(PVSClient* newConnection) +{ +#ifdef never + // code is voided because the info-management will be overhauled sometime + + QString host; + if (newConnection) + { + host = newConnection->getIp(); // copy hostname for message + } + else + host = "spooky unknown"; + + // now inform + QString caption, secondary; + + caption = "Hostname \""; + caption.append(host); + caption.append("\" terminated connection."); + secondary = "The server has closed the connection to your client."; + + QMessageBox::information(*this, caption, secondary); + /*Gtk::MessageDialog dialog(*this, Glib::ustring(caption)); + dialog.set_secondary_text(secondary); + dialog.run();*/ +#endif +} + +void MainWindow::onConnectionRemoved(PVSClient* newConnection) +{ + // TODO this would be the place to handle the rest of the fullscreen issue + conWin->onConnectionRemoved(newConnection); +} + +void MainWindow::onPasswordFailed(QString Qhost) +{ +#ifdef never + // code is voided because the info-management will be overhauled sometime + QString caption, secondary; + if (Qhost != "") + { + caption = "Hostname \""; + caption.append(Qhost); + caption.append("\" refused password."); + secondary = "You have entered no or a wrong password."; + } + else + return; // unknown connection was terminated? too spooky + QMessageBox::information(*this, caption, secondary); + /* Gtk::MessageDialog dialog(*this, Glib::ustring(caption)); + dialog.set_secondary_text(secondary); + Gtk::Main::run(dialog);*/ +#endif +} + +void MainWindow::sendChatMsg(PVSMsg myMsg) +{ + PVSConnectionManager::getManager()->onChat(myMsg); +} + +void MainWindow::receiveChatMsg(QString nick_from, QString nick_to, QString msg) +{ + sChatDialog.chat_receive(nick_from, nick_to, msg); +} + +int MainWindow::getPrevWidth() // PVSConnectionManager::getManager()->getPrevWidth() +{ + return prev_width; +} + +void MainWindow::setPrevWidth(int newWidth) +{ + if (newWidth > 100) + prev_width = newWidth; + else + prev_width = 100; +} + +int MainWindow::getPrevHeight() +{ + return prev_height; +} + +void MainWindow::setPrevHeight(int newHeight) +{ + if (newHeight > 100) + prev_height = newHeight; + else + prev_height = 100; +} + +void MainWindow::changeEvent(QEvent *e) +{ + QMainWindow::changeEvent(e); + switch (e->type()) + { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +/* + * The resize Event is called when the mainwindow is resized! + * Whe need this event to resize the Frame on the Connectionwindow. + * The Frames are resized proportionally to the new size of the mainwindow. + * But this Function is called by Qt 3 times before the whole + * mainwdow is constructed. We can only resize the Frame on Window and + * get the initial size of the Connectionwindow after this 3 times. + */ +void MainWindow::resizeEvent(QResizeEvent *event) +{ + + if (bgimage == true){ + repaintbackgroundpicture(); // repaint the backgroundpicture scaled to the window size + } + + if (_firstResize == 3) + { + QSize oldSize = event->oldSize(); + _initW = ui->widget->width(); + _initH = ui->widget->height(); + _firstResize++; + } + std::list<QString>* selectedClients = + MainWindow::getConnectionList()->getSelectedClients(); + if (is_closeup && selectedClients->size() == 1) + { + PVSClient* pvsClient = + PVSConnectionManager::getManager()->getClientFromIp( + selectedClients->front().toStdString().c_str()); + pvsClient->getConnectionFrame()->paintCloseUp(ui->widget->width(), + ui->widget->height()); + } + else if (!is_closeup && _firstResize > 3) + { + int ratio_w = (ui->widget->width()*100)/_initW; + int ratio_h = (ui->widget->height()*100)/_initH; + foreach (ConnectionFrame* cf, getConnectionWindow()->getFrameList()) + { + /*int margin = ui->widget->style()->pixelMetric(QStyle::PM_DefaultTopLevelMargin); + int x = ui->widget->width() - margin; + int y = ui->widget->height() - margin; + updatePos(cf, x, y);*/ + int w = (cf->init_w * ratio_w) / 100; + int h = (cf->init_h * ratio_h) / 100; + cf->paintCloseUp(w,h); + } + } + + if (_firstResize < 3) + _firstResize++; +} + +void MainWindow::updatePos(ConnectionFrame* cf, int x, int y) +{ + int posx = (x*cf->pos().x())/_initW; + int posy = (y*cf->pos().y())/_initH; + cf->move(posx, posy); + /*QSize size = cf->sizeHint(); + cf->setGeometry(x - size.rwidth(), y - size.rheight(), + size.rwidth(), size.rheight());*/ +} + +void MainWindow::on_log_line(LogEntry consoleEntry) +{ + ConsoleLogger::LOG_LEVEL level = consoleEntry.getLevel(); + if (level == ConsoleLogger::LOG_ERROR && !showError) + return; + if (level == ConsoleLogger::LOG_NORMAL && !showNormal) + return; + if (level == ConsoleLogger::LOG_NETWORK && !showNetwork) + return; + if (level == ConsoleLogger::LOG_TERMINAL && !showTerminal) + return; + if (level == ConsoleLogger::LOG_CHAT && !showChat) + return; + + ui->pvsLog->insertPlainText(consoleEntry.getLine()); + +} + +void MainWindow::onToggleLog(bool showtime) +{ + if (showtime) + ;//to kill the system warning due "unused variable" + showError = ui->actionShow_Error->isChecked(); + showTerminal = ui->actionShow_Terminal->isChecked(); + showNetwork = ui->actionShow_Network->isChecked(); + showChat = ui->actionShow_Chat->isChecked(); + showNormal = ui->actionShow_Normal->isChecked(); + //showAtAll = ui->logAtAllAction->get_active(); + + + ConsoleLog dump2Listener(this, &MainWindow::on_log_line); +} + +void MainWindow::setLogConsoleDisabled(bool visible) +{ + if (!visible) + ui->pvsLog->hide(); + else + ui->pvsLog->show(); +} + +/*void MainWindow::close() +{ + //sChatDialog.close(); + QApplication::closeAllWindows(); +}*/ + +void MainWindow::disconnect() +{ + conWin->removeVNC(); +} + +void MainWindow::lockUnlockAll() +{ + if (_isLockAll) + { + //ui->actionLock set icon to unlock + MainWindow::getConnectionWindow()->unlockAllStations(); + _isLockAll = false; + } + else + { + //ui->actionLock set icon to lock + MainWindow::getConnectionWindow()->lockAllStations(); + _isLockAll = true; //tell the manager all the clients are locked + } +} + +void MainWindow::closeUp() +{ + std::list<QString>* selectedClients = + MainWindow::getConnectionList()->getSelectedClients(); + if (!is_closeup) + { + if (selectedClients->size() == 1) + { + PVSClient + * pvsClient = + PVSConnectionManager::getManager()->getClientFromIp( + selectedClients->front().toStdString().c_str()); + _framePosOnCloseUp = pvsClient->getConnectionFrame()->pos();//get the actualy position before run closeup + if (pvsClient->getVNCConnection()) + { + conWin->setCloseupFrame(pvsClient->getConnectionFrame()); + _updatefreq = pvsClient->getConnectionFrame()->getFrame()->getVNCClientThread()->getUpdatefreq(); + pvsClient->getConnectionFrame()->getFrame()->getVNCClientThread()->setUpdatefreq(50); + pvsClient->getConnectionFrame()->move(5,5); + pvsClient->getConnectionFrame()->setWindowFlags(Qt::WindowStaysOnTopHint); + pvsClient->getConnectionFrame()->raise(); + pvsClient->getConnectionFrame()->paintCloseUp(ui->widget->width(),ui->widget->height()); + + is_closeup = true; + conWin->setCloseupFrame(pvsClient->getConnectionFrame()); + } + } + else + { + QString + message = + QString( + tr( + "This operation can only be performed for one selected Client!")); + QMessageBox::information(this, "PVS", message); + } + } + else if (conWin->getCloseupFrame()) + { + /*PVSClient* pvsClient = + PVSConnectionManager::getManager()->getClientFromIp( + selectedClients->front().toStdString().c_str());*/ + conWin->getCloseupFrame()->setWindowFlags(Qt::Widget); + conWin->getCloseupFrame()->paintCloseUp(conWin->getCloseupFrame()->getPrevWidth(), conWin->getCloseupFrame()->getPrevHeight()); + conWin->getCloseupFrame()->move(_framePosOnCloseUp);//back to the position before the closeup + if (conWin->getCloseupFrame()->getConnection()->getVNCConnection()) + conWin->getCloseupFrame()->getFrame()->getVNCClientThread()->setUpdatefreq(_updatefreq); + + is_closeup = false; + conWin->setCloseupFrame(NULL); + } +} + +void MainWindow::foto() // makes a screenshot of the selected client +{ + std::list<QString>* selectedClients = + MainWindow::getConnectionList()->getSelectedClients(); + if (selectedClients->size() > 0) + { + QString format = "png"; + for (std::list<QString>::iterator tmpIt = selectedClients->begin(); tmpIt + != selectedClients->end(); tmpIt++) + { + + QString path = QDir::homePath().append("/").append(*tmpIt).append( + ".png"); + PVSClient + * pvsClient = + PVSConnectionManager::getManager()->getClientFromIp( + (*tmpIt).toUtf8().data()); + if (pvsClient->getVNCConnection()) + { + const QImage img = pvsClient->getConnectionFrame()->getFrame()->getImageForFoto(); + if (!img.isNull()) + img.save(path, format.toAscii()); + } + else printf("Cannot save screen: Image is null.\n"); + } + } + else + { + QString + message = + QString( + tr( + "This operation can only be performed for at least one selected Client!")); + QMessageBox::information(this, "PVS", message); + } +} + +void MainWindow::createProfile() +{ + profileDialog proDiag; + proDiag.exec(); +} + +void MainWindow::showusername() +{ + MainWindow::getConnectionList()->setColumnHidden(2, false); + MainWindow::getConnectionList()->setColumnHidden(0, true); + MainWindow::getConnectionList()->setColumnHidden(1, true); +} + +void MainWindow::showname() +{ + MainWindow::getConnectionList()->setColumnHidden(0, false); + MainWindow::getConnectionList()->setColumnHidden(1, true); + MainWindow::getConnectionList()->setColumnHidden(2, true); +} + +void MainWindow::showip() +{ + MainWindow::getConnectionList()->setColumnHidden(1, false); + MainWindow::getConnectionList()->setColumnHidden(2, true); + MainWindow::getConnectionList()->setColumnHidden(0, true); +} + +void MainWindow::incomingFile() +{ + QTcpSocket *socket = _serverSocket->nextPendingConnection(); + ServerFileTransfert* sft = new ServerFileTransfert(this); + sft->receiveFileFromHost(socket); +} + +void MainWindow::changeRatio(int ratio) // needed the change the size of the vnc-screens +{ + + if (!_isThumbnailrate) + { + QString str; + str.append(QString("%1").arg(ratio)); + ui->label_2->setText(str); + + std::list<QString>* selClients = getConnectionList()->getSelectedClients(); + if (selClients->size() > 0) + { + for (std::list<QString>::iterator client = selClients->begin(); client + != selClients->end(); client++) + { + PVSClient* pvsClient = + PVSConnectionManager::getManager()->getClientFromIp( + (*client).toUtf8().data()); + ConnectionFrame *frame = pvsClient->getConnectionFrame(); + int w = (frame->init_w * ratio) / 100; + int h = (frame->init_h * ratio) / 100; + frame->setPrevWidth(w); + frame->setPrevHeight(h); + frame->paintCloseUp(w, h); + frame->setRatio(ratio); + } + } + else + { + QList<ConnectionFrame *> frameList = + MainWindow::getConnectionWindow()->getFrameList(); + ConnectionFrame *frame; + foreach(frame, frameList) + { + int w = (frame->init_w * ratio) / 100; + int h = (frame->init_h * ratio) / 100; + frame->setPrevWidth(w); + frame->setPrevHeight(h); + frame->paintCloseUp(w, h); + } + } + } + else + { + int updatefreq = (ratio*500)/100; + QString str; + str.append(QString("%1").arg(updatefreq)); + ui->label_2->setText(str); + std::list<QString>* selClients = getConnectionList()->getSelectedClients(); + if (selClients->size() > 0) + { + for (std::list<QString>::iterator client = selClients->begin(); client + != selClients->end(); client++) + { + PVSClient* pvsClient = + PVSConnectionManager::getManager()->getClientFromIp( + (*client).toUtf8().data()); + if (pvsClient->getVNCConnection()) + pvsClient->getConnectionFrame()->getFrame()->getVNCClientThread()->setUpdatefreq(updatefreq); + } + } + else + { + std::list<PVSClient*> clients = PVSConnectionManager::getManager()->getConnections(); + foreach (PVSClient* client, clients) + { + if (client->getVNCConnection()) + client->getConnectionFrame()->getFrame()->getVNCClientThread()->setUpdatefreq(updatefreq); + } + } + + } +} + +/* + * We can change the status for the action that we want to assign to the thumbnails. + * The actions are to be perform over the horizontalslider from QSlider only on the not dummies clients. + * The dummies clients aren't involved. + * We distingue two status: + * -Thumbnailratio:hier we can change the ratio of the thumbnails. + * -Thumbnailrate:we change the rate of the VNCClientThread of the frames. These actions are perform on the selected clients. + * If no clients are selected, we change the ratio of the whole clients on the clientlist * + */ +void MainWindow::changeStatus(int index) +{ + QString status = ui->thumbStatus->currentText (); + + if (status == "Thumbnailratio") + { + _isThumbnailrate = false; + ui->label_3->setText("%"); + std::list<QString>* selClients = getConnectionList()->getSelectedClients(); + if (selClients->size() == 1) + { + PVSClient* pvsClient = + PVSConnectionManager::getManager()->getClientFromIp( + selClients->front().toStdString().c_str()); + int ratio = pvsClient->getConnectionFrame()->getRatio(); + ui->label_2->setText(QString::number(ratio)); + ui->horizontalSlider->setValue(ratio); + } + else + { + ui->label_2->setText("100"); + ui->horizontalSlider->setValue(100); + } + + } + else if (status == "Thumbnailrate") + { + _isThumbnailrate = true; + ui->label_3->setText("ms"); + std::list<QString>* selClients = getConnectionList()->getSelectedClients(); + if (selClients->size() == 1) + { + PVSClient* pvsClient = + PVSConnectionManager::getManager()->getClientFromIp( + selClients->front().toStdString().c_str()); + if (pvsClient->getVNCConnection()) + { + int updatefreq = pvsClient->getConnectionFrame()->getFrame()->getVNCClientThread()->getUpdatefreq(); + int showfreq = (updatefreq*100)/500; + ui->label_2->setText(QString::number(updatefreq)); + ui->horizontalSlider->setValue(showfreq); + } + } + else + { + ui->label_2->setText("500"); + ui->horizontalSlider->setValue(100); + } + } +} + + +/* + * Going to run a new vncthread with quality: quality + */ +void MainWindow::setVNCQuality(int quality) +{ + std::list<QString>* selClients = getConnectionList()->getSelectedClients(); + if (selClients->size() > 0) + { + for (std::list<QString>::iterator client = selClients->begin(); client + != selClients->end(); client++) + { + PVSClient* pvsClient = + PVSConnectionManager::getManager()->getClientFromIp( + (*client).toUtf8().data()); + pvsClient->getConnectionFrame()->resetConnectionWithQuality(quality); + pvsClient->getConnectionFrame()->update(); + } + } + else + { + QList<ConnectionFrame*> FrameList = MainWindow::getConnectionWindow()->getFrameList(); + foreach(ConnectionFrame* frame, FrameList) + { + frame->resetConnectionWithQuality(quality); + frame->update(); + } + } + +} + + +void MainWindow::setPasswordForConnection(int enabled) +{ + if(enabled == 0)//the checkbox isn't checked, so no passowrd needed, we remove it in the titlebar + { + QString dummy = PVSConnectionManager::getManager()->setNeedPassword(false); + _sessionName = PVSConnectionManager::getManager()->getSessionName(); + QString title = "PVSmgr - "; + title.append(_profilName); + title.append(" ["+_sessionName + " : ]"); + setWindowTitle(title); + } + else if (enabled == 2) //password is needed, we show it in the titlebar + { + _pwdCon = PVSConnectionManager::getManager()->setNeedPassword(true); + _sessionName = PVSConnectionManager::getManager()->getSessionName(); + QString title = "PVSmgr - "; + title.append(_profilName); + title.append(" ["+_sessionName + " : "); + title.append(_pwdCon+"]"); + setWindowTitle(title); + } +} +//#endif + + +void MainWindow::setindexback() //sets the index of the combobox back +{ +#ifdef MAINWINDOW_USE_TOUCHGUI + ui->comboBox_touch1->setCurrentIndex(0); +#endif +} + +void MainWindow::clientlisthide() // hide or show the clientlist +{ + + if (locked1 == false) + { + ui->ClWidget->show(); + locked1 = true; + } + + else + { + ui->ClWidget->hide(); + locked1 = false; + } + +} + + +void MainWindow::lockalltoolbar() // locks all if a dozent is set +{ + + + if (locked == false) + { + if (MainWindow::getConnectionWindow()->hasDozent) + { + MainWindow::getConnectionList()->on_lock_all(); + locked = true; + } + else + { + QString message = QString(tr("You have to set a Superclient-machine before performing this action.")); + QMessageBox::information(this, "PVS", message); + } + } + + else + { + MainWindow::getConnectionList()->on_unlock_all(); + locked = false; + } + +} + +void MainWindow::locksingle() // locks a single client +{ + + MainWindow::getConnectionList()->on_lock(); + +} + +void MainWindow::unlocksingle() // unlocks a single client +{ + + MainWindow::getConnectionList()->on_unlock(); + +} + + +void MainWindow::combobox1(int menuindex1) // defines the functions to call from the combobox +{ + switch (menuindex1) + // index comes from the slot definition + { + case 1: + // Lock all + MainWindow::getConnectionList()->on_lock_all(); + break; + + case 2: + // UnLock all + MainWindow::getConnectionList()->on_unlock_all(); + break; + + case 3: + // UnProject all + MainWindow::getConnectionList()->on_unproject_all(); + break; + + case 4: + //Background Picture + backgroundpicture(); + break; + } +} + +void MainWindow::resetall() // unlock and unproject all in toolbar + { + MainWindow::getConnectionList()->on_unlock_all(); + MainWindow::getConnectionList()->on_unproject_all(); + } + + +void MainWindow::projecttoolbar() // projection from toolbar button + { + + MainWindow::getConnectionList()->on_projection(); + + } +void MainWindow::unprojecttoolbar() // unproject all in toolbar + { + + MainWindow::getConnectionList()->on_unprojection(); + + } + +void MainWindow::backgroundpicture() + { + + + fileName = QFileDialog::getOpenFileName(this, + tr("Open Image"), "/home", tr("Image Files (*.png *.jpg *.svg)")); // user chooses a file + + QImage img(""+fileName+""); // set image + QString test("/tmp/test.png"); // set path for saving the scaled picture + QImage img2 = img.scaled(ui->widget->size(),Qt::IgnoreAspectRatio,Qt::FastTransformation); // scale it + + img2.save(""+test+""); // save it + + ui->widget->setStyleSheet("background-image: url(/tmp/test.png);background-repeat:no-repeat; background-position:center;"); //set the picture as background + foreach (ConnectionFrame* cf, MainWindow::getConnectionWindow()->getAllFrameOnWindow()) + { + cf->setStyleSheet(QString::fromUtf8("background-color: rgb(150, 150, 168);")); + } + + bgimage=true; // for the resize event, set background true + + + } + +void MainWindow::repaintbackgroundpicture() // same as backgroundpicture but called when mainwindow is resized + { + + QImage img("/tmp/test.png"); + QString test("/tmp/test.png"); + QImage img2 = img.scaled(ui->widget->size(),Qt::IgnoreAspectRatio,Qt::FastTransformation); + + img2.save(""+test+""); + + ui->widget->setStyleSheet("background-image: url(/tmp/test.png);background-repeat:no-repeat; background-position:center;"); + + + } + +void MainWindow::setdozenttoolbar() // set the dozents pc which is not locked with lockedall +{ + + std::list<QString>* selectedClients = + MainWindow::getConnectionList()->getSelectedClients(); + + if (selectedClients->size() == 1) + { + + PVSClient* pvsClient = + PVSConnectionManager::getManager()->getClientFromIp( + selectedClients->front().toStdString().c_str()); + if (pvsClient->getVNCConnection()) + pvsClient->getConnectionFrame()->getFrame()->setDozent(); + } + +} + +void MainWindow::startChatDialog() +{ + if (!sChatDialog.isVisible()) + sChatDialog.show(); //show the chat dialog + else + sChatDialog.raise();//show the chat dialog on top level +} + + + +MainWindow* MainWindow::myself = NULL; +ConnectionList* MainWindow::conList = NULL; +ConnectionWindow* MainWindow::conWin = NULL; +bool MainWindow::_isLockAll = false; diff --git a/src/gui/mainWindow.h b/src/gui/mainWindow.h new file mode 100644 index 0000000..00bd927 --- /dev/null +++ b/src/gui/mainWindow.h @@ -0,0 +1,200 @@ +#ifndef _MAINWINDOW_H_ +#define _MAINWINDOW_H_ + +#include <QtGui> +#include <QtNetwork> +#include <QMainWindow> +#include <QFileDialog> +#include <src/gui/connectionList.h> +#include <src/util/consoleLogger.h> +#include <src/gui/connectionWindow.h> +#include <src/gui/profileDialog.h> +//#include <src/gui/dialog.h> +#include <src/core/pvsClient.h> +#include <src/core/pvsConnectionManager.h> +#include "src/gui/aboutDialog.h" +#include "src/gui/serverChatDialog.h" +#include <src/gui/serverFileTransfert.h> + + +namespace Ui +{ +class MainWindow; +} + + +class PVSClient; +class ConnectionList; +class ConnectionWindow; +class profileDialog; +class ServerChatDialog; +//class Dialog; + + +class MainWindow : public QMainWindow +{ + friend class PVSConnectionManager; + + Q_OBJECT + + +public: + MainWindow(QWidget *parent = 0); + ~MainWindow(); + + //singleton methods + static MainWindow* getWindow(); + static ConnectionWindow* getConnectionWindow(); + static ConnectionList* getConnectionList(); + + ServerChatDialog sChatDialog; + + + int getConnectionWindowWidth(); + int getConnectionWindowHeight(); + int x,y; + QImage img; + QImage img2; + QString test; + QStringList profilList; + QStringList getProfilList(); + void addProfileInMenu(QString name); + void removeProfileInMenu(QString name); + QString currentProfi; + QString getCurrentProfi() + { + return currentProfi; + } + void loadSettings(); + void loadSettings(QString profilname); + void saveSettings(QString profilname); + void removeProfil(QString profilname); + + // connection add/remove and dialog methods + void addConnection(PVSClient* newCon); + void removeConnection(PVSClient* newCon); + //ConnectionFrame* getNewFrame(); + void onConnectionFailed(QString host = ""); + void onConnectionTerminated(PVSClient* newConnection); + void onConnectionRemoved(PVSClient* newConnection); + void onPasswordFailed(QString Qhost = ""); + + void sendChatMsg(PVSMsg myMsg); + void receiveChatMsg(QString nick_from, QString nick_to, QString msg); + + // view mode related methods + unsigned int getGlobalFrameRate(); + void setGlobalFrameRate(unsigned int newRate); + int getPrevWidth(); + void setPrevWidth(int newWidth); + int getPrevHeight(); + void setPrevHeight(int newHeight); + + // int createMsgDiag(); + void setMsgDialog(QString msgd){msgDialog = msgd;}; + QString getMsgDialog(){return msgDialog;}; + + bool isLockAllStatus() + { + return _isLockAll; + } + + void appendLogMsg(); + + + +protected: + void closeEvent(QCloseEvent *e); + void changeEvent(QEvent *e); + void resizeEvent(QResizeEvent *event); //We need this to resize the frame in the window when window are resized. + void updatePos(ConnectionFrame* cf, int x, int y); + virtual void on_log_line(LogEntry consoleEntry); + + + + +private: + Ui::MainWindow *ui; + static ConnectionWindow* conWin; + static ConnectionList* conList; + //Dialog messageDiag; + static MainWindow* myself; + QString _pwdCon; + QString _sessionName; + QString _profilName; + + QStringList _chatListClients; + + + + /*ConnectionDialog* myConDiag; + ConnectionDialog* pwDiag; + ConnectionDialog* messageDiag;*/ + + AboutDialog *_aboutDialog; + + QString msgDialog; + bool bgimage; + bool locked, locked1; + bool force_square; + bool is_fullscreen; + bool is_closeup; + static bool _isLockAll; + bool showError, showNormal, showNetwork, showTerminal, showChat, showAtAll; + bool isDozent; + QString fileName; + + int _initW, _initH, _firstResize; + + unsigned int updateRate, frameRate; + int prev_width, prev_height, menuindex1, menuindex2; + + QTcpServer *_serverSocket; + QPoint _framePosOnCloseUp; + + bool _isThumbnailrate; + int _updatefreq; + QString _oldRatio; + + QMenu* _profileMenuList; + QMap<QString, QAction*> _mapProfileToAction; + +public slots: + void loadProfile(QAction* actiontriggered); + void setindexback(); + //void setindexback2(); + void lockalltoolbar(); + void resetall(); + void locksingle(); + void unlocksingle(); + void clientlisthide(); + void projecttoolbar(); + void unprojecttoolbar(); + void closeUp(); + void foto(); + void backgroundpicture(); + void repaintbackgroundpicture(); + void setdozenttoolbar(); + void startChatDialog(); + +private slots: + void onToggleLog(bool showtime); + void setLogConsoleDisabled(bool visible); + //void close(); + void disconnect(); + void lockUnlockAll(); + void createProfile(); + void showusername(); + void showname(); + void showip(); + void incomingFile(); + void changeRatio(int ratio); + void changeStatus (int index); + void setVNCQuality(int quality); + void setPasswordForConnection(int enabled); + void combobox1(int menuindex1); // Funktion um index der combobox auszulesen und weiterzuverarbeiten s. Ticker 671 + //void combobox2(int menuindex2); // Funktion um index der combobox auszulesen und weiterzuverarbeiten +}; + + +#endif diff --git a/src/gui/profileDialog.cpp b/src/gui/profileDialog.cpp new file mode 100644 index 0000000..2cbc155 --- /dev/null +++ b/src/gui/profileDialog.cpp @@ -0,0 +1,179 @@ +/* + # 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/ + # ----------------------------------------------------------------------------- + # profileDialog.cpp + # - GUI to define the profile. + # ----------------------------------------------------------------------------- + */ + +#include "profileDialog.h" +#include "ui_profileDialog.h" +#include <src/gui/mainWindow.h> +#include <iostream> + +profileDialog::profileDialog(QWidget * parent): + QDialog(parent), + uidiag(new Ui::Dialog) +{ + uidiag->setupUi(this); + content = new QTableView(uidiag->widget); + uidiag->gridLayout->addWidget(content); + + /*Das Modelfestlegen, wo die Clientname angezeigt werden.*/ + model = new QStandardItemModel(0,1,content); //Leere Tabelle mit einer Spalte erstellen + model->setHeaderData(0, Qt::Horizontal, tr("Profile")); //Spalte name definieren + content->setModel(model); + + QItemSelectionModel *selectionModel = new QItemSelectionModel(model); + content->setSelectionModel(selectionModel); + QHeaderView *headerView = content->horizontalHeader(); + headerView->setStretchLastSection(true); + + content->setEditTriggers(QAbstractItemView::NoEditTriggers); //Die Einträge in der Tabelle werden nicht editierbar. + content->setSelectionMode(QAbstractItemView::ExtendedSelection); //Damit mehere Einträge selektierbar werden. + + content->resizeColumnToContents(0); + + + + uidiag->add->setDisabled(true); + uidiag->edit->setDisabled(true); + uidiag->edit->setVisible(false); + uidiag->remove->setDisabled(true); + uidiag->load->setDisabled(true); + uidiag->lineEdit->setDisabled(true); + + setUpProfile(); + + connect(uidiag->add, SIGNAL(clicked ()), this, SLOT(AddProfile())); + connect(uidiag->new_2, SIGNAL(clicked ()), this, SLOT(onNew())); + connect(uidiag->load, SIGNAL(clicked ()), this, SLOT(onLoad())); + connect(uidiag->remove, SIGNAL(clicked ()), this, SLOT(removeProfile())); + connect(uidiag->close, SIGNAL(clicked ()), this, SLOT(accept())); + connect(content, SIGNAL(clicked(const QModelIndex)), this, SLOT(selectionChange(const QModelIndex))); + //show(); + +} + +profileDialog::~profileDialog() +{ + // TODO Auto-generated destructor stub +} + +void profileDialog::setUpProfile() +{ + QStringList list = MainWindow::getWindow()->getProfilList(); + for (int i=0; i<list.size(); i++) + { + model->insertRow(0, QModelIndex()); + model->setData(model->index(0, 0, QModelIndex()),list.at(i)); + } +} + +void profileDialog::AddProfile() +{ + QString name = QString(uidiag->lineEdit->text()); + if (!ProfilList.contains(name)) + { + if (!name.isEmpty()) + { + model->insertRow(0, QModelIndex()); + model->setData(model->index(0, 0, QModelIndex()),name); + ProfilList.append(name); + MainWindow::getWindow()->saveSettings(name); + uidiag->lineEdit->setText(""); + } + else + { + QString message = QString(tr("This field can't be empty.")); + QMessageBox::information(this, "PVS", message); + } + } + else + { + QString message = QString(tr("This name is already in the list.")); + QMessageBox::information(this, "PVS", message); + } +} + +void profileDialog::removeProfile() +{ + QTableView *temp = static_cast<QTableView*>(content); + QItemSelectionModel *selectionModel = temp->selectionModel(); + + QModelIndexList indexes = selectionModel->selectedRows(); + QModelIndex index; + + foreach(index, indexes) + { + int row = content->currentIndex().row(); + QString current = model->index(content->currentIndex().row(), 0).data(Qt::DisplayRole).toString(); + model->removeRow(row, QModelIndex()); + ProfilList.removeOne(current); + MainWindow::getWindow()->removeProfil(current); + } + + + /* if (temp->model()->rowCount()<=0) + {*/ + uidiag->remove->setDisabled(true); + uidiag->edit->setDisabled(true); + uidiag->add->setDisabled(true); + uidiag->load->setDisabled(true); + //} +} + +void profileDialog::onNew() +{ + uidiag->add->setDisabled(false); + uidiag->lineEdit->setDisabled(false); + uidiag->lineEdit->setFocus(); +} + +void profileDialog::onLoad() +{ + QTableView *temp = static_cast<QTableView*>(content); + QItemSelectionModel *selectionModel = temp->selectionModel(); + + QModelIndexList indexes = selectionModel->selectedRows(); + QModelIndex index; + if (indexes.size()>1) + { + QMessageBox::information(this, "PVS", tr("You can only load one profile at time")); + } + else if(indexes.size() == 1) + { + foreach(index, indexes) + { + //int row = content->currentIndex().row(); + QString current = model->index(content->currentIndex().row(), 0).data(Qt::DisplayRole).toString(); + MainWindow::getWindow()->loadSettings(current); + } + } + + emit accept(); +} + +void profileDialog::selectionChange(const QModelIndex & index) +{ + uidiag->remove->setDisabled(false); + uidiag->edit->setDisabled(false); + uidiag->add->setDisabled(false); + uidiag->load->setDisabled(false); + +} + +void profileDialog::close() +{ + close(); +} + + diff --git a/src/gui/profileDialog.h b/src/gui/profileDialog.h new file mode 100644 index 0000000..5caebfa --- /dev/null +++ b/src/gui/profileDialog.h @@ -0,0 +1,46 @@ +#ifndef PROFILEDIALOG_H_ +#define PROFILEDIALOG_H_ + +#include <QtGui> +#include <QDialog> +#include <src/gui/mainWindow.h> + +namespace Ui +{ +class Dialog; +} + +class MainWindow; + +class profileDialog : public QDialog +{ + Q_OBJECT + +public: + profileDialog(QWidget * parent = 0); + virtual ~profileDialog(); + + void setUpProfile(); + + + +signals: + void selectionChanged (const QItemSelection &selected); + +private: + Ui::Dialog *uidiag; + QTableView *content; + QAbstractItemModel *model; + QItemSelectionModel *selectionModel; + QList<QString> ProfilList; + +private Q_SLOTS: + void AddProfile(); + void removeProfile(); + void onNew(); + void onLoad(); + void selectionChange(const QModelIndex & index); + void close(); +}; + +#endif /* PROFILEDIALOG_H_ */ diff --git a/src/gui/projectionDialog.cpp b/src/gui/projectionDialog.cpp new file mode 100644 index 0000000..c091f54 --- /dev/null +++ b/src/gui/projectionDialog.cpp @@ -0,0 +1,140 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# projectionDialog.cpp + Dialog to select client for the projection +# ----------------------------------------------------------------------------- +*/ + +#include "projectionDialog.h" +#include "ui_projectionDialog.h" +#include <src/gui/mainWindow.h> +#include <QtGui> +#include <iostream> + +ProjectionDialog::ProjectionDialog(QWidget *parent) : + QDialog(parent), + pui(new Ui::projectionDialog) +{ + pui->setupUi(this); + this->setWindowTitle(tr("Target for Projection")); + + source = MainWindow::getConnectionList()->getSelectedClients()->front(); + setupContent(MainWindow::getWindow()->getConnectionList()->getTargetToDisplay(source)); + + pui->send->setDisabled(true); + + connect( pui->send, SIGNAL( clicked() ), this, SLOT( sendListToProject() ) ); + connect( pui->cancel, SIGNAL( clicked() ), this, SLOT( cancelProject() ) ); + connect( pui->checkBox, SIGNAL( clicked() ), this, SLOT( selectAll() ) ); +} + +ProjectionDialog::~ProjectionDialog() +{ + delete pui; + QCheckBox* cbox; + foreach(cbox, checkList) + { + disconnect( cbox, SIGNAL( clicked() ), this, SLOT( sendState() ) ); + } +} + +void ProjectionDialog::setupContent(QList<QString> content) +{ + if (!content.isEmpty()) + { + QString item; + foreach(item, content) + { + QCheckBox *checkbox = new QCheckBox(item,this); + pui->verticalLayout_2->addWidget(checkbox); + checkList.push_back(checkbox); + connect( checkbox, SIGNAL( clicked() ), this, SLOT( sendState() ) ); + } + } + else + { + QLabel *textInfo = new QLabel(this); + textInfo->setText("No Target available"); + pui->verticalLayout_2->addWidget(textInfo); + pui->checkBox->setDisabled(true); + } +} + +void ProjectionDialog::sendListToProject() +{ + MainWindow::getConnectionList()->setProjectProporties(source); + QCheckBox* cbox; + + foreach(cbox, checkList) + { + if (cbox->isChecked()) + { + MainWindow::getConnectionList()->addTargetToProjectList(cbox->text()); + } + } + emit accept(); +} + +void ProjectionDialog::cancelProject() +{ + emit reject(); +} + +void ProjectionDialog::sendState() +{ + QCheckBox* cbox; + bool set = false; + + foreach(cbox, checkList) + { + if (cbox->isChecked()) + { + pui->send->setDisabled(false); + set = true; + break; + } + } + + if (!set) + pui->send->setDisabled(true); + +} + +void ProjectionDialog::selectAll() +{ + if(pui->checkBox->isChecked()) + { + QCheckBox* cbox; + foreach(cbox, checkList) + cbox->setChecked(true); + pui->send->setDisabled(false); + } + else + { + QCheckBox* cbox; + foreach(cbox, checkList) + cbox->setChecked(false); + pui->send->setDisabled(true); + } +} + +void ProjectionDialog::changeEvent(QEvent *e) +{ + QDialog::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + pui->retranslateUi(this); + break; + default: + break; + } +} diff --git a/src/gui/projectionDialog.h b/src/gui/projectionDialog.h new file mode 100644 index 0000000..842d255 --- /dev/null +++ b/src/gui/projectionDialog.h @@ -0,0 +1,46 @@ +/* + * projectionDialog.h + * + * Created on: 28.02.2010 + * Author: achillenana + */ + +#ifndef PROJECTIONDIALOG_H_ +#define PROJECTIONDIALOG_H_ + +#include <QDialog> +#include <QCheckBox> +//#include <src/gui/mainWindow.h> + + +class MainWindow; + +namespace Ui { + class projectionDialog; +} + +class ProjectionDialog : public QDialog { + Q_OBJECT +public: + ProjectionDialog(QWidget *parent = 0); + ~ProjectionDialog(); + + void setupContent(QList<QString> content); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::projectionDialog *pui; + std::list<QCheckBox *> checkList; + QString source; + +private slots: + void sendListToProject(); + void cancelProject(); + void sendState(); + void selectAll(); +}; + + +#endif /* PROJECTIONDIALOG_H_ */ diff --git a/src/gui/serverChatDialog.cpp b/src/gui/serverChatDialog.cpp new file mode 100644 index 0000000..ec1f299 --- /dev/null +++ b/src/gui/serverChatDialog.cpp @@ -0,0 +1,281 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + # ----------------------------------------------------------------------------- + # serverChatDialog.cpp + # - graphical chat interface for the pvsmgr + # ----------------------------------------------------------------------------- + */ + +#include "serverChatDialog.h" +#include <src/gui/mainWindow.h> +#include "ui_serverChatDialog.h" + +ServerChatDialog::ServerChatDialog(QWidget *parent) : + QDialog(parent), uichat(new Ui::ServerChatDialogClass) +{ + uichat->setupUi(this); + _nickname = "PVSMGR"; + connect(uichat->pushButton, SIGNAL(clicked()), this, SLOT(chat_send())); + + // add first tab for public messages + uichat->tabWidget->clear(); + QTextEdit *t = new QTextEdit(); + t->setReadOnly(true); + uichat->tabWidget->addTab(t, "@all"); + _hash = new QHash<QString, QTextEdit*> (); + _hash->insert(uichat->tabWidget->tabText(0), t); + + // setup menu + _menu = new QMenu(); + _sendFileAction = new QAction(tr("&Send File..."), this); + _menu->addAction(_sendFileAction); + + connect(uichat->listWidget, SIGNAL(doubleClicked(QModelIndex)), this, + SLOT(addTab(QModelIndex))); + connect(uichat->tabWidget, SIGNAL(tabCloseRequested(int)), this, + SLOT(removeTab(int))); + connect(uichat->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(removeIcon(int))); + connect(uichat->listWidget, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(showMenu(QPoint))); + connect(_sendFileAction, SIGNAL(triggered()), this, SLOT(sendFile())); + + this->setAcceptDrops(true); +} + +ServerChatDialog::~ServerChatDialog() +{ +} + +void ServerChatDialog::setTrayIcon(QSystemTrayIcon *trayIcon) +{ + // _trayIcon = trayIcon; + // FIXME: messageClicked() is always emitted, not only on chat msg + //connect(_trayIcon, SIGNAL(messageClicked()), this, SLOT(open())); +} + +//////////////////////////////////////////////////////////////////////////////// +// Slots + +void ServerChatDialog::open() +{ + uichat->lineEdit->setFocus(); + setVisible(true); +} + +void ServerChatDialog::chat_receive(QString nick_from, QString nick_to, + QString msg) +{ + qDebug("[%s] R %s <- %s : %s", metaObject()->className(), + qPrintable(nick_to), qPrintable(nick_from), qPrintable(msg)); + + if (nick_to == uichat->tabWidget->tabText(0)) + showMsg(nick_from, msg, getTab(nick_to)); // public message or own msg + else + { + if (nick_to == "PVSMGR") + showMsg(nick_from, msg, getTab(nick_from)); // private message + else if (nick_from == "PVSMGR") + showMsg(nick_from, msg, getTab(nick_to)); // private message + } +} + +void ServerChatDialog::chat_send() +{ + QString msg = uichat->lineEdit->text(); + if (msg != "") + { + msg = "PVSMGR:"+ msg; + QString nick_to = uichat->tabWidget->tabText(uichat->tabWidget->currentIndex()); + PVSMsg myMsg(PVSMESSAGE, nick_to, msg, 0); + MainWindow::getWindow()->sendChatMsg(myMsg); + uichat->lineEdit->clear(); + uichat->lineEdit->setFocus(); + + qDebug("[%s] S %s -> %s : %s", metaObject()->className(), + qPrintable(_nickname), qPrintable(nick_to), qPrintable(msg)); + + } +} + +void ServerChatDialog::chat_nicklist_update() +{ + uichat->listWidget->clear(); + uichat->listWidget->addItems(_nickList); +} + +void ServerChatDialog::chat_client_add(QString nick) +{ + if (!_nickList.contains(nick)) + _nickList.append(nick); + showEvent("-> " + nick + tr(" has joined the chat.")); +} + +void ServerChatDialog::chat_client_remove(QString nick) +{ + _nickList.removeOne(nick); + showEvent("<- " + nick + tr(" has left the chat.")); +} + +void ServerChatDialog::addTab(QModelIndex i) +{ + QString text = i.data().toString(); + if (_hash->contains(text)) + { + uichat->tabWidget->setCurrentWidget(_hash->value(text)); + } + else + { + QTextEdit *t = new QTextEdit(); + t->setReadOnly(true); + uichat->tabWidget->setCurrentIndex(uichat->tabWidget->addTab(t, text)); + _hash->insert(text, t); + } + uichat->lineEdit->setFocus(); +} + +void ServerChatDialog::removeTab(int i) +{ + if (i != 0) + { + _tabList.removeOne(_hash->value(uichat->tabWidget->tabText(i))); + _hash->remove(uichat->tabWidget->tabText(i)); + uichat->tabWidget->removeTab(i); + uichat->lineEdit->setFocus(); + } +} + +void ServerChatDialog::removeIcon(int i) +{ + uichat->tabWidget->setTabIcon(i, QIcon()); +} + +//////////////////////////////////////////////////////////////////////////////// +// Private + +QTextEdit* ServerChatDialog::getTab(QString text) +{ + if (!_hash->contains(text)) + { + QTextEdit *t = new QTextEdit(); + t->setReadOnly(true); + uichat->tabWidget->addTab(t, text); + _hash->insert(text, t); + _tabList.append(t); + } + uichat->lineEdit->setFocus(); + return _hash->value(text); +} + +void ServerChatDialog::showMsg(QString nick_from, QString msg, QTextEdit *t) +{ + // move cursor at the end + t->moveCursor(QTextCursor::End); + + // print time + if (nick_from == "PVSMGR") + t->setTextColor(QColor(0, 100, 100)); + else + t->setTextColor(QColor(0, 100, 0)); + t->append("[" + QTime::currentTime().toString("hh:mm") + "] "); + + // print nickname + if (nick_from == "PVSMGR") + t->setTextColor(QColor(0, 100, 255)); + else + t->setTextColor(QColor(0, 0, 255)); + t->insertPlainText("<" + nick_from + "> "); + + // print message + if (nick_from == "PVSMGR") + t->setTextColor(QColor(100, 100, 100)); + else + t->setTextColor(QColor(0, 0, 0)); + t->insertPlainText(msg); + + // show icon if not current tab + if (uichat->tabWidget->currentIndex() != uichat->tabWidget->indexOf(t)) + uichat->tabWidget->setTabIcon(uichat->tabWidget->indexOf(t), QIcon(":chat_msg16.svg")); +} + +void ServerChatDialog::showMenu(QPoint p) +{ + _menu->popup(uichat->listWidget->mapToGlobal(p)); +} + +void ServerChatDialog::sendFile() +{ + ServerFileTransfert* sft = new ServerFileTransfert(this); + QString cTab = uichat->listWidget->currentItem()->text(); + QString hostIP = PVSConnectionManager::getManager()->getClientFromUsername(cTab)->getIp(); + if (hostIP != "") + sft->sendFileToHost(hostIP); +} + +void ServerChatDialog::sendFile(QString filename) +{ + if (uichat->tabWidget->currentIndex() == 0 || filename == "") + return; + + // ask user + QString nick = uichat->tabWidget->tabText(uichat->tabWidget->currentIndex()); + QMessageBox::StandardButton result = QMessageBox::question(0, + tr("PVS File Transfer with ")+nick, + tr("Send file '") + filename + tr("' to ") + nick + "?", + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); + + if (result != QMessageBox::Ok) + return; + + ServerFileTransfert* sft = new ServerFileTransfert(this); + QString hostIP = PVSConnectionManager::getManager()->getClientFromUsername(nick)->getIp(); + if (hostIP != "") + sft->sendFileToHost(hostIP, filename); +} + + +void ServerChatDialog::showEvent(QString msg) +{ + QTextEdit *t = _hash->value(uichat->tabWidget->tabText(0)); + + // move cursor at the end + t->moveCursor(QTextCursor::End); + + t->setTextColor(QColor(150, 150, 150)); + + // print time + t->append("[" + QTime::currentTime().toString("hh:mm") + "] "); + + // print message + t->insertPlainText(msg); +} + +void ServerChatDialog::dragEnterEvent(QDragEnterEvent *event) +{ + event->accept(); +} + +void ServerChatDialog::dragMoveEvent(QDragMoveEvent *event) +{ + event->accept(); +} + +void ServerChatDialog::dragLeaveEvent(QDragLeaveEvent *event) +{ + event->accept(); +} + +void ServerChatDialog::dropEvent(QDropEvent *event) +{ + event->accept(); + if (event->mimeData()->hasUrls()) + sendFile(event->mimeData()->urls()[0].toLocalFile()); +} diff --git a/src/gui/serverChatDialog.h b/src/gui/serverChatDialog.h new file mode 100644 index 0000000..728af05 --- /dev/null +++ b/src/gui/serverChatDialog.h @@ -0,0 +1,67 @@ +#ifndef SERVERCHATDIALOG_H_ +#define SERVERCHATDIALOG_H_ + +#include <QtGui> +#include <src/gui/serverFileTransfert.h> +#include "pvsinterface.h" + +class MainWindow; + +namespace Ui +{ + class ServerChatDialogClass; +} + +class ServerChatDialog: public QDialog +{ + Q_OBJECT + +public: + ServerChatDialog(QWidget *parent = 0); + ~ServerChatDialog(); + void setTrayIcon(QSystemTrayIcon *trayIcon); + void chat_nicklist_update(); + void chat_client_add(QString nick); + void chat_client_remove(QString nick); + +public Q_SLOTS: + void open(); + void chat_receive(QString nick_from, QString nick_to, QString msg); + void chat_send(); + + +private Q_SLOTS: + void addTab(QModelIndex i); + void sendFile(); + void showMenu(QPoint p); + void removeTab(int i); + void removeIcon(int i); + +private: + Ui::ServerChatDialogClass *uichat; + QTextEdit* getTab(QString text); + void showMsg(QString nick_from, QString msg, QTextEdit *t); + void sendFile(QString filename); + void showEvent(QString msg); + + QList<QTextEdit *> _tabList; + + QHash<QString, QTextEdit*> *_hash; + + QString _nickname; + QStringList _nickList; + + QMenu* _menu; + QAction* _sendFileAction; + +protected: + void dragEnterEvent(QDragEnterEvent *event); + void dragMoveEvent(QDragMoveEvent *event); + void dragLeaveEvent(QDragLeaveEvent *event); + void dropEvent(QDropEvent *event); + +}; + + + +#endif /* SERVERCHATDIALOG_H_ */ diff --git a/src/gui/serverFileTransfert.cpp b/src/gui/serverFileTransfert.cpp new file mode 100644 index 0000000..22e268b --- /dev/null +++ b/src/gui/serverFileTransfert.cpp @@ -0,0 +1,265 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/gui/serverFileTransfert.cpp +# This class manage any file transfert from and to server. +# ----------------------------------------------------------------------------- +*/ + +#include "serverFileTransfert.h" + +ServerFileTransfert::ServerFileTransfert(QWidget *parent): + QDialog(parent) +{ + setupUi(this); + _file = NULL; + _socket = NULL; + + connect(this, SIGNAL(finished(int)), this, SLOT(deleteLater())); +} + +ServerFileTransfert::~ServerFileTransfert() +{ +} + +void ServerFileTransfert::sendFileToHost(QString host) +{ + QString filename = QFileDialog::getOpenFileName(this, tr("Open File"), + QDir::homePath(), ""); + if (filename == "") + { + reject(); + return; + } + sendFileToHost(host, filename); +} + +void ServerFileTransfert::sendFileToHost(QString host, QString filename) +{ + // open file + _file = new QFile(filename); + _file->open(QIODevice::ReadOnly); + _bytesToWrite = _file->size(); + div = 1 + _bytesToWrite / 1000000000; // bc. progressBar supports only int + + // get host from backend + + // gui + filenameLabel->setText(filename); + progressBar->setValue(0); + progressBar->setMaximum(_bytesToWrite/div); + labelB->setText(formatSize(_bytesToWrite)); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); + + // open socket + _socket = new QTcpSocket(); + _socket->connectToHost(host, 29481); + if (_socket->isOpen()) + qDebug("connection open"); + else + qDebug("connection closed"); + qDebug("[%s] Remote host: %s", metaObject()->className(), qPrintable(host)); + + connect(_socket, SIGNAL(connected()), this, SLOT(sendHeader())); + connect(_socket, SIGNAL(disconnected()), this, SLOT(close())); + connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(error(QAbstractSocket::SocketError))); + qDebug("connect is set"); +} + +void ServerFileTransfert::receiveFileFromHost(QTcpSocket* socket) +{ + + _bytesToRead = 0; + _socket = socket; + + connect(_socket, SIGNAL(readyRead()), this, SLOT(receiveHeader())); + connect(_socket, SIGNAL(disconnected()), this, SLOT(close())); + connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(error(QAbstractSocket::SocketError))); + + qDebug("[%s] New Connection: %s", metaObject()->className(), + qPrintable(_socket->peerAddress().toString())); +} + +void ServerFileTransfert::sendHeader() +{ + qDebug("[%s] Sending header(1)...", metaObject()->className()); + QFileInfo info(_file->fileName()); + QString size = QString::number(_bytesToWrite); + QString header = "PVSMGR;" + info.fileName() + ";" + size + "\n"; + _socket->write(header.toLocal8Bit()); + connect(_socket, SIGNAL(readyRead()), this, SLOT(receiveAck())); + qDebug("[%s] Sending header...", metaObject()->className()); +} + +void ServerFileTransfert::receiveHeader() +{ + // parse header + QString header = QString::fromUtf8(_socket->readLine()); + QStringList args = header.split(";"); + QString nick = args[0]; + QString filename = args[1]; + _bytesToRead = args[2].toLongLong(); + div = 1 + _bytesToRead / 1000000000; // bc. progressBar supports only int + + qDebug("[%s] Received header.", metaObject()->className()); + + // ask user + QMessageBox::StandardButton result = QMessageBox::question(0, + tr("PVS File Transfer"),tr("User '") + nick + + tr("' would like to send you a file: ") + filename + + " (" + formatSize(_bytesToRead) + ").", + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); + + if (result != QMessageBox::Ok) + { + sendAck(false); + return; + } + + // open file + QString saveAs = QFileDialog::getSaveFileName(this, tr("Open File"), + QDir::homePath() + QDir::separator() + filename, ""); + if (saveAs == "") + { + sendAck(false); + return; + } + _file = new QFile(saveAs); + _file->open(QIODevice::WriteOnly); + + // gui + filenameLabel->setText(saveAs); + progressBar->setValue(0); + progressBar->setMaximum(_bytesToRead/div); + labelB->setText(formatSize(_bytesToRead)); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); + + sendAck(true); + show(); +} + +void ServerFileTransfert::sendAck(bool b) +{ + disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveHeader())); + + if (b) + { + QString ack = QString("ok\n"); + _socket->write(ack.toUtf8()); + qDebug("[%s] Sending ack...", metaObject()->className()); + connect(_socket, SIGNAL(readyRead()), this, SLOT(receiveFile())); + } + else + { + QString ack = QString("no\n"); + _socket->write(ack.toUtf8()); + qDebug("[%s] Sending nack!!!", metaObject()->className()); + close(); + } +} + +void ServerFileTransfert::receiveAck() +{ + QString ack = QString::fromUtf8(_socket->readLine()); + if (ack != "ok\n") + { + qDebug("[%s] Received nack!", metaObject()->className()); + close(); + return; + } + qDebug("[%s] Received ack.", metaObject()->className()); + + disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveAck())); + connect(_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(sendFile())); + this->show(); + qDebug("[%s] Sending file...", metaObject()->className()); + sendFile(); +} + +void ServerFileTransfert::sendFile() +{ + if (_bytesToWrite == 0) + { + qDebug("[%s] Transfer completed.", metaObject()->className()); + close(); // finished + } + else + { + qint64 bytesWritten = _socket->write(_file->read(1024)); // data left + _bytesToWrite -= bytesWritten; + progressBar->setValue(progressBar->value() + bytesWritten/div); + labelA->setText(formatSize(progressBar->value()*div)); + } +} + +void ServerFileTransfert::receiveFile() +{ + qint64 bytesRead = _file->write(_socket->readAll()); + _bytesToRead -= bytesRead; + progressBar->setValue(progressBar->value() + bytesRead/div); + labelA->setText(formatSize(progressBar->value()*div)); +} + +void ServerFileTransfert::close() +{ + if (_file && _file->isOpen()) + { + _file->close(); + qDebug("[%s] File closed.", metaObject()->className()); + } + + if (_socket && _socket->isOpen()) + { + disconnect(_socket, SIGNAL(readyRead()), this, SLOT(receiveAck())); + disconnect(_socket, SIGNAL(bytesWritten(qint64)), this, SLOT(sendFile())); + disconnect(_socket, SIGNAL(disconnected()), this, SLOT(close())); + disconnect(_socket, SIGNAL(connected()), this, SLOT(sendHeader())); + disconnect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(error(QAbstractSocket::SocketError))); + _socket->disconnectFromHost(); + qDebug("[%s] Connection closed.", metaObject()->className()); + } + + disconnect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); + + if (_bytesToWrite == 0) + { + accept(); + QMessageBox::information(0, tr("PVS - File Transfer"), + tr("File Transfer complete.")); + } + else + { + reject(); + QMessageBox::warning(0, tr("PVS - File Transfer"), + tr("File Transfer canceled!")); + } +} + +void ServerFileTransfert::error(QAbstractSocket::SocketError error) +{ + qDebug("[%s] Socket error: %i", metaObject()->className(), error); + close(); +} + +QString ServerFileTransfert::formatSize(qint64 size) +{ + if (size >= 1000000000) // GB + return QString("%1GB").arg((qreal)size / 1000000000, 0, 'f',1); + else if (size >= 1000000) // MB + return QString("%1MB").arg((qreal)size / 1000000, 0, 'f',1); + else if (size >= 1000) // KB + return QString("%1KB").arg((qreal)size / 1000, 0, 'f',1); + else // B + return QString("%1B").arg((qreal)size, 0, 'f',1); +} diff --git a/src/gui/serverFileTransfert.h b/src/gui/serverFileTransfert.h new file mode 100644 index 0000000..96b30e5 --- /dev/null +++ b/src/gui/serverFileTransfert.h @@ -0,0 +1,52 @@ +#ifndef SERVERFILETRANSFERT_H_ +#define SERVERFILETRANSFERT_H_ + + +#include <QtGui> +#include <QtNetwork> +#include "ui_clientFileSendDialog.h" + +/*namespace Ui +{ + class ClientFileSendDialogClass; +}*/ + +class ServerFileTransfert: public QDialog, + private Ui::ClientFileSendDialogClass + +{ + Q_OBJECT + +public: + ServerFileTransfert (QWidget *parent=0); + ~ServerFileTransfert (); + + void sendFileToHost(QString host); + void sendFileToHost(QString host, QString filename); + void receiveFileFromHost(QTcpSocket* socket); + + //Ui::ClientFileSendDialogClass* uitr; + +private Q_SLOTS: + void sendHeader(); + void receiveHeader(); + void receiveAck(); + void sendFile(); + void receiveFile(); + void close(); + void error(QAbstractSocket::SocketError error); + +private: + void sendAck(bool b); + QString formatSize(qint64 size); + + QTcpSocket *_socket; + QFile *_file; + qint64 _bytesToWrite; + qint64 _bytesToRead; + int div; + +}; + + +#endif /* SERVERFILETRANSFERT_H_ */ diff --git a/src/gui/ui/aboutDialog.ui b/src/gui/ui/aboutDialog.ui new file mode 100644 index 0000000..07d9852 --- /dev/null +++ b/src/gui/ui/aboutDialog.ui @@ -0,0 +1,251 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AboutDialogClass</class> + <widget class="QDialog" name="AboutDialogClass"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>460</width> + <height>363</height> + </rect> + </property> + <property name="windowTitle"> + <string>PVS - About</string> + </property> + <property name="windowIcon"> + <iconset resource="../../../pvsgui.qrc"> + <normaloff>:/cam32.svg</normaloff>:/cam32.svg</iconset> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="../../../pvsgui.qrc">:/cam32.svg</pixmap> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string notr="true"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:24pt; font-weight:600;">PVS</span></p></body></html></string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label_version"> + <property name="text"> + <string notr="true">Version: xx.xx.xx</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>About</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string notr="true">Pool Video Switch</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string notr="true">feedback@openslx.org</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string notr="true">(c) 2009-2010, OpenSLX Project, University of Freiburg</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string notr="true"><a href="http://lab.openslx.org/projects/pvs">http://lab.openslx.org/projects/pvs</a></string> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string><a href="http://www.gnu.org/licenses/gpl-2.0.txt">License: GNU General Public License Version 2</a></string> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_1"> + <attribute name="title"> + <string>Authors</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QPlainTextEdit" name="plainTextEdit_authors"> + <property name="lineWrapMode"> + <enum>QPlainTextEdit::NoWrap</enum> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="plainText"> + <string/> + </property> + <property name="centerOnScroll"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_2"> + <attribute name="title"> + <string>Translation</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QPlainTextEdit" name="plainTextEdit_translation"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources> + <include location="../../../pvsgui.qrc"/> + </resources> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>AboutDialogClass</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>388</x> + <y>351</y> + </hint> + <hint type="destinationlabel"> + <x>109</x> + <y>333</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/gui/ui/clientChatDialog.ui b/src/gui/ui/clientChatDialog.ui new file mode 100644 index 0000000..43f64a9 --- /dev/null +++ b/src/gui/ui/clientChatDialog.ui @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ClientChatDialogClass</class> + <widget class="QDialog" name="ClientChatDialogClass"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>641</width> + <height>659</height> + </rect> + </property> + <property name="windowTitle"> + <string>PVS - Chat </string> + </property> + <property name="windowIcon"> + <iconset resource="../../../pvsgui.qrc"> + <normaloff>:/cam32.svg</normaloff>:/cam32.svg</iconset> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QSplitter" name="splitter"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QListWidget" name="listWidget"> + <property name="maximumSize"> + <size> + <width>150</width> + <height>16777215</height> + </size> + </property> + <property name="contextMenuPolicy"> + <enum>Qt::CustomContextMenu</enum> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + </widget> + <widget class="QTabWidget" name="tabWidget"> + <property name="tabPosition"> + <enum>QTabWidget::South</enum> + </property> + <property name="tabsClosable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string notr="true">@all</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout"/> + </widget> + </widget> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit"/> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="pushButton"> + <property name="text"> + <string>&Send</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources> + <include location="../../../pvsgui.qrc"/> + </resources> + <connections> + <connection> + <sender>lineEdit</sender> + <signal>returnPressed()</signal> + <receiver>pushButton</receiver> + <slot>click()</slot> + <hints> + <hint type="sourcelabel"> + <x>252</x> + <y>560</y> + </hint> + <hint type="destinationlabel"> + <x>529</x> + <y>589</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/gui/ui/clientConfigDialog.ui b/src/gui/ui/clientConfigDialog.ui new file mode 100644 index 0000000..3262b6b --- /dev/null +++ b/src/gui/ui/clientConfigDialog.ui @@ -0,0 +1,280 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ClientConfigDialogClass</class> + <widget class="QDialog" name="ClientConfigDialogClass"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>438</width> + <height>257</height> + </rect> + </property> + <property name="windowTitle"> + <string>PVS - Configuration</string> + </property> + <property name="windowIcon"> + <iconset resource="../../../pvsgui.qrc"> + <normaloff>:/cam32.svg</normaloff>:/cam32.svg</iconset> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="tabPosition"> + <enum>QTabWidget::North</enum> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tabPermissions"> + <attribute name="title"> + <string>Permissions</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Allow vnc access to lecturer?</string> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <property name="checkable"> + <bool>false</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QRadioButton" name="radioButtonLecturerRW"> + <property name="text"> + <string>Full access</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="radioButtonLecturerRO"> + <property name="text"> + <string>View only</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="radioButtonLecturerNO"> + <property name="text"> + <string>None</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="Line" name="line_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Allow vnc access to other?</string> + </property> + <property name="flat"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QRadioButton" name="radioButtonOtherRW"> + <property name="text"> + <string>Full access</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="radioButtonOtherRO"> + <property name="text"> + <string>View only</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="radioButtonOtherNO"> + <property name="text"> + <string>None</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QCheckBox" name="checkBoxAllowChat"> + <property name="text"> + <string>Accept chat messages</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="checkBoxAllowFiletransfer"> + <property name="text"> + <string>Accept file transfers</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWidget" name="tabDisplay"> + <attribute name="title"> + <string>Display</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QComboBox" name="comboBox"> + <item> + <property name="text"> + <string>Top Left</string> + </property> + </item> + <item> + <property name="text"> + <string>Top Center</string> + </property> + </item> + <item> + <property name="text"> + <string>Top Right</string> + </property> + </item> + <item> + <property name="text"> + <string>Bottom Left</string> + </property> + </item> + <item> + <property name="text"> + <string>Bottom Center</string> + </property> + </item> + <item> + <property name="text"> + <string>Bottom Right</string> + </property> + </item> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources> + <include location="../../../pvsgui.qrc"/> + </resources> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ClientConfigDialogClass</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>62</x> + <y>274</y> + </hint> + <hint type="destinationlabel"> + <x>4</x> + <y>37</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ClientConfigDialogClass</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>195</x> + <y>274</y> + </hint> + <hint type="destinationlabel"> + <x>233</x> + <y>32</y> + </hint> + </hints> + </connection> + <connection> + <sender>radioButtonOtherRW</sender> + <signal>clicked()</signal> + <receiver>radioButtonLecturerRW</receiver> + <slot>click()</slot> + <hints> + <hint type="sourcelabel"> + <x>87</x> + <y>167</y> + </hint> + <hint type="destinationlabel"> + <x>198</x> + <y>56</y> + </hint> + </hints> + </connection> + <connection> + <sender>radioButtonLecturerNO</sender> + <signal>clicked()</signal> + <receiver>radioButtonOtherNO</receiver> + <slot>click()</slot> + <hints> + <hint type="sourcelabel"> + <x>149</x> + <y>106</y> + </hint> + <hint type="destinationlabel"> + <x>84</x> + <y>219</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/gui/ui/clientFileReceiveDialog.ui b/src/gui/ui/clientFileReceiveDialog.ui new file mode 100644 index 0000000..af3a135 --- /dev/null +++ b/src/gui/ui/clientFileReceiveDialog.ui @@ -0,0 +1,134 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ClientFileReceiveDialogClass</class> + <widget class="QDialog" name="ClientFileReceiveDialogClass"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>208</width> + <height>108</height> + </rect> + </property> + <property name="windowTitle"> + <string>PVS - File Transfer</string> + </property> + <property name="windowIcon"> + <iconset resource="../../../pvsgui.qrc"> + <normaloff>:/cam32.svg</normaloff>:/cam32.svg</iconset> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="filenameLabel"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QProgressBar" name="progressBar"> + <property name="value"> + <number>0</number> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Receiving from:</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="labelNick"> + <property name="text"> + <string>unknown</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="labelA"> + <property name="text"> + <string>0</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>/</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="labelB"> + <property name="text"> + <string>0</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="cancelButton"> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources> + <include location="../../../pvsgui.qrc"/> + </resources> + <connections> + <connection> + <sender>cancelButton</sender> + <signal>clicked()</signal> + <receiver>ClientFileReceiveDialogClass</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>220</x> + <y>242</y> + </hint> + <hint type="destinationlabel"> + <x>345</x> + <y>270</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/gui/ui/clientFileSendDialog.ui b/src/gui/ui/clientFileSendDialog.ui new file mode 100644 index 0000000..d2d9c75 --- /dev/null +++ b/src/gui/ui/clientFileSendDialog.ui @@ -0,0 +1,134 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ClientFileSendDialogClass</class> + <widget class="QDialog" name="ClientFileSendDialogClass"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>186</width> + <height>108</height> + </rect> + </property> + <property name="windowTitle"> + <string>PVS - File Transfer</string> + </property> + <property name="windowIcon"> + <iconset resource="../../../pvsgui.qrc"> + <normaloff>:/cam32.svg</normaloff>:/cam32.svg</iconset> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="filenameLabel"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QProgressBar" name="progressBar"> + <property name="value"> + <number>0</number> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Sending to:</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="labelNick"> + <property name="text"> + <string>unknown</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="labelA"> + <property name="text"> + <string>0</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>/</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="labelB"> + <property name="text"> + <string>0</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="cancelButton"> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources> + <include location="../../../pvsgui.qrc"/> + </resources> + <connections> + <connection> + <sender>cancelButton</sender> + <signal>clicked()</signal> + <receiver>ClientFileSendDialogClass</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>116</x> + <y>61</y> + </hint> + <hint type="destinationlabel"> + <x>38</x> + <y>55</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/gui/ui/clientInfoDialog.ui b/src/gui/ui/clientInfoDialog.ui new file mode 100644 index 0000000..a186641 --- /dev/null +++ b/src/gui/ui/clientInfoDialog.ui @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>InfoDialogClass</class> + <widget class="QDialog" name="InfoDialogClass"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>312</width> + <height>203</height> + </rect> + </property> + <property name="windowTitle"> + <string>PVS - Information</string> + </property> + <property name="windowIcon"> + <iconset resource="../../../pvsgui.qrc"> + <normaloff>:/cam32.svg</normaloff>:/cam32.svg</iconset> + </property> + <property name="styleSheet"> + <string notr="true">QDialog { + background-color: white; +}</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="hostLabel"> + <property name="text"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:72pt; font-weight:600; color:#0000ff;">HOST</span></p></body></html></string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="passwdLabel"> + <property name="text"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:48pt; font-weight:600; color:#ff0000;">PASSWD</span></p></body></html></string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources> + <include location="../../../pvsgui.qrc"/> + </resources> + <connections/> +</ui> diff --git a/src/gui/ui/clientNicklistDialog.ui b/src/gui/ui/clientNicklistDialog.ui new file mode 100644 index 0000000..afd84f1 --- /dev/null +++ b/src/gui/ui/clientNicklistDialog.ui @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ClientNicklistDialogClass</class> + <widget class="QDialog" name="ClientNicklistDialogClass"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>264</width> + <height>396</height> + </rect> + </property> + <property name="windowTitle"> + <string>PVS - Users</string> + </property> + <property name="windowIcon"> + <iconset resource="../../../pvsgui.qrc"> + <normaloff>:/cam32.svg</normaloff>:/cam32.svg</iconset> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Select user:</string> + </property> + </widget> + </item> + <item> + <widget class="QListWidget" name="listWidget"/> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources> + <include location="../../../pvsgui.qrc"/> + </resources> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ClientNicklistDialogClass</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>258</x> + <y>390</y> + </hint> + <hint type="destinationlabel"> + <x>373</x> + <y>526</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ClientNicklistDialogClass</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>258</x> + <y>390</y> + </hint> + <hint type="destinationlabel"> + <x>428</x> + <y>525</y> + </hint> + </hints> + </connection> + <connection> + <sender>listWidget</sender> + <signal>doubleClicked(QModelIndex)</signal> + <receiver>ClientNicklistDialogClass</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>88</x> + <y>120</y> + </hint> + <hint type="destinationlabel"> + <x>27</x> + <y>375</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/gui/ui/clientToolbar.ui b/src/gui/ui/clientToolbar.ui new file mode 100644 index 0000000..5a59c5f --- /dev/null +++ b/src/gui/ui/clientToolbar.ui @@ -0,0 +1,214 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ClientToolbarClass</class> + <widget class="QWidget" name="ClientToolbarClass"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>577</width> + <height>28</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <property name="styleSheet"> + <string notr="true">QFrame { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f6f7fa, stop: 1 #dadbde); + border-radius: 0px; +} +QLabel { + background-color: none; +} +/* QPushButton */ +QPushButton { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f6f7fa, stop: 1 #dadbde); + border: 2px solid #8f8f91; + border-radius: 4px; + min-width: 80px; +} +QPushButton:hover { + border: 2px solid rgb(0, 170, 255); +} +QPushButton:pressed { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #dadbde, stop: 1 #f6f7fa); +} +QPushButton::menu-indicator { + image: url(:/darrow16.svg); +} +/* QCheckBox */ +QCheckBox { +} +QCheckBox::indicator { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f6f7fa, stop: 1 #dadbde); + border: 2px solid #8f8f91; + border-radius: 4px; + width: 16px; + height: 16px; +} +QCheckBox::indicator:unchecked { +} +QCheckBox::indicator:unchecked:hover { + border: 2px solid rgb(0, 170, 255); +} +QCheckBox::indicator:unchecked:pressed { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #dadbde, stop: 1 #f6f7fa); +} +QCheckBox::indicator:checked { + image: url(:/ok16.svg); +} +QCheckBox::indicator:checked:hover { + border: 2px solid rgb(0, 170, 255); +} +QCheckBox::indicator:checked:pressed { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #dadbde, stop: 1 #f6f7fa); +} +</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="pvsButton"> + <property name="toolTip"> + <string>Menu</string> + </property> + <property name="text"> + <string notr="true">Menu</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Host:</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="hostButton"> + <property name="toolTip"> + <string>Click to connect</string> + </property> + <property name="text"> + <string>-</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="statusLabel"> + <property name="text"> + <string notr="true"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#ff0000;">Offline</span></p></body></html></string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="vncCheckBox"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>Enable/Disable VNC only for this session</string> + </property> + <property name="text"> + <string>Allow VNC</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600; font-style:italic; color:#0055ff;">Pool Video Switch</span></p></body></html></string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_3"> + <property name="maximumSize"> + <size> + <width>16</width> + <height>16</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="../../../pvsgui.qrc">:/cam32.svg</pixmap> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources> + <include location="../../../pvsgui.qrc"/> + </resources> + <connections/> +</ui> diff --git a/src/gui/ui/dialog.ui b/src/gui/ui/dialog.ui new file mode 100644 index 0000000..ec16160 --- /dev/null +++ b/src/gui/ui/dialog.ui @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MsgDialog</class> + <widget class="QDialog" name="MsgDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>193</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <widget class="QWidget" name="layoutWidget"> + <property name="geometry"> + <rect> + <x>20</x> + <y>20</y> + <width>351</width> + <height>171</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTextEdit" name="message"/> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>108</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="cancel"> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="send"> + <property name="text"> + <string>Send</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources/> + <connections/> +</ui> diff --git a/src/gui/ui/mainwindow.ui b/src/gui/ui/mainwindow.ui new file mode 100644 index 0000000..eb49d1b --- /dev/null +++ b/src/gui/ui/mainwindow.ui @@ -0,0 +1,540 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>838</width> + <height>607</height> + </rect> + </property> + <property name="windowTitle"> + <string>PVSmgr</string> + </property> + <widget class="QWidget" name="centralWidget"> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QScrollArea" name="scrollArea"> + <property name="styleSheet"> + <string>border-color: rgb(0, 0, 0);</string> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>776</width> + <height>534</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>VNC quality</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="vncQuality"> + <item> + <property name="text"> + <string>HIGH</string> + </property> + </item> + <item> + <property name="text"> + <string>MEDIUM</string> + </property> + </item> + <item> + <property name="text"> + <string>LOW</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="Line" name="separator"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="setPassword"> + <property name="text"> + <string>Set password</string> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="thumbStatus"> + <item> + <property name="text"> + <string>Thumbnailratio</string> + </property> + </item> + <item> + <property name="text"> + <string>Thumbnailrate</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QSlider" name="horizontalSlider"> + <property name="minimum"> + <number>25</number> + </property> + <property name="maximum"> + <number>200</number> + </property> + <property name="singleStep"> + <number>25</number> + </property> + <property name="pageStep"> + <number>25</number> + </property> + <property name="value"> + <number>25</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBothSides</enum> + </property> + <property name="tickInterval"> + <number>0</number> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string> 0</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>%</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QSplitter" name="splitter_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QWidget" name="ClWidget" native="true"> + <property name="minimumSize"> + <size> + <width>150</width> + <height>240</height> + </size> + </property> + <property name="styleSheet"> + <string>background-color: rgb(255, 255, 255);</string> + </property> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="0" column="0"> + <layout class="QGridLayout" name="ClientGLayout"/> + </item> + </layout> + </widget> + <widget class="QWidget" name="widget" native="true"> + <property name="styleSheet"> + <string>background-color: rgb(150, 150, 150);</string> + </property> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="VconWinLayout"/> + </item> + </layout> + </widget> + </widget> + <widget class="QTextEdit" name="pvsLog"/> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menuBar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>838</width> + <height>28</height> + </rect> + </property> + <widget class="QMenu" name="menu_File"> + <property name="title"> + <string>&File</string> + </property> + <widget class="QMenu" name="menuLoad_profile"> + <property name="title"> + <string>Load profile </string> + </property> + </widget> + <addaction name="action_Disconnect"/> + <addaction name="separator"/> + <addaction name="actionCreate_profile"/> + <addaction name="separator"/> + <addaction name="menuLoad_profile"/> + <addaction name="separator"/> + <addaction name="action_Exit"/> + </widget> + <widget class="QMenu" name="menuClients"> + <property name="title"> + <string>&Clients</string> + </property> + <addaction name="actionShow_Fullname"/> + <addaction name="actionShow_Hostname_IP"/> + <addaction name="actionShow_Username"/> + <addaction name="separator"/> + <addaction name="actionVNC_Placeholders"/> + </widget> + <widget class="QMenu" name="menuLogging"> + <property name="title"> + <string>&Logging</string> + </property> + <addaction name="actionShow_Log"/> + <addaction name="separator"/> + <addaction name="actionShow_Normal"/> + <addaction name="actionShow_Error"/> + <addaction name="actionShow_Network"/> + <addaction name="actionShow_Terminal"/> + <addaction name="actionShow_Chat"/> + </widget> + <widget class="QMenu" name="menu_Help"> + <property name="title"> + <string>&Help</string> + </property> + <addaction name="actionAbout_pvs"/> + </widget> + <addaction name="menu_File"/> + <addaction name="menuClients"/> + <addaction name="menuLogging"/> + <addaction name="menu_Help"/> + </widget> + <widget class="QStatusBar" name="statusBar"/> + <widget class="QToolBar" name="toolBar"> + <property name="maximumSize"> + <size> + <width>129000</width> + <height>12900</height> + </size> + </property> + <property name="windowTitle"> + <string>toolBar</string> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="autoFillBackground"> + <bool>true</bool> + </property> + <property name="movable"> + <bool>true</bool> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonIconOnly</enum> + </property> + <property name="floatable"> + <bool>false</bool> + </property> + <attribute name="toolBarArea"> + <enum>LeftToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + <addaction name="action_Exit"/> + <addaction name="action_Disconnect"/> + <addaction name="actionFoto"/> + <addaction name="actionView"/> + <addaction name="actionLock"/> + <addaction name="actionChat"/> + </widget> + <action name="actionShow_Username"> + <property name="checkable"> + <bool>false</bool> + </property> + <property name="text"> + <string>Show Username</string> + </property> + <property name="shortcut"> + <string>Ctrl+3</string> + </property> + </action> + <action name="actionShow_Hostname_IP"> + <property name="checkable"> + <bool>false</bool> + </property> + <property name="text"> + <string>Show IP</string> + </property> + <property name="shortcut"> + <string>Ctrl+2</string> + </property> + </action> + <action name="actionVNC_Placeholders"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>VNC-Placeholders</string> + </property> + </action> + <action name="actionShow_Log"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>false</bool> + </property> + <property name="text"> + <string>Show Log</string> + </property> + <property name="shortcut"> + <string>Ctrl+L</string> + </property> + </action> + <action name="actionShow_Normal"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Show Normal</string> + </property> + <property name="shortcut"> + <string>Ctrl+O</string> + </property> + </action> + <action name="actionShow_Error"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Show Error</string> + </property> + <property name="shortcut"> + <string>Ctrl+E</string> + </property> + </action> + <action name="actionShow_Network"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Show Network</string> + </property> + <property name="shortcut"> + <string>Ctrl+N</string> + </property> + </action> + <action name="actionShow_Terminal"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Show Terminal</string> + </property> + <property name="shortcut"> + <string>Ctrl+T</string> + </property> + </action> + <action name="actionShow_Chat"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Show Chat</string> + </property> + <property name="shortcut"> + <string>Ctrl+G</string> + </property> + </action> + <action name="actionAbout_pvs"> + <property name="text"> + <string>About pvs</string> + </property> + <property name="shortcut"> + <string>Ctrl+P</string> + </property> + </action> + <action name="action100_x_100"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>100 x 100</string> + </property> + </action> + <action name="action200_x_200"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>200 x 200</string> + </property> + </action> + <action name="action500_x_500"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>500 x 500</string> + </property> + </action> + <action name="action_Disconnect"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/logout</normaloff>:/logout</iconset> + </property> + <property name="text"> + <string>&Disconnect</string> + </property> + <property name="shortcut"> + <string>Ctrl+W</string> + </property> + </action> + <action name="action_Exit"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/exit</normaloff> + <normalon>:/exit</normalon>:/exit</iconset> + </property> + <property name="text"> + <string>&Exit</string> + </property> + <property name="toolTip"> + <string>Exit</string> + </property> + <property name="shortcut"> + <string>Ctrl+Q</string> + </property> + </action> + <action name="actionFoto"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/photos</normaloff>:/photos</iconset> + </property> + <property name="text"> + <string>Foto</string> + </property> + <property name="toolTip"> + <string>Foto</string> + </property> + <property name="shortcut"> + <string>Ctrl+F</string> + </property> + </action> + <action name="actionView"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/restore</normaloff>:/restore</iconset> + </property> + <property name="text"> + <string>view</string> + </property> + <property name="toolTip"> + <string>View</string> + </property> + <property name="shortcut"> + <string>Ctrl+V</string> + </property> + </action> + <action name="actionLock"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/lock</normaloff>:/lock</iconset> + </property> + <property name="text"> + <string>lock</string> + </property> + <property name="toolTip"> + <string>Lock or Unlock all Clients</string> + </property> + <property name="shortcut"> + <string>Ctrl+A</string> + </property> + </action> + <action name="actionCreate_profile"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/profile</normaloff>:/profile</iconset> + </property> + <property name="text"> + <string>Profile &manager</string> + </property> + <property name="shortcut"> + <string>Ctrl+M</string> + </property> + </action> + <action name="actionShow_Fullname"> + <property name="text"> + <string>Show Name</string> + </property> + <property name="shortcut"> + <string>Ctrl+1</string> + </property> + </action> + <action name="actionChat"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/chat</normaloff>:/chat</iconset> + </property> + <property name="text"> + <string>Chat</string> + </property> + <property name="toolTip"> + <string>Start Chat with client(s)</string> + </property> + <property name="shortcut"> + <string>Ctrl+D</string> + </property> + </action> + <action name="dummy"> + <property name="text"> + <string>-</string> + </property> + </action> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources> + <include location="../../../pvsmgr.qrc"/> + </resources> + <connections/> +</ui> diff --git a/src/gui/ui/mainwindowtouch.ui b/src/gui/ui/mainwindowtouch.ui new file mode 100644 index 0000000..9030b17 --- /dev/null +++ b/src/gui/ui/mainwindowtouch.ui @@ -0,0 +1,645 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1349</width> + <height>768</height> + </rect> + </property> + <property name="windowTitle"> + <string>PVSmgr</string> + </property> + <widget class="QWidget" name="centralWidget"> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QScrollArea" name="scrollArea"> + <property name="styleSheet"> + <string>border-color: rgb(0, 0, 0);</string> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1327</width> + <height>658</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QComboBox" name="comboBox_touch1"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <item> + <property name="text"> + <string>All</string> + </property> + </item> + <item> + <property name="text"> + <string>Lock</string> + </property> + </item> + <item> + <property name="text"> + <string>Unlock</string> + </property> + </item> + <item> + <property name="text"> + <string>Unproject</string> + </property> + </item> + <item> + <property name="text"> + <string>Backgroundimage</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="Line" name="line_5"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>VNC-Quality</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="vncQuality"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <item> + <property name="text"> + <string>HIGH</string> + </property> + </item> + <item> + <property name="text"> + <string>MEDIUM</string> + </property> + </item> + <item> + <property name="text"> + <string>LOW</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="Line" name="line_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton_2"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <property name="text"> + <string>ClientList</string> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <property name="text"> + <string>Profile</string> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line_4"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QProgressBar" name="progressBar"> + <property name="styleSheet"> + <string>border-color: rgb(0, 0, 0);</string> + </property> + <property name="value"> + <number>0</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="Line" name="separator"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="setPassword"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <property name="text"> + <string>setPassword</string> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="thumbStatus"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <item> + <property name="text"> + <string>Thumbnailratio</string> + </property> + </item> + <item> + <property name="text"> + <string>Thumbnailrate</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QSlider" name="horizontalSlider"> + <property name="minimum"> + <number>25</number> + </property> + <property name="maximum"> + <number>200</number> + </property> + <property name="singleStep"> + <number>25</number> + </property> + <property name="pageStep"> + <number>25</number> + </property> + <property name="value"> + <number>25</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBothSides</enum> + </property> + <property name="tickInterval"> + <number>0</number> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string> 0</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>%</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="1" column="0"> + <widget class="QSplitter" name="splitter_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QWidget" name="ClWidget" native="true"> + <property name="minimumSize"> + <size> + <width>150</width> + <height>240</height> + </size> + </property> + <property name="styleSheet"> + <string>background-color: rgb(255, 255, 255);</string> + </property> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="0" column="0"> + <layout class="QGridLayout" name="ClientGLayout"/> + </item> + </layout> + </widget> + <widget class="QWidget" name="widget" native="true"> + <property name="styleSheet"> + <string>background-color: rgb(150, 150, 150);</string> + </property> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="VconWinLayout"/> + </item> + </layout> + </widget> + </widget> + <widget class="QTextEdit" name="pvsLog"/> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QStatusBar" name="statusBar"/> + <widget class="QToolBar" name="toolBar"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="maximumSize"> + <size> + <width>129000</width> + <height>12900</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>15</pointsize> + <kerning>true</kerning> + </font> + </property> + <property name="windowTitle"> + <string>toolBar</string> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="autoFillBackground"> + <bool>true</bool> + </property> + <property name="movable"> + <bool>false</bool> + </property> + <property name="iconSize"> + <size> + <width>50</width> + <height>50</height> + </size> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonIconOnly</enum> + </property> + <property name="floatable"> + <bool>false</bool> + </property> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + <addaction name="action_Exit"/> + <addaction name="separator"/> + <addaction name="actionFoto"/> + <addaction name="separator"/> + <addaction name="actionView"/> + <addaction name="separator"/> + <addaction name="actionProjection"/> + <addaction name="separator"/> + <addaction name="actionUnprojection"/> + <addaction name="separator"/> + <addaction name="actionLocksingle"/> + <addaction name="separator"/> + <addaction name="actionUnlocksingle"/> + <addaction name="separator"/> + <addaction name="actionLock"/> + <addaction name="separator"/> + <addaction name="actionresetall"/> + <addaction name="separator"/> + <addaction name="actionDozent"/> + </widget> + <action name="actionShow_Username"> + <property name="checkable"> + <bool>false</bool> + </property> + <property name="text"> + <string>Show Username</string> + </property> + </action> + <action name="actionShow_Hostname_IP"> + <property name="checkable"> + <bool>false</bool> + </property> + <property name="text"> + <string>Show Hostname/IP</string> + </property> + </action> + <action name="actionVNC_Placeholders"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>VNC-Placeholders</string> + </property> + </action> + <action name="actionShow_Log"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>false</bool> + </property> + <property name="text"> + <string>Show Log</string> + </property> + </action> + <action name="actionShow_Normal"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Show Normal</string> + </property> + </action> + <action name="actionShow_Error"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Show Error</string> + </property> + </action> + <action name="actionShow_Network"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Show Network</string> + </property> + </action> + <action name="actionShow_Terminal"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Show Terminal</string> + </property> + </action> + <action name="actionShow_Chat"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Show Chat</string> + </property> + </action> + <action name="actionAbout_pvs"> + <property name="text"> + <string>About pvs</string> + </property> + </action> + <action name="action100_x_100"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>100 x 100</string> + </property> + </action> + <action name="action200_x_200"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>200 x 200</string> + </property> + </action> + <action name="action500_x_500"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>500 x 500</string> + </property> + </action> + <action name="action_Disconnect"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/logout</normaloff>:/logout</iconset> + </property> + <property name="text"> + <string>&Disconnect</string> + </property> + <property name="shortcut"> + <string>Ctrl+W</string> + </property> + </action> + <action name="action_Exit"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/exit</normaloff> + <normalon>:/exit</normalon>:/exit</iconset> + </property> + <property name="text"> + <string>&Exit</string> + </property> + <property name="shortcut"> + <string>Ctrl+Q</string> + </property> + </action> + <action name="actionFoto"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/photos</normaloff>:/photos</iconset> + </property> + <property name="text"> + <string>Foto</string> + </property> + <property name="toolTip"> + <string>Foto</string> + </property> + </action> + <action name="actionView"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/restore</normaloff>:/restore</iconset> + </property> + <property name="text"> + <string>view</string> + </property> + <property name="toolTip"> + <string>View</string> + </property> + </action> + <action name="actionLock"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/lock</normaloff>:/lock</iconset> + </property> + <property name="text"> + <string>lock</string> + </property> + <property name="toolTip"> + <string>Lock All Clients</string> + </property> + </action> + <action name="actionCreate_profile"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/profile</normaloff>:/profile</iconset> + </property> + <property name="text"> + <string>Create profile</string> + </property> + </action> + <action name="actionresetall"> + <property name="icon"> + <iconset> + <activeon>:/icons/reset.png</activeon> + </iconset> + </property> + <property name="text"> + <string>resetall</string> + </property> + <property name="toolTip"> + <string>Reset Projections and Locks</string> + </property> + <property name="shortcut"> + <string>Ctrl+R</string> + </property> + </action> + <action name="actionLocksingle"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/icons/locksingle.png</normaloff>:/icons/locksingle.png</iconset> + </property> + <property name="text"> + <string>locksingle</string> + </property> + <property name="toolTip"> + <string>Locks a Single Target</string> + </property> + </action> + <action name="actionUnlocksingle"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/icons/unlocksingle.png</normaloff>:/icons/unlocksingle.png</iconset> + </property> + <property name="text"> + <string>unlocksingle</string> + </property> + <property name="toolTip"> + <string>Unlocks a single target</string> + </property> + </action> + <action name="actionProjection"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/icons/projection.png</normaloff>:/icons/projection.png</iconset> + </property> + <property name="text"> + <string>projection</string> + </property> + <property name="toolTip"> + <string>Projects a single target</string> + </property> + </action> + <action name="actionUnprojection"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/icons/unprojection.png</normaloff>:/icons/unprojection.png</iconset> + </property> + <property name="text"> + <string>unprojection</string> + </property> + <property name="toolTip"> + <string>Unprojects a single target</string> + </property> + </action> + <action name="actionDozent"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/dozent2</normaloff>:/dozent2</iconset> + </property> + <property name="text"> + <string>dozent</string> + </property> + <property name="toolTip"> + <string>Select Tutor PC</string> + </property> + </action> + <action name="actionShow_Fullname"> + <property name="text"> + <string>Show Name</string> + </property> + </action> + <action name="actionChat"> + <property name="icon"> + <iconset resource="../../../pvsmgr.qrc"> + <normaloff>:/chat</normaloff>:/chat</iconset> + </property> + <property name="text"> + <string>Chat</string> + </property> + <property name="toolTip"> + <string>Start chat with client(s)</string> + </property> + <property name="shortcut"> + <string>Ctrl+D</string> + </property> + </action> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources> + <include location="../../../pvsmgr.qrc"/> + </resources> + <connections/> +</ui> diff --git a/src/gui/ui/profileDialog.ui b/src/gui/ui/profileDialog.ui new file mode 100644 index 0000000..3302a56 --- /dev/null +++ b/src/gui/ui/profileDialog.ui @@ -0,0 +1,179 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Dialog</class> + <widget class="QDialog" name="Dialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>332</width> + <height>485</height> + </rect> + </property> + <property name="windowTitle"> + <string>ProfileDialog</string> + </property> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QWidget" name="widget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="styleSheet"> + <string>background-color: rgb(255, 255, 255);</string> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <layout class="QGridLayout" name="gridLayout"/> + </item> + </layout> + </widget> + <widget class="QWidget" name="layoutWidget_2"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QPushButton" name="remove"> + <property name="text"> + <string>&Remove</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_6"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>18</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="edit"> + <property name="text"> + <string>&Edit</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_5"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>18</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="new_2"> + <property name="text"> + <string>&New</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_4"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="load"> + <property name="text"> + <string>&Load</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>218</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLineEdit" name="lineEdit"/> + </item> + <item> + <widget class="QPushButton" name="add"> + <property name="text"> + <string>Add</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QPushButton" name="close"> + <property name="text"> + <string>Close</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/gui/ui/projectionDialog.ui b/src/gui/ui/projectionDialog.ui new file mode 100644 index 0000000..17cdf05 --- /dev/null +++ b/src/gui/ui/projectionDialog.ui @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>projectionDialog</class> + <widget class="QDialog" name="projectionDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>234</width> + <height>282</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="1" column="0"> + <widget class="QFrame" name="frame"> + <property name="styleSheet"> + <string notr="true">QFrame{ +border-color: rgb(0, 0, 0); +border: 1px outset black; +}</string> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_2"/> + </item> + </layout> + </widget> + </item> + <item row="2" column="0"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QCheckBox" name="checkBox"> + <property name="text"> + <string>Select all</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>108</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="cancel"> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="send"> + <property name="text"> + <string>Project</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>15</height> + </size> + </property> + <property name="text"> + <string>Select Target for projection</string> + </property> + </widget> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources/> + <connections/> +</ui> diff --git a/src/gui/ui/serverChatDialog.ui b/src/gui/ui/serverChatDialog.ui new file mode 100644 index 0000000..973d803 --- /dev/null +++ b/src/gui/ui/serverChatDialog.ui @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ServerChatDialogClass</class> + <widget class="QDialog" name="ServerChatDialogClass"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>641</width> + <height>659</height> + </rect> + </property> + <property name="windowTitle"> + <string>PVSmgr - Chat </string> + </property> + <property name="windowIcon"> + <iconset resource="../../../pvsgui.qrc"> + <normaloff>:/cam32.svg</normaloff>:/cam32.svg</iconset> + </property> + <property name="locale"> + <locale language="English" country="UnitedStates"/> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QSplitter" name="splitter"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QListWidget" name="listWidget"> + <property name="maximumSize"> + <size> + <width>150</width> + <height>16777215</height> + </size> + </property> + <property name="contextMenuPolicy"> + <enum>Qt::CustomContextMenu</enum> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + </widget> + <widget class="QTabWidget" name="tabWidget"> + <property name="tabPosition"> + <enum>QTabWidget::South</enum> + </property> + <property name="tabsClosable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string notr="true">@all</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout"/> + </widget> + </widget> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit"/> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="pushButton"> + <property name="text"> + <string>&Send</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources> + <include location="../../../pvsgui.qrc"/> + </resources> + <connections> + <connection> + <sender>lineEdit</sender> + <signal>returnPressed()</signal> + <receiver>pushButton</receiver> + <slot>click()</slot> + <hints> + <hint type="sourcelabel"> + <x>252</x> + <y>560</y> + </hint> + <hint type="destinationlabel"> + <x>529</x> + <y>589</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/gui/ui/startdialog.ui b/src/gui/ui/startdialog.ui new file mode 100644 index 0000000..8001862 --- /dev/null +++ b/src/gui/ui/startdialog.ui @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Test</class> + <widget class="QDialog" name="Test"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>367</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="geometry"> + <rect> + <x>20</x> + <y>250</y> + <width>341</width> + <height>32</height> + </rect> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + <widget class="QWidget" name="gridLayoutWidget"> + <property name="geometry"> + <rect> + <x>60</x> + <y>10</y> + <width>301</width> + <height>231</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="0"> + <widget class="QCheckBox" name="checkBox"> + <property name="toolTip"> + <string>Zur Bedienung mit Tastatur und Maus</string> + </property> + <property name="text"> + <string>Standard-Oberfläche</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QCheckBox" name="checkBox_2"> + <property name="toolTip"> + <string>Zur Bedienung an einem Touchscreen</string> + </property> + <property name="text"> + <string>Touchscreen-Oberfläche</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="Line" name="line_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="Line" name="line_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="KIconButton" name="kiconbutton"> + <property name="geometry"> + <rect> + <x>0</x> + <y>150</y> + <width>51</width> + <height>41</height> + </rect> + </property> + <property name="styleSheet"> + <string notr="true">background-image: url(:icons/touch.jpg);</string> + </property> + </widget> + <widget class="KIconButton" name="kiconbutton_2"> + <property name="geometry"> + <rect> + <x>0</x> + <y>60</y> + <width>51</width> + <height>41</height> + </rect> + </property> + <property name="styleSheet"> + <string notr="true">background-image: url(:icons/keyboard.jpg);</string> + </property> + </widget> + </widget> + <customwidgets> + <customwidget> + <class>KIconButton</class> + <extends>QPushButton</extends> + <header>kicondialog.h</header> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>buttonBox</tabstop> + <tabstop>kiconbutton_2</tabstop> + <tabstop>checkBox_2</tabstop> + <tabstop>checkBox</tabstop> + <tabstop>kiconbutton</tabstop> + </tabstops> + <resources> + <include location="startdialog.qrc"/> + </resources> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>Test</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>Test</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>checkBox</sender> + <signal>toggled(bool)</signal> + <receiver>checkBox_2</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>180</x> + <y>81</y> + </hint> + <hint type="destinationlabel"> + <x>180</x> + <y>169</y> + </hint> + </hints> + </connection> + <connection> + <sender>checkBox_2</sender> + <signal>toggled(bool)</signal> + <receiver>checkBox</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>180</x> + <y>169</y> + </hint> + <hint type="destinationlabel"> + <x>180</x> + <y>81</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/gui/ui/touchgui.ui b/src/gui/ui/touchgui.ui new file mode 100644 index 0000000..05d7614 --- /dev/null +++ b/src/gui/ui/touchgui.ui @@ -0,0 +1,322 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PVSMainWindow</class> + <widget class="QMainWindow" name="PVSMainWindow"> + <property name="windowModality"> + <enum>Qt::NonModal</enum> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>600</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>800</width> + <height>600</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>800</width> + <height>600</height> + </size> + </property> + <property name="cursor"> + <cursorShape>PointingHandCursor</cursorShape> + </property> + <property name="windowTitle"> + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralWidget"> + <widget class="QWidget" name="horizontalLayoutWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>801</width> + <height>41</height> + </rect> + </property> + <layout class="QHBoxLayout" name="ButtonList"> + <item> + <widget class="QComboBox" name="AllUsersBox"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <item> + <property name="text"> + <string>Alle</string> + </property> + </item> + <item> + <property name="text"> + <string>Sperren/entsperren</string> + </property> + </item> + <item> + <property name="text"> + <string>Beamerbild verteilen</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QComboBox" name="MarkedUsersBox"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <item> + <property name="text"> + <string>Auswahl</string> + </property> + </item> + <item> + <property name="text"> + <string>Aktualisieren</string> + </property> + </item> + <item> + <property name="text"> + <string>Sperren/Entsperren</string> + </property> + </item> + <item> + <property name="text"> + <string>Einzelansicht</string> + </property> + </item> + <item> + <property name="text"> + <string>Einzelhilfe</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QPushButton" name="PropertyButton"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <property name="text"> + <string>Einstellungen</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="ExitButton"> + <property name="font"> + <font> + <pointsize>15</pointsize> + </font> + </property> + <property name="text"> + <string>Beenden</string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="horizontalLayoutWidget_2"> + <property name="geometry"> + <rect> + <x>0</x> + <y>530</y> + <width>801</width> + <height>31</height> + </rect> + </property> + <layout class="QHBoxLayout" name="Slider"> + <item> + <widget class="QPushButton" name="NavigateLeft"> + <property name="text"> + <string><-</string> + </property> + </widget> + </item> + <item> + <widget class="QSlider" name="horizontalSlider"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="NavigateRight"> + <property name="text"> + <string>-></string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="ClWidget" native="true"> + <property name="geometry"> + <rect> + <x>0</x> + <y>40</y> + <width>151</width> + <height>481</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>150</width> + <height>240</height> + </size> + </property> + <property name="styleSheet"> + <string>background-color: rgb(255, 255, 255);</string> + </property> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="0" column="0"> + <layout class="QGridLayout" name="ClientGLayout"/> + </item> + </layout> + </widget> + <widget class="QWidget" name="widget" native="true"> + <property name="geometry"> + <rect> + <x>160</x> + <y>40</y> + <width>631</width> + <height>481</height> + </rect> + </property> + <property name="styleSheet"> + <string>background-color: rgb(150, 150, 150);</string> + </property> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="VconWinLayout"/> + </item> + </layout> + </widget> + </widget> + <widget class="QMenuBar" name="menuBar"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>24</height> + </rect> + </property> + <widget class="QMenu" name="menuTestApp"> + <property name="title"> + <string>Datei</string> + </property> + <addaction name="actionDisconnect"/> + <addaction name="actionBeenden"/> + </widget> + <widget class="QMenu" name="menuAnsicht"> + <property name="title"> + <string>Ansicht</string> + </property> + <addaction name="actionVollbild"/> + </widget> + <widget class="QMenu" name="menuHilfe"> + <property name="title"> + <string>Hilfe</string> + </property> + <addaction name="actionGibts_noch_keine"/> + </widget> + <widget class="QMenu" name="menuLogging"> + <property name="title"> + <string>Logging</string> + </property> + </widget> + <addaction name="menuTestApp"/> + <addaction name="menuAnsicht"/> + <addaction name="menuHilfe"/> + <addaction name="menuLogging"/> + </widget> + <action name="actionBeenden"> + <property name="text"> + <string>Beenden</string> + </property> + <property name="shortcut"> + <string>Alt+B</string> + </property> + </action> + <action name="actionGibts_noch_keine"> + <property name="text"> + <string>Version</string> + </property> + </action> + <action name="actionVollbild"> + <property name="text"> + <string>Vollbild</string> + </property> + </action> + <action name="actionDisconnect"> + <property name="text"> + <string>Disconnect</string> + </property> + </action> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources/> + <connections> + <connection> + <sender>actionBeenden</sender> + <signal>activated()</signal> + <receiver>PVSMainWindow</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>399</x> + <y>299</y> + </hint> + </hints> + </connection> + <connection> + <sender>ExitButton</sender> + <signal>clicked()</signal> + <receiver>PVSMainWindow</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>109</x> + <y>129</y> + </hint> + <hint type="destinationlabel"> + <x>299</x> + <y>199</y> + </hint> + </hints> + </connection> + <connection> + <sender>actionVollbild</sender> + <signal>activated()</signal> + <receiver>PVSMainWindow</receiver> + <slot>showMaximized()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>399</x> + <y>299</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/net/SslServer.cpp b/src/net/SslServer.cpp new file mode 100644 index 0000000..e353e0a --- /dev/null +++ b/src/net/SslServer.cpp @@ -0,0 +1,130 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/net/SslServer.cpp +# - provide QTcpServer-like behaviour for SSL +# ----------------------------------------------------------------------------- +*/ + +#include "SslServer.h" +#include <QtNetwork/QSslCipher> +#include <QtNetwork/QSslSocket> +#include "src/util/CertManager.h" + + +SslServer::SslServer() +{ + _tmr = startTimer(7000); + //QSslSocket::setDefaultCiphers(QSslSocket::supportedCiphers()); +} + +SslServer::~SslServer() +{ + killTimer((_tmr)); +} + +void SslServer::incomingConnection(int socketDescriptor) +{ + QSslSocket *serverSocket = new QSslSocket(this); + connect(serverSocket, + SIGNAL(sslErrors(const QList<QSslError> &)), + this, + SLOT(sslErrors(const QList<QSslError> &)) + ); + serverSocket->setPrivateKey(CertManager::getPrivateKey("manager")); + serverSocket->setLocalCertificate(CertManager::getCertificate("manager")); + serverSocket->setPeerVerifyMode(QSslSocket::VerifyNone); + serverSocket->setProtocol(QSsl::SslV3); + //printf("Keylen %d\n", serverSocket->privateKey().length()); + if (serverSocket->setSocketDescriptor(socketDescriptor)) + { + // Once the connection is successfully encrypted, raise out newConnection event + connect(serverSocket, SIGNAL(encrypted()), this, SIGNAL(newConnection())); + serverSocket->startServerEncryption(); + _pending.push_back(serverSocket); + } + else + { + delete serverSocket; + } +} + +void SslServer :: sslErrors ( const QList<QSslError> & errors ) +{ + printf("FIXME: SSL ERRORS on SERVER: %s\n", errors.begin()->errorString().toUtf8().data()); +} + +void SslServer::timerEvent (QTimerEvent* event) +{ + // Remove all sockets marked for deletion + for (QList<QSslSocket*>::iterator it = _delete.begin(); it != _delete.end(); it++) + { + (*it)->deleteLater(); + } + _delete.clear(); + // Mark all sockets for deletion where the ssl handshake did not happen after connecting + /* + bool flag; + do + { + flag = false; + for (QList<QSslSocket*>::iterator it = _pending.begin(); it != _pending.end(); it++) + { + if ((*it)->state() != QAbstractSocket::ConnectedState || !(*it)->isEncrypted()) + { + _delete.push_back(*it); + _pending.removeAll(*it); + flag = true; + break; + } + + } + } + while (flag); + */ + _delete.append(_pending); + _pending.clear(); +} + +bool SslServer::hasPendingConnections() +{ + for (QList<QSslSocket*>::iterator it = _pending.begin(); it != _pending.end(); it++) + { + printf("State: %d - Encrypted: %d\n", (int)(*it)->state(), (*it)->isEncrypted()); + if ((*it)->state() == QAbstractSocket::ConnectedState && (*it)->isEncrypted()) return true; + } + return false; +} + +QTcpSocket* SslServer::nextPendingConnection() +{ + for (QList<QSslSocket*>::iterator it = _pending.begin(); it != _pending.end(); it++) + { + if ((*it)->state() == QAbstractSocket::ConnectedState && (*it)->isEncrypted()) + { + _pending.removeAll(*it); + _delete.removeAll(*it); + return *it; + } + } + for (QList<QSslSocket*>::iterator it = _delete.begin(); it != _delete.end(); it++) + { + if ((*it)->state() == QAbstractSocket::ConnectedState && (*it)->isEncrypted()) + { + _pending.removeAll(*it); + _delete.removeAll(*it); + return *it; + } + } + return NULL; +} + + diff --git a/src/net/SslServer.h b/src/net/SslServer.h new file mode 100644 index 0000000..b1efeea --- /dev/null +++ b/src/net/SslServer.h @@ -0,0 +1,50 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/net/SslServer.cpp +# - provide QTcpServer-like behaviour for SSL +# ----------------------------------------------------------------------------- +*/ + +#ifndef SSLSERVER_H_ +#define SSLSERVER_H_ + +#include <QtCore/QList> +#include <QtNetwork/QTcpServer> +#include <QtNetwork/QSslError> + +class QSslSocket; + +class SslServer : public QTcpServer +{ + Q_OBJECT + +private Q_SLOTS: + void sslErrors ( const QList<QSslError> & errors ); + +public: + SslServer(); + virtual ~SslServer(); + + virtual bool hasPendingConnections (); + // This one has to return a TcpSocket as we're overwriting from the base class + // just cast it to QSslSocket later + virtual QTcpSocket* nextPendingConnection(); + +protected: + virtual void incomingConnection(int socketDescriptor); + void timerEvent (QTimerEvent* event); + QList<QSslSocket*> _pending; + QList<QSslSocket*> _delete; + int _tmr; +}; + +#endif /* SSLSERVER_H_ */ diff --git a/src/net/pvsClientConnection.cpp b/src/net/pvsClientConnection.cpp new file mode 100644 index 0000000..dff40d5 --- /dev/null +++ b/src/net/pvsClientConnection.cpp @@ -0,0 +1,178 @@ +/* +# Copyright (c) 2009,2010 - 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/ +# ----------------------------------------------------------------------------- +# pvsClientConnection.cpp +# - ???. +# ----------------------------------------------------------------------------- +*/ + +#include "pvsClientConnection.h" +#include "pvsListenServer.h" +#include "src/util/consoleLogger.h" + +#include <cassert> +#include <QtNetwork/QHostAddress> + + +PVSClientConnection::PVSClientConnection(PVSListenServer* server, QSslSocket* sock) +{ + assert(sock); + assert(server); + _socket = sock; + _incomplete = NULL; + _toldDisconnect = false; + _server = server; + _lastData = time(NULL); + sock->setParent(this); // for automatic deletion + connect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival())); + connect(_socket, SIGNAL(disconnected()), this, SLOT(sock_closed())); + connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sock_error(QAbstractSocket::SocketError))); +} + +PVSClientConnection::~PVSClientConnection() +{ + this->closeConnection(); + if (_incomplete != NULL) delete _incomplete; + if (_socket != NULL) + { + disconnect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival())); + disconnect(_socket, SIGNAL(disconnected()), this, SLOT(sock_closed())); + disconnect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sock_error(QAbstractSocket::SocketError))); + _socket->abort(); + } +} + +void PVSClientConnection::closeConnection() +{ + if (_toldDisconnect) return; // we already got served + if (_socket == NULL || _socket->state() == QAbstractSocket::UnconnectedState) + { + // should not happen but handled anyway + _toldDisconnect = true; + _server->disconnectClient(this); + return; + } + if (_socket->state() == QAbstractSocket::ClosingState) return; // sock_close() slot should eventually be called, nothing to do + if (_socket->state() == QAbstractSocket::ConnectedState) // this is what should be the case normally + { + _socket->disconnectFromHost(); // graceful shutdown of socket, sock_close() will be called once complete + return; + } + // otherwise the socket is in some unknown state, so do a harsh shutdown + _socket->abort(); + _toldDisconnect = true; + _server->disconnectClient(this); +} + +void PVSClientConnection::sock_dataArrival() +{ + if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState) + { + ConsoleLog writeError("dataArrival called in bad state"); + return; + } + + _lastData = time(NULL); + while (_socket->bytesAvailable()) + { + int retval = 0; + do + { + if (_incomplete == NULL) _incomplete = new PVSMsg(); // we need a pvsmsg object + retval = _incomplete->readMessage(_socket); // let the message read data from socket + if (retval == -1) // error parsing msg, disconnect client! + { + this->closeConnection(); + return; + } + if (retval == 1) // message is complete + { + _server->handleClientMsg(_id, *_incomplete); + delete _incomplete; // ...and delete... + _incomplete = NULL; // ...so the next msg can be parsed + } + } while (retval == 1); + } +} + +void PVSClientConnection::sock_closed() +{ + // should this be unreliable in some way i suggest using the signal "stateChanged()" instead + // and check if the state changed to unconnected. + if (_toldDisconnect) return; + _toldDisconnect = true; + _server->disconnectClient(this); +} + +void PVSClientConnection::sock_error(QAbstractSocket::SocketError errcode) +{ + this->closeConnection(); +} + +/* +void PVSClientConnection::push_back_receive(PVSMsg newMsg) +{ + _recQueue.push_back(newMsg); +} +*/ + +bool PVSClientConnection::push_back_send(PVSMsg newMsg) +{ + if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState) return false; + newMsg.setSndID(_id); + int len; + char data[2000]; + char *tmp = data; + if (!newMsg.getBinaryData(tmp, len)) + { + printf("Message empty. Ignored.\n"); + return false; + } + QByteArray ba; + ba.append(tmp, len); + int ret = (int)_socket->write(ba); + //printf("Sent %d of %d bytes.\n", ret, len); + if (ret == -1) + { + this->closeConnection(); + return false; + } + return true; +} + +QSslSocket* PVSClientConnection::getSocket() +{ + return _socket; +} + +void PVSClientConnection::setID(unsigned int id) +{ + _id = id; + this->push_back_send(PVSMsg(PVSLOGIN, "ID", int2String(_id))); +} + +void PVSClientConnection::ping() +{ + // still needs flag/timer to check for a ping timeout (and a reply from the client) + this->push_back_send(PVSMsg(PVSCOMMAND, "PING", "HELLO?", _id)); +} + +QString PVSClientConnection::getAddress() +{ + if (_socket == NULL) return QString(); + return _socket->peerAddress().toString(); +} + +QString PVSClientConnection::getNameUser() +{ + return getUserName(); +} diff --git a/src/net/pvsClientConnection.h b/src/net/pvsClientConnection.h new file mode 100644 index 0000000..cfbf98e --- /dev/null +++ b/src/net/pvsClientConnection.h @@ -0,0 +1,67 @@ +/** + * PVSClientConnection + * + * holds and maintains a Connection made from/to a PVSServerConnection (or derivate) + * PVSClientConnections are created by the PVSListenServer if a PVSCLientConnection is accepted + * + */ + +#include "pvsMsg.h" + +#include <QtNetwork/QSslSocket> + + +#ifndef _PVSCLIENTCONNECTION_H_ +#define _PVSCLIENTCONNECTION_H_ + +class PVSListenServer; + +class PVSClientConnection : public QObject +{ + Q_OBJECT + +public: + //C'Tor + PVSClientConnection(PVSListenServer* server, QSslSocket* sock = NULL); + // D'Tor + ~PVSClientConnection(); + + void closeConnection(); + bool isConnected() + { + return _socket != NULL && _socket->state() == QAbstractSocket::ConnectedState; + } + time_t lastData() + { + return _lastData; + } + + //void push_back_receive(PVSMsg newMsg); + bool push_back_send(PVSMsg newMsg); + QSslSocket* getSocket(); + + int getID() { return _id; } + void setID(unsigned int id); + void setServerID(unsigned int id) { _serverId = id; } + + QString getAddress(); + void setUsername(QString username); + QString getNameUser(); + void ping(); + +private Q_SLOTS: + void sock_dataArrival(); + void sock_closed(); + void sock_error(QAbstractSocket::SocketError errcode); + +private: + QSslSocket *_socket; + int _id; + unsigned int _serverId; + PVSMsg *_incomplete; + PVSListenServer *_server; + bool _toldDisconnect; + time_t _lastData; +}; + +#endif diff --git a/src/net/pvsDiscoveredServer.cpp b/src/net/pvsDiscoveredServer.cpp new file mode 100644 index 0000000..dddb5a0 --- /dev/null +++ b/src/net/pvsDiscoveredServer.cpp @@ -0,0 +1,152 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/net/pvsDiscoveredServer.cpp +# - represents an entry in the list of available servers +# - handles some extra things like validating the identity of the remote host +# ----------------------------------------------------------------------------- +*/ + +#include "pvsDiscoveredServer.h" +#include "src/util/serviceDiscoveryUtil.h" +#include <QtNetwork/QSslKey> + +PVSDiscoveredServer::PVSDiscoveredServer(QObject* parent, QHostAddress host, int port, QByteArray fingerprint, QString name) + : QObject(parent) +{ + _validated = false; + _socket = NULL; + _host = host; + _port = port; + _fingerprint = fingerprint; + _name = name; + _lastUpdate = QDateTime::currentDateTime(); + _lastCheck = QDateTime::fromTime_t(1000000); + this->validateCertificate(); +} + +PVSDiscoveredServer::~PVSDiscoveredServer() { + delete _socket; +} + +void PVSDiscoveredServer::ssl_Error( const QList<QSslError> & errors ) +{ + for (QList<QSslError>::const_iterator it = errors.begin(); it != errors.end(); it++) + { + QSslError err = *it; + if (err.error() == QSslError::HostNameMismatch) continue; // We don't pay attention to hostnames for validation + if (err.error() == QSslError::SelfSignedCertificate) { + continue; // Also, this will always be the case; we check the fingerprint later + } + //ConsoleLog writeNetwork(err.errorString().toUtf8().data()); + //ConsoleLog writeNetwork("***** SSL ERROR, ABORTING *****"); + printf("Unhandled SSL Error in SD: %s\n", err.errorString().toUtf8().data()); + return; + } + _socket->ignoreSslErrors(); +} + +void PVSDiscoveredServer::sock_dataArrival() +{ + if (_socket == NULL) return; + + char charbuff[2000]; + while (_socket->bytesAvailable()) + { + _socket->read(charbuff, 2000); + } +} + +void PVSDiscoveredServer::sock_connected() +{ + QByteArray cert = _socket->peerCertificate().digest(QCryptographicHash::Sha1); + if (_socket->peerCertificate().isNull()) + { + printf("**** WARNING - PEER CERTIFICATE IS NULL ****\n"); + } + else + { + printf("%s\n", _socket->peerCertificate().subjectInfo(QSslCertificate::Organization).toUtf8().data()); + printf("%s\n", _socket->peerCertificate().subjectInfo(QSslCertificate::CommonName).toUtf8().data()); + printf("%s\n", _socket->peerCertificate().subjectInfo(QSslCertificate::LocalityName).toUtf8().data()); + printf("%s\n", _socket->peerCertificate().subjectInfo(QSslCertificate::OrganizationalUnitName ).toUtf8().data()); + printf("%s\n", _socket->peerCertificate().subjectInfo(QSslCertificate::CountryName ).toUtf8().data()); + printf("%s\n", _socket->peerCertificate().subjectInfo(QSslCertificate::StateOrProvinceName ).toUtf8().data()); + } + if (cert == _fingerprint && !_validated) + { + _validated = true; + emit validated(this); + printf("Validated certificate of %s :)\n", _socket->peerAddress().toString().toUtf8().data()); + } + else + { + printf("Certificate of %s is invalid :(\n", _socket->peerAddress().toString().toUtf8().data()); + QByteArray is, should; + is = cert.toBase64(); + should = _fingerprint.toBase64(); + printf("Is %s and should be %s\n", is.data(), should.data()); + } + _socket->disconnectFromHost(); +} + +void PVSDiscoveredServer::validateCertificate() +{ + if (_validated) return; // Nothing to do, this one is legit + QDateTime now = QDateTime::currentDateTime(); + if (_lastCheck.secsTo(now) < 30) return; // Too soon! + if (_host.isNull() || _port < 1 || _port > 65535) return; // Invalid + if (_socket != NULL) { + disconnect(_socket, SIGNAL(connected()), this, SLOT(sock_connected())); + disconnect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival())); + disconnect(_socket, SIGNAL(sslErrors(const QList<QSslError> &)), + this, SLOT(ssl_Error(const QList<QSslError> &)) + ); + _socket->abort(); + _socket->deleteLater(); + } + _socket = new QSslSocket(this); + _socket->setProtocol(QSsl::SslV3); + _socket->setPeerVerifyMode(QSslSocket::VerifyPeer); + connect(_socket, SIGNAL(encrypted()), this, SLOT(sock_connected())); + connect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival())); + connect(_socket, SIGNAL(sslErrors(const QList<QSslError> &)), + this, SLOT(ssl_Error(const QList<QSslError> &)) + ); + _socket->connectToHostEncrypted(_host.toString(), _port); + _lastCheck = now; +} + +bool PVSDiscoveredServer::hasFingerprint(QByteArray &fingerprint) +{ + return _fingerprint == fingerprint; +} + +bool PVSDiscoveredServer::hasHost(QHostAddress &host) +{ + return _host == host; +} + +void PVSDiscoveredServer::update(int port) +{ + _port = port; + _lastUpdate = QDateTime::currentDateTime(); +} + +int PVSDiscoveredServer::getAge() +{ + return _lastUpdate.secsTo(QDateTime::currentDateTime()); +} + +QString PVSDiscoveredServer::getName() +{ + return _name; +} diff --git a/src/net/pvsDiscoveredServer.h b/src/net/pvsDiscoveredServer.h new file mode 100644 index 0000000..d9f0c01 --- /dev/null +++ b/src/net/pvsDiscoveredServer.h @@ -0,0 +1,63 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/net/pvsDiscoveredServer.h +# - represents an entry in the list of available servers +# - handles some extra things like validating the identity of the remote host +# ----------------------------------------------------------------------------- +*/ + +#ifndef PVSDISCOVEREDSERVER_H_ +#define PVSDISCOVEREDSERVER_H_ + +#include <QtNetwork/QSslSocket> +#include <QtNetwork/QHostAddress> +#include <QtCore/QDateTime> + +class PVSDiscoveredServer; + +class PVSDiscoveredServer : public QObject { + Q_OBJECT + +private: + QHostAddress _host; + int _port; + QByteArray _fingerprint; + bool _validated; + QSslSocket *_socket; + QDateTime _lastCheck; + QDateTime _lastUpdate; + QString _name; + +public: + PVSDiscoveredServer(QObject* parent, QHostAddress host, int port, QByteArray fingerprint, QString name); + virtual ~PVSDiscoveredServer(); + bool isValid() { return _validated; } + bool hasFingerprint(QByteArray &fingerprint); + bool hasHost(QHostAddress &host); + void update(int port); + int getAge(); + QString getName(); + QHostAddress getHost() { return _host; } + QByteArray getFingerprint() { return _fingerprint; } + int getPort() { return _port; } + void validateCertificate(); + +private Q_SLOTS: + void ssl_Error( const QList<QSslError> & errors ); + void sock_dataArrival(); + void sock_connected(); + +Q_SIGNALS: + void validated(PVSDiscoveredServer*); +}; + +#endif /* PVSDISCOVEREDSERVER_H_ */ diff --git a/src/net/pvsListenServer.cpp b/src/net/pvsListenServer.cpp new file mode 100644 index 0000000..1dac9c0 --- /dev/null +++ b/src/net/pvsListenServer.cpp @@ -0,0 +1,308 @@ +/* + # Copyright (c) 2009,2010 - 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/ + # ----------------------------------------------------------------------------- + # src/net/pvsListenServer.cpp + # - handling of clients (server side) + # - accepting new connections etc. + # ----------------------------------------------------------------------------- + */ + +#include "pvsListenServer.h" +#include "pvsMsg.h" +#include "pvsClientConnection.h" +#include "src/util/consoleLogger.h" +#include <QtNetwork/QSslSocket> +#include "SslServer.h" +#include <cassert> +//#define verbose + +// Create listener +PVSListenServer::PVSListenServer(int port, int clients) +{ + _id = generateID(); + _listenSocket = NULL; + _timer = 0; + if (clients < 1) + _clientsMax = 100; + else + _clientsMax = clients; + _port = port; + init(); + +} + +PVSListenServer::~PVSListenServer() +{ + if (_listenSocket != NULL) + { + disconnect(_listenSocket, SIGNAL(newConnection()), this, SLOT( + server_connectionRequest())); + _listenSocket->deleteLater(); + } +} + +PVSClientConnection* PVSListenServer::getConnectionFromId(int id) +{ + if (!(_clients.empty())) + { + // Check for ping timeout + for (std::list<PVSClientConnection*>::iterator it = _clients.begin(); it + != _clients.end(); it++) + { + PVSClientConnection *client = *it; + if (client) + if (client->getID() == id) + return client; + } + } + return NULL; +} + +void PVSListenServer::sendToAll(PVSMsg msg) +{ + if (!(_clients.empty())) + { + // Check for ping timeout + for (std::list<PVSClientConnection*>::iterator it = _clients.begin(); it + != _clients.end(); it++) + { + PVSClientConnection *client = *it; + if (client) + client->push_back_send(msg); + } + } +} + +// listen on a specific port +bool PVSListenServer::startListen(int port) +{ + if (_listenSocket != NULL) + { + ConsoleLog writeError( + QString("Server already listening on port :").append( + int2String(_port))); + if (shutdown()) + { + ConsoleLog writeError(QString("Server shutdown failed!")); + return false; + } + } + _port = port; + return init(); +} + +// stop listening and free socket descriptor +bool PVSListenServer::shutdown() +{ + if (_timer != 0) + killTimer( _timer); + _timer = 0; + if (_listenSocket != NULL) + { + disconnect(_listenSocket, SIGNAL(newConnection()), this, SLOT( + server_connectionRequest())); + _listenSocket->close(); + _listenSocket->deleteLater(); + } + _listenSocket = NULL; + _fresh = true; + return false; +} + +// timer event, 5 second interval +void PVSListenServer::timerEvent(QTimerEvent *event) +{ + if (!(_clients.empty())) + { + // Check for ping timeout + time_t refval = time(NULL) - 10; + for (std::list<PVSClientConnection*>::iterator it = _clients.begin(); it + != _clients.end(); it++) + { + PVSClientConnection *client = *it; + client->ping(); + if (!client->isConnected()) + { // disconnected + if (disconnectClient(client)) + break; // list was modified, iterator not valid anymore + } + if (client->lastData() < refval) + { // ping timeout + printf("Ping timeout for client %s\n", client->getNameUser().toLocal8Bit().data()); + if (disconnectClient(client)) + break; // list was modified, iterator not valid anymore + } + } + } +} + +// remove a client +bool PVSListenServer::disconnectClient(PVSClientConnection* delinquent) +{ + assert(delinquent); + delinquent->deleteLater(); + if (!(_clients.empty())) + { + for (std::list<PVSClientConnection*>::iterator it = _clients.begin(); it + != _clients.end(); it++) + { + if ((*it) == delinquent) + { + (*it)->closeConnection(); + _clients.remove((*it)); + onClientDisconnected(delinquent); + return true; + } + } + } + return false; +} + +// All sorts of events: + +void PVSListenServer::onConnectionRemoved(PVSClientConnection* delinquent) +{ + +} + +void PVSListenServer::onClientConnected(PVSClientConnection* connected) +{ + connected->setServerID(_id); + connected->setID(generateID()); +} + +void PVSListenServer::onClientDisconnected(PVSClientConnection* disconnected) +{ + // +} + +// Get client class for a given socket +PVSClientConnection* PVSListenServer::getConnectionFromSocket(QSslSocket* sock) +{ + for (std::list<PVSClientConnection*>::iterator it = _clients.begin(); it + != _clients.end(); it++) + { + if ((*it)->getSocket() == sock) // match! + return (*it); + } + return NULL; +} + +// generate a random (unique) id +unsigned int PVSListenServer::generateID() +{ + int random_integer; + do + { + random_integer = getRandom(0, 0); + } + while (getConnectionFromID(random_integer)); + + return (unsigned int) random_integer; +} + +// Get client class for a given id +PVSClientConnection* PVSListenServer::getConnectionFromID(int id) +{ + for (std::list<PVSClientConnection*>::iterator it = _clients.begin(); it + != _clients.end(); it++) + { + if ((*it)->getID() == id || id == _id) + { + return (*it); + } + } + return NULL; +} + +// Initialize listening socket +bool PVSListenServer::init() +{ + if (_listenSocket != NULL) + shutdown(); + + if (_port > 0) + { + // make a socket, bind it, and listen on it: + _listenSocket = new SslServer; + QHostAddress addr(QHostAddress::Any); + _listenSocket->listen(addr, _port); + + if (!_listenSocket->isListening()) + { + ConsoleLog writeNetwork( + QString("Error listening on Port ").append(int2String( + _port))); + return false; + } + ConsoleLog writeNetwork( + QString("Server is listening. Socket: ").append(int2String( + (int) _listenSocket))); + connect(_listenSocket, SIGNAL(newConnection()), this, SLOT( + server_connectionRequest())); + + _fresh = true; + if (_timer != 0) + killTimer( _timer); + _timer = startTimer(5000); + return true; + } + return false; +} + +void PVSListenServer::server_connectionRequest() +{ + //printf("ConnReq\n"); + if (_listenSocket == NULL) + return; // o.O + while (_listenSocket->hasPendingConnections()) + { + QSslSocket* sock = (QSslSocket*)_listenSocket->nextPendingConnection(); + //printf("Got one: %d: %s\n", (int)sock->isEncrypted(), sock->peerAddress().toString().toUtf8().data()); + if (_clients.size() >= _clientsMax) + { + sock->abort(); + sock->deleteLater(); + continue; + } + PVSClientConnection* client = new PVSClientConnection(this, sock); + _clients.push_back(client); // create new client class and add to list + onClientConnected(client); // trigger event + _fresh = false; + } +} + +void PVSListenServer::handleClientMsg(unsigned int clientID, PVSMsg msg) +{ + printf("Got Message for client %ud: [%c][%s][%s]\n", clientID, + (char) msg.getType(), msg.getIdent().toUtf8().data(), + msg.getMessage().toUtf8().data()); + msg.setSndID(clientID); + if (msg.getType() == PVSCOMMAND) + _commandDispatcher.fire(msg.getIdent(), msg); + else if (msg.getType() == PVSMESSAGE) + _chatDispatcher.fire(msg.getIdent(), msg); + else if (msg.getType() == PVSLOGIN) + _loginDispatcher.fire(msg.getIdent(), msg); + else + ConsoleLog + writeNetwork( + QString( + "Could not dispatch Message of unknown Type.\n\t Message was: ").append( + msg.getIdent().append(QString(":").append( + msg.getMessage())))); +} + +bool PVSListenServer::isListening() +{ + return _listenSocket != NULL && _listenSocket->isListening(); +} diff --git a/src/net/pvsListenServer.h b/src/net/pvsListenServer.h new file mode 100644 index 0000000..ab021c7 --- /dev/null +++ b/src/net/pvsListenServer.h @@ -0,0 +1,106 @@ +#ifndef _PVSLISTENSERVER_H_ +#define _PVSLISTENSERVER_H_ +#include <list> +#include <src/util/dispatcher.h> +#include <src/util/consoleLogger.h> +#include <QtNetwork/QSslSocket> +//#include <QtNetwork/QTcpServer> + +class SslServer; + +class PVSClientConnection; +class PVSMsg; + +class PVSListenServer : public QObject +{ + Q_OBJECT + +private: + + // internal control functions + + std::list<PVSClientConnection*> _clients; + + + int _numCon; + bool _fresh; + unsigned int _clientsMax; + int _port; + + //QTcpServer *_listenSocket; + SslServer *_listenSocket; + + int _id; + EventIdentDispatcher<PVSMsg> _loginDispatcher; + EventIdentDispatcher<PVSMsg> _commandDispatcher; + EventIdentDispatcher<PVSMsg> _chatDispatcher; + int _timer; + + // obvious init method is obvious + bool init(); + unsigned int generateID(); + +protected: + void timerEvent(QTimerEvent *event); + +public: + + +// typedef void (A::*function)(void); + // C'Tor + explicit PVSListenServer(int port = 0, int clients = 0); + virtual ~PVSListenServer(); + + PVSClientConnection* getConnectionFromId(int id); + void sendToAll(PVSMsg msg); + // control methods + bool startListen(int port); + bool shutdown(); + bool isListening(); + bool disconnectClient(PVSClientConnection* delinquent); + void onConnectionRemoved(PVSClientConnection* delinquent); + + std::list<PVSClientConnection*>* getClientListPtr() + { + return &_clients; + } + // methods which can/should be overwritten by derivates + virtual void onClientConnected(PVSClientConnection* connected); // you can hook up additional services on client connection here + virtual void onClientDisconnected(PVSClientConnection* disconnected); // deletes the client, but you can hook up stuff here too + + void handleClientMsg(unsigned int clientID, PVSMsg msg); ///< called by a clientconnection if a msg was received + + + template<class T> void addLoginHandler(QString ident, T* who, void (T :: *func)(PVSMsg)) + { + printf("Listener got added to LoginHandler\n"); + _loginDispatcher.addListener(ident, who, func); + }; + template<class T> void removeLoginHandler(QString ident, T* who, void (T :: *func)(PVSMsg)) + { + _loginDispatcher.removeListener(ident, who, func); + }; + template<class T> void addChatHandler(QString ident, T* who, void (T :: *func)(PVSMsg)) + { + _chatDispatcher.addListener(ident, who, func); + }; + template<class T> void removeChatHandler(QString ident, T* who, void (T :: *func)(PVSMsg)) + { + _chatDispatcher.removeListener(ident, who, func); + }; + template<class T> void addCommandHandler(QString ident, T* who, void (T :: *func)(PVSMsg)) + { + _commandDispatcher.addListener(ident, who, func); + }; + template<class T> void removeCommandHandler(QString ident, T* who, void (T :: *func)(PVSMsg)) + { + _commandDispatcher.removeListener(ident, who, func); + }; + PVSClientConnection* getConnectionFromSocket(QSslSocket* sock); + PVSClientConnection* getConnectionFromID(int id); + +private Q_SLOTS: + void server_connectionRequest(); +}; + +#endif diff --git a/src/net/pvsLocalhostCommunicator.cpp b/src/net/pvsLocalhostCommunicator.cpp new file mode 100644 index 0000000..199b39c --- /dev/null +++ b/src/net/pvsLocalhostCommunicator.cpp @@ -0,0 +1,104 @@ +#include "pvsLocalhostCommunicator.h" +#include "src/util/consoleLogger.h" +#include "src/net/pvsMsg.h" + +static QHostAddress localhost(QHostAddress::LocalHost); +#define localport 14913 + +PVSLocalhostCommunicator::PVSLocalhostCommunicator(QString path) +{ + _isServer = _isRunning = false; + _sock = NULL; +} + +void PVSLocalhostCommunicator::run() +{ + if (_isRunning) + return; + + // First try to run as server + _sock = new QUdpSocket(); + // We'll bind only to localhost, so nobody else can send commands (from remote hosts) + // Otherwise we had to check the remote addr when receiving a datagram, but this + // wouldn't be as secure since you can easily fake it + _sock->bind(localhost, localport); // QUdpSocket::DontShareAddress? would need root + connect(_sock, SIGNAL(readyRead()), this, SLOT(sock_dataArrival())); + + if (_sock->state() == QAbstractSocket::BoundState) + { + // OK, we are the first daemon to run + _isServer = true; + _isRunning = true; + return; + } + if (_sock->bind()) + { + _isRunning = true; + } +} + +void PVSLocalhostCommunicator::stop() +{ + _isRunning = false; + _sock->deleteLater(); + _sock = NULL; +} + +void PVSLocalhostCommunicator::sock_dataArrival() +{ + if (_sock == NULL) return; + + qint64 dsize; + while ((dsize = _sock->pendingDatagramSize()) > -1) // returns -1 if no more datagrams are pending + { + if (dsize < 4) // anything shorter than 4 bytes is not a valid PVSMsg anyways, so take a shortcut + { + char x; + _sock->readDatagram(&x, 1, NULL, NULL); + continue; // discard the packet and see if there is more + } + + PVSMsg receiver; + receiver.readMessage(_sock, true); + + if (receiver.isMsgComplete()) + { + // we received a message, so fire away + ConsoleLog writeNetwork(QString("Received UDS command: ").append(receiver.getIdent())); + _daemonDispatcher.fire(receiver.getIdent(), receiver); + } // If the msg is not complete we have to discard it, since UDP + // is packet oriented and we could not say for sure if the next one + // would be the continuation of this msg. + // Usually on the loopback interface it is safe to send datagrams + // up to 8kb, so this is not be an issue anyway. + } +} + +void PVSLocalhostCommunicator::sendCommand(QString ident, QString cmd) +{ + if (_isRunning && !_isServer && _sock != NULL) + { + PVSMsg sender(PVSDAEMON, ident, cmd); + char *data; + int len; + sender.getBinaryData(data, len); + QByteArray qba(data, len); + printf("Sending %d bytes to daemon...\n", qba.length()); + qint64 result = _sock->writeDatagram(qba, localhost, localport); + _sock->waitForBytesWritten(100); + + // simply bail out on an error or disconnect or whatever + if (result != len) + { + if (result == -1) + { + printf("Error sending PVSMsg to daemon: %s\n", _sock->errorString().toUtf8().data()); + } + else + { + printf("Sent PVSMsg was incomplete.\n"); + } + stop(); + } + } +} diff --git a/src/net/pvsLocalhostCommunicator.h b/src/net/pvsLocalhostCommunicator.h new file mode 100644 index 0000000..425cc37 --- /dev/null +++ b/src/net/pvsLocalhostCommunicator.h @@ -0,0 +1,51 @@ +/// test documentation +/// whatever +//! and one more + + + +#ifndef _PVSLocalhostCommunicator_H_ +#define _PVSLocalhostCommunicator_H_ +#include <src/util/dispatcher.h> +#include <QtNetwork/QUdpSocket> + + +class PVSMsg; + +class PVSLocalhostCommunicator : public QObject +{ + Q_OBJECT +public: + PVSLocalhostCommunicator(QString path); + void run(); + bool server() + { + return _isServer; + }; + bool running() + { + return _isRunning; + }; + void stop(); + void sendCommand(QString ident, QString cmd); + EventIdentDispatcher<PVSMsg>* getDispatcher() + { + return &_daemonDispatcher; + }; + +private Q_SLOTS: + void sock_dataArrival(); + +private: + + bool _isServer, _isRunning; + QUdpSocket* _sock; + + + + EventIdentDispatcher<PVSMsg> _daemonDispatcher; //!< Dispatcher for Daemon Commands +}; + +typedef PVSLocalhostCommunicator PVSUDSC; + +#endif diff --git a/src/net/pvsMsg.cpp b/src/net/pvsMsg.cpp new file mode 100644 index 0000000..b56c979 --- /dev/null +++ b/src/net/pvsMsg.cpp @@ -0,0 +1,207 @@ +/* + # Copyright (c) 2010 - 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/ + # ----------------------------------------------------------------------------- + # src/net/pvsMsg.cpp + # - ??? . + # ----------------------------------------------------------------------------- + */ + +#include "pvsMsg.h" +#include <cstring> +#include <QtNetwork/QUdpSocket> +#include <QtNetwork/QHostAddress> + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif + +static unsigned char PVS_ID = 'P'; + +// Several constructors for the PVSMsg class... +PVSMsg::PVSMsg() +{ + _msgType = PVSMESSAGE; + _buffer = NULL; + _buffLen = 0; + _buffFill = 0; +} + +PVSMsg::PVSMsg(PVSMsgType type, QString ident, QString msg, int recID) +{ + this->_recID = recID; + + if (ident.size()) + _msgIdent = ident; + else + _msgIdent = QString("invalid"); + + _msgType = type; + _msgString = msg; + _buffer = NULL; + _buffLen = 0; + _buffFill = 0; +} + +PVSMsg::PVSMsg(PVSMsg const& copyMe) +{ + _msgType = copyMe._msgType; + _msgString = copyMe._msgString; + _msgIdent = copyMe._msgIdent; + _remoteIp = copyMe._remoteIp; + + _buffLen = copyMe._buffLen; + _buffFill = copyMe._buffFill; + if (_buffLen > 0) + { + _buffer = new char[_buffLen]; + memcpy(_buffer, copyMe._buffer, _buffLen); + } + else + _buffer = NULL; + _sndID = copyMe._sndID; + _recID = copyMe._recID; +} + +// Destructor... +PVSMsg::~PVSMsg() +{ + if (_buffer) + delete[] _buffer; +} + +int PVSMsg::readMessage(QAbstractSocket* sock, bool udp) +{ + if (_buffFill > 0 && _buffLen <= _buffFill) + return 1; + qint64 ret = 0; + if (_buffFill < 4) // message header is not complete yet + { + if (_buffer == NULL) + { + _remoteIp = sock->peerAddress().toString(); + if (udp) + _buffer = new char[1000]; + else + _buffer = new char[4]; + } + // Read as many bytes as needed to complete the 4 byte header + if (udp) + ret = ((QUdpSocket*)sock)->readDatagram(_buffer, 1000); + else + ret = sock->read(_buffer + _buffFill, 4 - _buffFill); + if (ret == -1) return -1; + _buffFill += (int)ret; + if (_buffFill == 0) + return 0; + if (_buffer[0] != PVS_ID) + { + // check if the id byte is correct + // otherwise either the message parsing is broken + // or someone is sending garbage + return -1; + } + if (_buffFill >= 4) + { + // header complete, allocate buffer + _buffLen = 4 + (unsigned char)_buffer[2] + (unsigned char)_buffer[3]; + char *nb = new char[_buffLen + 1]; // +1 for \0 + memcpy(nb, _buffer, _buffFill); + delete[] _buffer; + _buffer = nb; + } + } + if (_buffFill >= 4) + { + // got header, assemble rest of msg + if (!udp) + { + ret = sock->read(_buffer + _buffFill, _buffLen - _buffFill); // read remaining bytes + if (ret == -1) return -1; + _buffFill += (int)ret; + } + if (_buffFill >= _buffLen) + { + // message is complete + _buffer[_buffLen] = '\0'; // first, terminate with nullchar + _msgString = QString::fromUtf8(_buffer + 4 + (unsigned char)_buffer[2]); // get message + _buffer[4 + (unsigned char)_buffer[2]] = '\0'; + _msgIdent = QString::fromUtf8(_buffer + 4); // get ident + _msgType = (PVSMsgType)_buffer[1]; // get msg type + return 1; + } + } + return 0; +} + +void PVSMsg::setMessage(QString text) +{ + _msgString = text; +} + +void PVSMsg::setIdent(QString ident) +{ + _msgIdent = ident; +} + +QString PVSMsg::getMessage() +{ + return _msgString; +} + +QString PVSMsg::getIdent() +{ + return _msgIdent; +} + +bool PVSMsg::getBinaryData(char*& data, int& dataLen) +{ + if (_msgIdent.size() == 0) + return false; + this->makeSndBuff(); + data = (char*) _buffer; + dataLen = _buffLen; + return true; +} + +void PVSMsg::setSndID(int id) +{ + _sndID = id; +} + +void PVSMsg::setRecID(int id) +{ + _recID = id; +} + +// Create a send buffer with the necessary size +bool PVSMsg::makeSndBuff() +{ + QByteArray uIdent = _msgIdent.toUtf8(); + QByteArray uString = _msgString.toUtf8(); + uIdent.truncate(255); + uString.truncate(255); + _buffLen = 4 + uIdent.size() + uString.size(); + if (_buffer != NULL) + delete[] _buffer; + unsigned char *tmpBuffer = new unsigned char[_buffLen + 1]; + + tmpBuffer[0] = PVS_ID; + tmpBuffer[1] = (unsigned char) _msgType; + tmpBuffer[2] = (unsigned char) uIdent.size(); + tmpBuffer[3] = (unsigned char) uString.size(); + memcpy(tmpBuffer + 4, uIdent.data(), uIdent.size()); + memcpy(tmpBuffer + 4 + uIdent.size(), uString.data(), uString.size()); + //printf("[%c] '%s' - '%s'\n", (char)_msgType, _msgIdent.toUtf8().data(), _msgString.toUtf8().data()); + tmpBuffer[_buffLen] = '\0'; + //printf("Binary: '%s'\n", _buffer); + _buffer = (char*)tmpBuffer; + return true; +} diff --git a/src/net/pvsMsg.h b/src/net/pvsMsg.h new file mode 100644 index 0000000..6fbcd99 --- /dev/null +++ b/src/net/pvsMsg.h @@ -0,0 +1,73 @@ +/* + * pvsMsg.h + * + * Created on: 08.01.2010 + * Author: sr + */ + +#ifndef PVSMSG_H_ +#define PVSMSG_H_ + + +#include <QtCore/QString> + +enum PVSMsgType +{ + PVSCOMMAND = 'C', + PVSMESSAGE = 'M', + PVSLOGIN = 'L', + PVSDAEMON = 'D', + PVSUNKNOWN = 'U' +}; + +class PVSServerConnection; +class PVSListenServer; +class PVSClientConnection; +class QAbstractSocket; + +class PVSMsg +{ +public: + friend class PVSServerConnection; + friend class PVSListenServer; + friend class PVSClientConnection; + + PVSMsg(); + PVSMsg(PVSMsgType type, QString _ident, QString msg, int recID = 0); + PVSMsg(PVSMsg const& copyMe); + ~PVSMsg(); + + int readMessage(QAbstractSocket* sock, bool udp = false); ///< -1 = error, 0 = incomplete, 1 = complete + unsigned int getLength() + { + return _msgString.size(); + }; + void setIdent(QString ident); + QString getIdent(); + void setMessage(QString text); + QString getMessage(); + PVSMsgType getType() { return _msgType; } + bool getBinaryData(char*& data, int& dataLen); ///< get binary representation of this PVSmsg + + unsigned int getRecID() { return _recID; } + int getSndID() { return _sndID; } + QString getRemoteIp() { return _remoteIp; } + bool isMsgComplete() { return _buffFill > 0 && _buffFill == _buffLen; } + +private: + void setSndID(int id); + void setRecID(int id); + bool makeSndBuff(); + PVSMsgType _msgType; ///< type of message (command, message, login, daemon) + QString _msgIdent; ///< message ident + QString _msgString; ///< message string + char *_buffer; ///< receive buffer + int _buffLen; ///< size of complete message in bytes + int _buffFill; ///< actual number of bytes in buffer + + int _sndID; + int _recID; + QString _remoteIp; +}; + +#endif /* PVSMSG_H_ */ diff --git a/src/net/pvsServerConnection.cpp b/src/net/pvsServerConnection.cpp new file mode 100644 index 0000000..04a1ef6 --- /dev/null +++ b/src/net/pvsServerConnection.cpp @@ -0,0 +1,243 @@ +#include "pvsServerConnection.h" +#include "src/util/consoleLogger.h" +#include "src/util/util.h" +#include "pvsMsg.h" +#include "src/pvs.h" +#include <QtNetwork/QHostAddress> +#include "src/core/pvsChatClient.h" +#include "src/util/serviceDiscoveryUtil.h" +#include "src/net/pvsDiscoveredServer.h" +//#define verbose + +PVSServerConnection::PVSServerConnection(PVS *parent) : QObject(parent) +{ + _client = parent; + _incomplete = NULL; + _socket = NULL; + _timerId = 0; + _timer = 0; + _wasConnected = false; + loadCommands(); +} + +inline void PVSServerConnection::timerStop() +{ + if (_timer == 0) return; + killTimer(_timer); + _timer = 0; +} + +bool PVSServerConnection::connectToServer(PVSDiscoveredServer* server, QString passwd) +{ + QHostAddress host = server->getHost(); + if (_socket != NULL && _socket->state() == QAbstractSocket::ConnectedState + && _socket->peerAddress() == host) return false; + int port = server->getPort(); + if (port < 1 || port > 65535) port = SERVER_PORT_INT; + ConsoleLog writeNetwork("Connecting to host:"); + ConsoleLog writeNetwork(host.toString().toUtf8().data()); + timerStop(); + if (_socket != NULL) + { + _socket->blockSignals(true); + _socket->abort(); + _socket->deleteLater(); + } + _name = server->getName(); + _expectedFingerprint = server->getFingerprint(); + _passwd = passwd; + _socket = new QSslSocket(this); + connect(_socket, SIGNAL(encrypted()), this, SLOT(sock_connected())); + connect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival())); + connect(_socket, SIGNAL(disconnected()), this, SLOT(sock_closed())); + connect(_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sock_error(QAbstractSocket::SocketError))); + char tex[2000]; + snprintf(tex, 2000, "Connecting to %s on port %d", host.toString().toUtf8().data(), (int)port); + ConsoleLog writeNetwork(tex); + connect(_socket, + SIGNAL(sslErrors(const QList<QSslError> &)), + this, + SLOT(sslErrors(const QList<QSslError> &)) + ); + _socket->connectToHostEncrypted(host.toString(), port); + if (_timer == 0) _timer = startTimer(10000); + + return true; // we really don't know yet if it will succeed since its async +} + +void PVSServerConnection::sslErrors ( const QList<QSslError> & errors ) +{ + for (QList<QSslError>::const_iterator it = errors.begin(); it != errors.end(); it++) + { + QSslError err = *it; + printf("Connect SSL: %s\n", err.errorString().toUtf8().data()); + if (err.error() == QSslError::HostNameMismatch) continue; // We don't pay attention to hostnames for validation + if (err.error() == QSslError::SelfSignedCertificate) continue; // Also, this will always be the case; we check the fingerprint later + ConsoleLog writeNetwork(err.errorString().toUtf8().data()); + ConsoleLog writeNetwork("***** SSL ERROR, ABORTING *****"); + return; + } + _socket->ignoreSslErrors(); +} + +void PVSServerConnection::disconnectFromServer() +{ + if (_socket == NULL) return; + _socket->disconnectFromHost(); + handleDisconnectInternal(); +} + +void PVSServerConnection::timerEvent(QTimerEvent *event) +{ + if (_socket != NULL && _socket->state() == QAbstractSocket::ConnectedState) return; + // TODO: Check for ping timeout +} + +void PVSServerConnection::sendMessage(PVSMsg newMessage) +{ + if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState) return; + char *data; + int len; + newMessage.getBinaryData(data, len); + QByteArray qba(data, len); + _socket->write(qba); +} + +void PVSServerConnection::ping() +{ + sendMessage(PVSMsg(PVSCOMMAND, "PING", "U THERE?"));; +} + +QString PVSServerConnection::getServerName() +{ + if (!isConnected()) return QString(); + return _name; +} + +void PVSServerConnection::loadCommands() +{ + addLoginHandler("ID", this, &PVSServerConnection::onID); + addCommandHandler("PING", this, &PVSServerConnection::onPing); +} + +void PVSServerConnection::onID(PVSMsg idmsg) +{ + _id = (unsigned int)string2Int(idmsg.getMessage()); +} + +void PVSServerConnection::onPing(PVSMsg pingmsg) +{ + if (pingmsg.getMessage().at(pingmsg.getMessage().size()-1) == '?') + { + sendMessage(PVSMsg(PVSCOMMAND, "PING", "HI!")); + } +} + +void PVSServerConnection::handleClientMsg(PVSMsg receiver) +{ + // FIXME: @SimonR, this line cuase problems with pvs in daemon mode and dbus + //qDebug("Got Message for this client: [%c][%s][%s]\n", (char)receiver.getType(), receiver.getIdent().toUtf8().data(), receiver.getMessage().toUtf8().data()); + if (receiver.getType() == PVSCOMMAND) + { + _commandDispatcher.fire(receiver.getIdent(), receiver); +// ConsoleLog writeNetwork(QString("Received a command and handled it.").append(receiver.getIdent().append(QString(":").append(receiver.getMessage())))); + } + else if (receiver.getType() == PVSMESSAGE) + { + _chatDispatcher.fire(receiver.getIdent(), receiver); + ConsoleLog writeNetwork(QString("Received a chat message and handled it.").append(receiver.getIdent().append(QString(":").append(receiver.getMessage())))); + } + else if (receiver.getType() == PVSLOGIN) + { + _loginDispatcher.fire(receiver.getIdent(), receiver); +// ConsoleLog writeNetwork(QString("Received a login and handled it. Ident: ").append(receiver.getIdent().append(QString(":")).append(receiver.getMessage()))); + } + else if (receiver.getType() == PVSUNKNOWN) + { + ConsoleLog writeNetwork(QString("Received an unknown type. Ident : ").append(receiver.getIdent().append(QString(" : ").append(receiver.getMessage())))); + } +} + +void PVSServerConnection::sock_dataArrival() +{ + if (_socket == NULL || _socket->state() != QAbstractSocket::ConnectedState) + { + ConsoleLog writeError("dataArrival called in bad state"); + return; + } + + while (_socket->bytesAvailable()) + { + int retval = 0; + do + { + if (_incomplete == NULL) _incomplete = new PVSMsg(); // we need a pvsmsg object + retval = _incomplete->readMessage(_socket); // let the message read data from socket + if (retval == -1) // error parsing msg, disconnect client! + { + this->disconnectFromServer(); + return; + } + if (retval == 1) // message is complete + { + this->handleClientMsg(*_incomplete); + delete _incomplete; // ...and delete... + _incomplete = NULL; // ...so the next msg can be parsed + } + } while (retval == 1); + } +} + +void PVSServerConnection::sock_closed() +{ + // should this be unreliable in some way i suggest using the signal "stateChanged()" instead + // and check if the state changed to unconnected. + ConsoleLog writeNetwork("Socket was closed... oh well.."); + handleDisconnectInternal(); +} + +void PVSServerConnection::sock_error(QAbstractSocket::SocketError errcode) +{ + char txt[204]; + snprintf(txt, 200, "Connection error: %d", (int)errcode); + ConsoleLog writeNetwork(txt); + handleDisconnectInternal(); +} + +// Send to server username and loginname. +void PVSServerConnection::sock_connected() +{ + QByteArray cert = _socket->peerCertificate().digest(QCryptographicHash::Sha1); + if (_expectedFingerprint != cert) + { // Nich mit mir, Freundchen! + disconnectFromServer(); + // Maybe you want to inform the user that there was a certificate mismatch + // and that it is very possible that the CIA is trying to eavesdrop on the connection + return; + } + ConsoleLog writeNetwork("Connected!"); + _wasConnected = true; + sendMessage( + PVSMsg(PVSLOGIN, "USERNAME", getFullUsername()+","+getenv("USER"))); + sendMessage( + PVSMsg(PVSLOGIN, "PASSWORD", _passwd)); + ConsoleLog writeNetwork("Sent Username and password."); + + _client->onConnected(_name); +} + +void PVSServerConnection::handleDisconnectInternal() +{ + _socket->blockSignals(true); + _socket->abort(); + _socket->deleteLater(); + _socket = NULL; + _name = QString(); + _client->securityUnlock(); + timerStop(); + if (_wasConnected) + { + _wasConnected = false; + _client->onDisconnected(); + } +} diff --git a/src/net/pvsServerConnection.h b/src/net/pvsServerConnection.h new file mode 100644 index 0000000..0669d88 --- /dev/null +++ b/src/net/pvsServerConnection.h @@ -0,0 +1,99 @@ +/** + * PVSServerConnection + * + * holds and maintains a Connection to a PVSListenServer (or derivate) + * + */ + + + +#ifndef _PVSSERVERCONNECTION_H_ +#define _PVSSERVERCONNECTION_H_ + +#include "src/util/dispatcher.h" +#include <QtNetwork/QSslSocket> + +class PVSMsg; +class PVS; +class PVSDiscoveredServer; + +class PVSServerConnection : public QObject +{ + Q_OBJECT +public: + PVSServerConnection(PVS *parent); + ~PVSServerConnection() {} + bool connectToServer(PVSDiscoveredServer* server, QString passwd = QString()); + void disconnectFromServer(); + bool isConnected() + { + return _socket != NULL && _socket->state() == QAbstractSocket::ConnectedState; + } + + void sendMessage(PVSMsg newMessage); + + void ping(); + QString getServerName(); + + virtual void loadCommands(); + void onID(PVSMsg idmsg); + void onPing(PVSMsg pingmsg); + template<class T> void addLoginHandler(QString ident, T* who, void (T :: *func)(PVSMsg)) + { + _loginDispatcher.addListener(ident, who, func); + }; + template<class T> void removeLoginHandler(QString ident, T* who, void (T :: *func)(PVSMsg)) + { + _loginDispatcher.removeListener(ident, who, func); + }; + template<class T> void addChatHandler(QString ident, T* who, void (T :: *func)(PVSMsg)) + { + _chatDispatcher.addListener(ident, who, func); + }; + template<class T> void removeChatHandler(QString ident, T* who, void (T :: *func)(PVSMsg)) + { + _chatDispatcher.removeListener(ident, who, func); + }; + template<class T> void addCommandHandler(QString ident, T* who, void (T :: *func)(PVSMsg)) + { + _commandDispatcher.addListener(ident, who, func); + }; + template<class T> void removeCommandHandler(QString ident, T* who, void (T :: *func)(PVSMsg)) + { + _commandDispatcher.removeListener(ident, who, func); + }; + +protected: + void timerEvent(QTimerEvent *event); + +private Q_SLOTS: + void sslErrors(const QList<QSslError> & errors); // triggered for errors that occur during SSL negotiation + void sock_dataArrival(); // triggered if data is available for reading + void sock_closed(); // triggered if the socket is closed + void sock_error(QAbstractSocket::SocketError errcode); // triggered if an error occurs on the socket + void sock_connected(); // triggered if the connection is established and ready to use + +private: + + inline void timerStop(); + void handleClientMsg(PVSMsg receiver); + void handleDisconnectInternal(); + + EventIdentDispatcher<PVSMsg> _commandDispatcher; + EventIdentDispatcher<PVSMsg> _chatDispatcher; + EventIdentDispatcher<PVSMsg> _loginDispatcher; + PVSMsg *_incomplete; + QSslSocket *_socket; + unsigned int _id; + int _timerId; + //QString _host; + //quint16 _port; + int _timer; + PVS *_client; + bool _wasConnected; + QByteArray _expectedFingerprint; + QString _name; + QString _passwd; +}; + +#endif diff --git a/src/net/pvsServiceBroadcast.cpp b/src/net/pvsServiceBroadcast.cpp new file mode 100644 index 0000000..cf15b5b --- /dev/null +++ b/src/net/pvsServiceBroadcast.cpp @@ -0,0 +1,51 @@ +/*
+# 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/
+# -----------------------------------------------------------------------------
+# src/net/pvsServiceBroadcast.cpp
+# - broadcast sessionname
+# -----------------------------------------------------------------------------
+*/
+/********** COMPILE-TIME SETTINGS ***************/
+
+#include "pvsServiceBroadcast.h"
+#include "src/setup.h"
+#include <cassert>
+#include "src/util/serviceDiscoveryUtil.h"
+
+PVSServiceBroadcast::PVSServiceBroadcast()
+{
+ _announce = NULL;
+ _timer = 0;
+ _broadcaster.bind(SD_PORT_CONSOLE);
+ _everyone = QHostAddress(QHostAddress::Broadcast);
+}
+
+PVSServiceBroadcast::~PVSServiceBroadcast()
+{
+ if (_announce != NULL) delete _announce;
+ if (_timer != 0) this->killTimer(_timer);
+}
+
+void PVSServiceBroadcast::setFingerprint(QByteArray sha1)
+{
+ if (_announce != NULL) _announce->clear();
+ else _announce = new QByteArray();
+ appendSdField(_announce, "hsh", QString(sha1.toBase64()));
+ appendSdField(_announce, "prt", SERVER_PORT); // TODO: maybe this has to come from somewhere else if configurable
+ appendSdField(_announce, "aut", "SHA1");
+ if (_timer == 0) _timer = this->startTimer(SB_INTERVAL * 1000);
+}
+
+void PVSServiceBroadcast::timerEvent(QTimerEvent *event)
+{
+ if (_announce == NULL) return;
+ _broadcaster.writeDatagram(*_announce, _everyone, SD_PORT_CLIENT);
+}
diff --git a/src/net/pvsServiceBroadcast.h b/src/net/pvsServiceBroadcast.h new file mode 100644 index 0000000..cf3f63d --- /dev/null +++ b/src/net/pvsServiceBroadcast.h @@ -0,0 +1,46 @@ +/*
+# 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/
+# -----------------------------------------------------------------------------
+# src/net/pvsServiceBroadcast.cpp
+# - broadcast sessionname, port, auth/encryption
+# -----------------------------------------------------------------------------
+*/
+
+#ifndef PVSSERVICEBROADCAST_H_
+#define PVSSERVICEBROADCAST_H_
+
+#include <QtCore/QString>
+#include <QtCore/QObject>
+#include <QtNetwork/QUdpSocket>
+#include "src/net/pvsMsg.h"
+
+class PVSMsg;
+
+class PVSServiceBroadcast : public QObject
+{
+ Q_OBJECT
+
+public:
+ PVSServiceBroadcast();
+ virtual ~PVSServiceBroadcast();
+ void setFingerprint(QByteArray sha1);
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+private:
+ QByteArray *_announce;
+ QUdpSocket _broadcaster;
+ QHostAddress _everyone;
+ int _timer;
+};
+
+#endif /* PVSSERVICEBROADCAST_H_ */
diff --git a/src/net/pvsServiceDiscovery.cpp b/src/net/pvsServiceDiscovery.cpp new file mode 100644 index 0000000..0a99802 --- /dev/null +++ b/src/net/pvsServiceDiscovery.cpp @@ -0,0 +1,181 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/net/pvsServiceDiscovery.cpp +# - handle console broadcasts, tell client to connect on match +# ----------------------------------------------------------------------------- +*/ + +#include <QtCore/QHash> +#include "src/pvs.h" +#include "pvsServiceDiscovery.h" +#include "pvsDiscoveredServer.h" +#include "src/setup.h" +#include "src/util/serviceDiscoveryUtil.h" +#include <cassert> + + + +PVSServiceDiscovery::PVSServiceDiscovery(PVS* client) +{ + assert(client); + bool ret = _sock.bind(SD_PORT_CLIENT); + if (!ret) + { + printf("Could not open SERVICE DISCOVERY port\n"); + exit(1); + } + connect(&_sock, SIGNAL(readyRead()), this, SLOT(sock_dataArrival())); + _currentServer = 0; + _last = QDateTime::currentDateTime(); + _client = client; + _timerId = startTimer(10000); +} + +PVSServiceDiscovery::~PVSServiceDiscovery() +{ + killTimer(_timerId); +} + +void PVSServiceDiscovery::connectToSession(QString name, QString passwd) +{ + _sessionName = name; + _sessionPasswd = passwd; + if (name.length() == 0) return; + for (tServerList::iterator it = _servers.begin(); it != _servers.end(); it++) + { + PVSDiscoveredServer *ds = *it; + if (ds->isValid() && ds->getName() == name) + { + _client->connectToHost(ds, _sessionPasswd); + } + } +} + +void PVSServiceDiscovery::sock_dataArrival() +{ + int len; + while ((len = _sock.pendingDatagramSize()) > -1) + { + if (len == 0) continue; + char *data = new char[len]; + QHostAddress host; + len = _sock.readDatagram(data, len, &host); + SdFields fields = parseSdFields((unsigned char*)data, len); + QDateTime now = QDateTime::currentDateTime(); + if (fields.contains("hsh") && fields.contains("prt") && fields.contains("aut")) + { + if (fields["aut"] == "SHA1") + { + this->handleDiscovery( + host, + atoi(fields["prt"].toUtf8().data()), + QByteArray::fromBase64(fields["hsh"].toAscii()) + ); + } + } + /* + // DEBUG ONLY: connect to any host without matching the session name + if (_last.secsTo(now) > 9 && fields.contains("prt")) + { + _last = now; + int port = atoi(fields["prt"].toUtf8().data()); + _client->connectToHost(host, QByteArray(), port); + } + // ^^^^^^^^^^ + */ + } +} + +void PVSServiceDiscovery::handleDiscovery(QHostAddress host, int port, QByteArray hash) +{ + int numhosts = 0; ///< while iterating we count how many entries have the same host + for (tServerList::iterator it = _servers.begin(); it != _servers.end(); it++) + { + if ((**it).hasHost(host)) + { + ConsoleLog writeNetwork(host.toString() + " == " + (**it).getHost().toString()); + if (++numhosts >= 5) return; // ddos through faked service broadcasts? ignore... + if ((**it).hasFingerprint(hash) && (**it).getPort() == port) // known entry... + { + if ((*it)->isValid() && (*it)->getName() == _sessionName && _sessionName.length() > 0) + { + ConsoleLog writeNetwork(QString("Connecting to ").append(_sessionName)); + _client->connectToHost((*it), _sessionPasswd); + } + (**it).update(port); + return; + } + } + } + if (_servers.length() >= 30) return; // !? + QString oname = sha1ToReadable(hash); + QString name = oname; + int dup = 0; + while (nameExists(name)) + { + name = "(" + QString::number(++dup) + ") " + oname; + } + PVSDiscoveredServer *ds = new PVSDiscoveredServer(this, host, port, hash, name); + connect(ds, SIGNAL(validated(PVSDiscoveredServer*)), this, SLOT(sendServerToGui(PVSDiscoveredServer*))); + _servers.push_back(ds); + setTimerInterval(); +} + +bool PVSServiceDiscovery::nameExists(QString name) +{ + for (tServerList::iterator it = _servers.begin(); it != _servers.end(); it++) + { + if ((**it).getName() == name) return true; + } + return false; +} + +QStringList PVSServiceDiscovery::getAllServers() +{ + QStringList hosts; + for (tServerList::iterator it = _servers.begin(); it != _servers.end(); it++) + { + if ((**it).isValid()) hosts.append((**it).getName()); + } + return hosts; +} + +void PVSServiceDiscovery::sendServerToGui(PVSDiscoveredServer* ds) +{ + _client->guiAddHost(ds->getName()); +} + +void PVSServiceDiscovery::timerEvent(QTimerEvent *event) +{ + if (_servers.size() == 0) return; + if (_currentServer >= _servers.size()) _currentServer = 0; + PVSDiscoveredServer *ds = _servers.at(_currentServer); + if (ds->getAge() >= SB_INTERVAL*2 + 1) // Entry too old? + { + disconnect(ds, SIGNAL(validated(PVSDiscoveredServer*)), this, SLOT(sendServerToGui(PVSDiscoveredServer*))); + _client->guiDelHost(ds->getName()); + delete ds; + _servers.removeAt(_currentServer); // Clean it up + setTimerInterval(); + } + else + { + ds->validateCertificate(); + } + ++_currentServer; +} + +void PVSServiceDiscovery::setTimerInterval() +{ + killTimer(_timerId); + _timerId = startTimer(10000 / (_servers.size() + 1)); +} diff --git a/src/net/pvsServiceDiscovery.h b/src/net/pvsServiceDiscovery.h new file mode 100644 index 0000000..08a38b8 --- /dev/null +++ b/src/net/pvsServiceDiscovery.h @@ -0,0 +1,57 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/net/pvsServiceDiscovery.cpp +# - handle console broadcasts, tell client to connect on match +# ----------------------------------------------------------------------------- +*/ + +#ifndef PVSSERVICEDISCOVERY_H_ +#define PVSSERVICEDISCOVERY_H_ + +#include <QtNetwork/QUdpSocket> +#include <QtCore/QDateTime> + +class PVS; +class PVSDiscoveredServer; +typedef QList<PVSDiscoveredServer*> tServerList; + +class PVSServiceDiscovery : public QObject +{ + Q_OBJECT +public: + PVSServiceDiscovery(PVS* client); + virtual ~PVSServiceDiscovery(); + void connectToSession(QString name, QString passwd); + bool nameExists(QString name); + QStringList getAllServers(); + +protected: + void timerEvent(QTimerEvent *event); + +private Q_SLOTS: + void sock_dataArrival(); + void sendServerToGui(PVSDiscoveredServer*); + +private: + void handleDiscovery(QHostAddress host, int port, QByteArray hash); + void setTimerInterval(); + QUdpSocket _sock; + QString _sessionName; + QString _sessionPasswd; + PVS *_client; + QDateTime _last; ///< to protect us from being abused as a ddos zombie + tServerList _servers; + int _currentServer; + int _timerId; +}; + +#endif /* PVSSERVICEDISCOVERY_H_ */ diff --git a/src/pvs.cpp b/src/pvs.cpp new file mode 100644 index 0000000..2069e36 --- /dev/null +++ b/src/pvs.cpp @@ -0,0 +1,629 @@ +/* + # 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(); + _blankScreen = NULL; + _vncPort = -1; + + // add a notify to the allow file, so we get informed when the file is changed + QString watchPath("/home/"); + watchPath.append(getUserName().append(QString("/.pvs/.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(); + dbus.registerObject("/", this); + dbus.registerService("org.openslx.pvs"); + + _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); + +} + +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; + } + +#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() +{ + if (allowExists()) + { + if (getAllowed()) + { + _vncAllowed = true; + } + else + { + _vncAllowed = false; + } + } + else + { + ConsoleLog writeError("No .allow file found."); + _vncAllowed = false; + //make sure the vncsever is off + ConsoleLog writeError("Shutting down vnc-server because we have no .allow file."); + } + + 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 (fileExists(_vncScriptPath)) + return true; + if (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; + } +} + +void PVS::start() +{ + _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROJECTING", "YES")); +} + +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))); + switch (signal) { + case SIGHUP: + mainClient->quit(); + break; + case SIGTERM: + mainClient->quit(); + break; + case SIGINT: + mainClient->quit(); + break; + case SIGQUIT: + mainClient->quit(); + break; + } + +} + diff --git a/src/pvs.h b/src/pvs.h new file mode 100644 index 0000000..4b1e29e --- /dev/null +++ b/src/pvs.h @@ -0,0 +1,146 @@ +/* + # 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/ + */ +#ifndef PVSCLIENT_H_ +#define PVSCLIENT_H_ + +#include <QtCore> +#include <X11/Xlib.h> +#include <X11/cursorfont.h> +#include <signal.h> + +#include "setup.h" +#include "src/core/pvsChatClient.h" +#include "src/core/pvsChatMsg.h" +#include "src/net/pvsServerConnection.h" +#include "src/version.h" +#include "src/util/consoleLogger.h" +#include "src/util/clientGUIUtils.h" + + +class PVSServiceDiscovery; +class PVSDiscoveredServer; + +/** + * PVSClient + * base class for the pool video switch client + */ +class PVS: public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.openslx.pvs") + +public: + PVS(); + ~PVS(); + + void loadCommands(); ///< not inherited, just named like the virtual methods of other net objects + void onCommand(PVSMsg cmdMessage); ///< not inherited, just named like the virtual methods of other net objects + void onLogin(PVSMsg cmdMessage); ///< not inherited, just named like the virtual methods of other net objects + void onDaemonCommand(PVSMsg cmdMessage); ///< not inherited, just named like the virtual methods of other net objects + void onMessage(PVSMsg cmdMessage); + + void securityUnlock() + { + unlock(); + } + ; ///< public forward to the unlock method + void stop(); ///< stop the client + + void setScriptPath(QString path); ///< vnc-start related + + void onConnected(QString name); + void onDisconnected(); + + void connectToHost(PVSDiscoveredServer* server, QString passwd); + void UpdateChatClients(PVSChatMsg chatCommand); + void chat_receive(PVSChatMsg msg); + + void guiAddHost(QString host); + void guiDelHost(QString host); + +public Q_SLOTS: + void start(); + void quit(); + void chat_send(QString nick_to, QString nick_from, QString msg); + QString chat_getNickname(); + QStringList chat_getNicknames(); + void fileChanged(const QString& path); + void pvsConnect(QString host, QString passwd); + void pvsDisconnect(); + QString isConnected(); + QStringList getAvailableHosts(); + QString getIpByNick(QString nick); + +Q_SIGNALS: + void project(QString host, int port, QString passwd, bool fullscreen, + bool smoothTransformation, int quality); + void unproject(); + void chat_receive(QString nick_from, QString nick_to, QString msg); + void chat_client_add(QString nick); + void chat_client_remove(QString nick); + void showMessage(QString title, QString msg, bool useDialog = false); + void connected(QString host); + void disconnected(); + void addHost(QString host); + void delHost(QString host); + +protected: + + void timerEvent(QTimerEvent *event); + +private: + + // own + bool allowExists(); ///< whether the .allow file exists + bool getVNCAllow(); ///< whether vnc-connections to this client are allowed + void readPolicyFiles(); ///< pars the policy files + + + // pvs features and related + bool lock(); ///< lock this client (blankscreen etc) + bool lock_inputs(); ///< lock this client mouse&keyboard only + bool unlock(); ///< remove the lock on this client + + bool _locked; ///< are we locked? + QString _lockMsg; ///< message to display while we're locked + bool _vncAllowed; ///< whether vncConnections to this client are allowed (dup?) + BlankScreen *_blankScreen;///< obhject to blank the screen + + QFileSystemWatcher* _notify; ///< used to get notifies about file changes + //vnc-server + QString _vncScriptPath; ///< path to the vnc script file + QString _vncScriptName; ///< name of the vnc script file + int _vncPort; ///< port to use for the vnc-server (also gets send to the pvsServer) + QString _vncPassword; ///< password to use for the vnc-server (also gets send to the pvsServer) - viewonly password + QString _vncRwPassword; ///< password to use for the vnc-server (also gets send to the pvsServer) - read-write password + + bool gotVNCScript(); ///< whether we got a vnc script + int bootVNC(); ///< init the password and port, then call the startVNCScript() method + int startVNCScript(int port, QString pass, QString rwpass); ///< start the vnc server (via script) + int stopVNCScript(); ///< stop the vnc server (via script) + static void signalHandler(int signal); //handles posix signals + + PVSServerConnection* _pvsServerConnection; ///< our tcp connection object to the pvsserver + + QSettings _settings; + + PVSServiceDiscovery *_sdClient; + + PVSChatClient *_chat; + + bool _vncRequested; ///< did pvsmgr request our screen? + + int _timerLockTest; + int _timerLockDelay; + +}; +#endif /* PVSCLIENT_H_ */ diff --git a/src/pvsDaemon.cpp b/src/pvsDaemon.cpp new file mode 100644 index 0000000..961e0f3 --- /dev/null +++ b/src/pvsDaemon.cpp @@ -0,0 +1,362 @@ +#include <QCoreApplication> +#include <getopt.h> +#include <stdlib.h> +#include "pvs.h" +#include "src/net/pvsLocalhostCommunicator.h" +#include "src/util/pvsSettingsManager.h" +#include "setup.h" +#include "src/net/pvsMsg.h" +#include "src/core/pvsChatClient.h" + +PVS *mainClient = NULL; + +// This define works as a switch whether to run as deamon or regular app +#define as_daemon + +/// VERSION_STRING is defined in src/version.h +void printVersion(bool doExit) +{ + + printf("Version:\t"VERSION_STRING"\n"); + if (doExit) + exit(0); +} + +/// outputs the full help text +void printHelp() +{ + printf("**************************************************************\n"); + printf("\nPool Video Switch Client\n"); + printf("**************************************************************\n"); + printVersion(false); + printf("**************************************************************\n"); + printf("Usage:\tpoolVSClient <<option> <value>, ... >\n\n"); + printf("Options:\n\n"); + printf("-vncScriptFile <fullpath\\filename>\n\tSpecifies a custom location for the vnc-start/stop-script.\n\tIf not specified, ~/.pvs/pvs-vncsrv is expected.\n\n"); + printf("-freq <seconds>\n\tSpecifies how long to wait until a reconnection attempt is made.\n\tDefault is 5.\n\n"); + printf("-port <port>\n\tSpecifies on which port to run.\n\tDefault is %d.\n\n", SERVER_PORT_INT); + printf("-h or --help\n\t Shows this help text and exits.\n\n"); + printf("-v or --version\n\t Shows the current version and exits.\n"); + printf( + "-c <string command>:<string value> \n\t Sends the command and the optional value to a running PVS-Client.\n\t Command and value may not contain spaces or colons.\n\t The dividing colon is mandatory.\n"); + printf("-commands: \n\tPrints out available commands to use with -c . \n "); + printf("**************************************************************\n"); + exit(0); +} + +/// outputs a brief help text +void printNotice() +{ + printf( + "Use -h or --help to get a listing of all options.\n-v or --version gives you the current version.\n\n"); +} + +void printCommands() +{ + printf("**************************************************************\n"); + printf("chat:<on/ off/ 1/ 2/ 3>\n "); + printf("on = turns that chat option on\n off = turns the chat option off\n 1 = bossmode\n 2 = community\n 3 = private\n"); + printf("stop \n\t Stops the running PVS-Client.\n"); + printf("**************************************************************\n"); + exit(0); +} + +/// +int main(int argc, char** argv) +{ + int frequency = 5; + int port = -1; + QString homeDir("/home/"); + QString scriptPath = homeDir; + scriptPath.append(getUserName().append(QString("/.pvs/pvs-vncsrv"))); + QString scriptName; + scriptName = getFilenameFromPath(scriptPath); + + QCoreApplication app(argc, argv); + app.setOrganizationName("openslx"); + app.setOrganizationDomain("openslx.org"); + app.setApplicationName("pvs"); + // use system locale as language to translate gui + QTranslator translator; + translator.load(":pvs"); + app.installTranslator(&translator); + + + PVSLocalhostCommunicator com(getPolicyFilePath(QString( + ".comfile"))); + com.run(); + if (!(com.running())) + { + printf("Error. UDS Communicator is not running. Exiting.\n"); + exit(0); + } + + printf("UDS Communicator is running.\n"); + int option_index = 0; + + while (1) + { + static struct option long_options[] = + { + { "help", no_argument, 0, 'h' }, + { "commands", no_argument, 0, 'o' }, + { "version", no_argument, 0, 'v' }, + { "port", required_argument, 0, 'p' }, + { "freq", required_argument, 0, 'f' }, + { "client", required_argument, 0, 'e' }, + { "script", required_argument, 0, 's' }, + { 0, 0, 0, 0 }, + }; + /* getopt_long stores the option index here. */ + + int c = getopt_long(argc, argv, "hvoc:f:e:s:p:", long_options, + &option_index); + option_index++; + if (c == -1) + break; + + switch (c) + { + case 'h': + printHelp(); + break; + case 'o': + printCommands(); + break; + case 'v': + printVersion(true); + break; + case 'c': + { + if (option_index + 1 < argc) + { + if (com.server()) + { + // wont work, no daemon running + printf("Error. No running PVS-Client found. Exiting.\n"); + com.stop(); + } + else + { + QStringList line = QString::fromLocal8Bit(argv[option_index + + 1]).split(":"); + QString &ident = line[0]; + QString message; + if (line.size() > 1) + message = line[1]; + if (ident.size() > 0) // no use sending empty idents... not even sure if this COULD happen + { + bool flag = false; + if (ident == "make") + PVSSettingsManager::getManager()->setConfigs(); + else if (ident == "chat" && message == "boss") + { + PVSSettingsManager::getManager()->reWriteConfigs("chatmode", "bossmode"); + flag = true; + + } + else if (ident == "chat" && message == "all") + { + PVSSettingsManager::getManager()->reWriteConfigs("chatmode", "community"); + flag = true; + } + else if (ident == "chat" && message == "private") + { + PVSSettingsManager::getManager()->reWriteConfigs("chatmode", "private"); + flag = true; + } + else if (ident == "chat" && message == "on") + { + PVSSettingsManager::getManager()->reWriteConfigs("chatstate", "on"); + flag = true; + } + else if (ident == "chat" && message == "off") + { + PVSSettingsManager::getManager()->reWriteConfigs("chatstate", "off"); + flag = true; + } + else if (ident == "room") + { + //PVSSettingsManager::getManager()->reWriteConfigs(ident, message); + flag = true; + } + else if (ident == "stop" && message == NULL) + flag = true; + else + printf("option %s doesn't exist\n", ident.toUtf8().data()); + + if (flag) + { + qDebug("Will send i: %s, m: %s\n", ident.toUtf8().data(), message.toUtf8().data()); + com.sendCommand(ident, message); + QCoreApplication::processEvents(QEventLoop::AllEvents); + printf("Sent command. Exiting.\n"); + } + } + + else + printf("Something went horribly wrong, since the ident is empty.\n"); + + } + } + else + { + printf("Error. No command issued. Exiting.\n"); + } + exit(0); // and gone + break; + } + case 'f': + { + if (option_index + 1 < argc) + { + frequency = atoi(argv[option_index + 1]); + if (frequency <= 0) + { + frequency = 5; // return to standard + ConsoleLog writeError(QString( + "malformed frequency, setting standard = 5")); + printNotice(); + } + else + ConsoleLog writeLine(QString("Using frequency ").append( + int2String(frequency))); + option_index++; + continue; + } + break; + } + case 'p': + { + if (option_index + 1 < argc) + { + port = atoi(argv[option_index + 1]); + if (port <= 0) + { + ConsoleLog writeTerminal(QString("port maybe malformed")); + printNotice(); + port = -1; // return to standard + } + else + ConsoleLog writeTerminal(QString("Using port ").append( + int2String(port))); + option_index++; + continue; + } + break; + } + case 'e': + { + if (option_index + 1 < argc) + { + printf("WARNING: -e is deprecated\n"); + option_index++; + continue; + } + break; + } + case 's': + { + if (option_index + 1 < argc) + { + scriptPath = QString(argv[option_index + 1]); + scriptName = getFilenameFromPath(scriptPath); + option_index++; + continue; + } + break; + } + case '?': + { + ConsoleLog writeError( + QString("Unrecognized option/paramter: ").append( + argv[option_index])); + printNotice(); + } + default: + abort(); + } + //else + // printNotice(); + } + + if (!com.server()) + { + printf("Error. PoolVSClient already running. Exiting\n"); + com.stop(); + exit(0); + } + + ConsoleLog setLogName(QString("log.client")); + ConsoleLog writeLine(QString("PVS-Client started.")); + +#ifdef as_daemon + + /* Our process ID and Session ID */ + pid_t pid, sid; + + /* Fork off the parent process */ + pid = fork(); + if (pid < 0) + { + exit(-1); + } + /* If we got a good PID, then + we can exit the parent process. */ + if (pid > 0) + { + exit(0); + } + + /* Change the file mode mask */ + umask(0); + + /* Open any logs here */ + + /* Create a new SID for the child process */ + sid = setsid(); + if (sid < 0) + { + /* Log the failure */ + exit(-1); + } + + /* Change the current working directory */ + if ((chdir("/")) < 0) + { + /* Log the failure */ + exit(-1); + } + + /* Close out the standard file descriptors */ + close(STDIN_FILENO); + freopen ((QString("/home/").append(getUserName().append(QString("/.pvs/dump")))).toUtf8().data(),"w",stdout); + //close(STDOUT_FILENO); + close(STDERR_FILENO); + + /* Daemon-specific initialization goes here */ + + /* The Big Loop */ + +#endif + + mainClient = new PVS(); + PVSSettingsManager::getManager()->setConfigFile(getPolicyFilePath("clientconf")); + com.getDispatcher()->addListener("*", mainClient, &PVS::onDaemonCommand); + + if (port <= 0) + port = SERVER_PORT_INT; + ConsoleLog writeLine(QString("TCP-Port: ").append(int2String(port))); + mainClient->setScriptPath(scriptPath); + ConsoleLog writeLine(QString("VNCScriptPath: ").append(scriptPath)); + createPolicyDir(); + createPolicyFiles(); + + // long int gr = 0; + mainClient->setScriptPath(scriptPath); + app.exec(); + delete mainClient; + + return 0; +} + diff --git a/src/pvsgui.cpp b/src/pvsgui.cpp new file mode 100644 index 0000000..25f1cd6 --- /dev/null +++ b/src/pvsgui.cpp @@ -0,0 +1,444 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + # ----------------------------------------------------------------------------- + # pvsClientGUI.cpp + # - main loop for pvs client GUI. + # - draws toolbar and system tray icon. + # - uses DBUS to communicate with pvs client. + # ----------------------------------------------------------------------------- + */ + +#include "pvsgui.h" + +PVSGUI::PVSGUI(QWidget *parent) : + QWidget(parent) +{ + setupUi(this); + + _menu = new QMenu(this); + _hostMenu = new QMenu(tr("Connect"), this); + _hosts = new QHash<QString, QAction*> (); + _vncViewer = new ClientVNCViewer(); + _chatDialog = new ClientChatDialog(); + _configDialog = new ClientConfigDialog(); + _infoDialog = new ClientInfoDialog(); + _aboutDialog = new AboutDialog(); + + _hostMenu->setEnabled(false); + hostButton->setEnabled(false); + + setupMenu(); + + if (QSystemTrayIcon::isSystemTrayAvailable()) + { + qDebug("[%s] System tray available.", metaObject()->className()); + _trayIcon = new QSystemTrayIcon(QIcon(":cam_off32.svg"), this); + _trayIcon->setContextMenu(_menu); + _trayIcon->setVisible(true); + _chatDialog->setTrayIcon(_trayIcon); + } + else + _trayIcon = NULL; + + // connect to D-Bus and get interface + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.registerObject("/", this); + dbus.registerService("org.openslx.pvsgui"); + _ifaceDBus = new OrgOpenslxPvsInterface("org.openslx.pvs", "/", dbus, this); + _ifaceDBus->start(); // start pvs if not running + + // get available hosts + QDBusPendingReply<QStringList> reply0 = _ifaceDBus->getAvailableHosts(); + reply0.waitForFinished(); + QStringList hosts = reply0.value(); + if (reply0.isValid() && !hosts.isEmpty()) + foreach (QString host, hosts) + addHost(host); + + // already connected? + QDBusPendingReply<QString> reply1 = _ifaceDBus->isConnected(); + reply1.waitForFinished(); + QString host = reply1.value(); + if (reply1.isValid() && host != "") + connected(host); + else + disconnected(); + + if (dbus.isConnected()) + qDebug("[%s] Connection to DBus successful!", metaObject()->className()); + + // TODO: perhaps this can go if fadi does his work + // check if vnc is allowed and setup checkbox + QFile file(QDir::toNativeSeparators(QDir::homePath() + "/.pvs/.allow")); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QTextStream in(&file); + QString line = in.readLine(); + if (line == "1") + vncCheckBox->setChecked(true); + file.close(); + } + + // listen on port 29481 for incoming file transfers + _serverSocket = new QTcpServer(); + _serverSocket->listen(QHostAddress::Any, 29481); + connect(_serverSocket, SIGNAL(newConnection()), this, SLOT(receiveFile())); + + // signals & slots - menu + connect(_disconnectAction, SIGNAL(triggered()), this, SLOT(pvsDisconnect())); + connect(_startChatAction, SIGNAL(triggered()), _chatDialog, SLOT(open())); + connect(_sendFileAction, SIGNAL(triggered()), this, SLOT(sendFile())); + connect(_configAction, SIGNAL(triggered()), _configDialog, SLOT(open())); + connect(_showInfoAction, SIGNAL(triggered()), _infoDialog, SLOT(open())); + connect(_aboutAction, SIGNAL(triggered()), _aboutDialog, SLOT(open())); + connect(_quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + connect(_configDialog, SIGNAL(configChanged()), this, SLOT(updateConfig())); + + // signals & slots - toolbar + connect(_menu, SIGNAL(aboutToHide()), this, SLOT(hide())); + connect(_hostMenu, SIGNAL(aboutToHide()), this, SLOT(hide())); + connect(_hostMenu, SIGNAL(triggered(QAction*)), this, + SLOT(pvsConnect(QAction*))); + connect(vncCheckBox, SIGNAL(stateChanged(int)), this, + SLOT(setVncAllow(int))); + + // signals & slots - dbus + connect(_ifaceDBus, SIGNAL(showMessage(QString, QString, bool)), this, + SLOT(showMessage(QString, QString, bool))); + connect(_ifaceDBus, SIGNAL(connected(QString)), this, + SLOT(connected(QString))); + connect(_ifaceDBus, SIGNAL(disconnected()), this, SLOT(disconnected())); + connect(_ifaceDBus, SIGNAL(addHost(QString)), this, SLOT(addHost(QString))); + connect(_ifaceDBus, SIGNAL(delHost(QString)), this, SLOT(delHost(QString))); + + // show toolbar + setWindowFlags(Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint); + setAttribute(Qt::WA_AlwaysShowToolTips); + updateConfig(); + setVisible(true); + hide(); +} + +PVSGUI::~PVSGUI() +{ + _ifaceDBus->quit(); +} + +//////////////////////////////////////////////////////////////////////////////// +// Public + +void PVSGUI::updateConfig() +{ + if (_settings.value("Display/location").isNull()) + setLocation(POSITION_TOP_CENTER); + else + setLocation(_settings.value("Display/location").toInt()); +} + +//////////////////////////////////////////////////////////////////////////////// +// Protected + +void PVSGUI::leaveEvent(QEvent * e) +{ + if (!_menu->isVisible() && !_hostMenu->isVisible()) + hide(true); + QWidget::leaveEvent(e); +} + +void PVSGUI::enterEvent(QEvent * e) +{ + hide(false); + QWidget::enterEvent(e); +} + +void PVSGUI::mousePressEvent(QMouseEvent *event) +{ + QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor)); + _clickPoint = event->pos(); +} + +void PVSGUI::mouseReleaseEvent(QMouseEvent *event) +{ + QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor)); +} + +void PVSGUI::mouseMoveEvent(QMouseEvent *event) +{ + if (event->globalX() - _clickPoint.x() >= 0 && event->globalX() + - _clickPoint.x() + width() <= QApplication::desktop()->width()) + { + move(event->globalX() - _clickPoint.x(), y()); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Private + +void PVSGUI::setupMenu() +{ + // setup actions + _disconnectAction = new QAction(tr("&Disconnect"), this); + _startChatAction = new QAction(tr("C&hat"), this); + _sendFileAction = new QAction(tr("&Send File"), this); + _configAction = new QAction(tr("&Config"), this); + _showInfoAction = new QAction(tr("&Information"), this); + _aboutAction = new QAction(tr("&About"), this); + _quitAction = new QAction(tr("&Quit"), this); + + // setup menu + _menu->addMenu(_hostMenu); + _menu->addAction(_disconnectAction); + _menu->addAction(_showInfoAction); + _menu->addSeparator(); + _menu->addAction(_startChatAction); + _menu->addAction(_sendFileAction); + _menu->addSeparator(); + _menu->addAction(_configAction); + _menu->addAction(_aboutAction); + _menu->addSeparator(); + _menu->addAction(_quitAction); + + pvsButton->setMenu(_menu); + hostButton->setMenu(_hostMenu); +} + +void PVSGUI::setLocation(int location) +{ + _location = location; + switch (_location) + { + case POSITION_TOP_LEFT: + move(0, 0); + break; + case POSITION_TOP_CENTER: + move((QApplication::desktop()->width() - width()) / 2, 0); + break; + case POSITION_TOP_RIGHT: + move(QApplication::desktop()->width() - width(), 0); + break; + case POSITION_BOTTOM_LEFT: + move(0, QApplication::desktop()->height() - height()); + break; + case POSITION_BOTTOM_CENTER: + move((QApplication::desktop()->width() - width()) / 2, + QApplication::desktop()->height() - height()); + break; + case POSITION_BOTTOM_RIGHT: + move(QApplication::desktop()->width() - width(), + QApplication::desktop()->height() - height()); + break; + default: + break; + } +} + +void PVSGUI::hide(bool b) +{ + if (b) + { + if (_location <= POSITION_TOP_RIGHT) + move(x(), 2 - height()); + else + move(x(), QApplication::desktop()->height() - 2); + } + else + { + if (_location <= POSITION_TOP_RIGHT) + move(x(), 0); + else + move(x(), QApplication::desktop()->height() - height()); + } +} + +void PVSGUI::hide() +{ + if (!_menu->isVisible() && !_hostMenu->isVisible()) + hide(true); +} + +void PVSGUI::pvsConnect(QAction *action) +{ + QString host = action->text(); + action->setChecked(false); // we set it manually + + // already connected? + if (host == hostButton->text()) + { + action->setChecked(true); + return; + } + + // ask user for passwd + bool ok = false; + QString passwd = QInputDialog::getText(0, tr("PVS Connection"), tr( + "Please enter password (If not needed leave blank):"), + QLineEdit::Password, QString(), &ok); + + if (ok) + { + _ifaceDBus->pvsConnect(host, passwd); // send via dbus + _passwd = passwd; // TODO: we have to ask the backend for passwd! + qDebug("[%s] Host '%s' send via DBus.", metaObject()->className(), + qPrintable(host)); + } +} + +void PVSGUI::pvsDisconnect() +{ + QMessageBox::StandardButton result = QMessageBox::question(0, tr( + "PVS Connection"), tr("Are you sure you want to disconnect?"), + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok); + + if (result == QMessageBox::Ok) + _ifaceDBus->pvsDisconnect(); +} + +void PVSGUI::showMessage(QString title, QString msg, bool useDialog) +{ + if (!isVisible()) + return; + + // show balloon message if supported, otherwise show message dialog + if (!useDialog && _trayIcon && QSystemTrayIcon::supportsMessages()) + _trayIcon->showMessage(title, msg, QSystemTrayIcon::Information, 10000); + else + QMessageBox::about(0, title, msg); +} + +void PVSGUI::connected(QString host) +{ + statusLabel->setText( + "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\"><html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">p, li { white-space: pre-wrap; }</style></head><body style=\" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;\"><p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" color:#00aa00;\">Online</span></p></body></html>"); + showMessage(tr("PVS connection"), tr("Connected to ") + host); + if (_hosts->contains(host)) + _hosts->value(host)->setChecked(true); + hostButton->setText(host); + _disconnectAction->setEnabled(true); + _startChatAction->setEnabled(true); + _sendFileAction->setEnabled(true); + _showInfoAction->setEnabled(true); + _infoDialog->setHost(host); + _infoDialog->setPasswd(_passwd); + + if (_trayIcon) + { + _trayIcon->setIcon(QIcon(":cam_on32.svg")); + _trayIcon->setToolTip(tr("Connected to ") + host); + } +} + +void PVSGUI::disconnected() +{ + statusLabel->setText( + "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\"><html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">p, li { white-space: pre-wrap; }</style></head><body style=\" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;\"><p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" color:#ff0000;\">Offline</span></p></body></html>"); + showMessage(tr("PVS connection"), tr("Disconnected")); + if (_hosts->contains(hostButton->text())) + _hosts->value(hostButton->text())->setChecked(false); + hostButton->setText("-"); + _disconnectAction->setEnabled(false); + _startChatAction->setEnabled(false); + _sendFileAction->setEnabled(false); + _showInfoAction->setEnabled(false); + _passwd = ""; + if (_trayIcon) + { + _trayIcon->setIcon(QIcon(":cam_off32.svg")); + _trayIcon->setToolTip(tr("Disconnected")); + } + _vncViewer->close(); +} + +void PVSGUI::addHost(QString host) +{ + // avoid duplicates + if (_hosts->contains(host)) + return; + + QAction *action = _hostMenu->addAction(host); + action->setCheckable(true); + _hosts->insert(host, action); + + if (!_hosts->isEmpty()) + { + _hostMenu->setEnabled(true); + hostButton->setEnabled(true); + } + + if (hostButton->text() == "-") + showMessage(tr("PVS Connection"), tr("New host available: ") + host); +} + +void PVSGUI::delHost(QString host) +{ + if (_hosts->contains(host)) + { + _hostMenu->removeAction(_hosts->value(host)); + _hosts->remove(host); + } + + if (_hosts->isEmpty()) + { + _hostMenu->setEnabled(false); + hostButton->setEnabled(false); + } +} + +// TODO: perhaps this can go if fadi does his work +void PVSGUI::setVncAllow(int i) +{ + QFile file(QDir::toNativeSeparators(QDir::homePath() + "/.pvs/.allow")); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) + return; + + QTextStream out(&file); + if (i == 0) + out << 0; + else + out << 1; + + file.close(); +} + +void PVSGUI::sendFile() +{ + ClientFileSendDialog *d = new ClientFileSendDialog(); + d->open(); +} + +void PVSGUI::receiveFile() +{ + QTcpSocket *socket = _serverSocket->nextPendingConnection(); + ClientFileReceiveDialog *d = new ClientFileReceiveDialog(socket); + d->open(); +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Main + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + app.setOrganizationName("openslx"); + app.setOrganizationDomain("openslx.org"); + app.setApplicationName("pvsgui"); + + // use system locale as language to translate gui + QTranslator translator; + translator.load(":pvsgui"); + app.installTranslator(&translator); + + PVSGUI pvsgui; + + return app.exec(); +} diff --git a/src/pvsgui.h b/src/pvsgui.h new file mode 100644 index 0000000..f9a0ab8 --- /dev/null +++ b/src/pvsgui.h @@ -0,0 +1,103 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + */ + +#ifndef PVSCLIENTGUI_H_ +#define PVSCLIENTGUI_H_ + +#include <QtGui> +#include <QtNetwork> +#include "ui_clientToolbar.h" +#include "src/gui/clientConfigDialog.h" +#include "src/gui/clientChatDialog.h" +#include "src/gui/clientFileSendDialog.h" +#include "src/gui/clientFileReceiveDialog.h" +#include "src/gui/clientVNCViewer.h" +#include "src/gui/clientInfoDialog.h" +#include "src/gui/aboutDialog.h" + +#include "pvsinterface.h" + +class PVSGUI: public QWidget, private Ui_ClientToolbarClass +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.openslx.pvsgui") + +public: + PVSGUI(QWidget *parent = 0); + ~PVSGUI(); + + int const static POSITION_TOP_LEFT = 0; + int const static POSITION_TOP_CENTER = 1; + int const static POSITION_TOP_RIGHT = 2; + int const static POSITION_BOTTOM_LEFT = 3; + int const static POSITION_BOTTOM_CENTER = 4; + int const static POSITION_BOTTOM_RIGHT = 5; + +public Q_SLOTS: + void updateConfig(); + +protected: + void enterEvent(QEvent *e); + void leaveEvent(QEvent *e); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + +private Q_SLOTS: + void showMessage(QString title, QString msg, bool useDialog = false); + void hide(); + void connected(QString host); + void disconnected(); + void addHost(QString host); + void delHost(QString host); + void pvsConnect(QAction *action); + void pvsDisconnect(); + void setVncAllow(int i); + void sendFile(); + void receiveFile(); + +private: + void setupMenu(); + void setLocation(int location); + void hide(bool b); + + QMenu *_menu; + QMenu *_hostMenu; + QHash<QString, QAction*> *_hosts; + QSettings _settings; + QSystemTrayIcon *_trayIcon; + ClientChatDialog *_chatDialog; + ClientConfigDialog *_configDialog; + ClientInfoDialog *_infoDialog; + ClientVNCViewer *_vncViewer; + AboutDialog *_aboutDialog; + + QAction *_disconnectAction; + QAction *_startChatAction; + QAction *_sendFileAction; + QAction *_configAction; + QAction *_showInfoAction; + QAction *_aboutAction; + QAction *_quitAction; + + int _location; + QPoint _clickPoint; + QString _passwd; + + QTcpServer *_serverSocket; + + OrgOpenslxPvsInterface *_ifaceDBus; + +}; + +#endif /* PVSCLIENTGUI_H_ */ diff --git a/src/pvsmgr.cpp b/src/pvsmgr.cpp new file mode 100644 index 0000000..83f5fe0 --- /dev/null +++ b/src/pvsmgr.cpp @@ -0,0 +1,55 @@ +/* + # 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/ + # ----------------------------------------------------------------------------- + # pvs.cpp + # - main loop for pvsmgr GUI. + # ----------------------------------------------------------------------------- + */ + +#include <QtGui> +#include <QtGui/QDesktopServices> +#include "gui/mainWindow.h" +#include "util/consoleLogger.h" +#include "util/pvsSettingsManager.h" +#include "util/CertManager.h" + +QApplication *qtApp; + +int main(int argc, char** argv) +{ + //system("openssl genrsa 1024 >~/.pvs/"); + qtApp = new QApplication(argc, argv); + qtApp->setOrganizationName("openslx"); + qtApp->setOrganizationDomain("openslx.org"); + qtApp->setApplicationName("pvsmgr"); + + // use system locale as language to translate gui + QTranslator translator; + translator.load(":pvsmgr"); + qtApp->installTranslator(&translator); + + ConsoleLog setLogName(QString("log.server")); + ConsoleLog writeLine(QString("PVS-Server started.")); + + QSslKey k = CertManager::getPrivateKey("manager"); // preload key so the gui won't hang later + /* + if (k.isNull()) + { + printf("FATAL: Private key could not be generated or loaded!\n"); + exit(123); + } + */ + PVSSettingsManager::getManager()->setConfigFile(getPolicyFilePath("serverconf")); + MainWindow w; + w.show(); + return qtApp->exec(); +} + diff --git a/src/pvsmgrtouch.cpp b/src/pvsmgrtouch.cpp new file mode 100644 index 0000000..fa34294 --- /dev/null +++ b/src/pvsmgrtouch.cpp @@ -0,0 +1,55 @@ +/* + # 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/ + # ----------------------------------------------------------------------------- + # pvs.cpp + # - main loop for pvs GUI. + # ----------------------------------------------------------------------------- + */ + +#include <QtGui> +#include <QtGui/QDesktopServices> +#include "gui/touchgui.h" +#include "util/consoleLogger.h" +#include "util/pvsSettingsManager.h" +#include "util/CertManager.h" + +QApplication *qtApp; + +int main(int argc, char** argv) +{ + //system("openssl genrsa 1024 >~/.pvs/"); + qtApp = new QApplication(argc, argv); + qtApp->setOrganizationName("openslx"); + qtApp->setOrganizationDomain("openslx.org"); + qtApp->setApplicationName("pvsmgr"); + + // use system locale as language to translate gui + /*QTranslator translator; + translator.load(":pvsmgr"); + qtApp->installTranslator(&translator);*/ + + ConsoleLog setLogName(QString("log.server")); + ConsoleLog writeLine(QString("PVS-Server started.")); + + QSslKey k = CertManager::getPrivateKey("manager"); // preload key so the gui won't hang later + /* + if (k.isNull()) + { + printf("FATAL: Private key could not be generated or loaded!\n"); + exit(123); + } + */ + PVSSettingsManager::getManager()->setConfigFile(getPolicyFilePath("serverconf")); + pvsMainWindow w; + w.show(); + return qtApp->exec(); +} + diff --git a/src/setup.h b/src/setup.h new file mode 100644 index 0000000..4a21754 --- /dev/null +++ b/src/setup.h @@ -0,0 +1,13 @@ +#ifndef _SETUP_H_
+#define _SETUP_H_
+
+#define SERVER_PORT "3490" // the port users will be connecting to
+#define SERVER_PORT_INT 3490 // the port users will be connecting to
+#define VNC_PORT_STRING "59000"
+#define VNC_PORT_INT 59000
+
+#define SB_INTERVAL 7 // Broadcast interval in seconds
+#define SD_PORT_CONSOLE 3491 // Not really used, Qt just wants a bind
+#define SD_PORT_CLIENT 3492 // This is where we expect announcements
+
+#endif
diff --git a/src/util/CertManager.cpp b/src/util/CertManager.cpp new file mode 100644 index 0000000..99d2438 --- /dev/null +++ b/src/util/CertManager.cpp @@ -0,0 +1,87 @@ +/*
+# 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/
+# -----------------------------------------------------------------------------
+# src/util/CertManager.cpp
+# - Manage SSL certificates
+# - provide access by name
+# -----------------------------------------------------------------------------
+*/
+
+#include "CertManager.h"
+#include "util.h"
+#include <QMap>
+#include <QFileInfo>
+#include <cstdlib>
+
+namespace CertManager
+{
+ static QMap<QString, QSslCertificate> _certs;
+ static QMap<QString, QSslKey> _keys;
+
+ void generateFiles(QString key, QString cert);
+
+ QSslKey getPrivateKey(QString name) {
+ if (_keys.contains(name)) return _keys[name];
+ QString cert = getPolicyFilePath(name);
+ QString key = cert;
+ key.append(".rsa");
+ cert.append(".crt");
+ //
+ QFileInfo keyfile(key);
+ QFileInfo certfile(cert);
+ if (keyfile.exists() && certfile.exists())
+ { // It wouldn't make sense to have one without the other
+ if (getCertificate(name).isNull()) return QSslKey();
+ QFile f(key);
+ f.open(QFile::ReadOnly);
+ QSslKey k = QSslKey(&f, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
+ _keys.insert(name, k);
+ return k;
+ }
+ generateFiles(key, cert);
+ keyfile = QFileInfo(key);
+ if (!keyfile.exists() || getCertificate(name).isNull()) return QSslKey();
+ QFile f(key);
+ f.open(QFile::ReadOnly);
+ QSslKey k = QSslKey(&f, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
+ if (!k.isNull()) _keys.insert(name, k);
+ return k;
+ }
+
+ QSslCertificate getCertificate(QString name) {
+ if (_certs.contains(name)) return _certs[name];
+ QString cert = getPolicyFilePath(name);
+ cert.append(".crt");
+ //
+ QFileInfo certfile(cert);
+ if (certfile.exists())
+ {
+ QList<QSslCertificate> certlist = QSslCertificate::fromPath(cert);
+ if (certlist.empty()) return QSslCertificate();
+ QSslCertificate c = certlist.first();
+ if (!c.isNull()) _certs.insert(name, c);
+ return c;
+ }
+ return QSslCertificate();
+ }
+
+ void generateFiles(QString key, QString cert)
+ {
+ char tmp[1000];
+ unlink(key.toLocal8Bit().data());
+ unlink(cert.toLocal8Bit().data());
+ snprintf(tmp, 1000, "openssl req -x509 -nodes -days 3650 -newkey rsa:1024 -subj '/C=DE/ST=BaWue/L=Freiburg/CN=openslx.org' -keyout \"%s\" -out \"%s\"",
+ key.toLocal8Bit().data(), cert.toLocal8Bit().data());
+ system(tmp);
+ snprintf(tmp, 1000, "chmod 0600 \"%s\" \"%s\"", key.toLocal8Bit().data(), cert.toLocal8Bit().data());
+ system(tmp);
+ }
+}
diff --git a/src/util/CertManager.h b/src/util/CertManager.h new file mode 100644 index 0000000..8caab8b --- /dev/null +++ b/src/util/CertManager.h @@ -0,0 +1,30 @@ +/*
+# 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/
+# -----------------------------------------------------------------------------
+# src/util/CertManager.cpp
+# - Manage SSL certificates
+# - provide access by name
+# -----------------------------------------------------------------------------
+*/
+
+#ifndef CERTMANAGER_H_
+#define CERTMANAGER_H_
+
+#include <QtNetwork/QSslCertificate>
+#include <QtNetwork/QSslKey>
+
+namespace CertManager
+{
+ QSslKey getPrivateKey(QString name);
+ QSslCertificate getCertificate(QString name);
+}
+
+#endif /* CERTMANAGER_H_ */
diff --git a/src/util/TextFile.cpp b/src/util/TextFile.cpp new file mode 100644 index 0000000..0d04e47 --- /dev/null +++ b/src/util/TextFile.cpp @@ -0,0 +1,39 @@ +/*
+ * TextFile.cpp
+ *
+ * Created on: 13.02.2010
+ * Author: Zahl
+ */
+
+#include "TextFile.h"
+
+TextFile::TextFile(QString filename) : QTextStream()
+{
+ _file = new QFile(filename);
+ if (_file->open(QIODevice::ReadOnly))
+ {
+ this->setDevice(_file);
+ _good = true;
+ }
+ else
+ {
+ _good = false;
+ }
+}
+
+bool TextFile::good()
+{
+ return _good;
+}
+
+bool TextFile::eof()
+{
+ if (!_good || this->atEnd()) return true;
+ return false;
+}
+
+TextFile::~TextFile()
+{
+ _file->close();
+ delete _file;
+}
diff --git a/src/util/TextFile.h b/src/util/TextFile.h new file mode 100644 index 0000000..49932fa --- /dev/null +++ b/src/util/TextFile.h @@ -0,0 +1,26 @@ +/*
+ * TextFile.h
+ *
+ * Created on: 13.02.2010
+ * Author: Zahl
+ */
+
+#ifndef TEXTFILE_H_
+#define TEXTFILE_H_
+
+#include <QtCore/QFile>
+#include <QtCore/QTextStream>
+
+class TextFile : public QTextStream
+{
+public:
+ TextFile(QString filename);
+ virtual ~TextFile();
+ bool good();
+ bool eof();
+protected:
+ QFile *_file;
+ bool _good;
+};
+
+#endif /* TEXTFILE_H_ */
diff --git a/src/util/clientGUIUtils.cpp b/src/util/clientGUIUtils.cpp new file mode 100644 index 0000000..4d4cc0d --- /dev/null +++ b/src/util/clientGUIUtils.cpp @@ -0,0 +1,144 @@ +#include "clientGUIUtils.h" + +BlankScreen::BlankScreen() +{ + dpy = XOpenDisplay(NULL); + scr = DefaultScreen(dpy); + assert(dpy); + blackColor = BlackPixel(dpy, DefaultScreen(dpy)); + whiteColor = WhitePixel(dpy, DefaultScreen(dpy)); +// win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 200, 100, 0, blackColor, whiteColor); + win = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 10, 10, 200, 200, 1, WhitePixel(dpy, scr), BlackPixel(dpy, scr)); + + XSelectInput(dpy, win, ExposureMask | KeyPressMask); + locked = false; + offX = offY = 0; +} + +void BlankScreen::draw(bool force) +{ + if (locked)// no need to draw if we're not showing the window + { + XWindowAttributes xwa; + XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &xwa); + int hx = (xwa.width)>>2, hy = (xwa.height)>>2; + + if (XCheckTypedEvent(dpy, Expose, &ev) || force ) + { + hx += offX; + hy += offY; + + GC gcc = XCreateGC(dpy, win, 0, NULL); + XSetForeground(dpy, gcc, whiteColor); +// XClearArea(dpy, win, 0, 0, xwa.width, xwa.height, false); + if (lockMsg.size() > 0) + { + char *msg = const_cast<char*>(lockMsg.toUtf8().data()); + XDrawString(dpy, win, gcc/*DefaultGC(dpy, scr)*/, hx, hy, msg, strlen(msg)); + } + else + { + } + } + } +} + +bool BlankScreen::lock() +{ +#define lock_test + + if (locked) + return locked; + + // We want to get MapNotify events + XSelectInput(dpy, win, StructureNotifyMask); + + // "Map" the window (that is, make it appear on the screen) + XMapWindow(dpy, win); + + // Create a "Graphics Context" + //GC gc = XCreateGC(dpy, win, 0, NULL); + + XEvent xev; + Atom wm_state = XInternAtom(dpy, "_NET_WM_STATE", False); + Atom fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); + memset(&xev, 0, sizeof(xev)); + xev.type = ClientMessage; + xev.xclient.window = win; + xev.xclient.message_type = wm_state; + xev.xclient.format = 32; + xev.xclient.data.l[0] = 1; + xev.xclient.data.l[1] = fullscreen; + xev.xclient.data.l[2] = 0; + + XSendEvent(dpy, DefaultRootWindow(dpy), False, + SubstructureNotifyMask, &xev); + + + + + // Wait for the MapNotify event + for (;;) + { + XEvent e; + XNextEvent(dpy, &e); + if (e.type == MapNotify) + break; + } + //Flush it! + //XFlush(dpy); + +#ifndef lock_test + // load the locked cursor, so people dont think they can click anything + // TODO: Use some kind of invisible cursor instead of the wait-cursor + Cursor locked_cur = XCreateFontCursor(dpy, XC_watch); + XDefineCursor(dpy, DefaultRootWindow(dpy),locked_cur); +#endif + + // grabbing of keyboard and mouse and hide the cursor + XGrabKeyboard(dpy, DefaultRootWindow(dpy), false, GrabModeAsync, GrabModeAsync, CurrentTime); + XGrabPointer(dpy, DefaultRootWindow(dpy), false, 0, GrabModeAsync, GrabModeAsync, None, NULL, CurrentTime); + + if (!locked) + ConsoleLog writeLine(QString("Locked")); + + // see header for more information on this switch + return locked = true; +} + +bool BlankScreen::lock_inputs() +{ + // grabbing of keyboard and mouse and hide the cursor + XGrabKeyboard(dpy, DefaultRootWindow(dpy), false, GrabModeAsync, GrabModeAsync, CurrentTime); + XGrabPointer(dpy, DefaultRootWindow(dpy), false, 0, GrabModeAsync, GrabModeAsync, None, NULL, CurrentTime); + return true; +} + +bool BlankScreen::unlock() +{ + + if (dpy) + { + + int retval = -1; + + //reset cursor to arrow (no *real* default here...) + Cursor normal_cur = XCreateFontCursor(dpy, XC_arrow); + XDefineCursor(dpy, DefaultRootWindow(dpy), normal_cur); + + // ungrabbing of keyboard and mouse + XUngrabPointer(dpy, CurrentTime); + XUngrabKeyboard(dpy, CurrentTime); + + + retval = XUnmapWindow(dpy,win); + if (retval == BadWindow) + ConsoleLog writeError(QString("Bad window while unmapping. Badwindow: ").append(int2String(retval))); + XFlush(dpy); + } + if (locked) + ConsoleLog writeLine(QString("Unlocked")); + + lockMsg.clear(); + return !(locked = false); +} diff --git a/src/util/clientGUIUtils.h b/src/util/clientGUIUtils.h new file mode 100644 index 0000000..28b05cc --- /dev/null +++ b/src/util/clientGUIUtils.h @@ -0,0 +1,39 @@ +#include "src/util/consoleLogger.h" +#include <X11/Xlib.h> // Every Xlib program must include this +#include <X11/cursorfont.h> +#include <assert.h> +#include <unistd.h> +#include <stdio.h> + + + +#define REFRESH_RATE 0.15 + +#ifndef _BLANKSCREEN_H_ +#define _BLANKSCREEN_H_ + +class BlankScreen +{ +public: + BlankScreen(); + void draw(bool force = false); + bool lock(); + bool unlock(); + void setLogMsg(QString msg); + bool lock_inputs(); + +private: + Display *dpy; + Window win; + XEvent ev; + int scr; + + bool locked; + + + QString lockMsg; + int blackColor, whiteColor; + int offX, offY; +}; + +#endif diff --git a/src/util/consoleLogger.cpp b/src/util/consoleLogger.cpp new file mode 100644 index 0000000..b523b40 --- /dev/null +++ b/src/util/consoleLogger.cpp @@ -0,0 +1,355 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + # ----------------------------------------------------------------------------- + # consoleLogger.cpp + # - ???. + # ----------------------------------------------------------------------------- + */ + +#include "consoleLogger.h" + +#ifdef never +template<class T> +void ConsoleLogger::addListener(T* who, void (T :: *func)(QString)) +{ + LogNotify<T> *test = new LogNotify<T>(who, func); + _CBLog.push_back(dynamic_cast<LogNotifyEntry*>(test)); +} + +template<class T> +void ConsoleLogger::removeListener(T* who, void (T :: *func)(QString)) +{ + if (_CBLog.size()) + { + for (std::list<LogNotifyEntry*>::iterator it = _CBLog.begin(); it != _CBLog.end(); it++) + { + LogNotify<T> *probe = dynamic_cast<LogNotify<T>*>((*it)); + if (probe) + { + if (probe->getCallee() == who && probe->getCB() == func) + { + _CBLog.remove((*it)); + } + } + } + } +// LogNotify<T> *test = new LogNotify<T>(who, func); + // _CBLog.push_back(dynamic_cast<LogNotifyEntry*>(test)); +} + +#endif +int ConsoleLogger::writeLine(QString message, LOG_LEVEL level) +{ + if (message.size() == 0) + return -1; + + ConsoleEntry consoleEntry(_getTimeStamp(), message, level); + _announceWrite(consoleEntry); // tell the listeners! + _writeLine2File(consoleEntry.getLine()); + _log.push_back(consoleEntry); + + return _log.size(); +} + +int ConsoleLogger::writeline(const char* message, LOG_LEVEL level) +{ + if (message) + { + if (strlen(message) > 0) + return writeLine(QString(message), level); + } + return -1; +} + +int ConsoleLogger::writeError(QString error) +{ + return writeLine(error, LOG_ERROR); +} + +int ConsoleLogger::writeError(const char* error) +{ + return writeLine(error, LOG_ERROR); +} + +int ConsoleLogger::writeTerminal(QString terminal) +{ + // printing the line on the console happens further down the line! + return writeLine(terminal, LOG_TERMINAL); +} + +int ConsoleLogger::writeTerminal(const char* terminal) +{ + if (terminal) + if (strlen(terminal) > 0) + return writeTerminal(QString(terminal)); + + terminal = NULL; + return -1; +} + +int ConsoleLogger::writeNetwork(QString network) +{ + // printing the line on the console happens further down the line! + return writeLine(network, LOG_NETWORK); +} + +int ConsoleLogger::writeNetwork(const char* network) +{ + if (network) + if (strlen(network) > 0) + return writeNetwork(QString(network)); + + network = NULL; + return -1; +} + +int ConsoleLogger::writeChat(QString chat) +{ + return writeLine(chat, LOG_CHAT); +} + +int ConsoleLogger::writeChat(const char* chat) +{ + if (chat) + if (strlen(chat) > 0) + return writeChat(QString(chat)); + + chat = NULL; + return -1; +} + +void ConsoleLogger::getLine(int lineNum, char* line) +{ + QString tmp; + getLine(lineNum, &tmp); + if (tmp.size() > 0) + { + line = new char[_log[lineNum].getLine().size()+1]; + if (line) + { + memcpy(line, _log[lineNum].getLine().toUtf8().data(), _log[lineNum].getLine().size()); + if (strlen(line) > 0) + return; + } + } + line = NULL; + +} + +void ConsoleLogger::getLine(int lineNum, QString* line) +{ + if (lineNum <= int(_log.size())) + { + if (lineNum > 0) + lineNum--; + else if (lineNum < 0) + { + line = NULL; + return; + } + } + else + { + line->clear(); + line = NULL; + } +} + +void ConsoleLogger::setLogPath(QString logPath) +{ + getLogger()->_logPath = logPath; + getLogger()->_prepareLog(); +} + +void ConsoleLogger::setLogName(QString logName) +{ + getLogger()->_logName = logName; + getLogger()->_prepareLog(); +} + +void ConsoleLogger::dumpLog(DUMP_MODE mode) +{ + if (mode == DUMP_FILE || (DUMP_FILE_CONCAT && !_fileRead)) + getLogger()->_writeLog(); + if (mode == DUMP_FILE_CONCAT && _fileRead) + getLogger()->_writeLog(true); + if (mode == DUMP_ALL_LISTENERS) + { + for (int i = 0; i <int(_log.size()); i++) + { + _announceWrite(_log[i]); + } + } +} + +int ConsoleLogger::count = 0; + +ConsoleLogger* ConsoleLogger::_logger; + +ConsoleLogger* ConsoleLogger::getLogger() +{ + if (!_logger) + { + return ConsoleLogger::_logger = new ConsoleLogger(); + } + else + return ConsoleLogger::_logger; +} + +ConsoleLogger::ConsoleLogger() + : _logName(""), + _logPath(getPolicyFilePath(QString(""))), + _fileRead(false), + entryDispatcher() +{ +// _prepareLog(); +} + +ConsoleLogger::~ConsoleLogger() +{ + // doesnt work!? + _writeLog(); +} + +void ConsoleLogger::_prepareLog() +{ + _logFile.close(); + _logFileGood = false; + _readLog(); + + mkdir(getPolicyFilePath(QString()).toUtf8().data(), 0777); + QString fullpath; + fullpath.append(_logPath); + //TODO: handle wether path/ or path were entered? + fullpath.append(_logName); + _logFile.open(fullpath.toUtf8().data(), std::ofstream::out | std::ofstream::app); + if (_logFile.good()) + { + _logFileGood = true; + writeTerminal(QString("LogPath/Name changed to: ").append(fullpath)); + } + else + { + printf("ERROR: Logfile ( %s ) not accessible/found. Logs will not be available.\n", _logPath.toUtf8().data()); + } + _logFile.close(); +} + +void ConsoleLogger::_writeLine2File(QString line) +{ + if (_logFileGood) + { + QString fullpath; + fullpath.append(_logPath); + //TODO: handle wether path/ or path were entered? + fullpath.append(_logName); + _logFile.open(fullpath.toUtf8().data(), std::ofstream::out | std::ofstream::app); + + if (_logFile.good()) // one can never be too sure + { + _logFile.write(line.toUtf8().data(), line.size()); + } + + _logFile.close(); + } + +} + +// overwrites the file and dumps the complete log archive of this session +void ConsoleLogger::_writeLog(bool concat) +{ + if (_logFileGood) + { + QString fullpath; + fullpath.append(_logPath); + //TODO: handle wether path/ or path were entered? + fullpath.append(_logName); + + std::vector<ConsoleEntry> *tmpLog = NULL; + + if (concat) + { + std::vector<ConsoleEntry> newLog = _prev_log; + newLog.insert(newLog.end(), _log.begin(), _log.end()); + tmpLog = &newLog; + } + else + { + tmpLog = &_log; + } + _logFile.open(fullpath.toUtf8().data(), std::ofstream::out | std::ofstream::trunc); + + if (_logFile.good()) // one can never be too sure + { + for (int i = 0; i < int(tmpLog->size()); i++) + { + _logFile.write(tmpLog->at(i).getLine().toUtf8().data(), tmpLog->at(i).getLine().size()); + } + } + + _logFile.close(); + } +} + +void ConsoleLogger::_announceWrite(ConsoleEntry consoleEntry) +{ + + entryDispatcher.fire(consoleEntry); +} + +void ConsoleLogger::_readLog(QString path) +{ + // todo, read the file, filter the entries and recombine them if possible etc.. + // then save it all to _log_prev. + // then set _readFile to true, so the dump will concat our current log to the old and THEN overwrite the whole file + _prev_log.clear(); + _fileRead = false; +} + +QString ConsoleLogger::_getTimeStamp() +{ + time_t rawtime; + tm * ptm; + time ( &rawtime ); + + //ptm = gmtime ( &rawtime ); + ptm = localtime ( &rawtime ); + + QString tmpStr; + if (ptm->tm_mday < 10) + tmpStr.append(QString("0")); + tmpStr.append(int2String(ptm->tm_mday)); + tmpStr.push_back('.'); + if (ptm->tm_mon < 10) + tmpStr.append(QString("0")); + tmpStr.append(int2String(int(ptm->tm_mon) +1)); + tmpStr.push_back('.'); + int year = (ptm->tm_year % 100); + if (year < 10) + tmpStr.append(QString("0")); + tmpStr.append(int2String(year)); + tmpStr.push_back(' '); + if (ptm->tm_hour < 10) + tmpStr.append(QString("0")); + tmpStr.append(int2String(ptm->tm_hour)); + tmpStr.push_back(':'); + if (ptm->tm_min < 10) + tmpStr.append(QString("0")); + tmpStr.append(int2String(ptm->tm_min)); + tmpStr.push_back(':'); + if (ptm->tm_sec < 10) + tmpStr.append(QString("0")); + tmpStr.append(int2String(ptm->tm_sec)); + + return tmpStr; +} + diff --git a/src/util/consoleLogger.h b/src/util/consoleLogger.h new file mode 100644 index 0000000..3a0950d --- /dev/null +++ b/src/util/consoleLogger.h @@ -0,0 +1,273 @@ + +#include "util.h" +#include "dispatcher.h" +#include <vector> +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <list> + + +//#define as_daemon +#ifndef _CONSOLELOGGER_H_ +#define _CONSOLELOGGER_H_ + +/**********************************************************************************************************************/ +// Console-, and Message Dispatching / Logging (With timestamping!) +/**********************************************************************************************************************/ +// +// :: Usage :: +// +#define ConsoleLog ConsoleLogger::getLogger()-> //ease of acces! +// +// +// *Logging: +// +// ConsoleLog writeLine(<string/char*>); // sends out a message with "normal" loglevel +// ConsoleLog writeLine(<string/char*>, <loglevel>); // sends out a message with the chosen loglevel --> enum LOG_LEVEL +// ConsoleLog writeError(<string/char*>); // sends out a message with "Error" loglevel +// ConsoleLog writeTerminal(<string/char*>); // sends out a message with "Terminal" loglevel, which means it is +// // also printed on stdout +// ConsoleLog writeNetwork(<string/char*>); // sends out a message with "network" loglevel +// ConsoleLog writeChat(<string/char*>); // sends out a message with "Chat" loglevel +// +// *un/subscribing to the LogDispatcher +// +// ConsoleLog addListener(<pointer-to-object-of-Type-myClass>, &myClass::myMethod); +// callback signature --> typedef void (T::*callback)(ConsoleEntry); // with <U, T> as template // for more on ConsoleEntry, see later +// ConsoleLog removeListener(<pointer-to-object-of-Type-myClass>, &myClass::myMethod); +// +// *Misc +// +// ConsoleLog setLogPath(<string-path-to-log-directory>); // set the log directory (with a final /, the logfilename is appended.) +// ConsoleLog setLogName(<string-name>); // like the above, but for the filename. +// ConsoleLog dumpLog(DUMP_MODE); +// +// DUMP_FILE ::>> Dumps the whole log since the logger was started into the specified logfile. the file content gets overwritten +// DUMP_FILE_CONCAT ::>> The Same as above, but it will just append itself to the previously (if implemented) log which got \** +// ***\ read from the logfile which was present at logger start. if no log is found or logfile was not read, behaves as DUMP_FILE +// DUMP_TERMINAL ::>> Dumps the whole log into the terminal +// DUMP_ALL_LISTENERS ::>> Dumps the whole log to all listeners +// +// Alternatively, you can request a dump to a certain listener: +// ConsoleLog dump2Listener(<pointer-to-object-of-Type-myClass>, &myClass::myMethod); // it expects the same information as when subscribing +// // the PVS-Server console makes heavy use of this feature to implement its filters +// +// +// :: using the ConsoleEntry class :: +// +// *methods and members +// +// +// LOG_LEVEL getLevel() // returns the loglevel as LOG_LEVEL Enum-type +// QString getLine() // returns the complete line as shown in the logfile, with timestamp, loglevel prefix etc +// QString getMessage() // returns the message body, no gimmicks attached +// QString getPrefix() // returns the loglevel as string-represenation +// QString getTimeStamp() // returns the timestamp which was set at the creation of the object +// +// +// +// +// +// +/**********************************************************************************************************************/ + + + + + + +// Typdef at bottom of file : +// typedef ConsoleLogger::ConsoleEntry LogEntry; + + +class ConsoleLogger +{ +public: + + enum LOG_LEVEL { LOG_NORMAL, + LOG_ERROR, + LOG_CHAT, + LOG_TERMINAL, + LOG_NETWORK + }; + enum DUMP_MODE { DUMP_FILE, + DUMP_FILE_CONCAT, + DUMP_TERMINAL, + DUMP_ALL_LISTENERS, + }; + class ConsoleEntry + { + public: + ConsoleEntry(QString timeStamp, QString message, LOG_LEVEL level) + { + setLine(timeStamp, message, level); + }; + void setLine(QString timeStamp, QString message, LOG_LEVEL level) + { + _message = message; + _prefix = _prefixLine(level); + _timeStamp = timeStamp; + _line.append(QString("[ ").append(timeStamp)); + _line.append(QString(" ] ").append(_prefix)); + _line.append(QString(": ").append(message)); + _level = level; + if ('\n' != _line[_line.size()-1] && '\n' != _line[_line.size()]) + _line.push_back('\n'); // add an explicit newline char, so it looks better in the logfile + //#ifndef as_daemon + if (_level == LOG_TERMINAL) // may look strange here, but its quite central :-) + printf("%s\n", _line.toUtf8().data()); + //#endif + }; + LOG_LEVEL getLevel() + { + return _level; + }; + QString getLine() + { + return _line; + }; + QString getMessage() + { + return _message; + }; + QString getPrefix() + { + return _prefix; + }; + QString getTimeStamp() + { + return _timeStamp; + }; + + private: + QString _prefixLine(LOG_LEVEL level) + { + // switch anyone? + if (level == LOG_NORMAL) + return QString("PVS"); + if (level == LOG_ERROR) + return QString("PVS ERROR"); + if (level == LOG_TERMINAL) + return QString("PVS Terminal"); + if (level == LOG_CHAT) + return QString("PVS Chat"); + if (level == LOG_NETWORK) + return QString("PVS Network"); + return QString("UNDEFINED"); + }; + QString _line; // the complete line with timestamp and everything + QString _message; // the message itself + QString _prefix; // just the prefix + QString _timeStamp; // just the timestamp + LOG_LEVEL _level; + }; + + class LogNotifyEntry + { + public: + virtual void fire(ConsoleEntry consoleEntry) {}; + LogNotifyEntry() {}; + }; + +#ifdef never +private: + template<class T> + class LogNotify : public LogNotifyEntry + { + public: + typedef void (T::*callback)(ConsoleEntry); + LogNotify(T* who, callback func )//void (T :: *func)(QString)) + { + callee = who; + //callback = func; + myCB = func; + }; + virtual void fire(ConsoleEntry consoleEntry) + { + if (callee) + (callee->*myCB)(consoleEntry); + }; + T* getCallee() + { + return callee; + }; + callback getCB() + { + return myCB; + }; + + private: + T *callee; + callback myCB; + }; + +public: +#endif + // interfaces for the dispatcher for easy of access ( --> ConsoleLog Makro) + template<class T> void addListener(T* who, void (T :: *func)(ConsoleEntry)) + { + entryDispatcher.addListener(who, func); + }; + template<class T> void removeListener(T* who, void (T :: *func)(ConsoleEntry)) + { + entryDispatcher.removeListener(who, func); + }; + template<class T> void dump2Listener(T* who, void (T :: *func)(ConsoleEntry)) + { + for (int i = 0; i < int(_log.size()) ; i++) + (who->*func)(_log[i]); + }; + + int writeLine(QString message, LOG_LEVEL = LOG_NORMAL); + int writeline(const char* message, LOG_LEVEL = LOG_NORMAL); + int writeError(QString error); + int writeError(const char* error); + int writeTerminal(QString terminal); + int writeTerminal(const char* terminal); + int writeNetwork(QString network); + int writeNetwork(const char* network); + int writeChat(QString chat); + int writeChat(const char* chat); + void getLine(int lineNum, char* line); + void getLine(int lineNum, QString* line); + void setLogPath(QString logPath); + void setLogName(QString logName); + void dumpLog(DUMP_MODE mode = DUMP_FILE); + static ConsoleLogger* getLogger(); + static int count; +private: + + + std::vector<ConsoleEntry>* _getLog() + { + return &_log; + }; + static ConsoleLogger* _logger; + void _prepareLog(); + void _writeLine2File(QString line); + void _writeLog(bool concat = false); + void _announceWrite(ConsoleEntry consoleEntry); + void _readLog(QString path = QString("")); + QString _getTimeStamp(); + void _prefixLine(QString* line, LOG_LEVEL level = LOG_NORMAL); + + + + ConsoleLogger(); + ~ConsoleLogger(); + + QString _logName; + QString _logPath; + + bool _logFileGood, _fileRead; +// std::list<LogNotifyEntry*> _CBLog; + EventDispatcher<ConsoleEntry> entryDispatcher; + std::vector<ConsoleEntry> _log; + std::vector<ConsoleEntry> _prev_log; + std::ofstream _logFile; +}; + +typedef ConsoleLogger::ConsoleEntry LogEntry; + +#endif diff --git a/src/util/dispatcher.h b/src/util/dispatcher.h new file mode 100644 index 0000000..490a3be --- /dev/null +++ b/src/util/dispatcher.h @@ -0,0 +1,210 @@ +#ifndef _DISPATCHER_H_ +#define _DISPATCHER_H_ +#include <list> +#include <QString> +#include <iostream> +#include <map> + + +//****************************************************************************************************/ +// EventDispatcher && EventIdentDispatcher // +/***************************************************************************************************/ +// This handy class(es) act as very simple signals/events. +// Its OOP-only, so dont even try to add static functions +// or C-like methods! +// +// :: Return Types :: +// +// at the moment only callbacks for void methods with a parameter +// count of one ( whos type is the primary template parameter) +// +// :: callback signature :: +// +// typedef void (T::*callback)(U); // with <U, T> as template +// +// :: Usage Example :: +// +// *creating a Dispatcher +// +// -- EventDispatcher<Type A>* nameYourDispatcher = new EventDispatcher<Type A>; // simple Dispatcher +// -- EventIdentDispatcher<Type A>* nameYourIdentDispatcher = new EventIdentDispatcher<Type A>; // ident dispatcher +// +// *difference between simple and ident +// +// a simple dispatcher features only one type of signal, so you can only call all +// attached listeners at once or none at all +// +// an ident dispatcher uses an ident string to hold and fire more than one event type at once +// but is limited to the one defined parameter type for its methods +// +// *subscribung to a dispatcher +// +// -- nameYourDispatcher->addListener(<pointer-to-object-of-Type-myClass>, &myClass::myMethod); // simple Dispatcher +// -- nameYourIdentDispatcher->addListener(<string-as-ident>, <pointer-to-object-of-Type-myClass>, &myClass::myMethod); // ident dispatcher// +// +// you can add the same method/instance to different dispatchers oder differnt ident-distinguished dispatchers in a identdispatcher. +// you can also add the same method/instance to the same dispatchers all over again, which is not recommended +// +// +// *firing a dispatcher +// +// -- nameYourDispatcher->fire(Type_A Object); // simple Dispatcher +// -- nameYourIdentDispatcher->fire(<string-as-ident>, Type_A Object); // ident dispatcher// +// +// All respective attached callbacks are called in the order they were added +// +// +// *unsubscribing +// +// -- nameYourDispatcher->removeListener(<pointer-to-object-of-Type-myClass>, &myClass::myMethod); // simple Dispatcher +// -- nameYourIdentDispatcher->removeListener(<string-as-ident>, <pointer-to-object-of-Type-myClass>, &myClass::myMethod); // ident dispatcher// +// +// just the reverse of addListener. currently no removeAll() available +// +// +// +/***************************************************************************************************/ +class CallbackHandle +{ +}; + +template<class U> +class CallbackBase : public CallbackHandle +{ +public: + virtual void fire(U u) {}; + +private: +}; + +template<class T, class U> +class Callback : public CallbackBase<U> +{ +public: + + virtual void fire(U u) + { + if (cbVU) + (callee->*cbVU)(u); + }; + + typedef void (T::*callbackVU)(U); + + Callback(T* who, callbackVU cb) + { + cbVU = cb; + callee = who; + }; + + T* getCallee() + { + return callee; + }; + callbackVU getCBVU() + { + return cbVU; + }; + +private: + callbackVU cbVU; + T* callee; + +}; + +template<class U> +class EventDispatcher +{ +public: + template<class T> void addListener(T *who, void (T :: *func)(U)) + { + Callback<T, U> *tmp = new Callback<T, U>(who, func); + _listener.push_back(dynamic_cast<CallbackBase<U>*>(tmp)); + }; + void fire(U u) + { + for (typename std::list<CallbackBase<U>*>::iterator it = _listener.begin(); it != _listener.end(); it++) + { + if (*it) + { + (*it)->fire(u); + } + } + }; + + template<class T> void removeListener(T* who, void (T :: *func)(U)) + { + if (_listener.size()) + { + for (typename std::list<CallbackBase<U>*>::iterator it = _listener.begin(); it != _listener.end(); it++) + { + CallbackBase<U>* pro = (*it); + Callback<T, U> *probe = dynamic_cast<Callback<T,U>*>(pro); + if (probe) + { + if (probe->getCallee() == who && probe->getCBVU() == func ) + { + delete (probe); + _listener.remove((*it)); + return; + } + } + } + } + }; + +private: + + std::list<CallbackBase<U>*> _listener; +}; + +template<class U> +class EventIdentDispatcher +{ +public: + template<class T> void addListener(QString ident, T* who, void (T :: *func)(U)) + { + Callback<T, U>* tmp = new Callback<T, U>(who, func); + _listener.push_back(std::pair<QString, CallbackBase<U>*>(ident, dynamic_cast<CallbackBase<U>*>(tmp))); + }; + + void fire(QString ident, U u) + { + for ( typename std::list<std::pair<QString, CallbackBase<U>* > >::iterator it = _listener.begin(); it != _listener.end(); it++) + { + if ((*it).first.compare(ident) == 0 || QString("*").compare((*it).first) == 0) + { + if ((*it).second) + { + (*it).second->fire(u); + } + } + } + }; + template<class T> void removeListener(QString ident, T* who, void (T :: *func)(U)) + { + if (_listener.size()) + { + for (std::list<std::pair <QString, CallbackHandle*> >::iterator it = _listener.begin(); it != _listener.end(); it++) + { + if ((*it).first.compare(ident) == 0) + { + CallbackBase<U>* pro = (*it).second; + Callback<T, U> *probe = dynamic_cast<Callback<T,U>*>(pro); + if (probe) + { + if (probe->getCallee() == who && probe->getVoidCB == func) + { + delete (*it).second; + _listener.remove((*it)); + return; + } + } + } + } + } + }; +private: + std::list<std::pair<QString, CallbackBase<U>* > > _listener; +}; + +#endif diff --git a/src/util/pvsSettingsManager.cpp b/src/util/pvsSettingsManager.cpp new file mode 100644 index 0000000..a6a742b --- /dev/null +++ b/src/util/pvsSettingsManager.cpp @@ -0,0 +1,185 @@ +#include "pvsSettingsManager.h" +#include "TextFile.h" + +PVSSettingsManager* PVSSettingsManager::getManager() +{ + if (myself) + return myself; + else + return myself = new PVSSettingsManager; +} + +void PVSSettingsManager::setConfigFile(QString path) +{ + if (path.size() && fileExists(path)) + { + _path = path; + _parseFile(_path); + + } + else + ConsoleLog writeError(QString("Can't open config file \"").append(QString(path).append("\""))); +} + +bool PVSSettingsManager::hasEntry(QString name) +{ + for (SettingsIter it = settingsList.begin(); it != settingsList.end(); it++) + { + if ((*it).first.compare(name) == 0) + { + return true; + } + } + return false; +} + +QString PVSSettingsManager::getEntryString(QString name) +{ + for (SettingsIter it = settingsList.begin(); it != settingsList.end(); it++) + { + if ((*it).first.compare(name) == 0) + { + return (*it).second; + } + } + return QString(); +} + +void PVSSettingsManager::writeEntry(QString name, QString value) +{ + if (name.size() && value.size()) + return; + bool unique = true; + for (SettingsIter it = settingsList.begin(); it != settingsList.end(); it++) + { + if ((*it).first.compare(name) == 0) + { + unique = false; + (*it).second = value; + break; + } + } + if (unique) + { + SettingsEntry tmp(name, value); + settingsList.push_back(tmp); + } +} + + +PVSSettingsManager* PVSSettingsManager::myself = NULL; + +PVSSettingsManager::PVSSettingsManager() +{ + +} + +void PVSSettingsManager::setConfigs() +{ + //default settings + _configs.setValue("Chat/chatstate", "on"); + _configs.setValue("Chat/chatmode", "bossmode"); + _configs.setValue("Room/roomId", "0"); + _configs.setValue("VNC/permit", "off"); + _configs.setValue("VNC/quality", "high"); + _configs.sync(); +} +void PVSSettingsManager::reWriteConfigs(QString set, QString val) +{ + _configs.setValue(set, val); + _configs.sync(); +} + +void PVSSettingsManager::readConfigs(QString sett, QString vall) +{ + //TODO: read the config file.. + _configs.value("Chat/chatstate").toBool(); + _configs.value("Chat/chatmode").toString(); + _configs.value("Room/room").toInt(); + _configs.value("VNC/permit").toBool(); + _configs.value("VNC/quality").toString(); +} + +void PVSSettingsManager::_parseFile(QString path) +{ + QString line; + TextFile file(path); + + SettingsList tmpList; + + if (file.good()) + { + while (!file.eof()) + { + line = file.readLine(); + if (!(line.length() <=1)) // ignore blank + { + if (!(line[0] == '#' || line[0] == '/' || line[0] == '[')) // ignore comments and section headers + { + SettingsEntry tmp = _parseLine(line); + if (tmp.first.size() && tmp.second.size()) + { + bool unique = true; + for (SettingsIter it = tmpList.begin(); it != tmpList.end(); it++) + { + if ((*it).first.compare(tmp.first) == 0) + { + unique = false; + break; + } + } + if (unique) + tmpList.push_back(tmp); + } + } + } + } + } + else + { + ConsoleLog writeError(QString("No configfile \"").append(QString(path).append("\" found or file corrupt."))); + } + + if (tmpList.size()) + settingsList = tmpList; +} +#ifdef verbose +ConsoleLog writeLine(QString("Dumping Config Content of ").append(QString(path).append(" : "))); +for (SettingsIter it = settingsList.begin(); it != settingsList.end(); it++) +{ + ConsoleLog writeLine(QString("Option: ").append(QString((*it).first).append(QString(" | Value: ").append((*it).second)))); +} +ConsoleLog writeLine(QString("End of ").append(QString(path).append("."))); +#endif + +SettingsEntry PVSSettingsManager::_parseLine(QString line) +{ + QString name; + QString value; + + name = lineSplitter(line, "=\n\t", true); + value = lineSplitter(line, "=\n\t", false); + + if (!(name.size() && value.size())) + return SettingsEntry("",""); + + + // remove whitespaces in front of option name + for (int i = 0; i < name.size(); i++) + { + if (name[i] == '\t' || name[i] == ' ') + { + name.remove(i, 1); + i--; + } + else + break; + } + // whitespaces after the value are trimmed by the lineSplitter + + SettingsEntry tmp(name, value); + return tmp; +} + + + diff --git a/src/util/pvsSettingsManager.h b/src/util/pvsSettingsManager.h new file mode 100644 index 0000000..78607eb --- /dev/null +++ b/src/util/pvsSettingsManager.h @@ -0,0 +1,50 @@ +/// documentation test 1 +/// line 2 +/// line 3 +#ifndef _PVSSETTINGSMANGER_H_ +#define _PVSSETTINGSMANGER_H_ + +#include <list> +#include <map> +#include <src/util/util.h> +#include <src/util/consoleLogger.h> +#include <QSettings> + + +/// documentation test 1.1 +/// line 2.1 +/// line 3.1 + +typedef std::pair<QString, QString> SettingsEntry; ///< first = option name, second = option value +typedef std::list<SettingsEntry> SettingsList; ///< obvious +typedef std::list<SettingsEntry>::iterator SettingsIter; + + +class PVSSettingsManager; +/// documentation test 1.2 +/// line 2.2 +/// line 3.2 +class PVSSettingsManager +{ +public: + static PVSSettingsManager* getManager(); + void setConfigFile(QString path); + bool hasEntry(QString name); + QString getEntryString(QString name); + void writeEntry(QString name, QString value); + void setConfigs(); + void reWriteConfigs(QString set, QString val); + void readConfigs(QString sett, QString vall); +private: + static PVSSettingsManager* myself; + PVSSettingsManager(); + void _parseFile(QString path); + SettingsEntry _parseLine(QString line); + QString _path; + SettingsList settingsList; + QSettings _configs; + +}; + + +#endif diff --git a/src/util/serviceDiscoveryUtil.cpp b/src/util/serviceDiscoveryUtil.cpp new file mode 100644 index 0000000..32aa0fc --- /dev/null +++ b/src/util/serviceDiscoveryUtil.cpp @@ -0,0 +1,65 @@ +#include "serviceDiscoveryUtil.h"
+#include <cassert>
+
+void appendSdField(QByteArray* target, const char* id, QString data)
+{
+ assert(strlen(id) == 3);
+ target->append(id);
+ QByteArray tmp = data.toUtf8();
+ if (tmp.size() > 100) tmp.truncate(100);
+ target->append((char)tmp.size());
+ target->append(tmp);
+}
+
+SdFields parseSdFields(unsigned char* data, int len)
+{
+ SdFields fields;
+ for (;;)
+ {
+ //printf("%d bytes left: %s\n", len, (char*)data);
+ if (len < 4 || len < 4 + data[3]) break; // end of data
+ QString key = QString::fromUtf8((char*)data, 3);
+ QString val = QString::fromUtf8((char*)data+4, data[3]);
+ //printf("Key: %s, Val: %s\n", key.toUtf8().data(), val.toUtf8().data());
+ fields.insert(key, val);
+ len -= (4 + data[3]);
+ data += (4 + data[3]);
+ }
+ return fields;
+}
+
+QString sha1ToReadable(QByteArray input)
+{
+ unsigned char *ptr = (unsigned char *)input.data();
+ QString retval;
+ for (int i = (input.length() < 10 ? input.length() : 10); i; --i)
+ {
+ switch(*ptr++ % 0xD)
+ {
+ case 0x0: retval.append('S'); break;
+ case 0x1: retval.append('F'); break;
+ case 0x2: retval.append('M'); break;
+ case 0x3: retval.append('K'); break;
+ case 0x4: retval.append('H'); break;
+ case 0x5: retval.append('T'); break;
+ case 0x6: retval.append('P'); break;
+ case 0x7: retval.append('D'); break;
+ case 0x8: retval.append('Y'); break;
+ case 0x9: retval.append('W'); break;
+ case 0xA: retval.append('G'); break;
+ case 0xB: retval.append('L'); break;
+ case 0xC: retval.append('B'); break;
+ }
+ if (--i == 0) break;
+ switch((*ptr >> 2) % 5)
+ {
+ case 0: retval.append('a'); break;
+ case 1: retval.append('i'); break;
+ case 2: retval.append('u'); break;
+ case 3: retval.append('e'); break;
+ case 4: retval.append('o'); break;
+ }
+ if ((*ptr++ & 3) == 0) retval.append('n');
+ }
+ return retval;
+}
diff --git a/src/util/serviceDiscoveryUtil.h b/src/util/serviceDiscoveryUtil.h new file mode 100644 index 0000000..537daeb --- /dev/null +++ b/src/util/serviceDiscoveryUtil.h @@ -0,0 +1,19 @@ +#ifndef SERVICEDISCOVERYUTIL_H_
+#define SERVICEDISCOVERYUTIL_H_
+
+#include <QtCore/QString>
+#include <QtCore/QHash>
+
+typedef QHash<QString, QString> SdFields;
+
+// These two functions build/parse the message format used in SD broadcasts
+// It is some kind of key-value pairs, encoded as follows:
+// <3 chars/bytes, key><1 byte, value length in bytes><up to 100 chars/bytes, value>
+void appendSdField(QByteArray* target, const char* id, QString data);
+SdFields parseSdFields(unsigned char* data, int len);
+
+// This algorithm is supposed to generate a readable and maybe pronouncable
+// string from the fingerprint of the servers certificate
+QString sha1ToReadable(QByteArray input);
+
+#endif /* SERVICEDISCOVERYUTIL_H_ */
diff --git a/src/util/timeUtil.cpp b/src/util/timeUtil.cpp new file mode 100644 index 0000000..6f8e93d --- /dev/null +++ b/src/util/timeUtil.cpp @@ -0,0 +1,42 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + # ----------------------------------------------------------------------------- + # timeUtil.cpp + # - ???. + # ----------------------------------------------------------------------------- + */ + +#include "timeUtil.h" + +TimeUtil::TimeUtil() +{ + seconds = useconds = mtime = 0; +} + +void TimeUtil::start() +{ + gettimeofday(&Begin, NULL); +} + +void TimeUtil::stop() +{ + gettimeofday(&End, NULL); + seconds = End.tv_sec - Begin.tv_sec; + useconds = End.tv_usec - Begin.tv_usec; + mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5; +} + +long TimeUtil::getMS() +{ + return mtime; +} + diff --git a/src/util/timeUtil.h b/src/util/timeUtil.h new file mode 100644 index 0000000..90d647d --- /dev/null +++ b/src/util/timeUtil.h @@ -0,0 +1,34 @@ +#ifndef TIME_UTIL +#define TIME_UTIL + +#include <sys/time.h> +#include <stdio.h> +#include <unistd.h> + + +#ifdef PROFILE +#define startTime(aaa) TimeUtil aaa ## Time = TimeUtil(); aaa ## Time.start(); +#define endTime(aaa) aaa ## Time.stop(); printf("Time to execute " #aaa " : %ld\n", aaa ## Time.getMS()); +#endif + +#ifndef PROFILE +#define startTime(aaa) +#define endTime(aaa) +#endif + + + +class TimeUtil +{ + +public: + TimeUtil(); + void start(); + void stop(); + long getMS(); +private: + long mtime, seconds, useconds; + struct timeval Begin, End; //initialize Begin and End for the timer +}; + +#endif diff --git a/src/util/util.cpp b/src/util/util.cpp new file mode 100644 index 0000000..c2d06a0 --- /dev/null +++ b/src/util/util.cpp @@ -0,0 +1,416 @@ +#include "util.h" +#include <QtGui/QDesktopServices> +#include "consoleLogger.h" +#include "TextFile.h" +#include <ctime> +#include <cstdlib> +#include <QStringList> +#include <iostream> + + +PVSServerEntry::PVSServerEntry(QString name) +{ + name_ = name; +} +void PVSServerEntry::addClient(QString client) +{ + clientList_.push_back(client); +} +bool PVSServerEntry::hasClient(QString client) +{ + for (std::list<QString>::iterator it = clientList_.begin(); it != clientList_.end(); it++) + { + if ((*it).compare(client) == 0) + return true; + } + return false; +} +QString PVSServerEntry::getName() +{ + return name_; +} + +int PVSServerEntry::getSize() +{ + return clientList_.size(); +} + + +//namespace util +//{ + +int getRandom(int min, int max) +{ + static bool init = true; + if (init) + { + init = false; + srand ( time(NULL) + getpid() ); + } + if (min >= max) return rand(); + return rand() % (max-min+1) + min; +} + +std::list<PVSServerEntry> getPVSServerEntryList(QString fileName) +{ + QString line; + TextFile file(fileName); + std::list<PVSServerEntry> entryList; + + if (file.good()) + { +// std::cout << "reading table file \"" << fileName <<"\"" << std::endl; + PVSServerEntry* tmpEntry = NULL; + while (!file.eof()) + { + line = file.readLine(); + + if (!(line.length() <=1)) // ignore blank + if (!(line[0] == '#' || line[0] == '/')) // ignore comments + { + if (line.mid(0, 5).compare(QString("start")) == 0) + { + if (tmpEntry != NULL) + { + // unclean file... but no reason to break down + //PVSServerEntry tmpEntry2 = *tmpEntry; + entryList.push_back(*tmpEntry); + delete tmpEntry; + tmpEntry = NULL; + } + QString tmpName(colonSplitter(line, false)); + if (tmpName.size()<1) + tmpName = QString("localhost"); + + tmpEntry = new PVSServerEntry(tmpName); + continue; + } + if (line.mid(0, 3).compare(QString("end")) == 0) + { + if (tmpEntry!=NULL) + { + entryList.push_back(*tmpEntry); + delete tmpEntry; + tmpEntry = NULL; + } + else + ;// ignore + + continue; + } + if (tmpEntry != NULL) + { + tmpEntry->addClient(line); + } + } + } + if (tmpEntry != NULL) + { + delete tmpEntry; + tmpEntry = NULL; + } + + return entryList; + } + else + { + std::cout << "ERROR: no file \"" << fileName.toStdString() <<"\" found or file corrupt" << std::endl; + } + return std::list<PVSServerEntry>(); +} +QString getFilenameFromPath(QString line) +{ + int lastSlash = 0; + for (int i = 0; i < line.length(); i++) + { + if (line.at(i) == '/') + { + lastSlash = i; + } + } + QString result; + if (lastSlash != 0 && lastSlash != line.length() -1) + { + result = line.mid(lastSlash+1, line.length()-(lastSlash+1)); + } + return result; +} + +QString lineSplitter(QString line, const char* signs, bool first) +{ + char *pch; + char* cLine = new char[line.length()+1]; + strcpy(cLine, line.toUtf8().data()); + pch = strtok (cLine,signs); + if (first) + { + QString tmp(pch); + delete cLine; + return tmp; + } + else + { + QString tmp; + char* tmpp = strtok(NULL, ";,\t\n"); + if (tmpp) + tmp = QString(tmpp); + delete cLine; + return tmp; + } +} + +QString colonSplitter(QString line, bool first) +{ + char *pch; + char* cLine = new char[line.length()+1]; + strcpy(cLine, line.toUtf8().data()); + pch = strtok (cLine," :\t\n"); + if (first) + { + QString tmp(pch); + delete[] cLine; + return tmp; + } + else + { + QString tmp; + char* tmpp = strtok(NULL, " ;,\t\n"); + if (tmpp) + tmp = QString(tmpp); + delete[] cLine; + return tmp; + } +} + +QString getUserName() +{ + struct passwd* passUser = getpwuid(getuid()); + QString username; + if (passUser) + { + username = QString(passUser->pw_name); + } + if (username.isEmpty()) + { + printf("USERNAME COULDNT BE RETRIEVED!\n"); + username = QString("USERNAMEERROR"); + } + return username; +} + +// Get full username. +QString getFullUsername() +{ + QString fullname = getUserName(); + struct passwd *pd; + + if (NULL == (pd = getpwuid(getuid()))) + {ConsoleLog writeError("getpwuid() error.");} + else + { + QString tmp = pd->pw_gecos; + QStringList userData = tmp.split(","); + if(userData[0].length() > 0 ) + { + fullname = userData[0]; + } + } + return fullname; +} + +bool fileExists(QString fileName) +{ + std::ifstream file(fileName.toLocal8Bit().data()); + if (file.good()) + { +#ifdef verbose + printf("fileExists(): file good.\n"); +#endif + file.close(); + return true; + } + return false; + +} + +QString getHomeDir() +{ + return QDesktopServices::storageLocation(QDesktopServices::HomeLocation); +} + +QString getPolicyDir() +{ + QString policyDir = getHomeDir(); + QString subPath("/.pvs/"); + policyDir.append(subPath); + return policyDir; +} + +QString getPolicyFilePath(QString fileName) +{ + + QString fullPath = getPolicyDir(); + fullPath.append(fileName); + return fullPath; +} +bool policyFileExists(QString fileName) +{ + std::ifstream file(getPolicyFilePath(fileName).toUtf8().data()); + if (file.good()) + { + file.close(); + return true; + } + return false; +} + +void createPolicyDir() +{ + mkdir(getPolicyDir().toUtf8().data(), 0777); +} + +void createPolicyFiles() +{ + if (!policyFileExists(QString(".allow"))) + { + std::ofstream file(getPolicyFilePath(QString(".allow")).toUtf8().data()); + file.close(); + } +#ifdef old_method + if (!policyFileExists(QString(".pass"))) + { + std::ofstream file(getPolicyFilePath(QString(".pass")).toUtf8().data()); + file.close(); + } +#endif +} + +QString readPassFromPassFile() +{ + TextFile file(getPolicyFilePath(".pass")); + if (file.good()) // should have been checked via exists before, but better be safe + { + QString pass; + pass = file.readLine(); // we expect a password in correct format. otherwise their fault + return pass; + } + else + return QString(); +} +bool getAllowed() +{ + printf("Checking %s\n", getPolicyFilePath(QString(".allow")).toUtf8().data()); + TextFile file(getPolicyFilePath(".allow")); + if (file.good()) // should have been checked via exists before, but better be safe + { + QString allowed; + allowed = file.readLine(); + if ( (allowed.compare(QString("1")) == 0) || + (allowed.compare(QString("true")) == 0) || + (allowed.compare(QString("t")) == 0) || + (allowed.compare(QString("T")) == 0) || + (allowed.compare(QString("true")) == 0) || + (allowed.compare(QString("allow")) == 0) || + (allowed.compare(QString("TRUE")) == 0) ) + return true; + } + printf("...negative\n"); + return false; +} + +QString int2String(int intInt) +{ + char tmp[50]; + snprintf(tmp, 49, "%d", intInt); + return QString(tmp); +} + +int string2Int(QString string) +{ + return atoi(string.toUtf8().data()); +} + +//}//end namespace util + + +#ifdef neverever +std::list<VNCConnectInfo*> readFile(char* fileName) +{ + QString line; + std::ifstream file(fileName); + std::list<VNCConnectInfo*> infoList; + + if (file.good()) + { +// std::cout << "reading clients file \"" << fileName <<"\"" << std::endl; + while (!file.eof()) + { + getline(file, line); + + if (!(line.length() <=1)) // ignore blank + if (!(line[0] == '#' || line[0] == '/')) // ignore comments + infoList.push_back(getConInfo(line)); + } + } + else + { + std::cout << "ERROR: no file \"" << fileName <<"\" found or file corrupt" << std::endl; + } + return infoList; +} + +VNCConnectInfo* getConInfo(QString line) +{ + char** arguments = new char*[100]; + char* cLine = new char[line.length()+1]; + strcpy(cLine, line.toUtf8().data()); + int count; + makeArgs(cLine , &count , arguments); + std::cout << "found " << count << " arguments" << std::endl; + if (count > 2) // assume that a password would be the second argument in the line, therefore the third argument in the argv + { + QString pass = QString(arguments[2]); + std::cout << "think i found a password" << std::endl; + count--; + delete arguments[2]; + // no changes to the arguments though, since the vnc-lib will ignore most of it anyway + return new VNCConnectInfo(count, arguments, pass); + } + + return new VNCConnectInfo(count, arguments); +} + +void makeArgs(char* line, int* count, char** arguments) +{ + (*count) = 1; + + arguments[(*count)-1] = new char[strlen("dummy")+1]; // get program name from somewhere + strcpy(arguments[(*count)-1], "dummy"); + + /*// include encodings + arguments[(*count)++] = new char[strlen("-encodings")+1]; + strcpy(arguments[(*count)], "-encodings"); + (*count)++; + arguments[(*count)++] = new char[strlen("tight")+1]; + strcpy(arguments[(*count)], "tight"); + (*count)++; + */ + + + if (line[strlen(line)-1] == '\n' || line[strlen(line)-1] == '\r') + line[strlen(line)-1] = '\0'; // remove newline + + char *pch; + pch = strtok (line," ,\t"); + while (pch != NULL && (*count) <= 3) + { + (*count)++; // count args + arguments[(*count)-1] = new char[strlen(pch)+1]; + strcpy(arguments[(*count)-1], pch); + pch = strtok (NULL, " ,\t"); + } +} + + +#endif + diff --git a/src/util/util.h b/src/util/util.h new file mode 100644 index 0000000..37565cb --- /dev/null +++ b/src/util/util.h @@ -0,0 +1,59 @@ +#include <QString> +#include <cstdio> +//#include <cstring> +#include <list> +#include <fstream> +#include <iostream> +#include <pwd.h> +#include <sys/types.h> +#include <sys/stat.h> + + + +#ifndef _PVSSERVERENTRY_H_ +#define _PVSSERVERENTRY_H_ +class PVSServerEntry +{ +public: + PVSServerEntry(QString name); + void addClient(QString client); + bool hasClient(QString client); + QString getName(); + int getSize(); +private: + QString name_; + std::list<QString> clientList_; +}; +#endif + +//namespace util +//{ +int getRandom(int min, int max); +std::list<PVSServerEntry> getPVSServerEntryList(QString fileName); +QString getFilenameFromPath(QString line); +QString lineSplitter(QString line, const char* signs, bool first); +QString colonSplitter(QString line, bool first); +QString getUserName(); +QString getFullUsername(); +bool fileExists(QString fileName); +QString getHomeDir(); +QString getPolicyDir(); +QString getPolicyFilePath(QString fileName); +bool policyFileExists(QString fileName); +void createPolicyFiles(); +void createPolicyDir(); +QString readPassFromPassFile(); +bool getAllowed(); + +QString int2String(int intInt); +int string2Int(QString string); +int string2Int(QString string); +//} // end namespace util + +//std::list<VNCConnectInfo*> readFile(char* fileName); +//void makeArgs(char* line, int* count, char** arguments); +//VNCConnectInfo* getConInfo(QString line); + + + + diff --git a/src/util/vncClientThread.cpp b/src/util/vncClientThread.cpp new file mode 100644 index 0000000..bb1d457 --- /dev/null +++ b/src/util/vncClientThread.cpp @@ -0,0 +1,249 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + # ----------------------------------------------------------------------------- + # vncClientThread.cpp + # - Connection to remove vnc server + # - Emits Qt signal on framebuffer updates + # ----------------------------------------------------------------------------- + */ + +#include "vncClientThread.h" + +VNCClientThread::VNCClientThread(QString host, int port, QString passwd, + int quality, int updatefreq) : + QThread(), _frameBuffer(0) +{ + _host = host; + _port = port; + _passwd = passwd; + _quality = quality; + _updatefreq = updatefreq; + terminate = false; + _client = NULL; + _connected = false; +} + +VNCClientThread::~VNCClientThread() +{ + if (this->isRunning()) this->wait(2000); + if (_frameBuffer) delete[] _frameBuffer; + _frameBuffer = NULL; + if (_client != NULL) + { + ::close(_client->sock); + _client->frameBuffer = NULL; + rfbClientCleanup(_client); + _client = NULL; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Public + +void VNCClientThread::run() +{ + qDebug("[%s] VNC client started.", metaObject()->className()); + qDebug("[%s] Host: '%s' Port: %i Passwd: '%s' Quality: %i", + metaObject()->className(), qPrintable(_host), _port, + qPrintable(_passwd), _quality); + + // setup network + _client = rfbGetClient(8, 3, 4); + _client->MallocFrameBuffer = frameBufferHandler; + _client->canHandleNewFBSize = true; + _client->serverHost = strdup(_host.toUtf8().constData()); + _client->desktopName = NULL; + _client->serverPort = _port; + _client->GetPassword = passwdHandler; + _client->GotFrameBufferUpdate = updateImage; + _client->frameBuffer = NULL; + + // save this instance in vnc-struct for callbacks + rfbClientSetClientData(_client, 0, this); + + // start client + if (!rfbInitClient(_client, NULL, NULL)) + { + _client = NULL; // !!! <- if you don't do this you will get a segfault + return; // later when you try to clean up _client, as rfbInitClient already did so + } + + qDebug("[%s] Connection successful!", metaObject()->className()); + + // Main VNC event loop + while (!terminate) + { + _connected = true; + const int i = WaitForMessage(_client, 500); // its usec, not msec + if (i < 0) + break; + if (i) if (!HandleRFBServerMessage(_client)) + break; + + /* + //work yourself through event queue and fire every event... + while (!_eventQueue.isEmpty()) { + SomeEvent* event = _eventQueue.dequeue(); + event->fire(_client); + delete event; + }*/ + + this->msleep(_updatefreq); + } + + // cleanup + ::close(_client->sock); + + qDebug("[%s] VNC client stopped.", metaObject()->className()); + _connected = false; +} + +QImage VNCClientThread::getImage() +{ + return _img; +} + +QSize VNCClientThread::getSize() +{ + return _clientSize; +} + +int VNCClientThread::getUpdatefreq() +{ + if (_updatefreq > 0) + return _updatefreq; + return 500; +} + +void VNCClientThread::setUpdatefreq(int updatefreq) +{ + _updatefreq = updatefreq; +} + +QString VNCClientThread::getDesktopName() +{ + if (_client == NULL || _client->desktopName == NULL) return QString(); + return QString(_client->desktopName); +} + +char* VNCClientThread::passwdHandler(rfbClient *client) +{ + VNCClientThread* t = (VNCClientThread*) rfbClientGetClientData(client, 0); + return strdup(t->_passwd.toLocal8Bit()); +} + +rfbBool VNCClientThread::frameBufferHandler(rfbClient *client) +{ + VNCClientThread *t = (VNCClientThread*) rfbClientGetClientData(client, 0); + const int width = client->width, height = client->height, depth = + client->format.bitsPerPixel; + const int size = width * height * (depth / 8); + qDebug("[%s] Remote desktop: %ix%ix%i", t->metaObject()->className(), + width, height, depth); + + if (t->_frameBuffer) + delete[] t->_frameBuffer; + + t->_frameBuffer = new uint8_t[size]; + client->frameBuffer = t->_frameBuffer; + memset(client->frameBuffer, '\0', size); + client->format.bitsPerPixel = 32; + client->format.redShift = 16; + client->format.greenShift = 8; + client->format.blueShift = 0; + client->format.redMax = 0xff; + client->format.greenMax = 0xff; + client->format.blueMax = 0xff; + + const int quality = t->_quality; + switch (quality) + { + case VNCClientThread::HIGH: + client->appData.useBGR233 = 0; + client->appData.encodingsString = "copyrect hextile raw"; + client->appData.compressLevel = 0; + client->appData.qualityLevel = 9; + client->appData.scaleSetting = 10; // FIXME: Doesn't work + break; + case VNCClientThread::MEDIUM: + client->appData.useBGR233 = 0; + client->appData.encodingsString + = "tight zrle ultra copyrect hextile zlib corre rre raw"; + client->appData.compressLevel = 5; + client->appData.qualityLevel = 7; + client->appData.scaleSetting = 10; + break; + case VNCClientThread::LOW: + default: + client->appData.useBGR233 = 1; + client->appData.encodingsString + = "tight zrle ultra copyrect hextile zlib corre rre raw"; + client->appData.compressLevel = 9; + client->appData.qualityLevel = 1; + client->appData.scaleSetting = 10; + break; + } + SetFormatAndEncodings(client); + + t->_clientSize = QSize(width, height); + + // If something stops working with VNC images/updates, move these two + // commands back tp updateImage + const QImage img = QImage(client->frameBuffer, client->width, + client->height, QImage::Format_RGB32); + t->_img = img; + // <> + + return true; +} + +void VNCClientThread::updateImage(rfbClient* client, int x, int y, int w, int h) +{ + VNCClientThread* t = (VNCClientThread*) rfbClientGetClientData(client, 0); + emit t->imageUpdated(x, y, w, h); +} + +/* rfbClient* VNCClientThread::getRfbClient(){ + return _client; +}*/ + +SomeEvent::~SomeEvent() +{ +} + +void PointerEvent::fire(rfbClient* cl) +{ + SendPointerEvent(cl, _x, _y, _buttonMask); +} + +void KeyEvent::fire(rfbClient* cl) +{ + SendKeyEvent(cl, _key, _pressed); +} + +void VNCClientThread::mouseEvent(int x, int y, int buttonMask) +{ + //QMutexLocker lock(&mutex); + if (terminate) + return; + + _eventQueue.enqueue(new PointerEvent(x, y, buttonMask)); +} + +void VNCClientThread::keyEvent(int key, bool pressed) +{ + //QMutexLocker lock(&mutex); + if (terminate) + return; + + _eventQueue.enqueue(new KeyEvent(key, pressed)); +} diff --git a/src/util/vncClientThread.h b/src/util/vncClientThread.h new file mode 100644 index 0000000..10980b8 --- /dev/null +++ b/src/util/vncClientThread.h @@ -0,0 +1,114 @@ +/* + # Copyright (c) 2009, 2010 - 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/ + */ + +#ifndef VNCCLIENTTHREAD_H_ +#define VNCCLIENTTHREAD_H_ + +#include <QtCore> +#include <QtGui/QImage> + +extern "C" +{ +#include <rfb/rfbclient.h> +} + +class SomeEvent +{ +public: + virtual ~SomeEvent(); + + virtual void fire(rfbClient*) = 0; +}; + +class KeyEvent : public SomeEvent +{ +public: + KeyEvent(int key, int pressed) + : _key(key), _pressed(pressed) {} + + void fire(rfbClient*); + +private: + int _key; + int _pressed; +}; + +class PointerEvent : public SomeEvent +{ +public: + PointerEvent(int x, int y, int buttonMask) + : _x(x), _y(y), _buttonMask(buttonMask) {} + + void fire(rfbClient*); + +private: + int _x; + int _y; + int _buttonMask; +}; + +class VNCClientThread: public QThread +{ + Q_OBJECT + +public: + VNCClientThread(QString host, int port, QString passwd, int quality, int updatefreq = 0); + ~VNCClientThread(); + + void run(); + QImage getImage(); + QSize getSize(); + int getUpdatefreq(); + void setUpdatefreq(int updatefreq); + QString getDesktopName(); + void mouseEvent(int x, int y, int buttonMask); + void keyEvent(int key, bool pressed); + bool isConnected() + { + return _connected; + } + + + static void updateImage(rfbClient *client, int x, int y, int w, int h); + static char* passwdHandler(rfbClient *client); + static rfbBool frameBufferHandler(rfbClient *client); + //rfbClient* getRfbClient(); + + bool terminate; + + int const static HIGH = 0; + int const static MEDIUM = 1; + int const static LOW = 2; + +Q_SIGNALS: + void imageUpdated(int x, int y, int w, int h); + +private: + rfbClient *_client; + uint8_t *_frameBuffer; + + QString _host; + int _port; + QString _passwd; + int _quality; + int _updatefreq; + QQueue<SomeEvent* > _eventQueue; + + QImage _img; + QSize _clientSize; + + bool _connected; + +}; + +#endif /* VNCCLIENTTHREAD_H_ */ diff --git a/src/version.h b/src/version.h new file mode 100644 index 0000000..c217c07 --- /dev/null +++ b/src/version.h @@ -0,0 +1,2 @@ +#define VERSION_STRING "1.9.8.0" +#define VERSION_NUMBER 1980 |
