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 :)
return isvalid;
}
-QString IrcChannel::name() const {
- return _name;
-}
-
-QString IrcChannel::topic() const {
- return _topic;
-}
-
-QList<IrcUser *> IrcChannel::ircUsers() const {
- return _userModes.keys();
-}
-
QString IrcChannel::userModes(IrcUser *ircuser) const {
if(_userModes.contains(ircuser))
return _userModes[ircuser];
return userModes(network->ircUser(nick));
}
-QTextCodec *IrcChannel::codecForEncoding() const {
- return _codecForEncoding;
-}
-
void IrcChannel::setCodecForEncoding(const QString &name) {
setCodecForEncoding(QTextCodec::codecForName(name.toAscii()));
}
_codecForEncoding = codec;
}
-QTextCodec *IrcChannel::codecForDecoding() const {
- return _codecForDecoding;
-}
-
void IrcChannel::setCodecForDecoding(const QString &name) {
setCodecForDecoding(QTextCodec::codecForName(name.toAscii()));
}
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();
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);
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<IrcUser *> ircUsers() const;
+ inline QList<IrcUser *> 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);
public slots:
void setTopic(const QString &topic);
+ void setPassword(const QString &password);
void join(IrcUser *ircuser);
void join(const QString &nick);
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);
bool _initialized;
QString _name;
QString _topic;
+ QString _password;
QHash<IrcUser *, QString> _userModes;
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<QString, QVariant> iter(supports);
while(iter.hasNext()) {
}
}
-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;
QList<IrcChannel *> ircChannels() const;
quint32 ircChannelCount() const;
+ inline QHash<QString, QString> persistentChannels() const { return _persistentChannels; }
+
QByteArray codecForServer() const;
QByteArray codecForEncoding() const;
QByteArray codecForDecoding() const;
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);
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 *);
QHash<QString, IrcUser *> _ircUsers; // stores all known nicks for the server
QHash<QString, IrcChannel *> _ircChannels; // stores all known channels
QHash<QString, QString> _supports; // stores results from RPL_ISUPPORT
+ QHash<QString, QString> _persistentChannels; // stores persistent channels and their passwords, if any
QVariantList _serverList;
bool _useRandomServer;
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)));
void CoreSession::saveSessionState() const {
QVariantMap res;
QVariantList conn;
- foreach(NetworkConnection *net, _connections.values()) {
+ foreach(NetworkConnection *nc, _connections.values()) {
+ QHash<QString, QString> 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<NetworkId>(net->networkId());
- m["State"] = net->state();
+ m["NetworkId"] = QVariant::fromValue<NetworkId>(nc->networkId());
+ m["PersistentChannels"] = list;
conn << m;
}
res["CoreBuild"] = Global::quasselBuild;
QVariantList conn = s.sessionState().toMap()["ConnectedNetworks"].toList();
foreach(QVariant v, conn) {
NetworkId id = v.toMap()["NetworkId"].value<NetworkId>();
- 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);
}
}
}
// FIXME remove
+/*
void CoreSession::connectToNetwork(QString netname, const QVariant &previousState) {
Network *net = 0;
foreach(Network *n, _networks.values()) {
}
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();
NetworkConnection *conn = networkConnection(id);
if(!conn) {
- conn = new NetworkConnection(net, this, previousState);
+ conn = new NetworkConnection(net, this);
_connections[id] = conn;
attachNetworkConnection(conn);
}
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);
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();
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<QByteArray> ¶ms) {
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<QByteArray> ¶ms) {
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<QByteArray> ¶ms) {
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;
#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);
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() {
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() {
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);
}
Q_OBJECT
public:
- NetworkConnection(Network *network, CoreSession *session, const QVariant &previousState = QVariant());
+ NetworkConnection(Network *network, CoreSession *session);
~NetworkConnection();
NetworkId networkId() const;
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;
//! 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);
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();
UserInputHandler *_userInputHandler;
CtcpHandler *_ctcpHandler;
- QVariant _previousState;
-
+ QHash<QString, QString> _channelKeys;
QTimer _autoReconnectTimer;
int _autoReconnectCount;
}
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) {