/***************************************************************************
- * Copyright (C) 2005-2013 by the Quassel Project *
+ * Copyright (C) 2005-2018 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
_initialized(false),
_name(channelname),
_topic(QString()),
+ _encrypted(false),
_network(network),
_codecForEncoding(0),
_codecForDecoding(0)
}
if (!_userModes.contains(ircuser)) {
- qWarning() << "Channel" << name() << "received data for unknown User" << ircuser->nick();
+ // This can happen e.g. when disconnecting from a network, so don't log a warning
return false;
}
{
bool isvalid = true;
if (mode.size() > 1) {
- qWarning() << "Channel" << name() << "received Channel User Mode which is longer then 1 Char:" << mode;
+ qWarning() << "Channel" << name() << "received Channel User Mode which is longer than 1 Char:" << mode;
isvalid = false;
}
return isvalid;
void IrcChannel::setCodecForEncoding(const QString &name)
{
- setCodecForEncoding(QTextCodec::codecForName(name.toAscii()));
+ setCodecForEncoding(QTextCodec::codecForName(name.toLatin1()));
}
void IrcChannel::setCodecForDecoding(const QString &name)
{
- setCodecForDecoding(QTextCodec::codecForName(name.toAscii()));
+ setCodecForDecoding(QTextCodec::codecForName(name.toLatin1()));
}
SYNC(ARG(password))
}
+void IrcChannel::setEncrypted(bool encrypted)
+{
+ _encrypted = encrypted;
+ SYNC(ARG(encrypted))
+ emit encryptedSet(encrypted);
+}
+
void IrcChannel::joinIrcUsers(const QList<IrcUser *> &users, const QStringList &modes)
{
return;
}
+ // Sort user modes first
+ const QStringList sortedModes = network()->sortPrefixModes(modes);
+
QStringList newNicks;
QStringList newModes;
QList<IrcUser *> newUsers;
IrcUser *ircuser;
for (int i = 0; i < users.count(); i++) {
ircuser = users[i];
- if (!ircuser || _userModes.contains(ircuser)) {
- addUserMode(ircuser, modes[i]);
+ if (!ircuser)
+ continue;
+ if (_userModes.contains(ircuser)) {
+ if (sortedModes[i].count() > 1) {
+ // Multiple modes received, do it one at a time
+ // TODO Better way of syncing this without breaking protocol?
+ for (int i_m = 0; i_m < sortedModes[i].count(); ++i_m) {
+ addUserMode(ircuser, sortedModes[i][i_m]);
+ }
+ } else {
+ addUserMode(ircuser, sortedModes[i]);
+ }
continue;
}
- _userModes[ircuser] = modes[i];
- ircuser->joinChannel(this);
+ _userModes[ircuser] = sortedModes[i];
+ ircuser->joinChannel(this, true);
connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickSet(QString)));
// connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
- // if you wonder why there is no counterpart to ircUserJoined:
- // the joines are propagted by the ircuser. the signal ircUserJoined is only for convenience
+ // If you wonder why there is no counterpart to ircUserJoined:
+ // the joins are propagated by the ircuser. The signal ircUserJoined is only for convenience
newNicks << ircuser->nick();
- newModes << modes[i];
+ newModes << sortedModes[i];
newUsers << ircuser;
}
if (isKnownUser(ircuser)) {
_userModes.remove(ircuser);
ircuser->partChannel(this);
- // if you wonder why there is no counterpart to ircUserParted:
- // the joines are propagted by the ircuser. the signal ircUserParted is only for convenience
+ // If you wonder why there is no counterpart to ircUserParted:
+ // the joins are propagted by the ircuser. The signal ircUserParted is only for convenience
disconnect(ircuser, 0, this, 0);
emit ircUserParted(ircuser);
void IrcChannel::setUserModes(IrcUser *ircuser, const QString &modes)
{
if (isKnownUser(ircuser)) {
- _userModes[ircuser] = modes;
+ // Keep user modes sorted
+ _userModes[ircuser] = network()->sortPrefixModes(modes);
QString nick = ircuser->nick();
SYNC_OTHER(setUserModes, ARG(nick), ARG(modes))
emit ircUserModesSet(ircuser, modes);
return;
if (!_userModes[ircuser].contains(mode)) {
- _userModes[ircuser] += mode;
+ // Keep user modes sorted
+ _userModes[ircuser] = network()->sortPrefixModes(_userModes[ircuser] + mode);
QString nick = ircuser->nick();
SYNC_OTHER(addUserMode, ARG(nick), ARG(mode))
emit ircUserModeAdded(ircuser, mode);
return;
if (_userModes[ircuser].contains(mode)) {
+ // Removing modes shouldn't mess up ordering
_userModes[ircuser].remove(mode);
QString nick = ircuser->nick();
SYNC_OTHER(removeUserMode, ARG(nick), ARG(mode));
QHash<IrcUser *, QString>::const_iterator iter = _userModes.constBegin();
while (iter != _userModes.constEnd()) {
usermodes[iter.key()->nick()] = iter.value();
- iter++;
+ ++iter;
}
return usermodes;
}
while (iter != usermodes.constEnd()) {
users << network()->newIrcUser(iter.key());
modes << iter.value().toString();
- iter++;
+ ++iter;
}
+ // joinIrcUsers handles sorting modes
joinIrcUsers(users, modes);
}
QHash<QChar, QStringList>::const_iterator A_iter = _A_channelModes.constBegin();
while (A_iter != _A_channelModes.constEnd()) {
A_modes[A_iter.key()] = A_iter.value();
- A_iter++;
+ ++A_iter;
}
channelModes["A"] = A_modes;
QHash<QChar, QString>::const_iterator B_iter = _B_channelModes.constBegin();
while (B_iter != _B_channelModes.constEnd()) {
B_modes[B_iter.key()] = B_iter.value();
- B_iter++;
+ ++B_iter;
}
channelModes["B"] = B_modes;
QHash<QChar, QString>::const_iterator C_iter = _C_channelModes.constBegin();
while (C_iter != _C_channelModes.constEnd()) {
C_modes[C_iter.key()] = C_iter.value();
- C_iter++;
+ ++C_iter;
}
channelModes["C"] = C_modes;
QSet<QChar>::const_iterator D_iter = _D_channelModes.constBegin();
while (D_iter != _D_channelModes.constEnd()) {
D_modes += *D_iter;
- D_iter++;
+ ++D_iter;
}
channelModes["D"] = D_modes;
QVariantMap::const_iterator iterEnd = channelModes["A"].toMap().constEnd();
while (iter != iterEnd) {
_A_channelModes[iter.key()[0]] = iter.value().toStringList();
- iter++;
+ ++iter;
}
iter = channelModes["B"].toMap().constBegin();
iterEnd = channelModes["B"].toMap().constEnd();
while (iter != iterEnd) {
_B_channelModes[iter.key()[0]] = iter.value().toString();
- iter++;
+ ++iter;
}
iter = channelModes["C"].toMap().constBegin();
iterEnd = channelModes["C"].toMap().constEnd();
while (iter != iterEnd) {
_C_channelModes[iter.key()[0]] = iter.value().toString();
- iter++;
+ ++iter;
}
QString D_modes = channelModes["D"].toString();
* C --> set value or remove
* D --> on/off
*
- * B and C behave very similar... we store the data in different datastructes
+ * B and C behave very similar... we store the data in different datastructures
* for future compatibility
******************************************************************************/
return _C_channelModes.contains(mode);
case Network::D_CHANMODE:
return _D_channelModes.contains(mode);
- default:
- return false;
}
+ return false;
}
case Network::A_CHANMODE:
if (_A_channelModes.contains(mode))
return _A_channelModes[mode];
+ break;
default:
- return QStringList();
+ ;
}
+ return {};
}
QSet<QChar>::const_iterator D_iter = _D_channelModes.constBegin();
while (D_iter != _D_channelModes.constEnd()) {
modeString += *D_iter;
- D_iter++;
+ ++D_iter;
}
QHash<QChar, QString>::const_iterator BC_iter = _C_channelModes.constBegin();
while (BC_iter != _C_channelModes.constEnd()) {
modeString += BC_iter.key();
params << BC_iter.value();
- BC_iter++;
+ ++BC_iter;
}
BC_iter = _B_channelModes.constBegin();
while (BC_iter != _B_channelModes.constEnd()) {
modeString += BC_iter.key();
params << BC_iter.value();
- BC_iter++;
+ ++BC_iter;
}
if (modeString.isEmpty())
return modeString;