From 7ec4585cecc74ce8d9a94b0e52f00a96d105e79e Mon Sep 17 00:00:00 2001 From: Manuel Nickschas Date: Tue, 19 Jun 2007 00:50:42 +0000 Subject: [PATCH] Big update this time - Core has been redesigned to be multi-user capable. At least partly. (BR #42) * Architecture changes mostly complete: - Core has been split in Core (static) and CoreSession (per-user objects) - Connection stuff has been moved out of CoreProxy into Core - Lots of cleanups, and we have finally real singletons! - Global is now (externally) a static class -- changes throughout the code * Monolithic Quassel works (or at least it seems to) * Standalone Core and GUI disabled for now: - While most of the new infrastructure is in place in Core, we still need GUI stuff for auth (BR #17) - Syncing with Core as well as getting session states not done yet Next steps will include the redesign of the GUI to make that cleaner as well (BR #41) --- CMakeLists.txt | 4 + Quassel.kdevelop.filelist | 44 +++--- core/core.cpp | 295 +++++++++++++++++++++++++++++++++----- core/core.h | 97 ++++++++++++- core/coreproxy.cpp | 91 ++---------- core/coreproxy.h | 17 +-- core/server.cpp | 6 +- core/server.h | 6 +- core/sqlitestorage.cpp | 3 +- core/storage.h | 3 + gui/bufferview.h | 3 +- gui/coreconnectdlg.cpp | 2 +- gui/guiproxy.h | 3 +- gui/identities.cpp | 12 +- gui/identities.h | 2 +- gui/mainwin.cpp | 2 +- gui/serverlist.cpp | 26 ++-- main/global.cpp | 66 ++++++--- main/global.h | 44 +++--- main/main_mono.cpp | 27 ++-- 20 files changed, 529 insertions(+), 224 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a365e5e..d2a89fd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,10 @@ IF(NOT BUILD_MONO AND NOT BUILD_CORE AND NOT BUILD_GUI) MESSAGE(FATAL_ERROR "\nYou have not selected which parts of Quassel I should build. Aborting.\nRun 'cmake -DBUILD=', where contains one or more of 'core', 'gui' or 'monolithic', or 'all' to build everything.\n") ENDIF(NOT BUILD_MONO AND NOT BUILD_CORE AND NOT BUILD_GUI) +IF(BUILD_CORE OR BUILD_GUI) + MESSAGE(FATAL_ERROR "\nBuilding of standalone core or GUI not supported at this time. Please check back later.\n") +ENDIF(BUILD_CORE OR BUILD_GUI) + SET(CMAKE_BUILD_TYPE Debug) # Define files diff --git a/Quassel.kdevelop.filelist b/Quassel.kdevelop.filelist index 4924499c..8fb3b40f 100644 --- a/Quassel.kdevelop.filelist +++ b/Quassel.kdevelop.filelist @@ -1,26 +1,16 @@ # KDevelop Custom Project File List -network/server.h -network/server.cpp core/core.cpp core/CMakeLists.txt core/core.h -gui/channelwidget.cpp -gui/channelwidget.h gui/CMakeLists.txt -gui/identitiesdlg.ui -gui/identitieseditdlg.ui gui/mainwin.cpp gui/mainwin.h -gui/networkeditdlg.ui -gui/nickeditdlg.ui gui/serverlist.cpp gui/serverlist.h -gui/serverlistdlg.ui images/iconmap.xml images/icons.qrc main/main_core.cpp main/main_mono.cpp -network/CMakeLists.txt CMakeLists.txt COPYING Doxyfile @@ -32,7 +22,6 @@ core/coreproxy.cpp core/coreproxy.h main/util.cpp main/util.h -gui/coreconnectdlg.ui gui/coreconnectdlg.cpp gui/coreconnectdlg.h main/proxy_common.h @@ -40,11 +29,8 @@ main/CMakeLists.txt images/qirc-icon.png main/global.cpp main/global.h -gui/channelwidget-old.ui gui/identities.cpp gui/identities.h -network/buffer.cpp -network/buffer.h gui/channelwidgetinput.h gui/channelwidgetinput.cpp plugins/plugin.h @@ -55,14 +41,11 @@ gui/ui/identitieseditdlg.ui gui/ui/ircwidget.ui gui/ui/mainwin.ui gui/ui/networkeditdlg.ui -gui/ui/networkwidget.ui gui/ui/nickeditdlg.ui gui/ui/servereditdlg.ui gui/ui/serverlistdlg.ui gui/ui/settingsdlg.ui gui/ui/bufferview.ui -gui/bufferview.cpp -gui/bufferview.h gui/buffer.cpp gui/buffer.h main/message.cpp @@ -74,3 +57,30 @@ gui/chatwidget.cpp gui/chatwidget.h gui/style.cpp gui/style.h +main/logger.cpp +main/logger.h +templates/cpp +templates/h +gui/bufferwidget.h +gui/bufferwidget.cpp +main/settings.cpp +main/settings.h +gui/settingsdlg.h +gui/settingsdlg.cpp +gui/settingspages.cpp +gui/settingspages.h +gui/bufferview.cpp +gui/bufferview.h +core/backlog.cpp +core/backlog.h +ChangeLog +core/storage.cpp +core/storage.h +core/sqlitestorage.cpp +dev-notes +dev-notes/builtin_cmds.obsolete.cpp +gui +gui/tabcompleter.cpp +gui/tabcompleter.h +core +core/sqlitestorage.h diff --git a/core/core.cpp b/core/core.cpp index 821ec2a5..b1815d9c 100644 --- a/core/core.cpp +++ b/core/core.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005/06 by The Quassel Team * + * Copyright (C) 2005-07 by The Quassel IRC Development Team * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -28,28 +28,212 @@ #include #include +Core *Core::instanceptr = 0; + +Core * Core::instance() { + if(instanceptr) return instanceptr; + instanceptr = new Core(); + instanceptr->init(); + return instanceptr; +} + +void Core::destroy() { + delete instanceptr; + instanceptr = 0; +} + Core::Core() { - if(core) qFatal("Trying to instantiate more than one Core object!"); +} + +void Core::init() { if(!SqliteStorage::isAvailable()) { qFatal("Sqlite is currently required! Please make sure your Qt library has sqlite support enabled."); } //SqliteStorage::init(); storage = new SqliteStorage(); - user = storage->validateUser("Default", "password"); - if(!user) user = storage->addUser("Default", "password"); - Q_ASSERT(user); + connect(Global::instance(), SIGNAL(dataPutLocally(UserId, QString)), this, SLOT(updateGlobalData(UserId, QString))); + connect(&server, SIGNAL(newConnection()), this, SLOT(incomingConnection())); + //startListening(); // FIXME + if(Global::runMode == Global::Monolithic) { // TODO Make GUI user configurable + guiUser = storage->validateUser("Default", "password"); + if(!guiUser) guiUser = storage->addUser("Default", "password"); + Q_ASSERT(guiUser); + Global::setGuiUser(guiUser); + createSession(guiUser); + } else guiUser = 0; - connect(coreProxy, SIGNAL(requestServerStates()), this, SIGNAL(serverStateRequested())); - connect(coreProxy, SIGNAL(gsRequestConnect(QStringList)), this, SLOT(connectToIrc(QStringList))); - connect(coreProxy, SIGNAL(gsUserInput(BufferId, QString)), this, SLOT(msgFromGUI(BufferId, QString))); - connect(coreProxy, SIGNAL(gsImportBacklog()), storage, SLOT(importOldBacklog())); - connect(coreProxy, SIGNAL(gsRequestBacklog(BufferId, QVariant, QVariant)), this, SLOT(sendBacklog(BufferId, QVariant, QVariant))); - connect(this, SIGNAL(displayMsg(Message)), coreProxy, SLOT(csDisplayMsg(Message))); - connect(this, SIGNAL(displayStatusMsg(QString, QString)), coreProxy, SLOT(csDisplayStatusMsg(QString, QString))); - connect(this, SIGNAL(backlogData(BufferId, QList, bool)), coreProxy, SLOT(csBacklogData(BufferId, QList, bool))); - connect(storage, SIGNAL(bufferIdUpdated(BufferId)), coreProxy, SLOT(csUpdateBufferId(BufferId))); - connect(this, SIGNAL(bufferIdUpdated(BufferId)), coreProxy, SLOT(csUpdateBufferId(BufferId))); + // Read global settings from config file + QSettings s; + s.beginGroup("Global"); + foreach(QString unum, s.childGroups()) { + UserId uid = unum.toUInt(); + s.beginGroup(unum); + foreach(QString key, s.childKeys()) { + Global::updateData(uid, key, s.value(key)); + } + s.endGroup(); + } + s.endGroup(); +} + +Core::~Core() { + foreach(QTcpSocket *sock, validClients.keys()) { + delete sock; + } + qDeleteAll(sessions); + delete storage; +} + +CoreSession *Core::session(UserId uid) { + Core *core = instance(); + if(core->sessions.contains(uid)) return core->sessions[uid]; + else return 0; +} + +CoreSession *Core::guiSession() { + Core *core = instance(); + if(core->guiUser && core->sessions.contains(core->guiUser)) return core->sessions[core->guiUser]; + else return 0; +} + +CoreSession *Core::createSession(UserId uid) { + Core *core = instance(); + Q_ASSERT(!core->sessions.contains(uid)); + CoreSession *sess = new CoreSession(uid, core->storage); + core->sessions[uid] = sess; + connect(sess, SIGNAL(proxySignal(CoreSignal, QVariant, QVariant, QVariant)), core, SLOT(recvProxySignal(CoreSignal, QVariant, QVariant, QVariant))); + return sess; +} + + +bool Core::startListening(uint port) { + if(!server.listen(QHostAddress::Any, port)) { + qWarning(QString(QString("Could not open GUI client port %1: %2").arg(port).arg(server.errorString())).toAscii()); + return false; + } + qDebug() << "Listening for GUI clients on port" << server.serverPort(); + return true; +} + +void Core::stopListening() { + server.close(); + qDebug() << "No longer listening for GUI clients."; +} + +void Core::incomingConnection() { + // TODO implement SSL + QTcpSocket *socket = server.nextPendingConnection(); + connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); + connect(socket, SIGNAL(readyRead()), this, SLOT(clientHasData())); + blockSizes.insert(socket, (quint32)0); + qDebug() << "Client connected from " << socket->peerAddress().toString(); +} + +void Core::clientHasData() { + QTcpSocket *socket = dynamic_cast(sender()); + Q_ASSERT(socket && blockSizes.contains(socket)); + quint32 bsize = blockSizes.value(socket); + QVariant item; + while(readDataFromDevice(socket, bsize, item)) { + if(validClients.contains(socket)) { + QList sigdata = item.toList(); + if((GUISignal)sigdata[0].toInt() == GS_UPDATE_GLOBAL_DATA) { + processClientUpdate(socket, sigdata[1].toString(), sigdata[2]); + } else { + sessions[validClients[socket]]->processSignal((GUISignal)sigdata[0].toInt(), sigdata[1], sigdata[2], sigdata[3]); + } + } else { + // we need to auth the client + try { + processClientInit(socket, item); + } catch(Storage::AuthError) { + qWarning() << "Authentification error!"; // FIXME + socket->close(); + return; + } catch(Exception e) { + qWarning() << "Client init error:" << e.msg(); + socket->close(); + return; + } + } + blockSizes[socket] = bsize = 0; + } + blockSizes[socket] = bsize; +} + +void Core::clientDisconnected() { + QTcpSocket *socket = dynamic_cast(sender()); + blockSizes.remove(socket); + validClients.remove(socket); + qDebug() << "Client disconnected."; + // TODO remove unneeded sessions - if necessary/possible... +} + +void Core::processClientInit(QTcpSocket *socket, const QVariant &v) { + VarMap msg = v.toMap(); + if(msg["GUIProtocol"].toUInt() != GUI_PROTOCOL) { + //qWarning() << "Client version mismatch."; + throw Exception("GUI client version mismatch"); + } + // Auth + UserId uid = storage->validateUser(msg["User"].toString(), msg["Password"].toString()); // throws exception if this failed + + // Find or create session for validated user + CoreSession *sess; + if(sessions.contains(uid)) sess = sessions[uid]; + else { + sess = createSession(uid); + validClients[socket] = uid; + } + VarMap reply; + VarMap coreData; + // FIXME + QStringList dataKeys = Global::keys(uid); + QString key; + foreach(key, dataKeys) { + coreData[key] = Global::data(key); + } + reply["CoreData"] = coreData; + reply["SessionState"] = sess->sessionState(); + QList sigdata; + sigdata.append(CS_CORE_STATE); sigdata.append(QVariant(reply)); sigdata.append(QVariant()); sigdata.append(QVariant()); + writeDataToDevice(socket, QVariant(sigdata)); + sess->sendServerStates(); +} + +void Core::processClientUpdate(QTcpSocket *socket, QString key, const QVariant &data) { + UserId uid = validClients[socket]; + Global::updateData(uid, key, data); + QList sigdata; + sigdata.append(CS_UPDATE_GLOBAL_DATA); sigdata.append(key); sigdata.append(data); sigdata.append(QVariant()); + foreach(QTcpSocket *s, validClients.keys()) { + if(validClients[s] == uid && s != socket) writeDataToDevice(s, QVariant(sigdata)); + } +} + +void Core::updateGlobalData(UserId uid, QString key) { + QVariant data = Global::data(uid, key); + QList sigdata; + sigdata.append(CS_UPDATE_GLOBAL_DATA); sigdata.append(key); sigdata.append(data); sigdata.append(QVariant()); + foreach(QTcpSocket *socket, validClients.keys()) { + if(validClients[socket] == uid) writeDataToDevice(socket, QVariant(sigdata)); + } +} + +void Core::recvProxySignal(CoreSignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { + CoreSession *sess = qobject_cast(sender()); + Q_ASSERT(sess); + UserId uid = sess->userId(); + QList sigdata; + sigdata.append(sig); sigdata.append(arg1); sigdata.append(arg2); sigdata.append(arg3); + //qDebug() << "Sending signal: " << sigdata; + foreach(QTcpSocket *socket, validClients.keys()) { + if(validClients[socket] == uid) writeDataToDevice(socket, QVariant(sigdata)); + } +} + +/* // Read global settings from config file QSettings s; s.beginGroup("Global"); @@ -65,30 +249,56 @@ Core::Core() { connect(global, SIGNAL(dataPutLocally(QString)), SLOT(globalDataUpdated(QString))); } + */ + +CoreSession::CoreSession(UserId uid, Storage *_storage) : user(uid), storage(_storage) { + coreProxy = new CoreProxy(); + connect(coreProxy, SIGNAL(send(CoreSignal, QVariant, QVariant, QVariant)), this, SIGNAL(proxySignal(CoreSignal, QVariant, QVariant, QVariant))); + + connect(coreProxy, SIGNAL(requestServerStates()), this, SIGNAL(serverStateRequested())); + connect(coreProxy, SIGNAL(gsRequestConnect(QStringList)), this, SLOT(connectToIrc(QStringList))); + connect(coreProxy, SIGNAL(gsUserInput(BufferId, QString)), this, SLOT(msgFromGui(BufferId, QString))); + connect(coreProxy, SIGNAL(gsImportBacklog()), storage, SLOT(importOldBacklog())); + connect(coreProxy, SIGNAL(gsRequestBacklog(BufferId, QVariant, QVariant)), this, SLOT(sendBacklog(BufferId, QVariant, QVariant))); + connect(this, SIGNAL(displayMsg(Message)), coreProxy, SLOT(csDisplayMsg(Message))); + connect(this, SIGNAL(displayStatusMsg(QString, QString)), coreProxy, SLOT(csDisplayStatusMsg(QString, QString))); + connect(this, SIGNAL(backlogData(BufferId, QList, bool)), coreProxy, SLOT(csBacklogData(BufferId, QList, bool))); + connect(this, SIGNAL(bufferIdUpdated(BufferId)), coreProxy, SLOT(csUpdateBufferId(BufferId))); + connect(storage, SIGNAL(bufferIdUpdated(BufferId)), coreProxy, SLOT(csUpdateBufferId(BufferId))); + connect(Global::instance(), SIGNAL(dataUpdatedRemotely(UserId, QString)), this, SLOT(globalDataUpdated(UserId, QString))); + connect(Global::instance(), SIGNAL(dataPutLocally(UserId, QString)), this, SLOT(globalDataUpdated(UserId, QString))); + +} + +CoreSession::~CoreSession() { -Core::~Core() { - //foreach(Server *s, servers) { - // delete s; - //} - delete storage; } -void Core::globalDataUpdated(QString key) { - QVariant data = global->getData(key); +UserId CoreSession::userId() { + return user; +} + +void CoreSession::processSignal(GUISignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { + coreProxy->recv(sig, arg1, arg2, arg3); +} + +void CoreSession::globalDataUpdated(UserId uid, QString key) { + Q_ASSERT(uid == userId()); + QVariant data = Global::data(userId(), key); QSettings s; - s.setValue(QString("Global/")+key, data); + s.setValue(QString("Global/%1/").arg(userId())+key, data); } -void Core::connectToIrc(QStringList networks) { +void CoreSession::connectToIrc(QStringList networks) { foreach(QString net, networks) { if(servers.contains(net)) { } else { - Server *server = new Server(net); + Server *server = new Server(userId(), net); connect(this, SIGNAL(serverStateRequested()), server, SLOT(sendState())); connect(this, SIGNAL(connectToIrc(QString)), server, SLOT(connectToIrc(QString))); connect(this, SIGNAL(disconnectFromIrc(QString)), server, SLOT(disconnectFromIrc(QString))); - connect(this, SIGNAL(msgFromGUI(QString, QString, QString)), server, SLOT(userInput(QString, QString, QString))); + connect(this, SIGNAL(msgFromGui(QString, QString, QString)), server, SLOT(userInput(QString, QString, QString))); connect(server, SIGNAL(serverState(QString, VarMap)), coreProxy, SLOT(csServerState(QString, VarMap))); //connect(server, SIGNAL(displayMsg(Message)), this, SLOT(recvMessageFromServer(Message))); connect(server, SIGNAL(displayMsg(Message::Type, QString, QString, QString, quint8)), this, SLOT(recvMessageFromServer(Message::Type, QString, QString, QString, quint8))); @@ -101,7 +311,7 @@ void Core::connectToIrc(QStringList networks) { connect(server, SIGNAL(nickUpdated(QString, QString, VarMap)), coreProxy, SLOT(csNickUpdated(QString, QString, VarMap))); connect(server, SIGNAL(ownNickSet(QString, QString)), coreProxy, SLOT(csOwnNickSet(QString, QString))); connect(server, SIGNAL(queryRequested(QString, QString)), coreProxy, SLOT(csQueryRequested(QString, QString))); - // add error handling + // TODO add error handling connect(server, SIGNAL(connected(QString)), coreProxy, SLOT(csServerConnected(QString))); connect(server, SIGNAL(disconnected(QString)), this, SLOT(serverDisconnected(QString))); @@ -112,20 +322,20 @@ void Core::connectToIrc(QStringList networks) { } } -void Core::serverDisconnected(QString net) { +void CoreSession::serverDisconnected(QString net) { delete servers[net]; servers.remove(net); coreProxy->csServerDisconnected(net); } -void Core::msgFromGUI(BufferId bufid, QString msg) { - emit msgFromGUI(bufid.network(), bufid.buffer(), msg); +void CoreSession::msgFromGui(BufferId bufid, QString msg) { + emit msgFromGui(bufid.network(), bufid.buffer(), msg); } // ALL messages coming pass through these functions before going to the GUI. // So this is the perfect place for storing the backlog and log stuff. -void Core::recvMessageFromServer(Message::Type type, QString target, QString text, QString sender, quint8 flags) { +void CoreSession::recvMessageFromServer(Message::Type type, QString target, QString text, QString sender, quint8 flags) { Server *s = qobject_cast(this->sender()); Q_ASSERT(s); BufferId buf; @@ -140,17 +350,32 @@ void Core::recvMessageFromServer(Message::Type type, QString target, QString tex emit displayMsg(msg); } -void Core::recvStatusMsgFromServer(QString msg) { +void CoreSession::recvStatusMsgFromServer(QString msg) { Server *s = qobject_cast(sender()); Q_ASSERT(s); emit displayStatusMsg(s->getNetwork(), msg); } -QList Core::getBuffers() { + +QList CoreSession::buffers() const { return storage->requestBuffers(user); } -void Core::sendBacklog(BufferId id, QVariant v1, QVariant v2) { + +QVariant CoreSession::sessionState() { + VarMap v; + QList bufs; + foreach(BufferId id, storage->requestBuffers(user)) { bufs.append(QVariant::fromValue(id)); } + v["Buffers"] = bufs; + + return v; +} + +void CoreSession::sendServerStates() { + emit serverStateRequested(); +} + +void CoreSession::sendBacklog(BufferId id, QVariant v1, QVariant v2) { QList log; QList msglist; if(v1.type() == QVariant::DateTime) { @@ -172,4 +397,4 @@ void Core::sendBacklog(BufferId id, QVariant v1, QVariant v2) { } -Core *core = 0; +//Core *core = 0; diff --git a/core/core.h b/core/core.h index a90a8f6f..400c21eb 100644 --- a/core/core.h +++ b/core/core.h @@ -21,16 +21,105 @@ #ifndef _CORE_H_ #define _CORE_H_ -#include #include #include #include #include "server.h" -#include "backlog.h" #include "storage.h" #include "global.h" +#include "coreproxy.h" + +class CoreSession; +class Core : public QObject { + Q_OBJECT + + public: + static Core * instance(); + static void destroy(); + + static CoreSession * session(UserId); + static CoreSession * guiSession(); + static CoreSession * createSession(UserId); + + private slots: + void recvProxySignal(CoreSignal, QVariant, QVariant, QVariant); + bool startListening(uint port = 4242); + void stopListening(); + void incomingConnection(); + void clientHasData(); + void clientDisconnected(); + void updateGlobalData(UserId, QString); + + private: + Core(); + ~Core(); + void init(); + static Core *instanceptr; + + void processClientInit(QTcpSocket *socket, const QVariant &v); + void processClientUpdate(QTcpSocket *socket, QString key, const QVariant &data); + + UserId guiUser; + QHash sessions; + Storage *storage; + + QTcpServer server; // TODO: implement SSL + QHash validClients; + QHash blockSizes; +}; + +class CoreSession : public QObject { + Q_OBJECT + + public: + CoreSession(UserId, Storage *); + ~CoreSession(); + + QList buffers() const; + inline UserId userId(); + QVariant sessionState(); + CoreProxy *proxy(); + + public slots: + void connectToIrc(QStringList); + void processSignal(GUISignal, QVariant, QVariant, QVariant); + void sendBacklog(BufferId, QVariant, QVariant); + void msgFromGui(BufferId, QString message); + void sendServerStates(); + + signals: + void proxySignal(CoreSignal, QVariant arg1 = QVariant(), QVariant arg2 = QVariant(), QVariant arg3 = QVariant()); + + void msgFromGui(QString net, QString buf, QString message); + void displayMsg(Message message); + void displayStatusMsg(QString, QString); + + void connectToIrc(QString net); + void disconnectFromIrc(QString net); + void serverStateRequested(); + + void backlogData(BufferId, QList, bool done); + + void bufferIdUpdated(BufferId); + + private slots: + //void recvProxySignal(CoreSignal, QVariant arg1 = QVariant(), QVariant arg2 = QVariant(), QVariant arg3 = QVariant()); + void globalDataUpdated(UserId, QString); + void recvStatusMsgFromServer(QString msg); + void recvMessageFromServer(Message::Type, QString target, QString text, QString sender = "", quint8 flags = Message::None); + void serverDisconnected(QString net); + + private: + CoreProxy *coreProxy; + Storage *storage; + QHash servers; + UserId user; + +}; + +/* class Core : public QObject { Q_OBJECT @@ -71,6 +160,8 @@ class Core : public QObject { }; -extern Core *core; +*/ +//extern Core *core; + #endif diff --git a/core/coreproxy.cpp b/core/coreproxy.cpp index 5ae8d961..c6325eef 100644 --- a/core/coreproxy.cpp +++ b/core/coreproxy.cpp @@ -26,88 +26,11 @@ #include "core.h" CoreProxy::CoreProxy() { - if(coreProxy) qFatal("Trying to instantiate more than one CoreProxy object!"); - coreProxy = this; - core = new Core(); - - connect(global, SIGNAL(dataPutLocally(QString)), this, SLOT(updateGlobalData(QString))); - connect(&server, SIGNAL(newConnection()), this, SLOT(incomingConnection())); - if(!server.listen(QHostAddress::Any, 4242)) { - qFatal(QString(QString("Could not open GUI client port %1: %2").arg(4242).arg(server.errorString())).toAscii()); - } - qDebug() << "Listening for GUI clients on port" << server.serverPort() << "."; -} - -void CoreProxy::incomingConnection() { - QTcpSocket *socket = server.nextPendingConnection(); - connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected())); - connect(socket, SIGNAL(readyRead()), this, SLOT(clientHasData())); - clients.append(socket); - blockSizes.insert(socket, (quint32)0); - qDebug() << "Client connected from " << socket->peerAddress().toString(); -} - -void CoreProxy::clientHasData() { - QTcpSocket *socket = dynamic_cast(sender()); - Q_ASSERT(socket && blockSizes.contains(socket)); - quint32 bsize = blockSizes.value(socket); - QVariant item; - while(readDataFromDevice(socket, bsize, item)) { - QList sigdata = item.toList(); - Q_ASSERT(sigdata.size() == 4); - switch((GUISignal)sigdata[0].toInt()) { - case GS_CLIENT_INIT: processClientInit(socket, sigdata[1]); break; - case GS_UPDATE_GLOBAL_DATA: processClientUpdate(socket, sigdata[1].toString(), sigdata[2]); break; - //case GS_CLIENT_READY: processClientReady(sigdata[1], sigdata[2], sigdata[3]); break; - default: recv((GUISignal)sigdata[0].toInt(), sigdata[1], sigdata[2], sigdata[3]); break; - } - blockSizes[socket] = bsize = 0; - } - blockSizes[socket] = bsize; -} - -void CoreProxy::clientDisconnected() { - QTcpSocket *socket = dynamic_cast(sender()); - blockSizes.remove(socket); - clients.removeAll(socket); - qDebug() << "Client disconnected."; -} - -void CoreProxy::processClientInit(QTcpSocket *socket, const QVariant &v) { - VarMap msg = v.toMap(); - if(msg["GUIProtocol"].toUInt() != GUI_PROTOCOL) { - qDebug() << "Client version mismatch. Disconnecting."; - socket->close(); - return; - } - VarMap reply; - VarMap coreData; - QStringList dataKeys = global->getKeys(); - QString key; - foreach(key, dataKeys) { - coreData[key] = global->getData(key); - } - reply["CoreData"] = coreData; - /* - VarMap bl; - QHash > log = core->getBackLog(); - foreach(QString net, log.keys()) { - QByteArray buf; - QDataStream out(&buf, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_4_2); - foreach(Message msg, log[net]) { out << msg; } - bl[net] = buf; - } - reply["CoreBackLog"] = bl; - */ - QList bufs; - foreach(BufferId id, core->getBuffers()) { bufs.append(QVariant::fromValue(id)); } - reply["CoreBuffers"] = bufs; - QList sigdata; - sigdata.append(CS_CORE_STATE); sigdata.append(QVariant(reply)); sigdata.append(QVariant()); sigdata.append(QVariant()); - writeDataToDevice(socket, QVariant(sigdata)); - emit requestServerStates(); +// connect(global, SIGNAL(dataPutLocally(QString)), this, SLOT(updateGlobalData(QString))); +// connect(&server, SIGNAL(newConnection()), this, SLOT(incomingConnection())); } +/* void CoreProxy::processClientUpdate(QTcpSocket *socket, QString key, QVariant data) { global->updateData(key, data); QList sigdata; @@ -122,9 +45,11 @@ void CoreProxy::updateGlobalData(QString key) { QVariant data = global->getData(key); emit csUpdateGlobalData(key, data); } +*/ +/* void CoreProxy::send(CoreSignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { - sendToGUI(sig, arg1, arg2, arg3); + QList sigdata; sigdata.append(sig); sigdata.append(arg1); sigdata.append(arg2); sigdata.append(arg3); //qDebug() << "Sending signal: " << sigdata; @@ -133,6 +58,7 @@ void CoreProxy::send(CoreSignal sig, QVariant arg1, QVariant arg2, QVariant arg3 writeDataToDevice(socket, QVariant(sigdata)); } } +*/ void CoreProxy::recv(GUISignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { //qDebug() << "[CORE] Received signal" << sig << ":" << arg1< clients; - QHash blockSizes; friend class GUIProxy; }; -extern CoreProxy *coreProxy; +//extern CoreProxy *coreProxy; diff --git a/core/server.cpp b/core/server.cpp index 74f9c7ad..ca878d12 100644 --- a/core/server.cpp +++ b/core/server.cpp @@ -26,7 +26,7 @@ #include #include -Server::Server(QString net) : network(net) { +Server::Server(UserId uid, QString net) : user(uid), network(net) { QString MQUOTE = QString('\020'); ctcpMDequoteHash[MQUOTE + '0'] = QString('\000'); ctcpMDequoteHash[MQUOTE + 'n'] = QString('\n'); @@ -67,8 +67,8 @@ void Server::sendState() { void Server::connectToIrc(QString net) { if(net != network) return; // not me! - networkSettings = global->getData("Networks").toMap()[net].toMap(); - identity = global->getData("Identities").toMap()[networkSettings["Identity"].toString()].toMap(); + networkSettings = Global::data(user, "Networks").toMap()[net].toMap(); + identity = Global::data(user, "Identities").toMap()[networkSettings["Identity"].toString()].toMap(); QList servers = networkSettings["Servers"].toList(); QString host = servers[0].toMap()["Address"].toString(); quint16 port = servers[0].toMap()["Port"].toUInt(); diff --git a/core/server.h b/core/server.h index d4fbfd2f..c17b4d0f 100644 --- a/core/server.h +++ b/core/server.h @@ -41,11 +41,12 @@ class Server : public QThread { Q_OBJECT public: - Server(QString network); + Server(UserId uid, QString network); ~Server(); + UserId userId() const { return user; } // serverState state(); - bool isConnected() { return socket.state() == QAbstractSocket::ConnectedState; } + bool isConnected() const { return socket.state() == QAbstractSocket::ConnectedState; } QString getNetwork() { return network; } QStringList providesUserHandlers(); @@ -143,6 +144,7 @@ class Server : public QThread { void defaultCtcpHandler(CtcpType ctcptype, QString prefix, QString cmd, QString target, QString param); private: + UserId user; QString network; QTcpSocket socket; //QHash buffers; diff --git a/core/sqlitestorage.cpp b/core/sqlitestorage.cpp index b45f1858..af5767dd 100644 --- a/core/sqlitestorage.cpp +++ b/core/sqlitestorage.cpp @@ -233,7 +233,8 @@ UserId SqliteStorage::validateUser(QString user, QString password) { if(query.first()) { return query.value(0).toUInt(); } else { - return 0; + throw AuthError(); + //return 0; } } diff --git a/core/storage.h b/core/storage.h index 31b2b09e..e0d24a9c 100644 --- a/core/storage.h +++ b/core/storage.h @@ -150,6 +150,9 @@ class Storage : public QObject { //! Sent if a new BufferId is created, or an existing one changed somehow. void bufferIdUpdated(BufferId); + public: + /* Exceptions */ + struct AuthError : public Exception {}; protected: // Old stuff, just for importing old file-based data diff --git a/gui/bufferview.h b/gui/bufferview.h index 0dea9bbe..307505e8 100644 --- a/gui/bufferview.h +++ b/gui/bufferview.h @@ -81,4 +81,5 @@ public: }; -#endif \ No newline at end of file +#endif + diff --git a/gui/coreconnectdlg.cpp b/gui/coreconnectdlg.cpp index 9cf41a49..b465ae18 100644 --- a/gui/coreconnectdlg.cpp +++ b/gui/coreconnectdlg.cpp @@ -74,7 +74,7 @@ void CoreConnectDlg::coreConnected() { ui.progressBar->show(); VarMap initmsg; initmsg["GUIProtocol"] = GUI_PROTOCOL; - guiProxy->send(GS_CLIENT_INIT, QVariant(initmsg)); + // FIXME guiProxy->send(GS_CLIENT_INIT, QVariant(initmsg)); } void CoreConnectDlg::coreConnectionError(QString err) { diff --git a/gui/guiproxy.h b/gui/guiproxy.h index 6e84b570..aeb12f3f 100644 --- a/gui/guiproxy.h +++ b/gui/guiproxy.h @@ -79,8 +79,9 @@ class GUIProxy : public QObject { void recvPartialItem(quint32 avail, quint32 size); - public: void send(GUISignal, QVariant arg1 = QVariant(), QVariant arg2 = QVariant(), QVariant arg3 = QVariant()); + + public slots: void recv(CoreSignal, QVariant arg1 = QVariant(), QVariant arg2 = QVariant(), QVariant arg3 = QVariant()); private slots: diff --git a/gui/identities.cpp b/gui/identities.cpp index 873039ff..31617179 100644 --- a/gui/identities.cpp +++ b/gui/identities.cpp @@ -22,11 +22,11 @@ IdentitiesDlg::IdentitiesDlg(QWidget *parent, QString selected) : QDialog(parent) { ui.setupUi(this); - connect(global, SIGNAL(dataUpdatedRemotely(QString)), this, SLOT(globalDataUpdated(QString))); + connect(Global::instance(), SIGNAL(dataUpdatedRemotely(UserId, QString)), this, SLOT(globalDataUpdated(UserId, QString))); connect(ui.enableAutoAway, SIGNAL(stateChanged(int)), this, SLOT(autoAwayChecked())); - identities = global->getData("Identities").toMap(); + identities = Global::data("Identities").toMap(); foreach(QString name, identities.keys()) { nameMapping[name] = name; } @@ -55,7 +55,7 @@ IdentitiesDlg::IdentitiesDlg(QWidget *parent, QString selected) : QDialog(parent } /* this needs more work! mapping? */ -void IdentitiesDlg::globalDataUpdated(QString key) { +void IdentitiesDlg::globalDataUpdated(UserId, QString key) { if(key == "Identities") { if(QMessageBox::warning(this, tr("Data changed remotely!"), tr("Some other GUI client changed the identities data!
" "Apply updated settings, losing all changes done locally?"), @@ -236,9 +236,9 @@ void IdentitiesDlg::accept() { updateIdentity(getCurIdentity()); QString result = checkValidity(); if(result.length() == 0) { - global->putData("Identities", identities); + Global::putData("Identities", identities); // We have to care about renamed identities and update the network list appropriately... - VarMap networks = global->getData("Networks").toMap(); + VarMap networks = Global::data("Networks").toMap(); foreach(QString netname, networks.keys()) { VarMap net = networks[netname].toMap(); if(nameMapping.contains(net["Identity"].toString())) { @@ -246,7 +246,7 @@ void IdentitiesDlg::accept() { } else net["Identity"] = "Default"; networks[netname] = net; } - global->putData("Networks", networks); + Global::putData("Networks", networks); QDialog::accept(); } else { QMessageBox::warning(this, tr("Invalid Identity!"), diff --git a/gui/identities.h b/gui/identities.h index d528d9de..81fffd6e 100644 --- a/gui/identities.h +++ b/gui/identities.h @@ -54,7 +54,7 @@ class IdentitiesDlg : public QDialog { void editIdentities(); - void globalDataUpdated(QString); + void globalDataUpdated(UserId, QString); private: Ui::IdentitiesDlg ui; diff --git a/gui/mainwin.cpp b/gui/mainwin.cpp index 1e88be01..08792035 100644 --- a/gui/mainwin.cpp +++ b/gui/mainwin.cpp @@ -40,7 +40,7 @@ LayoutThread *layoutThread; MainWin::MainWin() : QMainWindow() { ui.setupUi(this); //widget = 0; - qDebug() << "Available DB drivers: " << QSqlDatabase::drivers (); + //qDebug() << "Available DB drivers: " << QSqlDatabase::drivers (); setWindowTitle("Quassel IRC"); //setWindowTitle("Κυασελ Εγαρζη"); setWindowIcon(QIcon(":/qirc-icon.png")); diff --git a/gui/serverlist.cpp b/gui/serverlist.cpp index f49708ca..855056c2 100644 --- a/gui/serverlist.cpp +++ b/gui/serverlist.cpp @@ -39,12 +39,12 @@ ServerListDlg::ServerListDlg(QWidget *parent) : QDialog(parent) { settings.endGroup(); // check if we already have a valid identity - if(!global->getData("Identities", VarMap()).toMap().contains("Default")) editIdentities(true); + if(!Global::data("Identities", VarMap()).toMap().contains("Default")) editIdentities(true); connect(this, SIGNAL(requestConnect(QStringList)), guiProxy, SLOT(gsRequestConnect(QStringList))); // Autoconnect QStringList list; - VarMap networks = global->getData("Networks").toMap(); + VarMap networks = Global::data("Networks").toMap(); foreach(QString net, networks.keys()) { if(networks[net].toMap()["AutoConnect"].toBool()) { list << net; @@ -58,7 +58,7 @@ ServerListDlg::~ServerListDlg() { } void ServerListDlg::updateNetworkTree() { - VarMap networks = global->getData("Networks").toMap(); + VarMap networks = Global::data("Networks").toMap(); //QStringList headers; //headers << "Network" << "Autoconnect"; ui.networkTree->clear(); @@ -110,23 +110,23 @@ bool ServerListDlg::showOnStartup() { void ServerListDlg::on_addButton_clicked() { NetworkEditDlg dlg(this, VarMap()); if(dlg.exec() == QDialog::Accepted) { - VarMap networks = global->getData("Networks").toMap(); + VarMap networks = Global::data("Networks").toMap(); VarMap net = dlg.getNetwork(); networks[net["Name"].toString()] = net; - global->putData("Networks", networks); + Global::putData("Networks", networks); updateNetworkTree(); } } void ServerListDlg::on_editButton_clicked() { QString curnet = ui.networkTree->currentItem()->text(0); - VarMap networks = global->getData("Networks").toMap(); + VarMap networks = Global::data("Networks").toMap(); NetworkEditDlg dlg(this, networks[curnet].toMap()); if(dlg.exec() == QDialog::Accepted) { VarMap net = dlg.getNetwork(); networks.remove(curnet); networks[net["Name"].toString()] = net; - global->putData("Networks", networks); + Global::putData("Networks", networks); updateNetworkTree(); } } @@ -134,12 +134,12 @@ void ServerListDlg::on_editButton_clicked() { void ServerListDlg::on_deleteButton_clicked() { if(QMessageBox::warning(this, tr("Remove Network?"), tr("Are you sure you want to delete the selected network(s)?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - VarMap networks = global->getData("Networks").toMap(); + VarMap networks = Global::data("Networks").toMap(); QList sel = ui.networkTree->selectedItems(); foreach(QTreeWidgetItem *item, sel) { networks.remove(item->text(0)); } - global->putData("Networks", networks); + Global::putData("Networks", networks); updateNetworkTree(); } } @@ -183,14 +183,14 @@ NetworkEditDlg::NetworkEditDlg(QWidget *parent, VarMap _network) : QDialog(paren connect(ui.serverList, SIGNAL(itemSelectionChanged()), this, SLOT(updateServerButtons())); - VarMap identities = global->getData("Identities").toMap(); + VarMap identities = Global::data("Identities").toMap(); ui.identityList->addItem(tr("Default Identity")); foreach(QString id, identities.keys()) { if(id != "Default") ui.identityList->addItem(id); } QStringList groups; groups << ""; - VarMap nets = global->getData("Networks").toMap(); + VarMap nets = Global::data("Networks").toMap(); foreach(QString net, nets.keys()) { QString gr = nets[net].toMap()["Group"].toString(); if(!groups.contains(gr) && !gr.isEmpty()) { @@ -273,7 +273,7 @@ void NetworkEditDlg::accept() { QString NetworkEditDlg::checkValidity() { QString r; - VarMap nets = global->getData("Networks").toMap(); + VarMap nets = Global::data("Networks").toMap(); if(ui.networkName->text() != oldName && nets.keys().contains(ui.networkName->text())) { r += tr(" Network name already exists."); } @@ -338,7 +338,7 @@ void NetworkEditDlg::on_editIdentities_clicked() { else id = "Default"; IdentitiesDlg dlg(this, id); if(dlg.exec() == QDialog::Accepted) { - VarMap identities = global->getData("Identities").toMap(); + VarMap identities = Global::data("Identities").toMap(); ui.identityList->clear(); ui.identityList->addItem(tr("Default Identity")); foreach(QString i, identities.keys()) { diff --git a/main/global.cpp b/main/global.cpp index 3317cfda..3c82e815 100644 --- a/main/global.cpp +++ b/main/global.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005 by The Quassel Team * + * Copyright (C) 2005-07 by The Quassel IRC Development Team * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -29,60 +29,89 @@ extern void messageHandler(QtMsgType type, const char *msg); +Global *Global::instanceptr = 0; + +Global * Global::instance() { + if(instanceptr) return instanceptr; + return instanceptr = new Global(); +} + +void Global::destroy() { + delete instanceptr; + instanceptr = 0; +} + Global::Global() { - if(global) qFatal("Trying to instantiate more than one Global object!"); qInstallMsgHandler(messageHandler); qRegisterMetaType("Message"); qRegisterMetaTypeStreamOperators("Message"); qRegisterMetaType("BufferId"); qRegisterMetaTypeStreamOperators("BufferId"); - //initIconMap(); + guiUser = 0; } -/* -void Global::setLogger(Logger *) { +Global::~Global() { -}; -*/ +} + +void Global::setGuiUser(UserId uid) { + guiUser = uid; +} + +QVariant Global::data(QString key, QVariant defval) { + return data(guiUser, key, defval); +} -QVariant Global::getData(QString key, QVariant defval) { +QVariant Global::data(UserId uid, QString key, QVariant defval) { QVariant d; mutex.lock(); - if(data.contains(key)) d = data[key]; + if(instance()->datastore[uid].contains(key)) d = instance()->datastore[uid][key]; else d = defval; mutex.unlock(); //qDebug() << "getData("<datastore[uid].keys(); mutex.unlock(); return k; } void Global::putData(QString key, QVariant d) { + putData(guiUser, key, d); +} + +void Global::putData(UserId uid, QString key, QVariant d) { mutex.lock(); - data[key] = d; + instance()->datastore[uid][key] = d; mutex.unlock(); - emit dataPutLocally(key); + emit instance()->dataPutLocally(uid, key); } void Global::updateData(QString key, QVariant d) { + updateData(guiUser, key, d); +} + +void Global::updateData(UserId uid, QString key, QVariant d) { mutex.lock(); - data[key] = d; + instance()->datastore[uid][key] = d; mutex.unlock(); - emit dataUpdatedRemotely(key); + emit instance()->dataUpdatedRemotely(uid, key); } /* not done yet */ +/* void Global::initIconMap() { // Do not depend on GUI in core! -/* QDomDocument doc("IconMap"); QFile file("images/iconmap.xml"); if(!file.open(QIODevice::ReadOnly)) { @@ -95,8 +124,8 @@ void Global::initIconMap() { file.close(); } -*/ } +*/ /**************************************************************************************/ @@ -141,6 +170,7 @@ uint qHash(const BufferId &bid) { // return 0; //} -Global *global = 0; +QMutex Global::mutex; Global::RunMode Global::runMode; +UserId Global::guiUser; QString Global::quasselDir; diff --git a/main/global.h b/main/global.h index a662fd77..fa961f2f 100644 --- a/main/global.h +++ b/main/global.h @@ -22,7 +22,7 @@ #define _GLOBAL_H_ /** The protocol version we use fo the communication between core and GUI */ -#define GUI_PROTOCOL 1 +#define GUI_PROTOCOL 2 #define BACKLOG_FORMAT 2 #define BACKLOG_STRING "QuasselIRC Backlog File" @@ -34,7 +34,6 @@ class Global; /* Some global stuff */ typedef QMap VarMap; -extern Global *global; typedef uint UserId; typedef uint MsgId; @@ -53,41 +52,52 @@ class Global : public QObject { Q_OBJECT public: - Global(); //static Logger *getLogger(); //static void setLogger(Logger *); // static QIcon *getIcon(QString symbol); - QVariant getData(QString key, QVariant defaultValue = QVariant()); - QStringList getKeys(); + static Global *instance(); + static void destroy(); + static void setGuiUser(UserId); + + static QVariant data(QString key, QVariant defaultValue = QVariant()); + static QVariant data(UserId, QString key, QVariant defaultValue = QVariant()); + static QStringList keys(); + static QStringList keys(UserId); + + static void putData(QString key, QVariant data); ///< Store data changed locally, will be propagated to all other clients and the core + static void putData(UserId, QString key, QVariant data); - public slots: - void putData(QString key, QVariant data); ///< Store data changed locally, will be propagated to all other clients and the core - void updateData(QString key, QVariant data); ///< Update stored data if requested by the core or other clients + static void updateData(QString key, QVariant data); ///< Update stored data if requested by the core or other clients + static void updateData(UserId, QString key, QVariant data); signals: - void dataPutLocally(QString key); - void dataUpdatedRemotely(QString key); // sent by remote update only! + void dataPutLocally(UserId, QString key); + void dataUpdatedRemotely(UserId, QString key); // sent by remote update only! public: - enum RunMode { Monolithic, GUIOnly, CoreOnly }; + enum RunMode { Monolithic, GuiOnly, CoreOnly }; static RunMode runMode; static QString quasselDir; private: - static void initIconMap(); + Global(); + ~Global(); + static Global *instanceptr; + + static UserId guiUser; + //static void initIconMap(); //static Logger *logger; // static QString iconPath; - QHash iconMap; - QMutex mutex; - QHash data; + //QHash iconMap; + static QMutex mutex; + QHash > datastore; }; -class Exception { - public: +struct Exception { Exception(QString msg = "Unknown Exception") : _msg(msg) {}; virtual inline QString msg() { return _msg; } diff --git a/main/main_mono.cpp b/main/main_mono.cpp index e12ad2e9..fdfb22f7 100644 --- a/main/main_mono.cpp +++ b/main/main_mono.cpp @@ -34,17 +34,19 @@ int main(int argc, char **argv) { QApplication app(argc, argv); - QApplication::setOrganizationDomain("quassel-irc.org"); - QApplication::setApplicationName("Quassel IRC"); - QApplication::setOrganizationName("The Quassel Team"); + QCoreApplication::setOrganizationDomain("quassel-irc.org"); + QCoreApplication::setApplicationName("Quassel IRC"); + QCoreApplication::setOrganizationName("Quassel IRC Development Team"); Global::runMode = Global::Monolithic; Global::quasselDir = QDir::homePath() + "/.quassel"; //settings = new Settings(); - global = new Global(); + //global = new Global(); guiProxy = new GUIProxy(); - coreProxy = new CoreProxy(); + //coreProxy = new CoreProxy(); + QObject::connect(Core::guiSession(), SIGNAL(proxySignal(CoreSignal, QVariant, QVariant, QVariant)), guiProxy, SLOT(recv(CoreSignal, QVariant, QVariant, QVariant))); + QObject::connect(guiProxy, SIGNAL(send(GUISignal, QVariant, QVariant, QVariant)), Core::guiSession(), SLOT(processSignal(GUISignal, QVariant, QVariant, QVariant))); Settings::init(); Style::init(); @@ -53,33 +55,38 @@ int main(int argc, char **argv) { mainWin->show(); mainWin->init(); int exitCode = app.exec(); - delete core; + //delete core; + Core::destroy(); delete guiProxy; - delete coreProxy; - delete global; + //delete coreProxy; + //delete global; delete mainWin; //delete settings; return exitCode; } void MainWin::syncToCore() { - Q_ASSERT(global->getData("CoreReady").toBool()); - coreBuffers = core->getBuffers(); + //Q_ASSERT(Global::data("CoreReady").toBool()); + coreBuffers = Core::guiSession()->buffers(); // NOTE: We don't need to request server states, because in the monolithic version there can't be // any servers connected at this stage... } +/* void CoreProxy::sendToGUI(CoreSignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { guiProxy->recv(sig, arg1, arg2, arg3); } +*/ GUIProxy::GUIProxy() { if(guiProxy) qFatal("Trying to instantiate more than one GUIProxy object!"); } +/* void GUIProxy::send(GUISignal sig, QVariant arg1, QVariant arg2, QVariant arg3) { coreProxy->recv(sig, arg1, arg2, arg3); } +*/ // Dummy function definitions // These are not needed, since we don't have a network connection to the core. -- 2.20.1