/***************************************************************************
- * Copyright (C) 2005-2015 by the Quassel Project *
+ * Copyright (C) 2005-2022 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
#include "ircchannel.h"
-#include "network.h"
-#include "ircuser.h"
-#include "util.h"
-
-#include <QMapIterator>
+#include <QDebug>
#include <QHashIterator>
+#include <QMapIterator>
#include <QTextCodec>
-#include <QDebug>
-
-INIT_SYNCABLE_OBJECT(IrcChannel)
-IrcChannel::IrcChannel(const QString &channelname, Network *network)
- : SyncableObject(network),
- _initialized(false),
- _name(channelname),
- _topic(QString()),
- _encrypted(false),
- _network(network),
- _codecForEncoding(0),
- _codecForDecoding(0)
-{
- setObjectName(QString::number(network->networkId().toInt()) + "/" + channelname);
-}
-
+#include "ircuser.h"
+#include "network.h"
+#include "util.h"
-IrcChannel::~IrcChannel()
+IrcChannel::IrcChannel(const QString& channelname, Network* network)
+ : SyncableObject(network)
+ , _initialized(false)
+ , _name(channelname)
+ , _topic(QString())
+ , _encrypted(false)
+ , _network(network)
+ , _codecForEncoding(nullptr)
+ , _codecForDecoding(nullptr)
{
+ setObjectName(QString::number(network->networkId().toInt()) + "/" + channelname);
}
-
// ====================
// PUBLIC:
// ====================
-bool IrcChannel::isKnownUser(IrcUser *ircuser) const
+bool IrcChannel::isKnownUser(IrcUser* ircuser) const
{
- if (ircuser == 0) {
+ if (ircuser == nullptr) {
qWarning() << "Channel" << name() << "received IrcUser Nullpointer!";
return false;
}
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;
}
return true;
}
-
-bool IrcChannel::isValidChannelUserMode(const QString &mode) const
+bool IrcChannel::isValidChannelUserMode(const QString& mode) const
{
bool isvalid = true;
if (mode.size() > 1) {
return isvalid;
}
-
-QString IrcChannel::userModes(IrcUser *ircuser) const
+QString IrcChannel::userModes(IrcUser* ircuser) const
{
if (_userModes.contains(ircuser))
return _userModes[ircuser];
return QString();
}
-
-QString IrcChannel::userModes(const QString &nick) const
+QString IrcChannel::userModes(const QString& nick) const
{
return userModes(network()->ircUser(nick));
}
-
-void IrcChannel::setCodecForEncoding(const QString &name)
+void IrcChannel::setCodecForEncoding(const QString& name)
{
setCodecForEncoding(QTextCodec::codecForName(name.toLatin1()));
}
-
-void IrcChannel::setCodecForEncoding(QTextCodec *codec)
+void IrcChannel::setCodecForEncoding(QTextCodec* codec)
{
_codecForEncoding = codec;
}
-
-void IrcChannel::setCodecForDecoding(const QString &name)
+void IrcChannel::setCodecForDecoding(const QString& name)
{
setCodecForDecoding(QTextCodec::codecForName(name.toLatin1()));
}
-
-void IrcChannel::setCodecForDecoding(QTextCodec *codec)
+void IrcChannel::setCodecForDecoding(QTextCodec* codec)
{
_codecForDecoding = codec;
}
-
-QString IrcChannel::decodeString(const QByteArray &text) const
+QString IrcChannel::decodeString(const QByteArray& text) const
{
- if (!codecForDecoding()) return network()->decodeString(text);
+ if (!codecForDecoding())
+ return network()->decodeString(text);
return ::decodeString(text, _codecForDecoding);
}
-
-QByteArray IrcChannel::encodeString(const QString &string) const
+QByteArray IrcChannel::encodeString(const QString& string) const
{
if (codecForEncoding()) {
return _codecForEncoding->fromUnicode(string);
return network()->encodeString(string);
}
-
// ====================
// PUBLIC SLOTS:
// ====================
-void IrcChannel::setTopic(const QString &topic)
+void IrcChannel::setTopic(const QString& topic)
{
_topic = topic;
SYNC(ARG(topic))
emit topicSet(topic);
}
-
-void IrcChannel::setPassword(const QString &password)
+void IrcChannel::setPassword(const QString& password)
{
_password = password;
SYNC(ARG(password))
emit encryptedSet(encrypted);
}
-
-void IrcChannel::joinIrcUsers(const QList<IrcUser *> &users, const QStringList &modes)
+void IrcChannel::joinIrcUsers(const QList<IrcUser*>& users, const QStringList& modes)
{
if (users.isEmpty())
return;
return;
}
+ // Sort user modes first
+ const QStringList sortedModes = network()->sortPrefixModes(modes);
+
QStringList newNicks;
QStringList newModes;
- QList<IrcUser *> newUsers;
+ QList<IrcUser*> newUsers;
- IrcUser *ircuser;
+ 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];
+ _userModes[ircuser] = sortedModes[i];
ircuser->joinChannel(this, true);
- connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickSet(QString)));
+ connect(ircuser, &IrcUser::nickSet, this, selectOverload<QString>(&IrcChannel::ircUserNickSet));
// connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
// 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;
}
emit ircUsersJoined(newUsers);
}
-
-void IrcChannel::joinIrcUsers(const QStringList &nicks, const QStringList &modes)
+void IrcChannel::joinIrcUsers(const QStringList& nicks, const QStringList& modes)
{
- QList<IrcUser *> users;
- foreach(QString nick, nicks)
- users << network()->newIrcUser(nick);
+ QList<IrcUser*> users;
+ foreach (QString nick, nicks)
+ users << network()->newIrcUser(nick);
joinIrcUsers(users, modes);
}
-
-void IrcChannel::joinIrcUser(IrcUser *ircuser)
+void IrcChannel::joinIrcUser(IrcUser* ircuser)
{
- QList<IrcUser *> users;
+ QList<IrcUser*> users;
users << ircuser;
QStringList modes;
modes << QString();
joinIrcUsers(users, modes);
}
-
-void IrcChannel::part(IrcUser *ircuser)
+void IrcChannel::part(IrcUser* ircuser)
{
if (isKnownUser(ircuser)) {
_userModes.remove(ircuser);
ircuser->partChannel(this);
// 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);
+ disconnect(ircuser, nullptr, this, nullptr);
emit ircUserParted(ircuser);
if (network()->isMe(ircuser) || _userModes.isEmpty()) {
// in either case we're no longer in the channel
// -> clean up the channel and destroy it
- QList<IrcUser *> users = _userModes.keys();
+ QList<IrcUser*> users = _userModes.keys();
_userModes.clear();
- foreach(IrcUser *user, users) {
- disconnect(user, 0, this, 0);
- user->partChannel(this);
+ foreach (IrcUser* user, users) {
+ disconnect(user, nullptr, this, nullptr);
+ user->partChannelInternal(this, true);
}
emit parted();
network()->removeIrcChannel(this);
}
}
-
-void IrcChannel::part(const QString &nick)
+void IrcChannel::part(const QString& nick)
{
part(network()->ircUser(nick));
}
-
// SET USER MODE
-void IrcChannel::setUserModes(IrcUser *ircuser, const QString &modes)
+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);
}
}
-
-void IrcChannel::setUserModes(const QString &nick, const QString &modes)
+void IrcChannel::setUserModes(const QString& nick, const QString& modes)
{
setUserModes(network()->ircUser(nick), modes);
}
-
// ADD USER MODE
-void IrcChannel::addUserMode(IrcUser *ircuser, const QString &mode)
+void IrcChannel::addUserMode(IrcUser* ircuser, const QString& mode)
{
if (!isKnownUser(ircuser) || !isValidChannelUserMode(mode))
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);
}
}
-
-void IrcChannel::addUserMode(const QString &nick, const QString &mode)
+void IrcChannel::addUserMode(const QString& nick, const QString& mode)
{
addUserMode(network()->ircUser(nick), mode);
}
-
// REMOVE USER MODE
-void IrcChannel::removeUserMode(IrcUser *ircuser, const QString &mode)
+void IrcChannel::removeUserMode(IrcUser* ircuser, const QString& mode)
{
if (!isKnownUser(ircuser) || !isValidChannelUserMode(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));
}
}
-
-void IrcChannel::removeUserMode(const QString &nick, const QString &mode)
+void IrcChannel::removeUserMode(const QString& nick, const QString& mode)
{
removeUserMode(network()->ircUser(nick), mode);
}
-
// INIT SET USER MODES
QVariantMap IrcChannel::initUserModes() const
{
QVariantMap usermodes;
- QHash<IrcUser *, QString>::const_iterator iter = _userModes.constBegin();
+ QHash<IrcUser*, QString>::const_iterator iter = _userModes.constBegin();
while (iter != _userModes.constEnd()) {
usermodes[iter.key()->nick()] = iter.value();
++iter;
return usermodes;
}
-
-void IrcChannel::initSetUserModes(const QVariantMap &usermodes)
+void IrcChannel::initSetUserModes(const QVariantMap& usermodes)
{
- QList<IrcUser *> users;
+ QList<IrcUser*> users;
QStringList modes;
QVariantMap::const_iterator iter = usermodes.constBegin();
while (iter != usermodes.constEnd()) {
modes << iter.value().toString();
++iter;
}
+ // joinIrcUsers handles sorting modes
joinIrcUsers(users, modes);
}
-
QVariantMap IrcChannel::initChanModes() const
{
QVariantMap channelModes;
return channelModes;
}
-
-void IrcChannel::initSetChanModes(const QVariantMap &channelModes)
+void IrcChannel::initSetChanModes(const QVariantMap& channelModes)
{
QVariantMap::const_iterator iter = channelModes["A"].toMap().constBegin();
QVariantMap::const_iterator iterEnd = channelModes["A"].toMap().constEnd();
}
}
-
void IrcChannel::ircUserDestroyed()
{
- IrcUser *ircUser = static_cast<IrcUser *>(sender());
+ auto* ircUser = static_cast<IrcUser*>(sender());
Q_ASSERT(ircUser);
_userModes.remove(ircUser);
// no further propagation.
// this leads only to fuck ups.
}
-
void IrcChannel::ircUserNickSet(QString nick)
{
- IrcUser *ircUser = qobject_cast<IrcUser *>(sender());
+ auto* ircUser = qobject_cast<IrcUser*>(sender());
Q_ASSERT(ircUser);
emit ircUserNickSet(ircUser, nick);
}
-
/*******************************************************************************
*
* 3.3 CHANMODES
// NOTE: the behavior of addChannelMode and removeChannelMode depends on the type of mode
// see list above for chanmode types
-void IrcChannel::addChannelMode(const QChar &mode, const QString &value)
+void IrcChannel::addChannelMode(const QChar& mode, const QString& value)
{
Network::ChannelModeType modeType = network()->channelModeType(mode);
SYNC(ARG(mode), ARG(value))
}
-
-void IrcChannel::removeChannelMode(const QChar &mode, const QString &value)
+void IrcChannel::removeChannelMode(const QChar& mode, const QString& value)
{
Network::ChannelModeType modeType = network()->channelModeType(mode);
SYNC(ARG(mode), ARG(value))
}
-
-bool IrcChannel::hasMode(const QChar &mode) const
+bool IrcChannel::hasMode(const QChar& mode) const
{
Network::ChannelModeType modeType = network()->channelModeType(mode);
return _C_channelModes.contains(mode);
case Network::D_CHANMODE:
return _D_channelModes.contains(mode);
- default:
- return false;
}
+ return false;
}
-
-QString IrcChannel::modeValue(const QChar &mode) const
+QString IrcChannel::modeValue(const QChar& mode) const
{
Network::ChannelModeType modeType = network()->channelModeType(mode);
}
}
-
-QStringList IrcChannel::modeValueList(const QChar &mode) const
+QStringList IrcChannel::modeValueList(const QChar& mode) const
{
Network::ChannelModeType modeType = network()->channelModeType(mode);
case Network::A_CHANMODE:
if (_A_channelModes.contains(mode))
return _A_channelModes[mode];
+ break;
default:
- return QStringList();
+ ;
}
+ return {};
}
-
QString IrcChannel::channelModeString() const
{
QStringList params;