Event backend porting
authorManuel Nickschas <sputnick@quassel-irc.org>
Wed, 13 Oct 2010 20:50:44 +0000 (22:50 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Wed, 13 Oct 2010 23:06:33 +0000 (01:06 +0200)
Port netsplit handling from IrcServerHandler to CoreSessionEventProcessor, and port
related commands: JOIN, QUIT, MODE, RPL_CHANNELMODEIS (324)

12 files changed:
src/common/event.h
src/common/eventmanager.h
src/common/networkevent.h
src/core/coresession.cpp
src/core/coresessioneventprocessor.cpp
src/core/coresessioneventprocessor.h
src/core/eventstringifier.cpp
src/core/eventstringifier.h
src/core/ircserverhandler.cpp
src/core/ircserverhandler.h
src/core/netsplit.cpp
src/core/netsplit.h

index 4e4abac..acca411 100644 (file)
@@ -36,6 +36,7 @@ public:
 
   inline void setFlag(EventManager::EventFlag flag) { _flags |= flag; }
   inline void setFlags(EventManager::EventFlags flags) { _flags = flags; }
+  inline bool testFlag(EventManager::EventFlag flag) { return _flags.testFlag(flag); }
   inline EventManager::EventFlags flags() const { return _flags; }
 
   inline void stop() { setFlag(EventManager::Stopped); }
index 4030cff..d4f49c7 100644 (file)
@@ -46,9 +46,11 @@ public:
   };
 
   enum EventFlag {
-    Backlog = 0x20,
-    Silent  = 0x40, ///< Don't generate a MessageEvent
-    Stopped = 0x80
+    Fake     = 0x08, ///< Ignore this in CoreSessionEventProcessor
+    Netsplit = 0x10, ///< Netsplit join/part, ignore on display
+    Backlog  = 0x20,
+    Silent   = 0x40, ///< Don't generate a MessageEvent
+    Stopped  = 0x80
   };
   Q_DECLARE_FLAGS(EventFlags, EventFlag)
 
@@ -71,6 +73,8 @@ public:
     NetworkReconnecting,
     NetworkDisconnecting,
     NetworkDisconnected,
+    NetworkSplitJoin,
+    NetworkSplitQuit,
     NetworkIncoming,
 
     IrcServerEvent              = 0x00020000,
index 67b47a0..a1d3a66 100644 (file)
@@ -90,4 +90,29 @@ private:
   QByteArray _data;
 };
 
+class NetworkSplitEvent : public NetworkEvent {
+
+public:
+  explicit NetworkSplitEvent(EventManager::EventType type,
+                             Network *network,
+                             const QString &channel,
+                             const QStringList &users,
+                             const QString &quitMsg)
+    : NetworkEvent(type, network),
+      _channel(channel),
+      _users(users),
+      _quitMsg(quitMsg)
+  {}
+
+  inline QString channel() const { return _channel; }
+  inline QStringList users() const { return _users; }
+  inline QString quitMessage() const { return _quitMsg; }
+
+private:
+  QString _channel;
+  QStringList _users;
+  QString _quitMsg;
+};
+
+
 #endif
index 8d2c877..0ea6dec 100644 (file)
@@ -100,6 +100,7 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
   eventManager()->registerObject(eventProcessor(), EventManager::HighPriority); // needs to process events *before* the stringifier!
   eventManager()->registerObject(eventStringifier(), EventManager::NormalPriority);
   eventManager()->registerObject(this, EventManager::LowPriority); // for sending MessageEvents to the client
+  eventManager()->registerObject(eventProcessor(), EventManager::LowPriority, "lateProcess"); // some events need to be handled after msg generation
 
   // periodically save our session state
   connect(&(Core::instance()->syncTimer()), SIGNAL(timeout()), this, SLOT(saveSessionState()));
index cb11691..bb2c211 100644 (file)
 #include "ircevent.h"
 #include "ircuser.h"
 #include "messageevent.h"
+#include "netsplit.h"
 
 CoreSessionEventProcessor::CoreSessionEventProcessor(CoreSession *session)
   : QObject(session),
   _coreSession(session)
 {
-
+  connect(coreSession(), SIGNAL(networkDisconnected(NetworkId)), this, SLOT(destroyNetsplits(NetworkId)));
 }
 
 bool CoreSessionEventProcessor::checkParamCount(IrcEvent *e, int minParams) {
@@ -122,6 +123,36 @@ void CoreSessionEventProcessor::processIrcEventInvite(IrcEvent *e) {
   }
 }
 
