Introduce a mechanism to test for certain core features
authorManuel Nickschas <sputnick@quassel-irc.org>
Sat, 10 Oct 2009 10:33:17 +0000 (12:33 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Fri, 1 Jan 2010 21:05:20 +0000 (22:05 +0100)
We sometimes implement features that needs an up-to-date core to work correctly, but not always
a protocol bump is justified (because it's just a giant PITA). So we now have Client::coreFeatures()
that returns a bitmask of such optional features, which can be checked for at runtime and used to disable
client features if a too-old core is present.

Note that with every protocol bump the feature enum in quassel.h needs to be cleaned, and runtime checks
removed. Please mark all such places with a nice FIXME so we can find them easily.

src/client/client.cpp
src/client/client.h
src/common/quassel.cpp
src/common/quassel.h
src/core/core.cpp

index 84d28ec..30c1100 100644 (file)
@@ -52,6 +52,7 @@
 #include <stdlib.h>
 
 QPointer<Client> Client::instanceptr = 0;
 #include <stdlib.h>
 
 QPointer<Client> Client::instanceptr = 0;
+Quassel::Features Client::_coreFeatures = 0;
 
 /*** Initialization/destruction ***/
 
 
 /*** Initialization/destruction ***/
 
@@ -159,6 +160,10 @@ AbstractUi *Client::mainUi() {
   return instance()->_mainUi;
 }
 
   return instance()->_mainUi;
 }
 
+void Client::setCoreFeatures(Quassel::Features features) {
+  _coreFeatures = features;
+}
+
 bool Client::isConnected() {
   return instance()->_connected;
 }
 bool Client::isConnected() {
   return instance()->_connected;
 }
@@ -377,6 +382,8 @@ void Client::disconnectFromCore() {
 
 void Client::setDisconnectedFromCore() {
   _connected = false;
 
 void Client::setDisconnectedFromCore() {
   _connected = false;
+  _coreFeatures = 0;
+
   emit disconnected();
   emit coreConnectionStateChanged(false);
 
   emit disconnected();
   emit coreConnectionStateChanged(false);
 
index 56083a9..53dc786 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "bufferinfo.h"
 #include "coreconnection.h"
 
 #include "bufferinfo.h"
 #include "coreconnection.h"
+#include "quassel.h"
 #include "types.h"
 
 class Message;
 #include "types.h"
 
 class Message;
@@ -118,6 +119,7 @@ public:
   static inline CoreAccountModel *coreAccountModel() { return instance()->_coreAccountModel; }
   static inline CoreConnection *coreConnection() { return instance()->_coreConnection; }
   static inline CoreAccount currentCoreAccount() { return coreConnection()->currentAccount(); }
   static inline CoreAccountModel *coreAccountModel() { return instance()->_coreAccountModel; }
   static inline CoreConnection *coreConnection() { return instance()->_coreConnection; }
   static inline CoreAccount currentCoreAccount() { return coreConnection()->currentAccount(); }
+  static inline Quassel::Features coreFeatures() { return _coreFeatures; }
 
   static bool isConnected();
   static bool internalCore();
 
   static bool isConnected();
   static bool internalCore();
@@ -200,6 +202,7 @@ private:
   void init();
 
   static void addNetwork(Network *);
   void init();
 
   static void addNetwork(Network *);
+  static void setCoreFeatures(Quassel::Features);
   static inline BufferSyncer *bufferSyncer() { return instance()->_bufferSyncer; }
 
   static QPointer<Client> instanceptr;
   static inline BufferSyncer *bufferSyncer() { return instance()->_bufferSyncer; }
 
   static QPointer<Client> instanceptr;
@@ -230,6 +233,7 @@ private:
   QHash<IdentityId, Identity *> _identities;
 
   bool _connected;
   QHash<IdentityId, Identity *> _identities;
 
   bool _connected;
+  static Quassel::Features _coreFeatures;
 
   QString _debugLogBuffer;
   QTextStream _debugLog;
 
   QString _debugLogBuffer;
   QTextStream _debugLog;
index 6b7fa78..e6e2072 100644 (file)
@@ -246,6 +246,14 @@ void Quassel::logFatalMessage(const char *msg) {
 #endif
 }
 
 #endif
 }
 
+Quassel::Features Quassel::features() {
+  Features feats = 0;
+  for(int i = 1; i <= NumFeatures; i<<=1)
+    feats |= (Feature) i;
+
+  return feats;
+}
+
 const QString &Quassel::coreDumpFileName() {
   if(_coreDumpFileName.isEmpty()) {
     QDir configDir(configDirPath());
 const QString &Quassel::coreDumpFileName() {
   if(_coreDumpFileName.isEmpty()) {
     QDir configDir(configDirPath());
index fa7d02c..b42ee47 100644 (file)
@@ -58,6 +58,25 @@ public:
     QString organizationDomain;
   };
 
     QString organizationDomain;
   };
 
+  //! A list of features that are optional in core and/or client, but need runtime checking
+  /** Some features require an uptodate counterpart, but don't justify a protocol break.
+   *  This is what we use this enum for. Add such features to it and check at runtime on the other
+   *  side for their existence.
+   *
+   *  This list should be cleaned up after every protocol break, as we can assume them to be present then.
+   */
+  enum Feature {
+    SynchronizedMarkerLine = 0x0001,
+
+    NumFeatures = 0x0001
+  };
+  Q_DECLARE_FLAGS(Features, Feature);
+
+  //! The features the current version of Quassel supports (\sa Feature)
+  /** \return An ORed list of all enum values in Feature
+   */
+  static Features features();
+
   virtual ~Quassel();
 
   static void setupBuildInfo(const QString &generated);
   virtual ~Quassel();
 
   static void setupBuildInfo(const QString &generated);
@@ -132,6 +151,8 @@ private:
   static QString _translationDirPath;
 };
 
   static QString _translationDirPath;
 };
 
+Q_DECLARE_OPERATORS_FOR_FLAGS(Quassel::Features);
+
 const Quassel::BuildInfo & Quassel::buildInfo() { return _buildInfo; }
 Quassel::RunMode Quassel::runMode() { return _runMode; }
 void Quassel::setRunMode(Quassel::RunMode mode) { _runMode = mode; }
 const Quassel::BuildInfo & Quassel::buildInfo() { return _buildInfo; }
 Quassel::RunMode Quassel::runMode() { return _runMode; }
 void Quassel::setRunMode(Quassel::RunMode mode) { _runMode = mode; }
index b24eefb..20049a8 100644 (file)
@@ -538,6 +538,8 @@ void Core::processClientMessage(QTcpSocket *socket, const QVariantMap &msg) {
                                                      .arg(Quassel::buildInfo().buildDate)
       .arg(updays).arg(uphours,2,10,QChar('0')).arg(upmins,2,10,QChar('0')).arg(startTime().toString(Qt::TextDate));
 
                                                      .arg(Quassel::buildInfo().buildDate)
       .arg(updays).arg(uphours,2,10,QChar('0')).arg(upmins,2,10,QChar('0')).arg(startTime().toString(Qt::TextDate));
 
+    reply["CoreFeatures"] = (int)Quassel::features();
+
 #ifdef HAVE_SSL
     SslServer *sslServer = qobject_cast<SslServer *>(&_server);
     QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket);
 #ifdef HAVE_SSL
     SslServer *sslServer = qobject_cast<SslServer *>(&_server);
     QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket);