From da3aa4136fe01e142238f0f42fe1273481037b9d Mon Sep 17 00:00:00 2001 From: Manuel Nickschas Date: Tue, 19 Feb 2008 22:42:25 +0000 Subject: [PATCH] Core now remembers the channels you've joined if a disconnect happens, so you'll automatically rejoin those channels upon reconnect. Moved session restore over to this mechanism - maybe it works now better? (Though I don't believe that...). Aaaand, especially for son: channel passwords are now remembered, so that +k channels will be automatically rejoined as well :) --- src/common/ircchannel.cpp | 25 +++++----------------- src/common/ircchannel.h | 17 +++++++++------ src/common/network.cpp | 36 ++++++++++++++++++++++++++++++- src/common/network.h | 17 +++++++++++++-- src/core/coresession.cpp | 32 +++++++++++++++++++++------- src/core/coresession.h | 4 ++-- src/core/ircserverhandler.cpp | 12 ++++++++++- src/core/networkconnection.cpp | 39 +++++++++++++++++++--------------- src/core/networkconnection.h | 12 +++++------ src/core/userinputhandler.cpp | 25 +++++++++++++++------- 10 files changed, 148 insertions(+), 71 deletions(-) diff --git a/src/common/ircchannel.cpp b/src/common/ircchannel.cpp index f5710ba2..832a5a99 100644 --- a/src/common/ircchannel.cpp +++ b/src/common/ircchannel.cpp @@ -73,18 +73,6 @@ bool IrcChannel::isValidChannelUserMode(const QString &mode) const { return isvalid; } -QString IrcChannel::name() const { - return _name; -} - -QString IrcChannel::topic() const { - return _topic; -} - -QList IrcChannel::ircUsers() const { - return _userModes.keys(); -} - QString IrcChannel::userModes(IrcUser *ircuser) const { if(_userModes.contains(ircuser)) return _userModes[ircuser]; @@ -96,10 +84,6 @@ QString IrcChannel::userModes(const QString &nick) const { return userModes(network->ircUser(nick)); } -QTextCodec *IrcChannel::codecForEncoding() const { - return _codecForEncoding; -} - void IrcChannel::setCodecForEncoding(const QString &name) { setCodecForEncoding(QTextCodec::codecForName(name.toAscii())); } @@ -108,10 +92,6 @@ void IrcChannel::setCodecForEncoding(QTextCodec *codec) { _codecForEncoding = codec; } -QTextCodec *IrcChannel::codecForDecoding() const { - return _codecForDecoding; -} - void IrcChannel::setCodecForDecoding(const QString &name) { setCodecForDecoding(QTextCodec::codecForName(name.toAscii())); } @@ -140,6 +120,11 @@ void IrcChannel::setTopic(const QString &topic) { emit topicSet(topic); } +void IrcChannel::setPassword(const QString &password) { + _password = password; + emit passwordSet(password); +} + void IrcChannel::join(IrcUser *ircuser) { if(!_userModes.contains(ircuser) && ircuser) { _userModes[ircuser] = QString(); diff --git a/src/common/ircchannel.h b/src/common/ircchannel.h index 2bf5f64b..dfc8de05 100644 --- a/src/common/ircchannel.h +++ b/src/common/ircchannel.h @@ -37,6 +37,7 @@ class IrcChannel : public SyncableObject { Q_PROPERTY(QString name READ name STORED false) Q_PROPERTY(QString topic READ topic WRITE setTopic STORED false) + Q_PROPERTY(QString password READ password WRITE setPassword STORED false) public: IrcChannel(const QString &channelname, Network *network); @@ -45,16 +46,17 @@ public: bool isKnownUser(IrcUser *ircuser) const; bool isValidChannelUserMode(const QString &mode) const; - QString name() const; - QString topic() const; + inline QString name() const { return _name; } + inline QString topic() const { return _topic; } + inline QString password() const { return _password; } - QList ircUsers() const; + inline QList ircUsers() const { return _userModes.keys(); } QString userModes(IrcUser *ircuser) const; QString userModes(const QString &nick) const; - QTextCodec *codecForEncoding() const; - QTextCodec *codecForDecoding() const; + inline QTextCodec *codecForEncoding() const { return _codecForEncoding; } + inline QTextCodec *codecForDecoding() const { return _codecForDecoding; } void setCodecForEncoding(const QString &codecName); void setCodecForEncoding(QTextCodec *codec); void setCodecForDecoding(const QString &codecName); @@ -65,6 +67,7 @@ public: public slots: void setTopic(const QString &topic); + void setPassword(const QString &password); void join(IrcUser *ircuser); void join(const QString &nick); @@ -88,7 +91,8 @@ public slots: void initSetUserModes(const QVariantMap &usermodes); signals: - void topicSet(QString topic); + void topicSet(const QString &topic); + void passwordSet(const QString &password); void userModesSet(QString nick, QString modes); //void userModesSet(IrcUser *ircuser, QString modes); void userModeAdded(QString nick, QString mode); @@ -111,6 +115,7 @@ private: bool _initialized; QString _name; QString _topic; + QString _password; QHash _userModes; diff --git a/src/common/network.cpp b/src/common/network.cpp index 7fa2a2ae..b1a17a66 100644 --- a/src/common/network.cpp +++ b/src/common/network.cpp @@ -631,6 +631,14 @@ QStringList Network::initIrcChannels() const { return _ircChannels.keys(); } +QStringList Network::initPersistentChannels() const { + QStringList list; + foreach(QString chan, _persistentChannels.keys()) { + list << QString("%1/%2").arg(chan).arg(_persistentChannels.value(chan)); + } + return list; +} + void Network::initSetSupports(const QVariantMap &supports) { QMapIterator iter(supports); while(iter.hasNext()) { @@ -651,13 +659,39 @@ void Network::initSetIrcUsers(const QStringList &hostmasks) { } } -void Network::initSetChannels(const QStringList &channels) { +void Network::initSetIrcChannels(const QStringList &channels) { + // FIXME This does not work correctly, "received data for unknown User" triggers + // So we disable this for now + return; + if(!_ircChannels.empty()) return; foreach(QString channel, channels) newIrcChannel(channel); } +void Network::initSetPersistentChannels(const QStringList &channels) { + foreach(QString chan, channels) { + QStringList l = chan.split("/"); + _persistentChannels[l[0]] = l[1]; + } +} + +void Network::addPersistentChannel(const QString &channel, const QString &key) { + _persistentChannels[channel.toLower()] = key; + emit persistentChannelAdded(channel, key); +} + +void Network::removePersistentChannel(const QString &channel) { + _persistentChannels.remove(channel.toLower()); + emit persistentChannelRemoved(channel); +} + +void Network::setPersistentChannelKey(const QString &channel, const QString &key) { + _persistentChannels[channel.toLower()] = key; + emit persistentChannelKeySet(channel, key); +} + IrcUser *Network::updateNickFromMask(const QString &mask) { QString nick(nickFromMask(mask).toLower()); IrcUser *ircuser; diff --git a/src/common/network.h b/src/common/network.h index c52cd594..c67fea89 100644 --- a/src/common/network.h +++ b/src/common/network.h @@ -133,6 +133,8 @@ public: QList ircChannels() const; quint32 ircChannelCount() const; + inline QHash persistentChannels() const { return _persistentChannels; } + QByteArray codecForServer() const; QByteArray codecForEncoding() const; QByteArray codecForDecoding() const; @@ -183,18 +185,24 @@ public slots: inline void addIrcUser(const QString &hostmask) { newIrcUser(hostmask); } void removeIrcUser(const QString &nick); void removeIrcChannel(const QString &channel); - + + void addPersistentChannel(const QString &channel, const QString &key = QString()); + void removePersistentChannel(const QString &channel); + void setPersistentChannelKey(const QString &channel, const QString &key); + //init geters QVariantMap initSupports() const; QVariantList initServerList() const; QStringList initIrcUsers() const; QStringList initIrcChannels() const; + QStringList initPersistentChannels() const; //init seters void initSetSupports(const QVariantMap &supports); void initSetServerList(const QVariantList &serverList); void initSetIrcUsers(const QStringList &hostmasks); - void initSetChannels(const QStringList &channels); + void initSetIrcChannels(const QStringList &channels); + void initSetPersistentChannels(const QStringList &channels); IrcUser *updateNickFromMask(const QString &mask); @@ -253,6 +261,10 @@ signals: void ircUserRemoved(const QString &nick); void ircChannelRemoved(const QString &channel); + void persistentChannelAdded(const QString &channel, const QString &key); + void persistentChannelRemoved(const QString &channel); + void persistentChannelKeySet(const QString &channel, const QString &key); + // needed for client sync progress void ircUserRemoved(QObject *); void ircChannelRemoved(QObject *); @@ -281,6 +293,7 @@ private: QHash _ircUsers; // stores all known nicks for the server QHash _ircChannels; // stores all known channels QHash _supports; // stores results from RPL_ISUPPORT + QHash _persistentChannels; // stores persistent channels and their passwords, if any QVariantList _serverList; bool _useRandomServer; diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index 33f094ce..e3c58450 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -45,8 +45,7 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) : QObje SignalProxy *p = signalProxy(); - p->attachSlot(SIGNAL(requestConnect(QString)), this, SLOT(connectToNetwork(QString))); - p->attachSlot(SIGNAL(disconnectFromNetwork(NetworkId)), this, SLOT(disconnectFromNetwork(NetworkId))); // FIXME + //p->attachSlot(SIGNAL(disconnectFromNetwork(NetworkId)), this, SLOT(disconnectFromNetwork(NetworkId))); // FIXME p->attachSlot(SIGNAL(sendInput(BufferInfo, QString)), this, SLOT(msgFromClient(BufferInfo, QString))); p->attachSlot(SIGNAL(requestBacklog(BufferInfo, QVariant, QVariant)), this, SLOT(sendBacklog(BufferInfo, QVariant, QVariant))); p->attachSignal(this, SIGNAL(displayMsg(Message))); @@ -170,10 +169,13 @@ void CoreSession::loadSettings() { void CoreSession::saveSessionState() const { QVariantMap res; QVariantList conn; - foreach(NetworkConnection *net, _connections.values()) { + foreach(NetworkConnection *nc, _connections.values()) { + QHash persistentChans = nc->network()->persistentChannels(); + QStringList list; + foreach(QString chan, persistentChans.keys()) list << QString("%1/%2").arg(chan).arg(persistentChans.value(chan)); QVariantMap m; - m["NetworkId"] = QVariant::fromValue(net->networkId()); - m["State"] = net->state(); + m["NetworkId"] = QVariant::fromValue(nc->networkId()); + m["PersistentChannels"] = list; conn << m; } res["CoreBuild"] = Global::quasselBuild; @@ -192,7 +194,19 @@ void CoreSession::restoreSessionState() { QVariantList conn = s.sessionState().toMap()["ConnectedNetworks"].toList(); foreach(QVariant v, conn) { NetworkId id = v.toMap()["NetworkId"].value(); - if(_networks.keys().contains(id)) connectToNetwork(id, v.toMap()["State"]); + // TODO remove migration code some time + QStringList list = v.toMap()["PersistentChannels"].toStringList(); + if(!list.count()) { + // migrate older state + QStringList old = v.toMap()["State"].toStringList(); + foreach(QString chan, old) list << QString("%1/").arg(chan); + } + foreach(QString chan, list) { + QStringList l = chan.split("/"); + network(id)->addPersistentChannel(l[0], l[1]); + } + qDebug() << "User" << user() << "connecting to" << network(id)->networkName(); + connectToNetwork(id); } } @@ -201,6 +215,7 @@ void CoreSession::updateBufferInfo(UserId uid, const BufferInfo &bufinfo) { } // FIXME remove +/* void CoreSession::connectToNetwork(QString netname, const QVariant &previousState) { Network *net = 0; foreach(Network *n, _networks.values()) { @@ -214,8 +229,9 @@ void CoreSession::connectToNetwork(QString netname, const QVariant &previousStat } connectToNetwork(net->networkId(), previousState); } +*/ -void CoreSession::connectToNetwork(NetworkId id, const QVariant &previousState) { +void CoreSession::connectToNetwork(NetworkId id) { Network *net = network(id); if(!net) { qWarning() << "Connect to unknown network requested! net:" << id << "user:" << user(); @@ -224,7 +240,7 @@ void CoreSession::connectToNetwork(NetworkId id, const QVariant &previousState) NetworkConnection *conn = networkConnection(id); if(!conn) { - conn = new NetworkConnection(net, this, previousState); + conn = new NetworkConnection(net, this); _connections[id] = conn; attachNetworkConnection(conn); } diff --git a/src/core/coresession.h b/src/core/coresession.h index a52e0399..f8134ccf 100644 --- a/src/core/coresession.h +++ b/src/core/coresession.h @@ -63,8 +63,8 @@ public slots: void addClient(QObject *socket); - void connectToNetwork(QString, const QVariant &previousState = QVariant()); - void connectToNetwork(NetworkId, const QVariant &previousState = QVariant()); +// void connectToNetwork(QString, const QVariant &previousState = QVariant()); + void connectToNetwork(NetworkId); void disconnectFromNetwork(NetworkId id); //void processSignal(ClientSignal, QVariant, QVariant, QVariant); diff --git a/src/core/ircserverhandler.cpp b/src/core/ircserverhandler.cpp index fd7e0554..3b58903c 100644 --- a/src/core/ircserverhandler.cpp +++ b/src/core/ircserverhandler.cpp @@ -136,7 +136,7 @@ void IrcServerHandler::defaultHandler(QString cmd, const QString &prefix, const break; } // Server error messages which will be displayed with a colon between the first param and the rest - case 413: case 414: case 423: case 441: case 444: case 461: + case 413: case 414: case 423: case 441: case 444: case 461: // FIXME see below for the 47x codes case 467: case 471: case 473: case 474: case 475: case 476: case 477: case 478: case 482: case 436: // ERR_NICKCOLLISION { QString p = params.takeFirst(); @@ -168,6 +168,7 @@ void IrcServerHandler::handleJoin(const QString &prefix, const QList emit displayMsg(Message::Join, BufferInfo::ChannelBuffer, channel, channel, prefix); //qDebug() << "IrcServerHandler::handleJoin()" << prefix << params; ircuser->joinChannel(channel); + if(network()->isMe(ircuser)) network()->addPersistentChannel(channel, networkConnection()->channelKey(channel)); } void IrcServerHandler::handleKick(const QString &prefix, const QList ¶ms) { @@ -185,6 +186,7 @@ void IrcServerHandler::handleKick(const QString &prefix, const QList msg = victim->nick(); emit displayMsg(Message::Kick, BufferInfo::ChannelBuffer, channel, msg, prefix); + //if(network()->isMe(victim)) networkConnection()->setKickedFromChannel(channel); } void IrcServerHandler::handleMode(const QString &prefix, const QList ¶ms) { @@ -276,6 +278,7 @@ void IrcServerHandler::handlePart(const QString &prefix, const QList msg = userDecode(ircuser->nick(), params[1]); emit displayMsg(Message::Part, BufferInfo::ChannelBuffer, channel, msg, prefix); + if(network()->isMe(ircuser)) network()->removePersistentChannel(channel); } void IrcServerHandler::handlePing(const QString &prefix, const QList ¶ms) { @@ -608,6 +611,13 @@ void IrcServerHandler::handle433(const QString &prefix, const QList tryNextNick(errnick); } +/* */ + +// FIXME networkConnection()->setChannelKey("") for all ERR replies indicating that a JOIN went wrong +// mostly, these are codes in the 47x range + +/* */ + void IrcServerHandler::tryNextNick(const QString &errnick) { QStringList desiredNicks = networkConnection()->coreSession()->identity(network()->identity())->nicks(); int nextNick = desiredNicks.indexOf(errnick) + 1; diff --git a/src/core/networkconnection.cpp b/src/core/networkconnection.cpp index 5830d02a..651a1bea 100644 --- a/src/core/networkconnection.cpp +++ b/src/core/networkconnection.cpp @@ -36,14 +36,13 @@ #include "userinputhandler.h" #include "ctcphandler.h" -NetworkConnection::NetworkConnection(Network *network, CoreSession *session, const QVariant &state) : QObject(network), +NetworkConnection::NetworkConnection(Network *network, CoreSession *session) : QObject(network), _connectionState(Network::Disconnected), _network(network), _coreSession(session), _ircServerHandler(new IrcServerHandler(this)), _userInputHandler(new UserInputHandler(this)), _ctcpHandler(new CtcpHandler(this)), - _previousState(state), _autoReconnectCount(0) { _autoReconnectTimer.setSingleShot(true); @@ -201,20 +200,11 @@ void NetworkConnection::networkInitialized(const QString ¤tServer) { sendPerform(); - // rejoin channels we've been in - QStringList chans = _previousState.toStringList(); - if(chans.count() > 0) { - qDebug() << "autojoining" << chans; - QVariantList list; - list << serverEncode(chans.join(",")); // TODO add channel passwords - putCmd("JOIN", list); // FIXME check for 512 byte limit! - } - // delete _previousState, we won't need it again - _previousState = QVariant(); // now we are initialized setConnectionState(Network::Initialized); network()->setConnected(true); emit connected(networkId()); + } void NetworkConnection::sendPerform() { @@ -227,12 +217,18 @@ void NetworkConnection::sendPerform() { foreach(QString line, network()->perform()) { if(!line.isEmpty()) userInput(statusBuf, line); } -} -QVariant NetworkConnection::state() const { - IrcUser *me = network()->ircUser(network()->myNick()); - if(!me) return QVariant(); // this shouldn't really happen, I guess - return me->channels(); + // rejoin channels we've been in + QStringList channels, keys; + foreach(QString chan, network()->persistentChannels().keys()) { + QString key = network()->persistentChannels()[chan]; + if(!key.isEmpty()) { + channels.prepend(chan); keys.prepend(key); + } else { + channels.append(chan); + } + } + userInputHandler()->handleJoin(statusBuf, QString("%1 %2").arg(channels.join(",")).arg(keys.join(","))); } void NetworkConnection::disconnectFromIrc() { @@ -342,6 +338,15 @@ void NetworkConnection::putCmd(const QString &cmd, const QVariantList ¶ms, c putRawLine(msg); } +void NetworkConnection::addChannelKey(const QString &channel, const QString &key) { + if(key.isEmpty()) removeChannelKey(channel); + else _channelKeys[channel] = key; +} + +void NetworkConnection::removeChannelKey(const QString &channel) { + _channelKeys.remove(channel); +} + void NetworkConnection::nickChanged(const QString &newNick, const QString &oldNick) { emit nickChanged(_network->networkId(), newNick, oldNick); } diff --git a/src/core/networkconnection.h b/src/core/networkconnection.h index 83dcdec7..f9db5154 100644 --- a/src/core/networkconnection.h +++ b/src/core/networkconnection.h @@ -43,7 +43,7 @@ class NetworkConnection : public QObject { Q_OBJECT public: - NetworkConnection(Network *network, CoreSession *session, const QVariant &previousState = QVariant()); + NetworkConnection(Network *network, CoreSession *session); ~NetworkConnection(); NetworkId networkId() const; @@ -59,9 +59,6 @@ public: UserInputHandler *userInputHandler() const; CtcpHandler *ctcpHandler() const; - //! Return data necessary to restore the connection state upon core restart - QVariant state() const; - //! Decode a string using the server (network) decoding. QString serverDecode(const QByteArray &string) const; @@ -80,6 +77,8 @@ public: //! Encode a string using the user-specific encoding, if set, and use the standard encoding else. QByteArray userEncode(const QString &userNick, const QString &string) const; + inline QString channelKey(const QString &channel) const { return _channelKeys.value(channel, QString()); } + public slots: // void setServerOptions(); void connectToIrc(bool reconnecting = false); @@ -89,6 +88,8 @@ public slots: void putRawLine(QByteArray input); void putCmd(const QString &cmd, const QVariantList ¶ms, const QByteArray &prefix = QByteArray()); + void addChannelKey(const QString &channel, const QString &key); + void removeChannelKey(const QString &channel); private slots: void sendPerform(); @@ -133,8 +134,7 @@ private: UserInputHandler *_userInputHandler; CtcpHandler *_ctcpHandler; - QVariant _previousState; - + QHash _channelKeys; QTimer _autoReconnectTimer; int _autoReconnectCount; diff --git a/src/core/userinputhandler.cpp b/src/core/userinputhandler.cpp index 956e3524..08561341 100644 --- a/src/core/userinputhandler.cpp +++ b/src/core/userinputhandler.cpp @@ -107,18 +107,27 @@ void UserInputHandler::handleInvite(const BufferInfo &bufferInfo, const QString } void UserInputHandler::handleJ(const BufferInfo &bufferInfo, const QString &msg) { - Q_UNUSED(bufferInfo) - QStringList params = msg.split(" "); - if(params.size() > 0 && !params[0].startsWith("#")) { - params[0] = QString("#%1").arg(params[0]); - } - emit putCmd("JOIN", serverEncode(params)); + QString trimmed = msg.trimmed(); + if(trimmed.length() == 0) return; + if(trimmed[0].isLetter()) trimmed.prepend("#"); + handleJoin(bufferInfo, trimmed); } void UserInputHandler::handleJoin(const BufferInfo &bufferInfo, const QString &msg) { Q_UNUSED(bufferInfo) - QStringList params = msg.split(" "); - emit putCmd("JOIN", serverEncode(params)); + QStringList params = msg.trimmed().split(" "); + QStringList chans = params[0].split(","); + QStringList keys; + if(params.count() > 1) keys = params[1].split(","); + emit putCmd("JOIN", serverEncode(params)); // FIXME handle messages longer than 512 bytes! + int i = 0; + for(; i < keys.count(); i++) { + if(i >= chans.count()) break; + networkConnection()->addChannelKey(chans[i], keys[i]); + } + for(; i < chans.count(); i++) { + networkConnection()->removeChannelKey(chans[i]); + } } void UserInputHandler::handleKick(const BufferInfo &bufferInfo, const QString &msg) { -- 2.20.1