+void CoreSessionEventProcessor::processIrcEventJoin(IrcEvent *e) {
+  if(e->testFlag(EventManager::Fake)) // generated by handleEarlyNetsplitJoin
+    return;
+
+  if(!checkParamCount(e, 1))
+    return;
+
+  CoreNetwork *net = coreNetwork(e);
+  QString channel = e->params()[0];
+  IrcUser *ircuser = net->updateNickFromMask(e->prefix());
+
+  bool handledByNetsplit = false;
+  foreach(Netsplit* n, _netsplits.value(e->network())) {
+    handledByNetsplit = n->userJoined(e->prefix(), channel);
+    if(handledByNetsplit)
+      break;
+  }
+
+  if(!handledByNetsplit)
+    ircuser->joinChannel(channel);
+  else
+    e->setFlag(EventManager::Netsplit);
+
+  if(net->isMe(ircuser)) {
+    net->setChannelJoined(channel);
+     // FIXME use event
+    net->putRawLine(net->serverEncode("MODE " + channel)); // we want to know the modes of the channel we just joined, so we ask politely
+  }
+}
+
 void CoreSessionEventProcessor::processIrcEventKick(IrcEvent *e) {
   if(checkParamCount(e, 2)) {
     e->network()->updateNickFromMask(e->prefix());
@@ -133,6 +164,112 @@ void CoreSessionEventProcessor::processIrcEventKick(IrcEvent *e) {
   }
 }
 
+void CoreSessionEventProcessor::processIrcEventMode(IrcEvent *e) {
+  if(!checkParamCount(e, 2))
+    return;
+
+  if(e->network()->isChannelName(e->params().first())) {
+    // Channel Modes
+
+    IrcChannel *channel = e->network()->ircChannel(e->params()[0]);
+    if(!channel) {
+      // we received mode information for a channel we're not in. that means probably we've just been kicked out or something like that
+      // anyways: we don't have a place to store the data --> discard the info.
+      return;
+    }
+
+    QString modes = e->params()[1];
+    bool add = true;
+    int paramOffset = 2;
+    for(int c = 0; c < modes.length(); c++) {
+      if(modes[c] == '+') {
+        add = true;
+        continue;
+      }
+      if(modes[c] == '-') {
+        add = false;
+        continue;
+      }
+
+      if(e->network()->prefixModes().contains(modes[c])) {
+        // user channel modes (op, voice, etc...)
+        if(paramOffset < e->params().count()) {
+          IrcUser *ircUser = e->network()->ircUser(e->params()[paramOffset]);
+          if(!ircUser) {
+            qWarning() << Q_FUNC_INFO << "Unknown IrcUser:" << e->params()[paramOffset];
+          } else {
+            if(add) {
+              bool handledByNetsplit = false;
+              QHash<QString, Netsplit *> splits = _netsplits.value(e->network());
+              foreach(Netsplit* n, _netsplits.value(e->network())) {
+                handledByNetsplit = n->userAlreadyJoined(ircUser->hostmask(), channel->name());
+                if(handledByNetsplit) {
+                  n->addMode(ircUser->hostmask(), channel->name(), QString(modes[c]));
+                  break;
+                }
+              }
+              if(!handledByNetsplit)
+                channel->addUserMode(ircUser, QString(modes[c]));
+            }
+            else
+              channel->removeUserMode(ircUser, QString(modes[c]));
+          }
+        } else {
+          qWarning() << "Received MODE with too few parameters:" << e->params();
+        }
+        ++paramOffset;
+      } else {
+        // regular channel modes
+        QString value;
+        Network::ChannelModeType modeType = e->network()->channelModeType(modes[c]);
+        if(modeType == Network::A_CHANMODE || modeType == Network::B_CHANMODE || (modeType == Network::C_CHANMODE && add)) {
+          if(paramOffset < e->params().count()) {
+            value = e->params()[paramOffset];
+          } else {
+            qWarning() << "Received MODE with too few parameters:" << e->params();
+          }
+          ++paramOffset;
+        }
+
+        if(add)
+          channel->addChannelMode(modes[c], value);
+        else
+          channel->removeChannelMode(modes[c], value);
+      }
+    }
+
+  } else {
+    // pure User Modes
+    IrcUser *ircUser = e->network()->newIrcUser(e->params().first());
+    QString modeString(e->params()[1]);
+    QString addModes;
+    QString removeModes;
+    bool add = false;
+    for(int c = 0; c < modeString.count(); c++) {
+      if(modeString[c] == '+') {
+        add = true;
+        continue;
+      }
+      if(modeString[c] == '-') {
+        add = false;
+        continue;
+      }
+      if(add)
+        addModes += modeString[c];
+      else
+        removeModes += modeString[c];
+    }
+    if(!addModes.isEmpty())
+      ircUser->addUserModes(addModes);
+    if(!removeModes.isEmpty())
+      ircUser->removeUserModes(removeModes);
+
+    if(e->network()->isMe(ircUser)) {
+      coreNetwork(e)->updatePersistentModes(addModes, removeModes);
+    }
+  }
+}
+
 void CoreSessionEventProcessor::processIrcEventNick(IrcEvent *e) {
   if(checkParamCount(e, 1)) {
     IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix());
@@ -176,6 +313,50 @@ void CoreSessionEventProcessor::processIrcEventPong(IrcEvent *e) {
   }
 }
 
+void CoreSessionEventProcessor::processIrcEventQuit(IrcEvent *e) {
+  IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix());
+  if(!ircuser)
+    return;
+
+  QString msg;
+  if(e->params().count() > 0)
+    msg = e->params()[0];
+
+  // check if netsplit
+  if(Netsplit::isNetsplit(msg)) {
+    Netsplit *n;
+    if(!_netsplits[e->network()].contains(msg)) {
+      n = new Netsplit(e->network(), this);
+      connect(n, SIGNAL(finished()), this, SLOT(handleNetsplitFinished()));
+      connect(n, SIGNAL(netsplitJoin(Network*,QString,QStringList,QStringList,QString)),
+              this, SLOT(handleNetsplitJoin(Network*,QString,QStringList,QStringList,QString)));
+      connect(n, SIGNAL(netsplitQuit(Network*,QString,QStringList,QString)),
+              this, SLOT(handleNetsplitQuit(Network*,QString,QStringList,QString)));
+      connect(n, SIGNAL(earlyJoin(Network*,QString,QStringList,QStringList)),
+              this, SLOT(handleEarlyNetsplitJoin(Network*,QString,QStringList,QStringList)));
+      _netsplits[e->network()].insert(msg, n);
+    }
+    else {
+      n = _netsplits[e->network()][msg];
+    }
+    // add this user to the netsplit
+    n->userQuit(e->prefix(), ircuser->channels(), msg);
+    e->setFlag(EventManager::Netsplit);
+  }
+  // normal quit is handled in lateProcessIrcEventQuit()
+}
+
+void CoreSessionEventProcessor::lateProcessIrcEventQuit(IrcEvent *e) {
+  if(e->testFlag(EventManager::Netsplit))
+    return;
+
+  IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix());
+  if(!ircuser)
+    return;
+
+  ircuser->quit();
+}
+
 void CoreSessionEventProcessor::processIrcEventTopic(IrcEvent *e) {
   if(checkParamCount(e, 2)) {
     e->network()->updateNickFromMask(e->prefix());
@@ -393,6 +574,11 @@ void CoreSessionEventProcessor::processIrcEvent323(IrcEvent *e) {
     e->stop(); // consumed by IrcListHelper, so don't further process/show this event
 }
 
+/* RPL_CHANNELMODEIS - "<channel> <mode> <mode params>" */
+void CoreSessionEventProcessor::processIrcEvent324(IrcEvent *e) {
+  processIrcEventMode(e);
+}
+
 /* RPL_NOTOPIC */
 void CoreSessionEventProcessor::processIrcEvent331(IrcEvent *e) {
   if(!checkParamCount(e, 1))
@@ -524,3 +710,91 @@ void CoreSessionEventProcessor::processIrcEvent(IrcEvent *e) {
 }
 */
 
+/* Handle signals from Netsplit objects  */
+
+void CoreSessionEventProcessor::handleNetsplitJoin(Network *net,
+                                                   const QString &channel,
+                                                   const QStringList &users,
+                                                   const QStringList &modes,
+                                                   const QString& quitMessage)
+{
+  IrcChannel *ircChannel = net->ircChannel(channel);
+  if(!ircChannel) {
+    return;
+  }
+  QList<IrcUser *> ircUsers;
+  QStringList newModes = modes;
+  QStringList newUsers = users;
+
+  foreach(const QString &user, users) {
+    IrcUser *iu = net->ircUser(nickFromMask(user));
+    if(iu)
+      ircUsers.append(iu);
+    else { // the user already quit
+      int idx = users.indexOf(user);
+      newUsers.removeAt(idx);
+      newModes.removeAt(idx);
+    }
+  }
+
+  ircChannel->joinIrcUsers(ircUsers, newModes);
+  NetworkSplitEvent *event = new NetworkSplitEvent(EventManager::NetworkSplitJoin, net, channel, newUsers, quitMessage);
+  coreSession()->eventManager()->sendEvent(event);
+}
+
+void CoreSessionEventProcessor::handleNetsplitQuit(Network *net, const QString &channel, const QStringList &users, const QString& quitMessage) {
+  NetworkSplitEvent *event = new NetworkSplitEvent(EventManager::NetworkSplitQuit, net, channel, users, quitMessage);
+  coreSession()->eventManager()->sendEvent(event);
+  foreach(QString user, users) {
+    IrcUser *iu = net->ircUser(nickFromMask(user));
+    if(iu)
+      iu->quit();
+  }
+}
+
+void CoreSessionEventProcessor::handleEarlyNetsplitJoin(Network *net, const QString &channel, const QStringList &users, const QStringList &modes) {
+  IrcChannel *ircChannel = net->ircChannel(channel);
+  if(!ircChannel) {
+    qDebug() << "handleEarlyNetsplitJoin(): channel " << channel << " invalid";
+    return;
+  }
+  QList<NetworkEvent *> events;
+  QList<IrcUser *> ircUsers;
+  QStringList newModes = modes;
+
+  foreach(QString user, users) {
+    IrcUser *iu = net->updateNickFromMask(user);
+    if(iu) {
+      ircUsers.append(iu);
+      // fake event for scripts that consume join events
+      events << new IrcEvent(EventManager::IrcEventJoin, net, iu->hostmask(), QStringList() << channel);
+    }
+    else {
+      newModes.removeAt(users.indexOf(user));
+    }
+  }
+  ircChannel->joinIrcUsers(ircUsers, newModes);
+  foreach(NetworkEvent *event, events) {
+    event->setFlag(EventManager::Fake); // ignore this in here!
+    coreSession()->eventManager()->sendEvent(event);
+  }
+}
+
+void CoreSessionEventProcessor::handleNetsplitFinished() {
+  Netsplit* n = qobject_cast<Netsplit*>(sender());
+  Q_ASSERT(n);
+  QHash<QString, Netsplit *> splithash  = _netsplits.take(n->network());
+  splithash.remove(splithash.key(n));
+  if(splithash.count())
+    _netsplits[n->network()] = splithash;
+  n->deleteLater();
+}
+
+void CoreSessionEventProcessor::destroyNetsplits(NetworkId netId) {
+  Network *net = coreSession()->network(netId);
+  if(!net)
+    return;
+
+  QHash<QString, Netsplit *> splits = _netsplits.take(net);
+  qDeleteAll(splits);
+}
index 59b4879..258dc44 100644 (file)
@@ -27,6 +27,7 @@
 class CoreSession;
 class IrcEvent;
 class IrcEventNumeric;
+class Netsplit;
 
 class CoreSessionEventProcessor : public QObject {
   Q_OBJECT
@@ -41,10 +42,14 @@ public:
   Q_INVOKABLE void processIrcEventAuthenticate(IrcEvent *event);   // SASL auth
   Q_INVOKABLE void processIrcEventCap(IrcEvent *event);            // CAP framework
   Q_INVOKABLE void processIrcEventInvite(IrcEvent *event);
+  Q_INVOKABLE void processIrcEventJoin(IrcEvent *event);
   Q_INVOKABLE void processIrcEventKick(IrcEvent *event);
+  Q_INVOKABLE void processIrcEventMode(IrcEvent *event);
   Q_INVOKABLE void processIrcEventNick(IrcEvent *event);
   Q_INVOKABLE void processIrcEventPart(IrcEvent *event);
   Q_INVOKABLE void processIrcEventPong(IrcEvent *event);
+  Q_INVOKABLE void processIrcEventQuit(IrcEvent *event);
+  Q_INVOKABLE void lateProcessIrcEventQuit(IrcEvent *event);
   Q_INVOKABLE void processIrcEventTopic(IrcEvent *event);
 
   Q_INVOKABLE void processIrcEvent001(IrcEvent *event);            // RPL_WELCOME
@@ -65,13 +70,14 @@ public:
   Q_INVOKABLE void processIrcEvent317(IrcEvent *event);            // RPL_WHOISIDLE
   Q_INVOKABLE void processIrcEvent322(IrcEvent *event);            // RPL_LIST
   Q_INVOKABLE void processIrcEvent323(IrcEvent *event);            // RPL_LISTEND
+  Q_INVOKABLE void processIrcEvent324(IrcEvent *event);            // RPL_CHANNELMODEIS
   Q_INVOKABLE void processIrcEvent331(IrcEvent *event);            // RPL_NOTOPIC
   Q_INVOKABLE void processIrcEvent332(IrcEvent *event);            // RPL_TOPIC
   Q_INVOKABLE void processIrcEvent352(IrcEvent *event);            // RPL_WHOREPLY
   Q_INVOKABLE void processIrcEvent353(IrcEvent *event);            // RPL_NAMREPLY
-  Q_INVOKABLE void processIrcEvent432(IrcEventNumeric *event);            // ERR_ERRONEUSNICKNAME
-  Q_INVOKABLE void processIrcEvent433(IrcEventNumeric *event);            // ERR_NICKNAMEINUSE
-  Q_INVOKABLE void processIrcEvent437(IrcEventNumeric *event);            // ERR_UNAVAILRESOURCE
+  Q_INVOKABLE void processIrcEvent432(IrcEventNumeric *event);     // ERR_ERRONEUSNICKNAME
+  Q_INVOKABLE void processIrcEvent433(IrcEventNumeric *event);     // ERR_NICKNAMEINUSE
+  Q_INVOKABLE void processIrcEvent437(IrcEventNumeric *event);     // ERR_UNAVAILRESOURCE
 
   // Q_INVOKABLE void processIrcEvent(IrcEvent *event);
 
@@ -80,8 +86,47 @@ protected:
   inline CoreNetwork *coreNetwork(NetworkEvent *e) const { return qobject_cast<CoreNetwork *>(e->network()); }
   void tryNextNick(NetworkEvent *e, const QString &errnick, bool erroneous = false);
 
+private slots:
+  //! Joins after a netsplit
+  /** This slot handles a bulk-join after a netsplit is over
+    * \param net     The network
+    * \param channel The channel the users joined
+    * \param users   The list of users that joind the channel
+    * \param modes   The list of modes the users get set
+    * \param quitMessage The message we received when the netsplit occured
+    */
+  void handleNetsplitJoin(Network *net, const QString &channel, const QStringList &users, const QStringList &modes, const QString &quitMessage);
+
+  //! Quits after a netsplit
+  /** This slot handles a bulk-quit after a netsplit occured
+    * \param net     The network
+    * \param channel The channel the users quitted
+    * \param users   The list of users that got split
+    * \param quitMessage The message we received when the netsplit occured
+    */
+  void handleNetsplitQuit(Network *net, const QString &channel, const QStringList &users, const QString &quitMessage);
+
+  //! Netsplit finished
+  /** This slot deletes the netsplit object that sent the finished() signal
+    */
+  void handleNetsplitFinished();
+
+  void handleEarlyNetsplitJoin(Network *net, const QString &channel, const QStringList &users, const QStringList &modes);
+
+  //! Destroy any existing netsplits
+  /** This slot deletes all netsplit objects
+    * Used to get rid of existing netsplits on network reconnect
+    * \param network The network we want to clear
+    */
+  void destroyNetsplits(NetworkId network);
+
 private:
   CoreSession *_coreSession;
+
+  // structure to organize netsplits
+  // key: quit message
+  // value: the corresponding netsplit object
+  QHash<Network *, QHash<QString, Netsplit*> > _netsplits;
 };
 
 #endif
index a7238b2..1578f78 100644 (file)
@@ -64,6 +64,19 @@ bool EventStringifier::checkParamCount(IrcEvent *e, int minParams) {
   return true;
 }
 
+/* These are only for legacy reasons; remove as soon as we handle NetworkSplitEvents properly */
+void EventStringifier::processNetworkSplitJoin(NetworkSplitEvent *e) {
+  QString msg = e->users().join("#:#") + "#:#" + e->quitMessage();
+  displayMsg(e, Message::NetsplitJoin, msg, QString(), e->channel());
+}
+
+void EventStringifier::processNetworkSplitQuit(NetworkSplitEvent *e) {
+  QString msg = e->users().join("#:#") + "#:#" + e->quitMessage();
+  displayMsg(e, Message::NetsplitQuit, msg, QString(), e->channel());
+}
+
+/* End legacy */
+
 void EventStringifier::processIrcEventNumeric(IrcEventNumeric *e) {
   //qDebug() << e->number();
   switch(e->number()) {
@@ -134,6 +147,13 @@ void EventStringifier::processIrcEventInvite(IrcEvent *e) {
   displayMsg(e, Message::Invite, tr("%1 invited you to channel %2").arg(e->nick(), e->params().at(1)));
 }
 
+void EventStringifier::processIrcEventJoin(IrcEvent *e) {
+  if(e->testFlag(EventManager::Netsplit))
+    return;
+
+  displayMsg(e, Message::Join, e->params()[0], e->prefix(), e->params()[0]);
+}
+
 void EventStringifier::earlyProcessIrcEventKick(IrcEvent *e) {
   IrcUser *victim = e->network()->ircUser(e->params().at(1));
   if(victim) {
@@ -146,6 +166,17 @@ void EventStringifier::earlyProcessIrcEventKick(IrcEvent *e) {
   }
 }
 
+void EventStringifier::processIrcEventMode(IrcEvent *e) {
+  if(e->network()->isChannelName(e->params().first())) {
+    // Channel Modes
+    displayMsg(e, Message::Mode, e->params().join(" "), e->prefix(), e->params().first());
+  } else {
+    // User Modes
+    // FIXME: redirect
+    displayMsg(e, Message::Mode, e->params().join(" "), e->prefix());
+  }
+}
+
 // this needs to be called before the ircuser is renamed!
 void EventStringifier::earlyProcessIrcEventNick(IrcEvent *e) {
   if(!checkParamCount(e, 1))
@@ -182,6 +213,18 @@ void EventStringifier::processIrcEventPong(IrcEvent *e) {
     displayMsg(e, Message::Server, "PONG " + e->params().join(" "), e->prefix());
 }
 
+void EventStringifier::processIrcEventQuit(IrcEvent *e) {
+  if(e->testFlag(EventManager::Netsplit))
+    return;
+
+  IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix());
+  if(!ircuser)
+    return;
+
+  foreach(const QString &channel, ircuser->channels())
+    displayMsg(e, Message::Quit, e->params().count()? e->params().first() : QString(), e->prefix(), channel);
+}
+
 void EventStringifier::processIrcEventTopic(IrcEvent *e) {
   displayMsg(e, Message::Topic, tr("%1 has changed topic for %2 to: \"%3\"")
              .arg(e->nick(), e->params().at(0), e->params().at(1)), QString(), e->params().at(0));
@@ -350,6 +393,11 @@ void EventStringifier::processIrcEvent323(IrcEvent *e) {
   displayMsg(e, Message::Server, tr("End of channel list"));
 }
 
+/* RPL_CHANNELMODEIS - "<channel> <mode> <mode params>" */
+void EventStringifier::processIrcEvent324(IrcEvent *e) {
+  processIrcEventMode(e);
+}
+
 /* RPL_??? - "<channel> <homepage> */
 void EventStringifier::processIrcEvent328(IrcEvent *e) {
   if(!checkParamCount(e, 2))
index 25733ad..eeecac9 100644 (file)
@@ -47,14 +47,21 @@ public:
                                    const QString &target = QString(),
                                    Message::Flags msgFlags = Message::None);
 
+  // legacy handlers
+  Q_INVOKABLE void processNetworkSplitJoin(NetworkSplitEvent *event);
+  Q_INVOKABLE void processNetworkSplitQuit(NetworkSplitEvent *event);
+
   //! Handle generic numeric events
   Q_INVOKABLE void processIrcEventNumeric(IrcEventNumeric *event);
 
   Q_INVOKABLE void processIrcEventInvite(IrcEvent *event);
+  Q_INVOKABLE void processIrcEventJoin(IrcEvent *event);
   Q_INVOKABLE void earlyProcessIrcEventKick(IrcEvent *event);
+  Q_INVOKABLE void processIrcEventMode(IrcEvent *event);
   Q_INVOKABLE void earlyProcessIrcEventNick(IrcEvent *event);
   Q_INVOKABLE void earlyProcessIrcEventPart(IrcEvent *event);
   Q_INVOKABLE void processIrcEventPong(IrcEvent *event);
+  Q_INVOKABLE void processIrcEventQuit(IrcEvent *event);
   Q_INVOKABLE void processIrcEventTopic(IrcEvent *event);
 
   Q_INVOKABLE void processIrcEvent005(IrcEvent *event);      // RPL_ISUPPORT
@@ -70,6 +77,7 @@ public:
   Q_INVOKABLE void processIrcEvent319(IrcEvent *event);      // RPL_WHOISCHANNELS
   Q_INVOKABLE void processIrcEvent322(IrcEvent *event);      // RPL_LIST
   Q_INVOKABLE void processIrcEvent323(IrcEvent *event);      // RPL_LISTEND
+  Q_INVOKABLE void processIrcEvent324(IrcEvent *event);      // RPL_CHANNELMODEIS
   Q_INVOKABLE void processIrcEvent328(IrcEvent *event);      // RPL_??? (channel creation time)
   Q_INVOKABLE void processIrcEvent329(IrcEvent *event);      // RPL_??? (channel homepage)
   Q_INVOKABLE void processIrcEvent330(IrcEvent *event);      // RPL_WHOISACCOUNT (quakenet/snircd/undernet)
index ae7c42b..3638129 100644 (file)
@@ -40,11 +40,11 @@ IrcServerHandler::IrcServerHandler(CoreNetwork *parent)
   : CoreBasicHandler(parent),
     _whois(false)
 {
-  connect(parent, SIGNAL(disconnected(NetworkId)), this, SLOT(destroyNetsplits()));
+
 }
 
 IrcServerHandler::~IrcServerHandler() {
-  destroyNetsplits();
+
 }
 
 /*! Handle a raw message string sent by the server. We try to find a suitable handler, otherwise we call a default handler. */
@@ -140,146 +140,6 @@ void IrcServerHandler::defaultHandler(QString cmd, const QString &prefix, const
 // IRC SERVER HANDLER
 //******************************/
 
-void IrcServerHandler::handleJoin(const QString &prefix, const QList<QByteArray> &params) {
-  if(!checkParamCount("IrcServerHandler::handleJoin()", params, 1))
-    return;
-
-  QString channel = serverDecode(params[0]);
-  IrcUser *ircuser = network()->updateNickFromMask(prefix);
-
-  bool handledByNetsplit = false;
-  if(!_netsplits.empty()) {
-    foreach(Netsplit* n, _netsplits) {
-      handledByNetsplit = n->userJoined(prefix, channel);
-      if(handledByNetsplit)
-        break;
-    }
-  }
-
-  // normal join
-  if(!handledByNetsplit) {
-    emit displayMsg(Message::Join, BufferInfo::ChannelBuffer, channel, channel, prefix);
-    ircuser->joinChannel(channel);
-  }
-  //qDebug() << "IrcServerHandler::handleJoin()" << prefix << params;
-
-  if(network()->isMe(ircuser)) {
-    network()->setChannelJoined(channel);
-    putCmd("MODE", params[0]); // we want to know the modes of the channel we just joined, so we ask politely
-  }
-}
-
-void IrcServerHandler::handleMode(const QString &prefix, const QList<QByteArray> &params) {
-  if(!checkParamCount("IrcServerHandler::handleMode()", params, 2))
-    return;
-
-  if(network()->isChannelName(serverDecode(params[0]))) {
-    // Channel Modes
-    emit displayMsg(Message::Mode, BufferInfo::ChannelBuffer, serverDecode(params[0]), serverDecode(params).join(" "), prefix);
-
-    IrcChannel *channel = network()->ircChannel(params[0]);
-    if(!channel) {
-      // we received mode information for a channel we're not in. that means probably we've just been kicked out or something like that
-      // anyways: we don't have a place to store the data --> discard the info.
-      return;
-    }
-
-    QString modes = params[1];
-    bool add = true;
-    int paramOffset = 2;
-    for(int c = 0; c < modes.length(); c++) {
-      if(modes[c] == '+') {
-        add = true;
-        continue;
-      }
-      if(modes[c] == '-') {
-        add = false;
-        continue;
-      }
-
-      if(network()->prefixModes().contains(modes[c])) {
-        // user channel modes (op, voice, etc...)
-        if(paramOffset < params.count()) {
-          IrcUser *ircUser = network()->ircUser(params[paramOffset]);
-          if(!ircUser) {
-            qWarning() << Q_FUNC_INFO << "Unknown IrcUser:" << params[paramOffset];
-          } else {
-            if(add) {
-              bool handledByNetsplit = false;
-              if(!_netsplits.empty()) {
-                foreach(Netsplit* n, _netsplits) {
-                  handledByNetsplit = n->userAlreadyJoined(ircUser->hostmask(), channel->name());
-                  if(handledByNetsplit) {
-                    n->addMode(ircUser->hostmask(), channel->name(), QString(modes[c]));
-                    break;
-                  }
-                }
-              }
-              if(!handledByNetsplit)
-                channel->addUserMode(ircUser, QString(modes[c]));
-            }
-            else
-              channel->removeUserMode(ircUser, QString(modes[c]));
-          }
-        } else {
-          qWarning() << "Received MODE with too few parameters:" << serverDecode(params);
-        }
-        paramOffset++;
-      } else {
-        // regular channel modes
-        QString value;
-        Network::ChannelModeType modeType = network()->channelModeType(modes[c]);
-        if(modeType == Network::A_CHANMODE || modeType == Network::B_CHANMODE || (modeType == Network::C_CHANMODE && add)) {
-          if(paramOffset < params.count()) {
-            value = params[paramOffset];
-          } else {
-            qWarning() << "Received MODE with too few parameters:" << serverDecode(params);
-          }
-          paramOffset++;
-        }
-
-        if(add)
-          channel->addChannelMode(modes[c], value);
-        else
-          channel->removeChannelMode(modes[c], value);
-      }
-    }
-
-  } else {
-    // pure User Modes
-    IrcUser *ircUser = network()->newIrcUser(params[0]);
-    QString modeString(serverDecode(params[1]));
-    QString addModes;
-    QString removeModes;
-    bool add = false;
-    for(int c = 0; c < modeString.count(); c++) {
-      if(modeString[c] == '+') {
-        add = true;
-        continue;
-      }
-      if(modeString[c] == '-') {
-        add = false;
-        continue;
-      }
-      if(add)
-        addModes += modeString[c];
-      else
-        removeModes += modeString[c];
-    }
-    if(!addModes.isEmpty())
-      ircUser->addUserModes(addModes);
-    if(!removeModes.isEmpty())
-      ircUser->removeUserModes(removeModes);
-
-    if(network()->isMe(ircUser)) {
-      network()->updatePersistentModes(addModes, removeModes);
-    }
-
-    // FIXME: redirect
-    emit displayMsg(Message::Mode, BufferInfo::StatusBuffer, "", serverDecode(params).join(" "), prefix);
-  }
-}
-
 void IrcServerHandler::handleNotice(const QString &prefix, const QList<QByteArray> &params) {
   if(!checkParamCount("IrcServerHandler::handleNotice()", params, 2))
     return;
@@ -363,117 +223,6 @@ void IrcServerHandler::handlePrivmsg(const QString &prefix, const QList<QByteArr
   }
 }
 
-void IrcServerHandler::handleQuit(const QString &prefix, const QList<QByteArray> &params) {
-  IrcUser *ircuser = network()->updateNickFromMask(prefix);
-  if(!ircuser) return;
-
-  QString msg;
-  if(params.count() > 0)
-    msg = userDecode(ircuser->nick(), params[0]);
-
-  // check if netsplit
-  if(Netsplit::isNetsplit(msg)) {
-    Netsplit *n;
-    if(!_netsplits.contains(msg)) {
-      n = new Netsplit();
-      connect(n, SIGNAL(finished()), this, SLOT(handleNetsplitFinished()));
-      connect(n, SIGNAL(netsplitJoin(const QString&, const QStringList&, const QStringList&, const QString&)),
-              this, SLOT(handleNetsplitJoin(const QString&, const QStringList&, const QStringList&, const QString&)));
-      connect(n, SIGNAL(netsplitQuit(const QString&, const QStringList&, const QString&)),
-              this, SLOT(handleNetsplitQuit(const QString&, const QStringList&, const QString&)));
-      connect(n, SIGNAL(earlyJoin(const QString&, const QStringList&, const QStringList&)),
-              this, SLOT(handleEarlyNetsplitJoin(const QString&, const QStringList&, const QStringList&)));
-      _netsplits.insert(msg, n);
-    }
-    else {
-      n = _netsplits[msg];
-    }
-    // add this user to the netsplit
-    n->userQuit(prefix, ircuser->channels(),msg);
-  }
-  // normal quit
-  else {
-    foreach(QString channel, ircuser->channels())
-      emit displayMsg(Message::Quit, BufferInfo::ChannelBuffer, channel, msg, prefix);
-    ircuser->quit();
-  }
-}
-
-/* RPL_CHANNELMODEIS - "<channel> <mode> <mode params>" */
-void IrcServerHandler::handle324(const QString &prefix, const QList<QByteArray> &params) {
-  Q_UNUSED(prefix);
-  handleMode(prefix, params);
-}
-
-/* Handle signals from Netsplit objects  */
-
-void IrcServerHandler::handleNetsplitJoin(const QString &channel, const QStringList &users, const QStringList &modes, const QString& quitMessage)
-{
-  IrcChannel *ircChannel = network()->ircChannel(channel);
-  if(!ircChannel) {
-    return;
-  }
-  QList<IrcUser *> ircUsers;
-  QStringList newModes = modes;
-  QStringList newUsers = users;
-
-  foreach(QString user, users) {
-    IrcUser *iu = network()->ircUser(nickFromMask(user));
-    if(iu)
-      ircUsers.append(iu);
-    else { // the user already quit
-      int idx = users.indexOf(user);
-      newUsers.removeAt(idx);
-      newModes.removeAt(idx);
-    }
-  }
-
-  QString msg = newUsers.join("#:#").append("#:#").append(quitMessage);
-  emit displayMsg(Message::NetsplitJoin, BufferInfo::ChannelBuffer, channel, msg);
-  ircChannel->joinIrcUsers(ircUsers, newModes);
-}
-
-void IrcServerHandler::handleNetsplitQuit(const QString &channel, const QStringList &users, const QString& quitMessage)
-{
-  QString msg = users.join("#:#").append("#:#").append(quitMessage);
-  emit displayMsg(Message::NetsplitQuit, BufferInfo::ChannelBuffer, channel, msg);
-  foreach(QString user, users) {
-    IrcUser *iu = network()->ircUser(nickFromMask(user));
-    if(iu)
-      iu->quit();
-  }
-}
-
-void IrcServerHandler::handleEarlyNetsplitJoin(const QString &channel, const QStringList &users, const QStringList &modes) {
-  IrcChannel *ircChannel = network()->ircChannel(channel);
-  if(!ircChannel) {
-    qDebug() << "handleEarlyNetsplitJoin(): channel " << channel << " invalid";
-    return;
-  }
-  QList<IrcUser *> ircUsers;
-  QStringList newModes = modes;
-
-  foreach(QString user, users) {
-    IrcUser *iu = network()->updateNickFromMask(user);
-    if(iu) {
-      ircUsers.append(iu);
-      emit displayMsg(Message::Join, BufferInfo::ChannelBuffer, channel, channel, user);
-    }
-    else {
-      newModes.removeAt(users.indexOf(user));
-    }
-  }
-  ircChannel->joinIrcUsers(ircUsers, newModes);
-}
-void IrcServerHandler::handleNetsplitFinished()
-{
-  Netsplit* n = qobject_cast<Netsplit*>(sender());
-  _netsplits.remove(_netsplits.key(n));
-  n->deleteLater();
-}
-
-/* */
-
 // FIXME networkConnection()->setChannelKey("") for all ERR replies indicating that a JOIN went wrong
 //       mostly, these are codes in the 47x range
 
@@ -505,11 +254,6 @@ bool IrcServerHandler::checkParamCount(const QString &methodName, const QList<QB
   }
 }
 
-void IrcServerHandler::destroyNetsplits() {
-  qDeleteAll(_netsplits);
-  _netsplits.clear();
-}
-
 #ifdef HAVE_QCA2
 QByteArray IrcServerHandler::decrypt(const QString &bufferName, const QByteArray &message_, bool isTopic) {
   if(message_.isEmpty())
index 59c470c..a457b30 100644 (file)
@@ -34,47 +34,12 @@ public:
   void handleServerMsg(QByteArray rawMsg);
 
 public slots:
-  void handleJoin(const QString &prefix, const QList<QByteArray> &params);
-  void handleMode(const QString &prefix, const QList<QByteArray> &params);
   void handleNotice(const QString &prefix, const QList<QByteArray> &params);
   void handlePing(const QString &prefix, const QList<QByteArray> &params);
   void handlePrivmsg(const QString &prefix, const QList<QByteArray> &params);
-  void handleQuit(const QString &prefix, const QList<QByteArray> &params);
-  void handle324(const QString &prefix, const QList<QByteArray> &params);   // RPL_CHANNELMODEIS
 
   void defaultHandler(QString cmd, const QString &prefix, const QList<QByteArray> &params);
 
-private slots:
-  //! Joins after a netsplit
-  /** This slot handles a bulk-join after a netsplit is over
-    * \param channel The channel the users joined
-    * \param users   The list of users that joind the channel
-    * \param modes   The list of modes the users get set
-    * \param quitMessage The message we received when the netsplit occured
-    */
-  void handleNetsplitJoin(const QString &channel, const QStringList &users, const QStringList &modes, const QString &quitMessage);
-
-  //! Quits after a netsplit
-  /** This slot handles a bulk-quit after a netsplit occured
-    * \param channel The channel the users quitted
-    * \param users   The list of users that got split
-    * \param quitMessage The message we received when the netsplit occured
-    */
-  void handleNetsplitQuit(const QString &channel, const QStringList &users, const QString &quitMessage);
-
-  //! Netsplit finished
-  /** This slot deletes the netsplit object that sent the finished() signal
-    */
-  void handleNetsplitFinished();
-
-  void handleEarlyNetsplitJoin(const QString &channel, const QStringList &users, const QStringList &modes);
-
-  //! Destroy any existing netsplits
-  /** This slot deletes all netsplit objects
-    * Used to get rid of existing netsplits on network reconnect
-    */
-  void destroyNetsplits();
-
 private:
   void tryNextNick(const QString &errnick, bool erroneus = false);
   bool checkParamCount(const QString &methodName, const QList<QByteArray> &params, int minParams);
index 265521a..bcc91ea 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-09 by the Quassel Project                          *
+ *   Copyright (C) 2005-2010 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  ***************************************************************************/
 
 #include "netsplit.h"
+#include "network.h"
 #include "util.h"
 
 #include <QRegExp>
 
-Netsplit::Netsplit()
-    : _quitMsg(""), _sentQuit(false), _joinCounter(0), _quitCounter(0)
+Netsplit::Netsplit(Network *network, QObject *parent)
+  : QObject(parent),
+    _network(network), _quitMsg(""), _sentQuit(false), _joinCounter(0), _quitCounter(0)
 {
   _discardTimer.setSingleShot(true);
   _joinTimer.setSingleShot(true);
@@ -133,7 +135,7 @@ void Netsplit::joinTimeout()
   */
   if(_joinCounter < _quitCounter/3) {
     for(it = _joins.begin(); it != _joins.end(); ++it)
-      emit earlyJoin(it.key(), it.value().first, it.value().second);
+      emit earlyJoin(network(), it.key(), it.value().first, it.value().second);
 
     // we don't care about those anymore
     _joins.clear();
@@ -147,7 +149,7 @@ void Netsplit::joinTimeout()
 
   // send netsplitJoin for every recorded channel
   for(it = _joins.begin(); it != _joins.end(); ++it)
-    emit netsplitJoin(it.key(), it.value().first, it.value().second ,_quitMsg);
+    emit netsplitJoin(network(), it.key(), it.value().first, it.value().second ,_quitMsg);
   _joins.clear();
   _discardTimer.stop();
   emit finished();
@@ -170,7 +172,7 @@ void Netsplit::quitTimeout()
     // not yet sure how that could happen, but never send empty netsplit-quits
     // anyway.
     if(!usersToSend.isEmpty())
-      emit netsplitQuit(channelIter.key(), usersToSend, _quitMsg);
+      emit netsplitQuit(network(), channelIter.key(), usersToSend, _quitMsg);
   }
   _sentQuit = true;
 }
index e7e644b..6e96fd4 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-09 by the Quassel Project                          *
+ *   Copyright (C) 2005-2010 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 #ifndef NETSPLIT_H
 #define NETSPLIT_H
 
-#include <QObject>
 #include <QTimer>
 #include <QHash>
 #include <QPair>
 #include <QStringList>
 
+class Network;
+
 class Netsplit : public QObject
 {
   Q_OBJECT
 public:
-  Netsplit();
+  Netsplit(Network *network, QObject *parent = 0);
+
+  inline Network *network() const { return _network; }
 
   //! Add a user to the netsplit
   /** Call this method if you noticed a netsplit.
@@ -46,7 +49,6 @@ public:
 
   //! Remove a user from the netsplit
   /** Call this method if a user joined after a netsplit occured.
-
     *
     * \param sender   The sender string of the joined user
     * \param channel The channel that user shares with us
@@ -83,29 +85,32 @@ signals:
   //! A bulk-join of netsplitted users timed out
   /** Whenever the internal join-timer times out, we consider the bulk-join to be finished and emit that signal
     * for every channel. This is the end of a netsplit.
+    * \param net     The network
     * \param channel The IRC channel
     * \param users   A list of all users that joined that channel
     * \param modes   A list of all modes the users got set after joining again
     * \param quitMessage The Quitmessage and thus the servers that got split
     */
-  void netsplitJoin(const QString &channel, const QStringList &users, const QStringList &modes, const QString &quitMessage);
+  void netsplitJoin(Network *net, const QString &channel, const QStringList &users, const QStringList &modes, const QString &quitMessage);
 
   //! A (probably bulk-) join of netsplitted users.
   /** If users hit by the split joined before the netsplit is considered over, join the users with a normal join.
+    * \param net     The network
     * \param channel The IRC channel
     * \param users   A list of all users that joined that channel
     * \param modes   A list of all modes the users got set after joining again
     */
-  void earlyJoin(const QString &channel, const QStringList &users, const QStringList &modes);
+  void earlyJoin(Network *net, const QString &channel, const QStringList &users, const QStringList &modes);
 
   //! A bulk-quit of netsplitted users timed out
   /** Whenever the internal quit-timer times out, we consider the bulk-quit to be finished and emit that signal
     * for every channel.
+    * \param net     The network
     * \param channel The IRC channel
     * \param users   A list of all users that quitted in that channel
     * \param quitMessage The Quitmessage and thus the servers that got split
     */
-  void netsplitQuit(const QString &channel, const QStringList &users, const QString &quitMessage);
+  void netsplitQuit(Network *net, const QString &channel, const QStringList &users, const QString &quitMessage);
 
   //! The Netsplit is considered finished
   /** This signal is emitted right after all netsplitJoin signals have been sent or whenever the
@@ -119,6 +124,7 @@ private slots:
   void quitTimeout();
 
 private:
+  Network *_network;
   QString _quitMsg;
   // key: channel name
   // value: senderstring, list of modes