From 63bc3c3a34a0df70cad72b1f36d4fb7b8245d79c Mon Sep 17 00:00:00 2001 From: Marcus Eggenberger Date: Thu, 13 May 2010 14:03:42 +0200 Subject: [PATCH] Fixes #746 - Quassel unsets default modes set by server upon first connect Quassel now uses a saner approach and only keeps track of the mode changes you really issued and also were confirmed by the server. You can reset the auto restore modes via "/mode -reset". This command gives currently no userfeedback as it would introduce new strings and this patch is intended to be backported. --- src/core/corenetwork.cpp | 143 +++++++++++++++++++++++++----- src/core/corenetwork.h | 6 ++ src/core/coreuserinputhandler.cpp | 13 ++- src/core/ircserverhandler.cpp | 4 + 4 files changed, 142 insertions(+), 24 deletions(-) diff --git a/src/core/corenetwork.cpp b/src/core/corenetwork.cpp index 959b3c44..76a9d559 100644 --- a/src/core/corenetwork.cpp +++ b/src/core/corenetwork.cpp @@ -43,8 +43,8 @@ CoreNetwork::CoreNetwork(const NetworkId &networkid, CoreSession *session) _lastUsedServerIndex(0), _lastPingTime(0), - _pingCount(0) - + _pingCount(0), + _requestedUserModes('-') { _autoReconnectTimer.setSingleShot(true); _socketCloseTimer.setSingleShot(true); @@ -200,7 +200,6 @@ void CoreNetwork::disconnectFromIrc(bool requested, const QString &reason, bool if(me_->isAway()) awayMsg = me_->awayMessage(); Core::setAwayMessage(userId(), networkId(), awayMsg); - Core::setUserModes(userId(), networkId(), me_->userModes()); } if(reason.isEmpty() && identityPtr()) @@ -421,17 +420,6 @@ void CoreNetwork::networkInitialized() { if(!awayMsg.isEmpty()) userInputHandler()->handleAway(BufferInfo(), Core::awayMessage(userId(), networkId())); - // restore old user modes if server default mode is set. - IrcUser *me_ = me(); - if(me_) { - if(!me_->userModes().isEmpty()) { - restoreUserModes(); - } else { - connect(me_, SIGNAL(userModesSet(QString)), this, SLOT(restoreUserModes())); - connect(me_, SIGNAL(userModesAdded(QString)), this, SLOT(restoreUserModes())); - } - } - sendPerform(); enablePingTimeout(); @@ -454,6 +442,17 @@ void CoreNetwork::sendPerform() { userInputHandler()->handleMsg(statusBuf, QString("%1 IDENTIFY %2").arg(autoIdentifyService(), autoIdentifyPassword())); } + // restore old user modes if server default mode is set. + IrcUser *me_ = me(); + if(me_) { + if(!me_->userModes().isEmpty()) { + restoreUserModes(); + } else { + connect(me_, SIGNAL(userModesSet(QString)), this, SLOT(restoreUserModes())); + connect(me_, SIGNAL(userModesAdded(QString)), this, SLOT(restoreUserModes())); + } + } + // send perform list foreach(QString line, perform()) { if(!line.isEmpty()) userInput(statusBuf, line); @@ -484,18 +483,118 @@ void CoreNetwork::restoreUserModes() { disconnect(me_, SIGNAL(userModesSet(QString)), this, SLOT(restoreUserModes())); disconnect(me_, SIGNAL(userModesAdded(QString)), this, SLOT(restoreUserModes())); - QString removeModes; - QString addModes = Core::userModes(userId(), networkId()); + QString modesDelta = Core::userModes(userId(), networkId()); QString currentModes = me_->userModes(); - removeModes = currentModes; - removeModes.remove(QRegExp(QString("[%1]").arg(addModes))); + QString addModes, removeModes; + if(modesDelta.contains('-')) { + addModes = modesDelta.section('-', 0, 0); + removeModes = modesDelta.section('-', 1); + } else { + addModes = modesDelta; + } + + addModes.remove(QRegExp(QString("[%1]").arg(currentModes))); + if(currentModes.isEmpty()) + removeModes = QString(); + else + removeModes.remove(QRegExp(QString("[^%1]").arg(currentModes))); + + if(addModes.isEmpty() && removeModes.isEmpty()) + return; + + if(!addModes.isEmpty()) + addModes = '+' + addModes; + if(!removeModes.isEmpty()) + removeModes = '-' + removeModes; + + // don't use InputHandler::handleMode() as it keeps track of our persistent mode changes + putRawLine(serverEncode(QString("MODE %1 %2%3").arg(me_->nick()).arg(addModes).arg(removeModes))); +} + +void CoreNetwork::updateIssuedModes(const QString &requestedModes) { + QString addModes; + QString removeModes; + bool addMode = true; + + for(int i = 0; i < requestedModes.length(); i++) { + if(requestedModes[i] == '+') { + addMode = true; + continue; + } + if(requestedModes[i] == '-') { + addMode = false; + continue; + } + if(addMode) { + addModes += requestedModes[i]; + } else { + removeModes += requestedModes[i]; + } + } + + + QString addModesOld = _requestedUserModes.section('-', 0, 0); + QString removeModesOld = _requestedUserModes.section('-', 1); + + addModes.remove(QRegExp(QString("[%1]").arg(addModesOld))); // deduplicate + addModesOld.remove(QRegExp(QString("[%1]").arg(removeModes))); // update + addModes += addModesOld; + + removeModes.remove(QRegExp(QString("[%1]").arg(removeModesOld))); // deduplicate + removeModesOld.remove(QRegExp(QString("[%1]").arg(addModes))); // update + removeModes += removeModesOld; + + _requestedUserModes = QString("%1-%2").arg(addModes).arg(removeModes); +} + +void CoreNetwork::updatePersistentModes(QString addModes, QString removeModes) { + QString persistentUserModes = Core::userModes(userId(), networkId()); + + QString requestedAdd = _requestedUserModes.section('-', 0, 0); + QString requestedRemove = _requestedUserModes.section('-', 1); + + QString persistentAdd, persistentRemove; + if(persistentUserModes.contains('-')) { + persistentAdd = persistentUserModes.section('-', 0, 0); + persistentRemove = persistentUserModes.section('-', 1); + } else { + persistentAdd = persistentUserModes; + } + + // remove modes we didn't issue + if(requestedAdd.isEmpty()) + addModes = QString(); + else + addModes.remove(QRegExp(QString("[^%1]").arg(requestedAdd))); + + if(requestedRemove.isEmpty()) + removeModes = QString(); + else + removeModes.remove(QRegExp(QString("[^%1]").arg(requestedRemove))); + + // deduplicate + persistentAdd.remove(QRegExp(QString("[%1]").arg(addModes))); + persistentRemove.remove(QRegExp(QString("[%1]").arg(removeModes))); + + // update + persistentAdd.remove(QRegExp(QString("[%1]").arg(removeModes))); + persistentRemove.remove(QRegExp(QString("[%1]").arg(addModes))); + + // update issued mode list + requestedAdd.remove(QRegExp(QString("[%1]").arg(addModes))); + requestedRemove.remove(QRegExp(QString("[%1]").arg(removeModes))); + _requestedUserModes = QString("%1-%2").arg(requestedAdd).arg(requestedRemove); + + persistentAdd += addModes; + persistentRemove += removeModes; + Core::setUserModes(userId(), networkId(), QString("%1-%2").arg(persistentAdd).arg(persistentRemove)); +} - removeModes = QString("%1 -%2").arg(me_->nick(), removeModes); - addModes = QString("%1 +%2").arg(me_->nick(), addModes); - userInputHandler()->handleMode(BufferInfo(), removeModes); - userInputHandler()->handleMode(BufferInfo(), addModes); +void CoreNetwork::resetPersistentModes() { + _requestedUserModes = QString('-'); + Core::setUserModes(userId(), networkId(), QString()); } void CoreNetwork::setUseAutoReconnect(bool use) { diff --git a/src/core/corenetwork.h b/src/core/corenetwork.h index d32734f4..a6d36780 100644 --- a/src/core/corenetwork.h +++ b/src/core/corenetwork.h @@ -114,6 +114,10 @@ public slots: bool setAutoWhoDone(const QString &channel); + void updateIssuedModes(const QString &requestedModes); + void updatePersistentModes(QString addModes, QString removeModes); + void resetPersistentModes(); + Server usedServer() const; inline void resetPingTimeout() { _pingCount = 0; } @@ -203,6 +207,8 @@ private: int _burstSize; // size of the token bucket int _tokenBucket; // the virtual bucket that holds the tokens QList _msgQueue; + + QString _requestedUserModes; // 2 strings separated by a '-' character. first part are requested modes to add, the second to remove }; #endif //CORENETWORK_H diff --git a/src/core/coreuserinputhandler.cpp b/src/core/coreuserinputhandler.cpp index 3184f253..ccba8b8a 100644 --- a/src/core/coreuserinputhandler.cpp +++ b/src/core/coreuserinputhandler.cpp @@ -274,8 +274,17 @@ void CoreUserInputHandler::handleMode(const BufferInfo &bufferInfo, const QStrin QStringList params = msg.split(' ', QString::SkipEmptyParts); // if the first argument is neither a channel nor us (user modes are only to oneself) the current buffer is assumed to be the target - if(!params.isEmpty() && !network()->isChannelName(params[0]) && !network()->isMyNick(params[0])) - params.prepend(bufferInfo.bufferName()); + if(!params.isEmpty()) { + if(!network()->isChannelName(params[0]) && !network()->isMyNick(params[0])) + params.prepend(bufferInfo.bufferName()); + if(network()->isMyNick(params[0]) && params.count() == 2) + network()->updateIssuedModes(params[1]); + if(params[0] == "-reset" && params.count() == 1) { + // FIXME: give feedback to the user (I don't want to add new strings right now) + network()->resetPersistentModes(); + return; + } + } // TODO handle correct encoding for buffer modes (channelEncode()) emit putCmd("MODE", serverEncode(params)); diff --git a/src/core/ircserverhandler.cpp b/src/core/ircserverhandler.cpp index ce15f781..ea598368 100644 --- a/src/core/ircserverhandler.cpp +++ b/src/core/ircserverhandler.cpp @@ -346,6 +346,10 @@ void IrcServerHandler::handleMode(const QString &prefix, const QList 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); } -- 2.20.1