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(&server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
51 //startListening(); // FIXME
54 if(Global::runMode == Global::Monolithic) { // TODO Make GUI user configurable
56 guiUser = storage->validateUser("Default", "password");
57 } catch(Storage::AuthError) {
58 guiUser = storage->addUser("Default", "password");
61 Global::setGuiUser(guiUser);
62 createSession(guiUser);
68 foreach(QTcpSocket *sock, validClients.keys()) {
75 CoreSession *Core::session(UserId uid) {
76 Core *core = instance();
77 if(core->sessions.contains(uid)) return core->sessions[uid];
81 CoreSession *Core::localSession() {
82 Core *core = instance();
83 if(core->guiUser && core->sessions.contains(core->guiUser)) return core->sessions[core->guiUser];
87 CoreSession *Core::createSession(UserId uid) {
88 Core *core = instance();
89 Q_ASSERT(!core->sessions.contains(uid));
90 CoreSession *sess = new CoreSession(uid, core->storage);
91 core->sessions[uid] = sess;
92 connect(sess, SIGNAL(proxySignal(CoreSignal, QVariant, QVariant, QVariant)), core, SLOT(recvProxySignal(CoreSignal, QVariant, QVariant, QVariant)));
97 bool Core::startListening(uint port) {
98 if(!server.listen(QHostAddress::Any, port)) {
99 qWarning(QString(QString("Could not open GUI client port %1: %2").arg(port).arg(server.errorString())).toAscii());
102 qDebug() << "Listening for GUI clients on port" << server.serverPort();
106 void Core::stopListening() {
108 qDebug() << "No longer listening for GUI clients.";
111 void Core::incomingConnection() {
112 // TODO implement SSL
113 QTcpSocket *socket = server.nextPendingConnection();
114 connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
115 connect(socket, SIGNAL(readyRead()), this, SLOT(clientHasData()));
116 blockSizes.insert(socket, (quint32)0);
117 qDebug() << "Client connected from " << socket->peerAddress().toString();
120 void Core::clientHasData() {
121 QTcpSocket *socket = dynamic_cast<QTcpSocket*>(sender());
122 Q_ASSERT(socket && blockSizes.contains(socket));
123 quint32 bsize = blockSizes.value(socket);
125 while(readDataFromDevice(socket, bsize, item)) {
126 if(validClients.contains(socket)) {
127 QList<QVariant> sigdata = item.toList();
128 sessions[validClients[socket]]->processSignal((ClientSignal)sigdata[0].toInt(), sigdata[1], sigdata[2], sigdata[3]);
130 // we need to auth the client
132 processClientInit(socket, item);
133 } catch(Storage::AuthError) {
134 qWarning() << "Authentification error!"; // FIXME
137 } catch(Exception e) {
138 qWarning() << "Client init error:" << e.msg();
143 blockSizes[socket] = bsize = 0;
145 blockSizes[socket] = bsize;
148 void Core::clientDisconnected() {
149 QTcpSocket *socket = dynamic_cast<QTcpSocket*>(sender());
150 blockSizes.remove(socket);
151 validClients.remove(socket);
152 qDebug() << "Client disconnected.";
153 // TODO remove unneeded sessions - if necessary/possible...
156 QVariant Core::connectLocalClient(QString user, QString passwd) {
157 UserId uid = instance()->storage->validateUser(user, passwd);
158 QVariant reply = instance()->initSession(uid);
159 instance()->guiUser = uid;
160 qDebug() << "Local client connected.";
164 void Core::disconnectLocalClient() {
165 qDebug() << "Local client disconnected.";
166 instance()->guiUser = 0;
169 void Core::processClientInit(QTcpSocket *socket, const QVariant &v) {
170 VarMap msg = v.toMap();
171 if(msg["GUIProtocol"].toUInt() != GUI_PROTOCOL) {
172 //qWarning() << "Client version mismatch.";
173 throw Exception("GUI client version mismatch");
176 UserId uid = storage->validateUser(msg["User"].toString(), msg["Password"].toString()); // throws exception if this failed
177 VarMap reply = initSession(uid).toMap();
178 validClients[socket] = uid;
179 QList<QVariant> sigdata;
180 sigdata.append(CS_CORE_STATE); sigdata.append(QVariant(reply)); sigdata.append(QVariant()); sigdata.append(QVariant());
181 writeDataToDevice(socket, QVariant(sigdata));
184 QVariant Core::initSession(UserId uid) {
185 // Find or create session for validated user
187 if(sessions.contains(uid)) sess = sessions[uid];
189 sess = createSession(uid);
190 //validClients[socket] = uid;
193 reply["SessionState"] = sess->sessionState();
197 void Core::recvProxySignal(CoreSignal sig, QVariant arg1, QVariant arg2, QVariant arg3) {
198 CoreSession *sess = qobject_cast<CoreSession*>(sender());
200 UserId uid = sess->userId();
201 QList<QVariant> sigdata;
202 sigdata.append(sig); sigdata.append(arg1); sigdata.append(arg2); sigdata.append(arg3);
203 //qDebug() << "Sending signal: " << sigdata;
204 foreach(QTcpSocket *socket, validClients.keys()) {
205 if(validClients[socket] == uid) writeDataToDevice(socket, QVariant(sigdata));