The Quassel Core now remembers on exit which networks where connected and which channels
authorManuel Nickschas <sputnick@quassel-irc.org>
Fri, 21 Dec 2007 01:41:01 +0000 (01:41 +0000)
committerManuel Nickschas <sputnick@quassel-irc.org>
Fri, 21 Dec 2007 01:41:01 +0000 (01:41 +0000)
everybody has joined, and restores this information upon restart (so all networks will
automagically connected and the appropriate channels rejoined).
Has not been tested with more than one active CoreSessions.
You can start the core without session restore by using --norestore as parameter.
Closes BR #63.

15 files changed:
Quassel.kdevelop.filelist
src/common/main.cpp
src/common/networkinfo.cpp
src/common/networkinfo.h
src/core/core.cpp
src/core/core.h
src/core/coresession.cpp
src/core/coresession.h
src/core/coresettings.cpp
src/core/coresettings.h
src/core/ircserverhandler.cpp
src/core/server.cpp
src/core/server.h
src/qtui/mainwin.cpp
src/qtui/ui/settingsdlg.ui

index 0bcef57..dfd181f 100644 (file)
@@ -199,8 +199,11 @@ src/uisupport/inputline.h
 src/uisupport/nickview.cpp
 src/uisupport/nickview.h
 src/uisupport/settingspage.cpp
+src/uisupport/settingspage.h
 src/uisupport/tabcompleter.cpp
 src/uisupport/tabcompleter.h
+src/uisupport/uisettings.cpp
+src/uisupport/uisettings.h
 src/uisupport/uistyle.cpp
 src/uisupport/uistyle.h
 src/uisupport/uisupport.pri
