Port netsplit handling from IrcServerHandler to CoreSessionEventProcessor, and port
related commands: JOIN, QUIT, MODE, RPL_CHANNELMODEIS (324)
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); }
};
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)
NetworkReconnecting,
NetworkDisconnecting,
NetworkDisconnected,
+ NetworkSplitJoin,
+ NetworkSplitQuit,
NetworkIncoming,
IrcServerEvent = 0x00020000,
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
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()));
#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) {
}
}
+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());
}
}
+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());
}
}
+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());
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))
}
*/
+/* 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);
+}
class CoreSession;
class IrcEvent;
class IrcEventNumeric;
+class Netsplit;
class CoreSessionEventProcessor : public QObject {
Q_OBJECT
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
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);
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
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()) {
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) {
}
}
+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))
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));
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))
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
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)
: 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. */
// IRC SERVER HANDLER
//******************************/
-void IrcServerHandler::handleJoin(const QString &prefix, const QList<QByteArray> ¶ms) {
- 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> ¶ms) {
- 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> ¶ms) {
if(!checkParamCount("IrcServerHandler::handleNotice()", params, 2))
return;
}
}
-void IrcServerHandler::handleQuit(const QString &prefix, const QList<QByteArray> ¶ms) {
- 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> ¶ms) {
- 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
}
}
-void IrcServerHandler::destroyNetsplits() {
- qDeleteAll(_netsplits);
- _netsplits.clear();
-}
-
#ifdef HAVE_QCA2
QByteArray IrcServerHandler::decrypt(const QString &bufferName, const QByteArray &message_, bool isTopic) {
if(message_.isEmpty())
void handleServerMsg(QByteArray rawMsg);
public slots:
- void handleJoin(const QString &prefix, const QList<QByteArray> ¶ms);
- void handleMode(const QString &prefix, const QList<QByteArray> ¶ms);
void handleNotice(const QString &prefix, const QList<QByteArray> ¶ms);
void handlePing(const QString &prefix, const QList<QByteArray> ¶ms);
void handlePrivmsg(const QString &prefix, const QList<QByteArray> ¶ms);
- void handleQuit(const QString &prefix, const QList<QByteArray> ¶ms);
- void handle324(const QString &prefix, const QList<QByteArray> ¶ms); // RPL_CHANNELMODEIS
void defaultHandler(QString cmd, const QString &prefix, const QList<QByteArray> ¶ms);
-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> ¶ms, int minParams);
/***************************************************************************
- * 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);
*/
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();
// 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();
// 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;
}
/***************************************************************************
- * 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.
//! 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
//! 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
void quitTimeout();
private:
+ Network *_network;
QString _quitMsg;
// key: channel name
// value: senderstring, list of modes