-void Core::clientDisconnected() {
- QTcpSocket *socket = dynamic_cast<QTcpSocket*>(sender());
- blocksizes.remove(socket);
- clientInfo.remove(socket);
- qDebug() << qPrintable(tr("Client %1 disconnected.").arg(socket->peerAddress().toString()));
- socket->deleteLater();
- socket = 0;
-
- // make server listen again if still not configured FIXME
- if (!configured) {
- startListening();
- }
-
- // TODO remove unneeded sessions - if necessary/possible...
- // Suggestion: kill sessions if they are not connected to any network and client.
-}
-
-void Core::processCoreSetup(QTcpSocket *socket, QVariantMap &msg) {
- if(msg["HasSettings"].toBool()) {
- QVariantMap auth;
- auth["User"] = msg["User"];
- auth["Password"] = msg["Password"];
- msg.remove("User");
- msg.remove("Password");
- qDebug() << "Initializing storage provider" << msg["Type"].toString();
-
- if(!initStorage(msg, true)) {
- // notify client to start wizard again
- qWarning("Core is currently not configured!");
- QVariantMap reply;
- reply["StartWizard"] = true;
- reply["StorageProviders"] = availableStorageProviders();
- SignalProxy::writeDataToDevice(socket, reply);
- } else {
- // write coresettings
- CoreSettings s;
- s.setDatabaseSettings(msg);
- // write admin user to database & make the core listen again to connections
- storage->addUser(auth["User"].toString(), auth["Password"].toString());
- startListening();
- // continue the normal procedure
- //processClientInit(socket, auth);
- }
- } else {
- // notify client to start wizard
- QVariantMap reply;
- reply["StartWizard"] = true;
- reply["StorageProviders"] = availableStorageProviders();
- SignalProxy::writeDataToDevice(socket, reply);
- }
-}
-
-void Core::setupClientSession(QTcpSocket *socket, UserId uid) {
- // Find or create session for validated user
- SessionThread *sess;
- if(sessions.contains(uid)) sess = sessions[uid];
- else sess = createSession(uid);
- // Hand over socket, session then sends state itself
- disconnect(socket, 0, this, 0);
- if(!sess) {
- qWarning() << qPrintable(tr("Could not initialize session for client %1!").arg(socket->peerAddress().toString()));
- socket->close();
- }
- sess->addClient(socket);
-}
-
-SessionThread *Core::createSession(UserId uid, bool restore) {
- if(sessions.contains(uid)) {
- qWarning() << "Calling createSession() when a session for the user already exists!";
- return 0;
- }
- SessionThread *sess = new SessionThread(uid, restore, this);
- sessions[uid] = sess;
- sess->start();
- return sess;
-}
-
-QStringList Core::availableStorageProviders() {
- QStringList storageProviders;
- if (SqliteStorage::isAvailable()) {
- storageProviders.append(SqliteStorage::displayName());
- }
- // TODO: temporary
- // storageProviders.append("MySQL");
-
- return storageProviders;
+void Core::clientDisconnected()
+{
+ CoreAuthHandler *handler = qobject_cast<CoreAuthHandler *>(sender());
+ Q_ASSERT(handler);
+
+ quInfo() << qPrintable(tr("Non-authed client disconnected:")) << qPrintable(handler->socket()->peerAddress().toString());
+ _connectingClients.remove(handler);
+ handler->deleteLater();
+
+ // make server listen again if still not configured
+ if (!_configured) {
+ startListening();
+ }
+
+ // TODO remove unneeded sessions - if necessary/possible...
+ // Suggestion: kill sessions if they are not connected to any network and client.
+}
+
+
+void Core::setupClientSession(RemotePeer *peer, UserId uid)
+{
+ CoreAuthHandler *handler = qobject_cast<CoreAuthHandler *>(sender());
+ Q_ASSERT(handler);
+
+ // From now on everything is handled by the client session
+ disconnect(handler, 0, this, 0);
+ _connectingClients.remove(handler);
+ handler->deleteLater();
+
+ // Find or create session for validated user
+ sessionForUser(uid);
+
+ // as we are currently handling an event triggered by incoming data on this socket
+ // it is unsafe to directly move the socket to the client thread.
+ QCoreApplication::postEvent(this, new AddClientEvent(peer, uid));
+}
+
+
+void Core::customEvent(QEvent *event)
+{
+ if (event->type() == AddClientEventId) {
+ AddClientEvent *addClientEvent = static_cast<AddClientEvent *>(event);
+ addClientHelper(addClientEvent->peer, addClientEvent->userId);
+ return;
+ }
+}
+
+
+void Core::addClientHelper(RemotePeer *peer, UserId uid)
+{
+ // Find or create session for validated user
+ SessionThread *session = sessionForUser(uid);
+ session->addClient(peer);
+}
+
+
+void Core::setupInternalClientSession(InternalPeer *clientPeer)
+{
+ if (!_configured) {
+ stopListening();
+ setupCoreForInternalUsage();
+ }
+
+ UserId uid;
+ if (_storage) {
+ uid = _storage->internalUser();
+ }
+ else {
+ qWarning() << "Core::setupInternalClientSession(): You're trying to run monolithic Quassel with an unusable Backend! Go fix it!";
+ return;
+ }
+
+ InternalPeer *corePeer = new InternalPeer(this);
+ corePeer->setPeer(clientPeer);
+ clientPeer->setPeer(corePeer);
+
+ // Find or create session for validated user
+ SessionThread *sessionThread = sessionForUser(uid);
+ sessionThread->addClient(corePeer);
+}
+
+
+SessionThread *Core::sessionForUser(UserId uid, bool restore)
+{
+ if (_sessions.contains(uid))
+ return _sessions[uid];
+
+ SessionThread *session = new SessionThread(uid, restore, this);
+ _sessions[uid] = session;
+ session->start();
+ return session;
+}
+
+
+void Core::socketError(QAbstractSocket::SocketError err, const QString &errorString)
+{
+ qWarning() << QString("Socket error %1: %2").arg(err).arg(errorString);
+}
+
+
+QVariantList Core::backendInfo()
+{
+ QVariantList backends;
+ foreach(const Storage *backend, instance()->_storageBackends.values()) {
+ QVariantMap v;
+ v["DisplayName"] = backend->displayName();
+ v["Description"] = backend->description();
+ v["SetupKeys"] = backend->setupKeys();
+ v["SetupDefaults"] = backend->setupDefaults();
+ backends.append(v);
+ }
+ return backends;
+}
+
+
+// migration / backend selection
+bool Core::selectBackend(const QString &backend)
+{
+ // reregister all storage backends
+ registerStorageBackends();
+ if (!_storageBackends.contains(backend)) {
+ qWarning() << qPrintable(QString("Core::selectBackend(): unsupported backend: %1").arg(backend));
+ qWarning() << " supported backends are:" << qPrintable(QStringList(_storageBackends.keys()).join(", "));
+ return false;
+ }
+
+ Storage *storage = _storageBackends[backend];
+ QVariantMap settings = promptForSettings(storage);
+
+ Storage::State storageState = storage->init(settings);
+ switch (storageState) {
+ case Storage::IsReady:
+ saveBackendSettings(backend, settings);
+ qWarning() << "Switched backend to:" << qPrintable(backend);
+ qWarning() << "Backend already initialized. Skipping Migration";
+ return true;
+ case Storage::NotAvailable:
+ qCritical() << "Backend is not available:" << qPrintable(backend);
+ return false;
+ case Storage::NeedsSetup:
+ if (!storage->setup(settings)) {
+ qWarning() << qPrintable(QString("Core::selectBackend(): unable to setup backend: %1").arg(backend));
+ return false;
+ }
+
+ if (storage->init(settings) != Storage::IsReady) {
+ qWarning() << qPrintable(QString("Core::migrateBackend(): unable to initialize backend: %1").arg(backend));
+ return false;
+ }
+
+ saveBackendSettings(backend, settings);
+ qWarning() << "Switched backend to:" << qPrintable(backend);
+ break;
+ }
+
+ // let's see if we have a current storage object we can migrate from
+ AbstractSqlMigrationReader *reader = getMigrationReader(_storage);
+ AbstractSqlMigrationWriter *writer = getMigrationWriter(storage);
+ if (reader && writer) {
+ qDebug() << qPrintable(QString("Migrating Storage backend %1 to %2...").arg(_storage->displayName(), storage->displayName()));
+ delete _storage;
+ _storage = 0;
+ delete storage;
+ storage = 0;
+ if (reader->migrateTo(writer)) {
+ qDebug() << "Migration finished!";
+ saveBackendSettings(backend, settings);
+ return true;
+ }
+ return false;
+ qWarning() << qPrintable(QString("Core::migrateDb(): unable to migrate storage backend! (No migration writer for %1)").arg(backend));
+ }
+
+ // inform the user why we cannot merge
+ if (!_storage) {
+ qWarning() << "No currently active backend. Skipping migration.";
+ }
+ else if (!reader) {
+ qWarning() << "Currently active backend does not support migration:" << qPrintable(_storage->displayName());
+ }
+ if (writer) {
+ qWarning() << "New backend does not support migration:" << qPrintable(backend);
+ }
+
+ // so we were unable to merge, but let's create a user \o/
+ _storage = storage;
+ createUser();
+ return true;
+}
+
+
+void Core::createUser()
+{
+ QTextStream out(stdout);
+ QTextStream in(stdin);
+ out << "Add a new user:" << endl;
+ out << "Username: ";
+ out.flush();
+ QString username = in.readLine().trimmed();
+
+ disableStdInEcho();
+ out << "Password: ";
+ out.flush();
+ QString password = in.readLine().trimmed();
+ out << endl;
+ out << "Repeat Password: ";
+ out.flush();
+ QString password2 = in.readLine().trimmed();
+ out << endl;
+ enableStdInEcho();
+
+ if (password != password2) {
+ qWarning() << "Passwords don't match!";
+ return;
+ }
+ if (password.isEmpty()) {
+ qWarning() << "Password is empty!";
+ return;
+ }
+
+ if (_configured && _storage->addUser(username, password).isValid()) {
+ out << "Added user " << username << " successfully!" << endl;
+ }
+ else {
+ qWarning() << "Unable to add user:" << qPrintable(username);
+ }
+}
+
+
+void Core::changeUserPass(const QString &username)
+{
+ QTextStream out(stdout);
+ QTextStream in(stdin);
+ UserId userId = _storage->getUserId(username);
+ if (!userId.isValid()) {
+ out << "User " << username << " does not exist." << endl;
+ return;
+ }
+
+ out << "Change password for user: " << username << endl;
+
+ disableStdInEcho();
+ out << "New Password: ";
+ out.flush();
+ QString password = in.readLine().trimmed();
+ out << endl;
+ out << "Repeat Password: ";
+ out.flush();
+ QString password2 = in.readLine().trimmed();
+ out << endl;
+ enableStdInEcho();
+
+ if (password != password2) {
+ qWarning() << "Passwords don't match!";
+ return;
+ }
+ if (password.isEmpty()) {
+ qWarning() << "Password is empty!";
+ return;
+ }
+
+ if (_configured && _storage->updateUser(userId, password)) {
+ out << "Password changed successfully!" << endl;
+ }
+ else {
+ qWarning() << "Failed to change password!";
+ }
+}
+
+
+bool Core::changeUserPassword(UserId userId, const QString &password)
+{
+ if (!isConfigured() || !userId.isValid())
+ return false;
+
+ return instance()->_storage->updateUser(userId, password);
+}
+
+
+AbstractSqlMigrationReader *Core::getMigrationReader(Storage *storage)
+{
+ if (!storage)
+ return 0;
+
+ AbstractSqlStorage *sqlStorage = qobject_cast<AbstractSqlStorage *>(storage);
+ if (!sqlStorage) {
+ qDebug() << "Core::migrateDb(): only SQL based backends can be migrated!";
+ return 0;
+ }
+
+ return sqlStorage->createMigrationReader();
+}
+
+
+AbstractSqlMigrationWriter *Core::getMigrationWriter(Storage *storage)
+{
+ if (!storage)
+ return 0;
+
+ AbstractSqlStorage *sqlStorage = qobject_cast<AbstractSqlStorage *>(storage);
+ if (!sqlStorage) {
+ qDebug() << "Core::migrateDb(): only SQL based backends can be migrated!";
+ return 0;
+ }
+
+ return sqlStorage->createMigrationWriter();