index 00d7c86..cb935e7 100644 (file)
@@ -98,8 +98,18 @@ int main(int argc, char **argv) {
   gui->init();
 #endif
 
+#ifndef BUILD_QTUI
+  if(!QCoreApplication::arguments().contains("--norestore")) {
+    Core::restoreState();
+  }
+#endif
+
   int exitCode = app.exec();
 
+#ifndef BUILD_QTUI
+  Core::saveState();
+#endif
+
 #ifndef BUILD_CORE
   // the mainWin has to be deleted before the Core
   // if not Quassel will crash on exit under certain conditions since the gui
index 8836a70..89e88cc 100644 (file)
@@ -75,7 +75,7 @@ bool NetworkInfo::isMyNick(const QString &nick) const {
 }
 
 bool NetworkInfo::isMyNick(IrcUser *ircuser) const {
-  return (ircuser->nick().toLower() == myNick());
+  return (ircuser->nick().toLower() == myNick().toLower());
 }
 
 bool NetworkInfo::isChannelName(const QString &channelname) const {
index e27c66b..0c6516b 100644 (file)
@@ -28,6 +28,8 @@
 #include <QVariantMap>
 #include <QPointer>
 
+#include "types.h"
+
 class SignalProxy;
 class IrcUser;
 class IrcChannel;
@@ -44,7 +46,7 @@ public:
   NetworkInfo(const uint &networkid, QObject *parent = 0);
   //virtual ~NetworkInfo();
 
-  uint networkId() const;
+  NetworkId networkId() const;
   bool initialized() const;
 
   SignalProxy *proxy() const;
index b3abba6..ee93bcd 100644 (file)
@@ -64,6 +64,7 @@ void Core::init() {
   connect(&server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
   startListening(s.port());
   guiUser = 0;
+
 }
 
 bool Core::initStorageSqlite(QVariantMap dbSettings, bool setup) {
@@ -92,6 +93,34 @@ Core::~Core() {
   }
 }
 
+void Core::restoreState() {
+  Q_ASSERT(!instance()->sessions.count());
+  CoreSettings s;
+  QList<QVariant> users = s.coreState().toList();
+  if(users.count() > 0) {
+    qDebug() << "Restoring previous core state...";
+    foreach(QVariant v, users) {
+      QVariantMap m = v.toMap();
+      if(m.contains("UserId")) {
+        CoreSession *sess = createSession(m["UserId"].toUInt());
+        sess->restoreState(m["State"]);
+      }
+    }
+  }
+}
+
+void Core::saveState() {
+  CoreSettings s;
+  QList<QVariant> users;
+  foreach(CoreSession *sess, instance()->sessions.values()) {
+    QVariantMap m;
+    m["UserId"] = sess->userId();
+    m["State"] = sess->state();
+    users << m;
+  }
+  s.setCoreState(users);
+}
+
 CoreSession *Core::session(UserId uid) {
   Core *core = instance();
   if(core->sessions.contains(uid)) return core->sessions[uid];
index 85fcd49..fc20772 100644 (file)
@@ -46,6 +46,9 @@ class Core : public QObject {
     static QVariant connectLocalClient(QString user, QString passwd);
     static void disconnectLocalClient();
 
+    static void saveState();
+    static void restoreState();
+
   private slots:
     bool startListening(uint port = DEFAULT_PORT);
     void stopListening();
index dcc5641..e807289 100644 (file)
@@ -60,6 +60,7 @@ CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent)
   p->attachSignal(this, SIGNAL(sessionDataChanged(const QString &, const QVariant &)), SIGNAL(coreSessionDataChanged(const QString &, const QVariant &)));
   p->attachSlot(SIGNAL(clientSessionDataChanged(const QString &, const QVariant &)), this, SLOT(storeSessionData(const QString &, const QVariant &)));
   /* Autoconnect. (When) do we actually do this?
+     --> session restore should be enough!
   QStringList list;
   QVariantMap networks = retrieveSessionData("Networks").toMap();
   foreach(QString net, networks.keys()) {
@@ -69,6 +70,7 @@ CoreSession::CoreSession(UserId uid, Storage *_storage, QObject *parent)
   } qDebug() << list;
   if(list.count()) connectToIrc(list);
   */
+
 }
 
 CoreSession::~CoreSession() {
@@ -78,6 +80,34 @@ UserId CoreSession::userId() const {
   return user;
 }
 
+QVariant CoreSession::state() const {
+  QVariantMap res;
+  QList<QVariant> conn;
+  foreach(Server *server, servers.values()) {
+    if(server->isConnected()) {
+      QVariantMap m;
+      m["Network"] = server->networkName();
+      m["State"] = server->state();
+      conn << m;
+    }
+  }
+  res["ConnectedServers"] = conn;
+  return res;
+}
+
+void CoreSession::restoreState(const QVariant &previousState) {
+  // Session restore
+  QVariantMap state = previousState.toMap();
+  if(state.contains("ConnectedServers")) {
+    foreach(QVariant v, state["ConnectedServers"].toList()) {
+      QVariantMap m = v.toMap();
+      QString net = m["Network"].toString();
+      if(!net.isEmpty()) connectToNetwork(net, m["State"]);
+    }
+  }
+}
+
+
 void CoreSession::storeSessionData(const QString &key, const QVariant &data) {
   QSettings s;
   s.beginGroup(QString("SessionData/%1").arg(user));
@@ -100,14 +130,14 @@ QVariant CoreSession::retrieveSessionData(const QString &key, const QVariant &de
 }
 
 // FIXME switch to NetworkIDs
-void CoreSession::connectToNetwork(QString network) {
+void CoreSession::connectToNetwork(QString network, const QVariant &previousState) {
   uint networkid = getNetworkId(network);
   if(networkid == 0) {
     qWarning() << "unable to connect to Network" << network << "(User:" << userId() << "): unable to determine NetworkId";
     return;
   }
   if(!servers.contains(networkid)) {
-    Server *server = new Server(userId(), networkid, network);
+    Server *server = new Server(userId(), networkid, network, previousState);
     servers[networkid] = server;
     attachServer(server);
     server->start();
index 0e18315..ce64b09 100644 (file)
@@ -38,18 +38,22 @@ public:
   CoreSession(UserId, Storage *, QObject *parent = 0);
   virtual ~CoreSession();
 
-  uint getNetworkId(const QString &network) const;
+  NetworkId getNetworkId(const QString &network) const;
   QList<BufferInfo> buffers() const;
   UserId userId() const;
   QVariant sessionState();
 
   //! Retrieve a piece of session-wide data.
   QVariant retrieveSessionData(const QString &key, const QVariant &def = QVariant());
-  
+
   SignalProxy *signalProxy() const;
-                                 
+
   void attachServer(Server *server);
-                                  
+
+  //! Return necessary data for restoring the session after restarting the core
+  QVariant state() const;
+  void restoreState(const QVariant &previousState);
+
 public slots:
   //! Store a piece session-wide data and distribute it to connected clients.
   void storeSessionData(const QString &key, const QVariant &data);
@@ -57,18 +61,19 @@ public slots:
   void serverStateRequested();
 
   void addClient(QIODevice *connection);
-  
-  void connectToNetwork(QString);
-  
+
+  void connectToNetwork(QString, const QVariant &previousState = QVariant());
+  //void connectToNetwork(NetworkId);
+
   //void processSignal(ClientSignal, QVariant, QVariant, QVariant);
   void sendBacklog(BufferInfo, QVariant, QVariant);
   void msgFromGui(BufferInfo, QString message);
-  
+
 signals:
   void msgFromGui(uint netid, QString buf, QString message);
   void displayMsg(Message message);
   void displayStatusMsg(QString, QString);
-  
+
   void connectToIrc(QString net);
   void disconnectFromIrc(QString net);
 
@@ -89,7 +94,7 @@ private:
   
   SignalProxy *_signalProxy;
   Storage *storage;
-  QHash<uint, Server *> servers;
+  QHash<NetworkId, Server *> servers;
   
   QVariantMap sessionData;
   QMutex mutex;
index 691a3eb..3c38b23 100644 (file)
@@ -44,6 +44,14 @@ uint CoreSettings::port(const uint &def) {
   return localValue("Port", def).toUInt();
 }
 
+void CoreSettings::setCoreState(const QVariant &data) {
+  setLocalValue("CoreState", data);
+}
+
+QVariant CoreSettings::coreState(const QVariant &def) {
+  return localValue("CoreState", def);
+}
+
 QStringList CoreSettings::sessionKeys() {
   Q_ASSERT(false);
   return QStringList();
index 6d7bd85..ea1b51b 100644 (file)
 #include "settings.h"
 
 class CoreSettings : public Settings {
-  
+
   public:
     virtual ~CoreSettings();
     CoreSettings();
-    
+
     void setDatabaseSettings(const QVariant &data);
     QVariant databaseSettings(const QVariant &def = QVariant());
-    
+
     void setPort(const uint &port);
     uint port(const uint &def = DEFAULT_PORT);
-        
+
+    void setCoreState(const QVariant &data);
+    QVariant coreState(const QVariant &def = QVariant());
+
   private:
     //virtual QStringList allSessionKeys() = 0;
     virtual QStringList sessionKeys();
-    
+
     virtual void setSessionValue(const QString &key, const QVariant &data);
     virtual QVariant sessionValue(const QString &key, const QVariant &def = QVariant());
 };
index ec39c57..acac5a2 100644 (file)
@@ -316,6 +316,7 @@ void IrcServerHandler::handle001(QString prefix, QStringList params) {
   networkInfo()->setMyNick(nickFromMask(myhostmask));
 
   emit displayMsg(Message::Server, "", params[0], prefix);
+  
 
   // TODO: reimplement perform List!
   //// send performlist
index b16b837..f88efab 100644 (file)
 #include "core.h"
 #include "coresession.h"
 
+#include "ircuser.h"
 #include "networkinfo.h"
 
 #include "ircserverhandler.h"
 #include "userinputhandler.h"
 #include "ctcphandler.h"
 
-Server::Server(UserId uid, uint networkId, QString net)
+Server::Server(UserId uid, NetworkId networkId, QString net, const QVariant &state)
   : _userId(uid),
     _networkId(networkId),
     _ircServerHandler(new IrcServerHandler(this)),
     _userInputHandler(new UserInputHandler(this)),
     _ctcpHandler(new CtcpHandler(this)),
-    _networkInfo(new NetworkInfo(networkId, this))
+    _networkInfo(new NetworkInfo(networkId, this)),
+    _previousState(state)
 {
+  connect(networkInfo(), SIGNAL(currentServerSet(const QString &)), this, SLOT(sendPerform()));
   networkInfo()->setNetworkName(net);
   networkInfo()->setProxy(coreSession()->signalProxy());
 }
@@ -78,6 +81,34 @@ void Server::connectToIrc(QString net) {
   socket.connectToHost(host, port);
 }
 
+void Server::sendPerform() {
+  // TODO: reimplement perform List!
+  //// send performlist
+  //QStringList performList = networkSettings["Perform"].toString().split( "\n" );
+  //int count = performList.count();
+  //for(int a = 0; a < count; a++) {
+  //  if(!performList[a].isEmpty() ) {
+  //    userInput(network, "", performList[a]);
+  //  }
+  //}
+
+  // rejoin channels we've been in
+  QStringList chans = _previousState.toStringList();
+  if(chans.count() > 0) {
+    qDebug() << "autojoining" << chans;
+    QString list = chans.join(",");
+    putCmd("join", QStringList(list));
+  }
+  // delete _previousState, we won't need it again
+  _previousState = QVariant();
+}
+
+QVariant Server::state() {
+  IrcUser *me = networkInfo()->ircUser(networkInfo()->myNick());
+  if(!me) return QVariant();  // this shouldn't really happen, I guess
+  return me->channels();
+}
+
 void Server::disconnectFromIrc(QString net) {
   if(net != networkName())
     return; // not me!
@@ -143,7 +174,7 @@ uint Server::networkId() const {
   return _networkId;
 }
 
-QString Server::networkName() {
+QString Server::networkName() const {
   return networkInfo()->networkName();
 }
 
index c99174c..3206085 100644 (file)
@@ -48,7 +48,7 @@ class Server : public QThread {
   Q_OBJECT
 
 public:
-  Server(UserId uid, uint networkId, QString network);
+  Server(UserId uid, NetworkId networkId, QString network, const QVariant &previousState = QVariant());
   ~Server();
 
   UserId userId() const { return _userId; } 
@@ -56,13 +56,15 @@ public:
   // serverState state();
   bool isConnected() const { return socket.state() == QAbstractSocket::ConnectedState; }
 
-  uint networkId() const;
-  QString networkName();  // hasbeen getNetwork()
+  NetworkId networkId() const;
+  QString networkName() const;  // hasbeen getNetwork()
 
-  NetworkInfo *networkInfo() { return _networkInfo; }
-  IrcServerHandler *ircServerHandler() {return _ircServerHandler; }
-  UserInputHandler *userInputHandler() {return _userInputHandler; }
-  CtcpHandler *ctcpHandler() {return _ctcpHandler; }
+  NetworkInfo *networkInfo() const { return _networkInfo; }
+  IrcServerHandler *ircServerHandler() const { return _ircServerHandler; }
+  UserInputHandler *userInputHandler() const { return _userInputHandler; }
+  CtcpHandler *ctcpHandler() const { return _ctcpHandler; }
+
+  QVariant state(); ///< Return data necessary to restore the server's state upon core restart
   
 public slots:
   // void setServerOptions();
@@ -76,6 +78,7 @@ public slots:
 
 private slots:
   void threadFinished();
+  void sendPerform();
 
 signals:
   void serverState(QString net, QVariantMap data);
@@ -86,6 +89,8 @@ signals:
   void connected(uint networkId);
   void disconnected(uint networkId);
 
+  void connectionInitialized(); ///< Emitted after receipt of 001 to indicate that we can now send data to the IRC server
+
   void synchronizeClients();
   
   void queryRequested(QString network, QString nick);
@@ -100,7 +105,7 @@ private slots:
 
 private:
   UserId _userId;
-  uint _networkId;
+  NetworkId _networkId;
 
   QTcpSocket socket;
 
@@ -113,6 +118,8 @@ private:
   QVariantMap networkSettings;
   QVariantMap identity;
 
+  QVariant _previousState;
+
   CoreSession *coreSession() const;
   
   class ParseError : public Exception {
index 963ee4b..10b2b98 100644 (file)
@@ -150,7 +150,7 @@ void MainWin::setupMenus() {
   connect(ui.actionNetworkList, SIGNAL(triggered()), this, SLOT(showServerList()));
   connect(ui.actionEditIdentities, SIGNAL(triggered()), serverListDlg, SLOT(editIdentities()));
   connect(ui.actionSettingsDlg, SIGNAL(triggered()), this, SLOT(showSettingsDlg()));
-  ui.actionSettingsDlg->setEnabled(false);
+  //ui.actionSettingsDlg->setEnabled(false);
   connect(ui.actionAboutQt, SIGNAL(triggered()), QApplication::instance(), SLOT(aboutQt()));
 }
 
index 683c82d..8d87a7c 100644 (file)
@@ -48,7 +48,7 @@
        <item>
         <widget class="QStackedWidget" name="settingsStack" >
          <property name="sizePolicy" >
-          <sizepolicy vsizetype="Preferred" hsizetype="MinimumExpanding" >
+          <sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>