1 /***************************************************************************
2 * Copyright (C) 2005-07 by The Quassel IRC Development Team *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
22 #include "coresession.h"
23 #include "sqlitestorage.h"
26 Core *Core::instanceptr = 0;
28 Core * Core::instance() {
29 if(instanceptr) return instanceptr;
30 instanceptr = new Core();
35 void Core::destroy() {
45 if(!SqliteStorage::isAvailable()) {
46 qFatal("Sqlite is currently required! Please make sure your Qt library has sqlite support enabled.");
48 //SqliteStorage::init();
49 storage = new SqliteStorage();
50 connect(Global::instance(), SIGNAL(dataPutLocally(UserId, QString)), this, SLOT(updateGlobalData(UserId, QString)));
51 connect(&server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
52 //startListening(); // FIXME
55 if(Global::runMode == Global::Monolithic) { // TODO Make GUI user configurable
57 guiUser = storage->validateUser("Default", "password");
58 } catch(Storage::AuthError) {
59 guiUser = storage->addUser("Default", "password");
62 Global::setGuiUser(guiUser);
63 createSession(guiUser);
66 // Read global settings from config file
68 s.beginGroup("Global");
69 foreach(QString unum, s.childGroups()) {
70 UserId uid = unum.toUInt();
72 foreach(QString key, s.childKeys()) {
73 Global::updateData(uid, key, s.value(key));
81 foreach(QTcpSocket *sock, validClients.keys()) {
88 CoreSession *Core::session(UserId uid) {
89 Core *core = instance();
90 if(core->sessions.contains(uid)) return core->sessions[uid];
94 CoreSession *Core::localSession() {
95 Core *core = instance();
96 if(core->guiUser && core->sessions.contains(core->guiUser)) return core->sessions[core->guiUser];
100 CoreSession *Core::createSession(UserId uid) {
101 Core *core = instance();
102 Q_ASSERT(!core->sessions.contains(uid));
103 CoreSession *sess = new CoreSession(uid, core->storage);
104 core->sessions[uid] = sess;
105 connect(sess, SIGNAL(proxySignal(CoreSignal, QVariant, QVariant, QVariant)), core, SLOT(recvProxySignal(CoreSignal, QVariant, QVariant, QVariant)));
110 bool Core::startListening(uint port) {
111 if(!server.listen(QHostAddress::Any, port)) {
112 qWarning(QString(QString("Could not open GUI client port %1: %2").arg(port).arg(server.errorString())).toAscii());
115 qDebug() << "Listening for GUI clients on port" << server.serverPort();
119 void Core::stopListening() {
121 qDebug() << "No longer listening for GUI clients.";
124 void Core::incomingConnection() {
125 // TODO implement SSL
126 QTcpSocket *socket = server.nextPendingConnection();
127 connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
128 connect(socket, SIGNAL(readyRead()), this, SLOT(clientHasData()));
129 blockSizes.insert(socket, (quint32)0);
130 qDebug() << "Client connected from " << socket->peerAddress().toString();
133 void Core::clientHasData() {
134 QTcpSocket *socket = dynamic_cast<QTcpSocket*>(sender());
135 Q_ASSERT(socket && blockSizes.contains(socket));
136 quint32 bsize = blockSizes.value(socket);
138 while(readDataFromDevice(socket, bsize, item)) {
139 if(validClients.contains(socket)) {
140 QList<QVariant> sigdata = item.toList();
141 if((ClientSignal)sigdata[0].toInt() == GS_UPDATE_GLOBAL_DATA) {
142 processClientUpdate(socket, sigdata[1].toString(), sigdata[2]);
144 sessions[validClients[socket]]->processSignal((ClientSignal)sigdata[0].toInt(), sigdata[1], sigdata[2], sigdata[3]);
147 // we need to auth the client
149 processClientInit(socket, item);
150 } catch(Storage::AuthError) {
151 qWarning() << "Authentification error!"; // FIXME
154 } catch(Exception e) {
155 qWarning() << "Client init error:" << e.msg();
160 blockSizes[socket] = bsize = 0;
162 blockSizes[socket] = bsize;
165 void Core::clientDisconnected() {
166 QTcpSocket *socket = dynamic_cast<QTcpSocket*>(sender());
167 blockSizes.remove(socket);
168 validClients.remove(socket);
169 qDebug() << "Client disconnected.";
170 // TODO remove unneeded sessions - if necessary/possible...
173 QVariant Core::connectLocalClient(QString user, QString passwd) {
174 UserId uid = instance()->storage->validateUser(user, passwd);
175 QVariant reply = instance()->initSession(uid);
176 instance()->guiUser = uid;
177 Global::setGuiUser(uid);
178 qDebug() << "Local client connected.";
182 void Core::disconnectLocalClient() {
183 qDebug() << "Local client disconnected.";
184 instance()->guiUser = 0;
185 Global::setGuiUser(0);
188 void Core::processClientInit(QTcpSocket *socket, const QVariant &v) {
189 VarMap msg = v.toMap();
190 if(msg["GUIProtocol"].toUInt() != GUI_PROTOCOL) {
191 //qWarning() << "Client version mismatch.";
192 throw Exception("GUI client version mismatch");
195 UserId uid = storage->validateUser(msg["User"].toString(), msg["Password"].toString()); // throws exception if this failed
196 VarMap reply = initSession(uid).toMap();
197 validClients[socket] = uid;
198 QList<QVariant> sigdata;
199 sigdata.append(CS_CORE_STATE); sigdata.append(QVariant(reply)); sigdata.append(QVariant()); sigdata.append(QVariant());
200 writeDataToDevice(socket, QVariant(sigdata));
203 QVariant Core::initSession(UserId uid) {
204 // Find or create session for validated user
206 if(sessions.contains(uid)) sess = sessions[uid];
208 sess = createSession(uid);
209 //validClients[socket] = uid;
213 QStringList dataKeys = Global::keys(uid);
214 foreach(QString key, dataKeys) {
215 coreData[key] = Global::data(uid, key);
217 reply["CoreData"] = coreData;
218 reply["SessionState"] = sess->sessionState();
222 void Core::processClientUpdate(QTcpSocket *socket, QString key, const QVariant &data) {
223 UserId uid = validClients[socket];
224 Global::updateData(uid, key, data);
225 QList<QVariant> sigdata;
226 sigdata.append(CS_UPDATE_GLOBAL_DATA); sigdata.append(key); sigdata.append(data); sigdata.append(QVariant());
227 foreach(QTcpSocket *s, validClients.keys()) {
228 if(validClients[s] == uid && s != socket) writeDataToDevice(s, QVariant(sigdata));
232 void Core::updateGlobalData(UserId uid, QString key) {
233 QVariant data = Global::data(uid, key);
234 QList<QVariant> sigdata;
235 sigdata.append(CS_UPDATE_GLOBAL_DATA); sigdata.append(key); sigdata.append(data); sigdata.append(QVariant());
236 foreach(QTcpSocket *socket, validClients.keys()) {
237 if(validClients[socket] == uid) writeDataToDevice(socket, QVariant(sigdata));
241 void Core::recvProxySignal(CoreSignal sig, QVariant arg1, QVariant arg2, QVariant arg3) {
242 CoreSession *sess = qobject_cast<CoreSession*>(sender());
244 UserId uid = sess->userId();
245 QList<QVariant> sigdata;
246 sigdata.append(sig); sigdata.append(arg1); sigdata.append(arg2); sigdata.append(arg3);
247 //qDebug() << "Sending signal: " << sigdata;
248 foreach(QTcpSocket *socket, validClients.keys()) {
249 if(validClients[socket] == uid) writeDataToDevice(socket, QVariant(sigdata));