+
+ QFileInfo info(Quassel::configDirPath() + "quassel-storage.sqlite");
+ if (!info.exists()) {
+ // move database, if we found it
+ QFile oldDb(quasselDir + "quassel-storage.sqlite");
+ if (oldDb.exists()) {
+ bool success = oldDb.rename(Quassel::configDirPath() + "quassel-storage.sqlite");
+ if (success)
+ qWarning() << "* Your database has been moved to" << Quassel::configDirPath() + "quassel-storage.sqlite";
+ else
+ qWarning() << "!!! Moving your database has failed. Please move it manually into" << Quassel::configDirPath();
+ }
+ }
+ // move certificate
+ QFileInfo certInfo(quasselDir + "quasselCert.pem");
+ if (certInfo.exists()) {
+ QFile cert(quasselDir + "quasselCert.pem");
+ bool success = cert.rename(Quassel::configDirPath() + "quasselCert.pem");
+ if (success)
+ qWarning() << "* Your certificate has been moved to" << Quassel::configDirPath() + "quasselCert.pem";
+ else
+ qWarning() << "!!! Moving your certificate has failed. Please move it manually into" << Quassel::configDirPath();
+ }
+#endif /* !Q_OS_MAC */
+ qWarning() << "*** Migration completed.\n\n";
+ }
+ }
+ // MIGRATION end
+
+ // check settings version
+ // so far, we only have 1
+ CoreSettings s;
+ if (s.version() != 1) {
+ qCritical() << "Invalid core settings version, terminating!";
+ exit(EXIT_FAILURE);
+ }
+
+ registerStorageBackends();
+
+ connect(&_storageSyncTimer, SIGNAL(timeout()), this, SLOT(syncStorage()));
+ _storageSyncTimer.start(10 * 60 * 1000); // 10 minutes
+}
+
+
+void Core::init()
+{
+ CoreSettings cs;
+ // legacy
+ QVariantMap dbsettings = cs.storageSettings().toMap();
+ _configured = initStorage(dbsettings.value("Backend").toString(), dbsettings.value("ConnectionProperties").toMap());
+
+ if (Quassel::isOptionSet("select-backend")) {
+ selectBackend(Quassel::optionValue("select-backend"));
+ exit(0);
+ }
+
+ if (!_configured) {
+ if (!_storageBackends.count()) {
+ qWarning() << qPrintable(tr("Could not initialize any storage backend! Exiting..."));
+ qWarning() << qPrintable(tr("Currently, Quassel supports SQLite3 and PostgreSQL. You need to build your\n"
+ "Qt library with the sqlite or postgres plugin enabled in order for quasselcore\n"
+ "to work."));
+ exit(1); // TODO make this less brutal (especially for mono client -> popup)
+ }
+ qWarning() << "Core is currently not configured! Please connect with a Quassel Client for basic setup.";
+ }
+
+ if (Quassel::isOptionSet("add-user")) {
+ createUser();
+ exit(0);
+ }
+
+ if (Quassel::isOptionSet("change-userpass")) {
+ changeUserPass(Quassel::optionValue("change-userpass"));
+ exit(0);
+ }
+
+ connect(&_server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
+ connect(&_v6server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
+ if (!startListening()) exit(1); // TODO make this less brutal
+
+ if (Quassel::isOptionSet("oidentd"))
+ _oidentdConfigGenerator = new OidentdConfigGenerator(this);
+}
+
+
+Core::~Core()
+{
+ // FIXME do we need more cleanup for handlers?
+ foreach(CoreAuthHandler *handler, _connectingClients) {
+ handler->deleteLater(); // disconnect non authed clients
+ }
+ qDeleteAll(_sessions);
+ qDeleteAll(_storageBackends);
+}
+
+
+/*** Session Restore ***/
+
+void Core::saveState()
+{
+ CoreSettings s;
+ QVariantMap state;
+ QVariantList activeSessions;
+ foreach(UserId user, instance()->_sessions.keys())
+ activeSessions << QVariant::fromValue<UserId>(user);
+ state["CoreStateVersion"] = 1;
+ state["ActiveSessions"] = activeSessions;
+ s.setCoreState(state);
+}
+
+
+void Core::restoreState()
+{
+ if (!instance()->_configured) {
+ // qWarning() << qPrintable(tr("Cannot restore a state for an unconfigured core!"));
+ return;
+ }
+ if (instance()->_sessions.count()) {
+ qWarning() << qPrintable(tr("Calling restoreState() even though active sessions exist!"));
+ return;
+ }
+ CoreSettings s;
+ /* We don't check, since we are at the first version since switching to Git
+ uint statever = s.coreState().toMap()["CoreStateVersion"].toUInt();
+ if(statever < 1) {
+ qWarning() << qPrintable(tr("Core state too old, ignoring..."));
+ return;
+ }
+ */
+
+ QVariantList activeSessions = s.coreState().toMap()["ActiveSessions"].toList();
+ if (activeSessions.count() > 0) {
+ quInfo() << "Restoring previous core state...";
+ foreach(QVariant v, activeSessions) {
+ UserId user = v.value<UserId>();
+ instance()->sessionForUser(user, true);
+ }
+ }
+}
+
+
+/*** Core Setup ***/
+
+QString Core::setup(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData)
+{
+ return instance()->setupCore(adminUser, adminPassword, backend, setupData);
+}
+
+
+QString Core::setupCore(const QString &adminUser, const QString &adminPassword, const QString &backend, const QVariantMap &setupData)
+{
+ if (_configured)
+ return tr("Core is already configured! Not configuring again...");
+
+ if (adminUser.isEmpty() || adminPassword.isEmpty()) {
+ return tr("Admin user or password not set.");
+ }
+ if (!(_configured = initStorage(backend, setupData, true))) {
+ return tr("Could not setup storage!");
+ }
+
+ saveBackendSettings(backend, setupData);
+
+ quInfo() << qPrintable(tr("Creating admin user..."));
+ _storage->addUser(adminUser, adminPassword);
+ startListening(); // TODO check when we need this
+ return QString();
+}
+
+
+QString Core::setupCoreForInternalUsage()
+{
+ Q_ASSERT(!_storageBackends.isEmpty());
+
+ qsrand(QDateTime::currentDateTime().toTime_t());
+ int pass = 0;
+ for (int i = 0; i < 10; i++) {
+ pass *= 10;
+ pass += qrand() % 10;
+ }
+
+ // mono client currently needs sqlite
+ return setupCore("AdminUser", QString::number(pass), "SQLite", QVariantMap());
+}
+
+
+/*** Storage Handling ***/
+void Core::registerStorageBackends()
+{
+ // Register storage backends here!
+ registerStorageBackend(new SqliteStorage(this));
+ registerStorageBackend(new PostgreSqlStorage(this));
+}
+
+
+bool Core::registerStorageBackend(Storage *backend)
+{
+ if (backend->isAvailable()) {
+ _storageBackends[backend->displayName()] = backend;
+ return true;
+ }
+ else {
+ backend->deleteLater();
+ return false;
+ }
+}
+
+
+void Core::unregisterStorageBackends()
+{
+ foreach(Storage *s, _storageBackends.values()) {
+ s->deleteLater();
+ }
+ _storageBackends.clear();
+}
+
+
+void Core::unregisterStorageBackend(Storage *backend)
+{
+ _storageBackends.remove(backend->displayName());
+ backend->deleteLater();
+}
+
+
+// old db settings:
+// "Type" => "sqlite"
+bool Core::initStorage(const QString &backend, const QVariantMap &settings, bool setup)
+{
+ _storage = 0;
+
+ if (backend.isEmpty()) {
+ return false;
+ }
+
+ Storage *storage = 0;
+ if (_storageBackends.contains(backend)) {
+ storage = _storageBackends[backend];
+ }
+ else {
+ qCritical() << "Selected storage backend is not available:" << backend;
+ return false;
+ }
+
+ Storage::State storageState = storage->init(settings);
+ switch (storageState) {
+ case Storage::NeedsSetup:
+ if (!setup)
+ return false; // trigger setup process
+ if (storage->setup(settings))
+ return initStorage(backend, settings, false);
+ // if initialization wasn't successful, we quit to keep from coming up unconfigured
+ case Storage::NotAvailable:
+ qCritical() << "FATAL: Selected storage backend is not available:" << backend;
+ exit(EXIT_FAILURE);
+ case Storage::IsReady:
+ // delete all other backends
+ _storageBackends.remove(backend);
+ unregisterStorageBackends();
+ connect(storage, SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &)), this, SIGNAL(bufferInfoUpdated(UserId, const BufferInfo &)));
+ }
+ _storage = storage;
+ return true;
+}
+
+
+void Core::syncStorage()
+{
+ if (_storage)
+ _storage->sync();
+}
+
+
+/*** Storage Access ***/
+bool Core::createNetwork(UserId user, NetworkInfo &info)
+{
+ NetworkId networkId = instance()->_storage->createNetwork(user, info);
+ if (!networkId.isValid())
+ return false;
+
+ info.networkId = networkId;
+ return true;
+}
+
+
+/*** Network Management ***/
+
+bool Core::sslSupported()
+{
+#ifdef HAVE_SSL
+ SslServer *sslServer = qobject_cast<SslServer *>(&instance()->_server);
+ return sslServer && sslServer->isCertValid();