mumble/src/Channel.cpp
2021-04-16 21:05:52 +02:00

236 lines
4.9 KiB
C++

// Copyright 2007-2021 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#include "Channel.h"
#include "ACL.h"
#include "Group.h"
#include "User.h"
#include <QtCore/QStack>
#ifdef MUMBLE
# include "PluginManager.h"
# include "Global.h"
QHash< int, Channel * > Channel::c_qhChannels;
QReadWriteLock Channel::c_qrwlChannels;
#endif
Channel::Channel(int id, const QString &name, QObject *p) : QObject(p) {
iId = id;
iPosition = 0;
qsName = name;
bInheritACL = true;
uiMaxUsers = 0;
bTemporary = false;
cParent = qobject_cast< Channel * >(p);
if (cParent)
cParent->addChannel(this);
#ifdef MUMBLE
uiPermissions = 0;
bFiltered = false;
hasEnterRestrictions.store(false);
localUserCanEnter.store(true);
#endif
}
Channel::~Channel() {
if (cParent)
cParent->removeChannel(this);
foreach (Channel *c, qlChannels)
delete c;
foreach (ChanACL *acl, qlACL)
delete acl;
foreach (Group *g, qhGroups)
delete g;
foreach (Channel *l, qhLinks.keys())
unlink(l);
Q_ASSERT(qlChannels.count() == 0);
Q_ASSERT(children().count() == 0);
}
#ifdef MUMBLE
Channel *Channel::get(int id) {
QReadLocker lock(&c_qrwlChannels);
return c_qhChannels.value(id);
}
Channel *Channel::add(int id, const QString &name) {
QWriteLocker lock(&c_qrwlChannels);
if (c_qhChannels.contains(id))
return nullptr;
Channel *c = new Channel(id, name, nullptr);
c_qhChannels.insert(id, c);
// We have to use a direct connection here in order to make sure that the user object that gets passed to the
// callback does not get invalidated or deleted while the callback is running.
QObject::connect(c, &Channel::channelEntered, Global::get().pluginManager, &PluginManager::on_channelEntered,
Qt::DirectConnection);
QObject::connect(c, &Channel::channelExited, Global::get().pluginManager, &PluginManager::on_channelExited,
Qt::DirectConnection);
return c;
}
void Channel::remove(Channel *c) {
QWriteLocker lock(&c_qrwlChannels);
c_qhChannels.remove(c->iId);
}
#endif
bool Channel::lessThan(const Channel *first, const Channel *second) {
if ((first->iPosition != second->iPosition) && (first->cParent == second->cParent))
return first->iPosition < second->iPosition;
else
return QString::localeAwareCompare(first->qsName, second->qsName) < 0;
}
bool Channel::isLinked(Channel *l) const {
return ((l == this) || qhLinks.contains(l));
}
void Channel::link(Channel *l) {
if (qsPermLinks.contains(l))
return;
qsPermLinks.insert(l);
qhLinks[l]++;
l->qsPermLinks.insert(this);
l->qhLinks[this]++;
}
void Channel::unlink(Channel *l) {
if (l) {
qsPermLinks.remove(l);
qhLinks.remove(l);
l->qsPermLinks.remove(this);
l->qhLinks.remove(this);
} else {
foreach (Channel *c, qhLinks.keys())
unlink(c);
}
}
QSet< Channel * > Channel::allLinks() {
QSet< Channel * > seen;
seen.insert(this);
if (qhLinks.isEmpty())
return seen;
QStack< Channel * > stack;
stack.push(this);
while (!stack.isEmpty()) {
Channel *lnk = stack.pop();
foreach (Channel *l, lnk->qhLinks.keys()) {
if (!seen.contains(l)) {
seen.insert(l);
stack.push(l);
}
}
}
return seen;
}
QSet< Channel * > Channel::allChildren() {
QSet< Channel * > seen;
if (!qlChannels.isEmpty()) {
QStack< Channel * > stack;
stack.push(this);
while (!stack.isEmpty()) {
Channel *c = stack.pop();
foreach (Channel *chld, c->qlChannels) {
seen.insert(chld);
if (!chld->qlChannels.isEmpty())
stack.append(chld);
}
}
}
return seen;
}
void Channel::addChannel(Channel *c) {
c->cParent = this;
c->setParent(this);
qlChannels << c;
}
void Channel::removeChannel(Channel *c) {
c->cParent = nullptr;
c->setParent(nullptr);
qlChannels.removeAll(c);
}
void Channel::addUser(User *p) {
Channel *prevChannel = p->cChannel;
if (prevChannel)
prevChannel->removeUser(p);
p->cChannel = this;
qlUsers << p;
emit channelEntered(this, prevChannel, p);
}
void Channel::removeUser(User *p) {
qlUsers.removeAll(p);
emit channelExited(this, p);
}
Channel::operator QString() const {
return QString::fromLatin1("%1[%2:%3%4]")
.arg(qsName, QString::number(iId), QString::number(cParent ? cParent->iId : -1),
bTemporary ? QLatin1String("*") : QLatin1String(""));
}
size_t Channel::getLevel() const {
size_t i = 0;
const Channel *c = this;
while (c->cParent) {
c = c->cParent;
++i;
}
return i;
}
size_t Channel::getDepth() const {
if (qlChannels.empty()) {
return 0;
}
size_t result = 0;
foreach (Channel *child, qlChannels) { result = qMax(result, child->getDepth() + 1); }
return result;
}
QString Channel::getPath() const {
QString out;
const Channel *tmp = this;
while (tmp->cParent) {
// Skip the root channel.
if (tmp->iId == 0) {
break;
}
out.prepend(QString::fromLatin1("/"));
out.prepend(tmp->qsName);
tmp = tmp->cParent;
}
return out;
}