mumble-voip_mumble/src/mumble/ACLEditor.cpp

1052 lines
26 KiB
C++

// Copyright 2007-2023 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 "ACLEditor.h"
#include "ACL.h"
#include "Channel.h"
#include "ClientUser.h"
#include "Database.h"
#include "Log.h"
#include "QtUtils.h"
#include "ServerHandler.h"
#include "User.h"
#if QT_VERSION >= 0x050000
# include <QtWidgets/QMessageBox>
#else
# include <QtGui/QMessageBox>
#endif
#include "Global.h"
#include <cassert>
ACLGroup::ACLGroup(const QString &name) : Group(nullptr, name) {
bInherited = false;
}
ACLEditor::ACLEditor(unsigned int channelparentid, QWidget *p) : QDialog(p) {
// Simple constructor for add channel menu
bAddChannelMode = true;
iChannel = channelparentid;
setupUi(this);
qsbChannelPosition->setRange(INT_MIN, INT_MAX);
setWindowTitle(tr("Mumble - Add channel"));
qtwTab->removeTab(2);
qtwTab->removeTab(1);
// Until I come around implementing it hide the password fields
qleChannelPassword->hide();
qlChannelPassword->hide();
if (Global::get().sh->m_version >= Version::fromComponents(1, 3, 0)) {
qsbChannelMaxUsers->setRange(0, INT_MAX);
qsbChannelMaxUsers->setValue(0);
qsbChannelMaxUsers->setSpecialValueText(tr("Default server value"));
} else {
qlChannelMaxUsers->hide();
qsbChannelMaxUsers->hide();
}
qlChannelID->hide();
qleChannelName->setFocus();
pcaPassword = nullptr;
adjustSize();
}
ACLEditor::ACLEditor(unsigned int channelid, const MumbleProto::ACL &mea, QWidget *p) : QDialog(p) {
QLabel *l;
bAddChannelMode = false;
iChannel = channelid;
Channel *pChannel = Channel::get(iChannel);
if (!pChannel) {
Global::get().l->log(Log::Warning, tr("Failed: Invalid channel"));
QDialog::reject();
return;
}
msg = mea;
setupUi(this);
qcbChannelTemporary->hide();
iId = static_cast< int >(mea.channel_id());
setWindowTitle(tr("Mumble - Edit %1").arg(Channel::get(static_cast< unsigned int >(iId))->qsName));
qlChannelID->setText(tr("ID: %1").arg(iId));
qleChannelName->setText(pChannel->qsName);
if (channelid == 0)
qleChannelName->setEnabled(false);
rteChannelDescription->setText(pChannel->qsDesc);
qsbChannelPosition->setRange(INT_MIN, INT_MAX);
qsbChannelPosition->setValue(pChannel->iPosition);
if (Global::get().sh->m_version >= Version::fromComponents(1, 3, 0)) {
qsbChannelMaxUsers->setRange(0, INT_MAX);
qsbChannelMaxUsers->setValue(static_cast< int >(pChannel->uiMaxUsers));
qsbChannelMaxUsers->setSpecialValueText(tr("Default server value"));
} else {
qlChannelMaxUsers->hide();
qsbChannelMaxUsers->hide();
}
QGridLayout *grid = new QGridLayout(qgbACLpermissions);
l = new QLabel(tr("Deny"), qgbACLpermissions);
grid->addWidget(l, 0, 1);
l = new QLabel(tr("Allow"), qgbACLpermissions);
grid->addWidget(l, 0, 2);
int idx = 1;
for (int i = 0; i < ((iId == 0) ? 30 : 16); ++i) {
ChanACL::Perm perm = static_cast< ChanACL::Perm >(1 << i);
QString name = ChanACL::permName(perm);
if (!name.isEmpty()) {
// If the server's version is less than 1.4.0 then it won't support the new permissions.
// Skipping this iteration of the loop prevents checkboxes for it being added to the UI.
if (Global::get().sh->m_version < Version::fromComponents(1, 4, 0)
&& (perm == ChanACL::ResetUserContent || perm == ChanACL::Listen)) {
continue;
}
QCheckBox *qcb;
l = new QLabel(name, qgbACLpermissions);
grid->addWidget(l, idx, 0);
qcb = new QCheckBox(qgbACLpermissions);
qcb->setToolTip(tr("Deny %1").arg(name));
qcb->setWhatsThis(
tr("This revokes the %1 privilege. If a privilege is both allowed and denied, it is denied.<br />%2")
.arg(name)
.arg(ChanACL::whatsThis(perm)));
connect(qcb, SIGNAL(clicked(bool)), this, SLOT(ACLPermissions_clicked()));
grid->addWidget(qcb, idx, 1);
qlACLDeny << qcb;
qcb = new QCheckBox(qgbACLpermissions);
qcb->setToolTip(tr("Allow %1").arg(name));
qcb->setWhatsThis(
tr("This grants the %1 privilege. If a privilege is both allowed and denied, it is denied.<br />%2")
.arg(name)
.arg(ChanACL::whatsThis(perm)));
connect(qcb, SIGNAL(clicked(bool)), this, SLOT(ACLPermissions_clicked()));
grid->addWidget(qcb, idx, 2);
qlACLAllow << qcb;
qlPerms << perm;
++idx;
}
}
QSpacerItem *si = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
grid->addItem(si, idx, 0);
connect(qcbGroupAdd->lineEdit(), SIGNAL(returnPressed()), qpbGroupAddAdd, SLOT(animateClick()));
connect(qcbGroupRemove->lineEdit(), SIGNAL(returnPressed()), qpbGroupRemoveAdd, SLOT(animateClick()));
foreach (User *u, ClientUser::c_qmUsers) {
if (u->iId >= 0) {
qhNameCache.insert(u->iId, u->qsName);
qhIDCache.insert(u->qsName.toLower(), u->iId);
}
}
ChanACL *def = new ChanACL(nullptr);
def->bApplyHere = true;
def->bApplySubs = true;
def->bInherited = true;
def->iUserId = -1;
def->qsGroup = QLatin1String("all");
def->pAllow =
ChanACL::Traverse | ChanACL::Enter | ChanACL::Speak | ChanACL::Whisper | ChanACL::TextMessage | ChanACL::Listen;
def->pDeny = (~def->pAllow) & ChanACL::All;
qlACLs << def;
for (int i = 0; i < mea.acls_size(); ++i) {
const MumbleProto::ACL_ChanACL &as = mea.acls(i);
ChanACL *acl = new ChanACL(nullptr);
acl->bApplyHere = as.apply_here();
acl->bApplySubs = as.apply_subs();
acl->bInherited = as.inherited();
acl->iUserId = -1;
if (as.has_user_id())
acl->iUserId = static_cast< int >(as.user_id());
else
acl->qsGroup = u8(as.group());
acl->pAllow = static_cast< ChanACL::Permissions >(as.grant());
acl->pDeny = static_cast< ChanACL::Permissions >(as.deny());
qlACLs << acl;
}
for (int i = 0; i < mea.groups_size(); ++i) {
const MumbleProto::ACL_ChanGroup &gs = mea.groups(i);
ACLGroup *gp = new ACLGroup(u8(gs.name()));
gp->bInherit = gs.inherit();
gp->bInherited = gs.inherited();
gp->bInheritable = gs.inheritable();
for (int j = 0; j < gs.add_size(); ++j)
gp->qsAdd.insert(static_cast< int >(gs.add(j)));
for (int j = 0; j < gs.remove_size(); ++j)
gp->qsRemove.insert(static_cast< int >(gs.remove(j)));
for (int j = 0; j < gs.inherited_members_size(); ++j)
gp->qsTemporary.insert(static_cast< int >(gs.inherited_members(j)));
qlGroups << gp;
}
iUnknown = -2;
numInheritACL = -1;
bInheritACL = mea.inherit_acls();
qcbACLInherit->setChecked(bInheritACL);
foreach (ChanACL *acl, qlACLs) {
if (acl->bInherited)
numInheritACL++;
}
refill(GroupAdd);
refill(GroupRemove);
refill(GroupInherit);
refill(ACLList);
refillGroupNames();
ACLEnableCheck();
groupEnableCheck();
updatePasswordField();
qleChannelName->setFocus();
adjustSize();
}
ACLEditor::~ACLEditor() {
foreach (ChanACL *acl, qlACLs) { delete acl; }
foreach (ACLGroup *gp, qlGroups) { delete gp; }
}
void ACLEditor::showEvent(QShowEvent *evt) {
ACLEnableCheck();
QDialog::showEvent(evt);
}
void ACLEditor::accept() {
Channel *pChannel = Channel::get(iChannel);
if (!pChannel) {
// Channel gone while editing
Global::get().l->log(Log::Warning, tr("Failed: Invalid channel"));
QDialog::reject();
return;
}
if (qleChannelName->text().isEmpty()) {
// Empty channel name
QMessageBox::warning(this, QLatin1String("Mumble"), tr("Channel must have a name"), QMessageBox::Ok);
qleChannelName->setFocus();
return;
}
// Update channel state
if (bAddChannelMode) {
Global::get().sh->createChannel(iChannel, qleChannelName->text(), rteChannelDescription->text(),
static_cast< unsigned int >(qsbChannelPosition->value()),
qcbChannelTemporary->isChecked(),
static_cast< unsigned int >(qsbChannelMaxUsers->value()));
} else {
bool needs_update = false;
updatePasswordACL();
MumbleProto::ChannelState mpcs;
mpcs.set_channel_id(pChannel->iId);
if (pChannel->qsName != qleChannelName->text()) {
mpcs.set_name(u8(qleChannelName->text()));
needs_update = true;
}
if (rteChannelDescription->isModified() && (pChannel->qsDesc != rteChannelDescription->text())) {
const QString &descriptionText = rteChannelDescription->text();
mpcs.set_description(u8(descriptionText));
needs_update = true;
Global::get().db->setBlob(sha1(descriptionText), descriptionText.toUtf8());
}
if (pChannel->iPosition != qsbChannelPosition->value()) {
mpcs.set_position(qsbChannelPosition->value());
needs_update = true;
}
if (pChannel->uiMaxUsers != static_cast< unsigned int >(qsbChannelMaxUsers->value())) {
assert(qsbChannelMaxUsers->value() >= 0);
mpcs.set_max_users(static_cast< unsigned int >(qsbChannelMaxUsers->value()));
needs_update = true;
}
if (needs_update)
Global::get().sh->sendMessage(mpcs);
// Update ACL
msg.set_inherit_acls(bInheritACL);
msg.clear_acls();
msg.clear_groups();
foreach (ChanACL *acl, qlACLs) {
if (acl->bInherited || (acl->iUserId < -1))
continue;
MumbleProto::ACL_ChanACL *mpa = msg.add_acls();
mpa->set_apply_here(acl->bApplyHere);
mpa->set_apply_subs(acl->bApplySubs);
if (acl->iUserId >= 0)
mpa->set_user_id(static_cast< unsigned int >(acl->iUserId));
else
mpa->set_group(u8(acl->qsGroup));
mpa->set_grant(acl->pAllow);
mpa->set_deny(acl->pDeny);
}
foreach (ACLGroup *gp, qlGroups) {
if (gp->bInherited && gp->bInherit && gp->bInheritable && (gp->qsAdd.count() == 0)
&& (gp->qsRemove.count() == 0))
continue;
MumbleProto::ACL_ChanGroup *mpg = msg.add_groups();
mpg->set_name(u8(gp->qsName));
mpg->set_inherit(gp->bInherit);
mpg->set_inheritable(gp->bInheritable);
foreach (int pid, gp->qsAdd)
if (pid >= 0)
mpg->add_add(static_cast< unsigned int >(pid));
foreach (int pid, gp->qsRemove)
if (pid >= 0)
mpg->add_remove(static_cast< unsigned int >(pid));
}
Global::get().sh->sendMessage(msg);
}
QDialog::accept();
}
const QString ACLEditor::userName(int pid) {
if (qhNameCache.contains(pid))
return qhNameCache.value(pid);
else
return QString::fromLatin1("#%1").arg(pid);
}
int ACLEditor::id(const QString &uname) {
QString name = uname.toLower();
if (qhIDCache.contains(name)) {
return qhIDCache.value(name);
} else {
if (!qhNameWait.contains(name)) {
MumbleProto::QueryUsers mpuq;
mpuq.add_names(u8(name));
Global::get().sh->sendMessage(mpuq);
iUnknown--;
qhNameWait.insert(name, iUnknown);
qhNameCache.insert(iUnknown, name);
}
return qhNameWait.value(name);
}
}
void ACLEditor::returnQuery(const MumbleProto::QueryUsers &mqu) {
if (mqu.names_size() != mqu.ids_size())
return;
for (int i = 0; i < mqu.names_size(); ++i) {
int pid = static_cast< int >(mqu.ids(i));
QString name = u8(mqu.names(i));
QString lname = name.toLower();
qhIDCache.insert(lname, pid);
qhNameCache.insert(pid, name);
if (qhNameWait.contains(lname)) {
int tid = qhNameWait.take(lname);
foreach (ChanACL *acl, qlACLs)
if (acl->iUserId == tid)
acl->iUserId = pid;
foreach (ACLGroup *gp, qlGroups) {
if (gp->qsAdd.remove(tid))
gp->qsAdd.insert(pid);
if (gp->qsRemove.remove(tid))
gp->qsRemove.insert(pid);
}
qhNameCache.remove(tid);
}
}
refillGroupInherit();
refillGroupRemove();
refillGroupAdd();
refillComboBoxes();
refillACL();
}
void ACLEditor::refill(WaitID wid) {
switch (wid) {
case ACLList:
refillACL();
break;
case GroupInherit:
refillGroupInherit();
break;
case GroupRemove:
refillGroupRemove();
break;
case GroupAdd:
refillGroupAdd();
break;
}
}
void ACLEditor::refillComboBoxes() {
QList< QComboBox * > ql;
ql << qcbGroupAdd;
ql << qcbGroupRemove;
ql << qcbACLUser;
QStringList names = qhNameCache.values();
names.sort();
foreach (QComboBox *qcb, ql) {
qcb->clear();
qcb->addItems(names);
qcb->clearEditText();
}
}
void ACLEditor::refillACL() {
int idx = qlwACLs->currentRow();
bool previousinherit = bInheritACL;
bInheritACL = qcbACLInherit->isChecked();
qlwACLs->clear();
bool first = true;
foreach (ChanACL *acl, qlACLs) {
if (first)
first = false;
else if (!bInheritACL && acl->bInherited)
continue;
QString text;
if (acl->iUserId == -1)
text = QString::fromLatin1("@%1").arg(acl->qsGroup);
else
text = userName(acl->iUserId);
QListWidgetItem *item = new QListWidgetItem(text, qlwACLs);
if (acl->bInherited) {
QFont f = item->font();
f.setItalic(true);
item->setFont(f);
}
}
if (bInheritACL && !previousinherit && (idx != 0))
idx += numInheritACL;
if (!bInheritACL && previousinherit)
idx -= numInheritACL;
qlwACLs->setCurrentRow(idx);
}
void ACLEditor::refillGroupNames() {
QString text = qcbGroupList->currentText().toLower();
QStringList qsl;
foreach (ACLGroup *gp, qlGroups) { qsl << gp->qsName; }
qsl.sort();
qcbGroupList->clear();
foreach (QString name, qsl) { qcbGroupList->addItem(name); }
int wantindex = qcbGroupList->findText(text, Qt::MatchFixedString);
qcbGroupList->setCurrentIndex(wantindex);
}
ACLGroup *ACLEditor::currentGroup() {
QString group = qcbGroupList->currentText();
foreach (ACLGroup *gp, qlGroups)
if (gp->qsName == group)
return gp;
group = group.toLower();
foreach (ACLGroup *gp, qlGroups)
if (gp->qsName == group)
return gp;
return nullptr;
}
ChanACL *ACLEditor::currentACL() {
int idx = qlwACLs->currentRow();
if (idx < 0)
return nullptr;
if (idx && !bInheritACL)
idx += numInheritACL;
return qlACLs[idx];
}
void ACLEditor::fillWidgetFromSet(QListWidget *qlw, const QSet< int > &qs) {
qlw->clear();
QList< idname > ql;
foreach (int pid, qs) { ql << idname(userName(pid), pid); }
std::stable_sort(ql.begin(), ql.end());
foreach (idname i, ql) {
QListWidgetItem *qlwi = new QListWidgetItem(i.first, qlw);
qlwi->setData(Qt::UserRole, i.second);
if (i.second < 0) {
QFont f = qlwi->font();
f.setItalic(true);
qlwi->setFont(f);
}
}
}
void ACLEditor::refillGroupAdd() {
ACLGroup *gp = currentGroup();
if (!gp)
return;
fillWidgetFromSet(qlwGroupAdd, gp->qsAdd);
}
void ACLEditor::refillGroupRemove() {
ACLGroup *gp = currentGroup();
if (!gp)
return;
fillWidgetFromSet(qlwGroupRemove, gp->qsRemove);
}
void ACLEditor::refillGroupInherit() {
ACLGroup *gp = currentGroup();
if (!gp)
return;
fillWidgetFromSet(qlwGroupInherit, gp->qsTemporary);
}
void ACLEditor::groupEnableCheck() {
ACLGroup *gp = currentGroup();
bool enabled;
if (!gp)
enabled = false;
else
enabled = gp->bInherit;
qlwGroupRemove->setEnabled(enabled);
qlwGroupInherit->setEnabled(enabled);
qcbGroupRemove->setEnabled(enabled);
qpbGroupRemoveAdd->setEnabled(enabled);
qpbGroupRemoveRemove->setEnabled(enabled);
qpbGroupInheritRemove->setEnabled(enabled);
enabled = gp;
qlwGroupAdd->setEnabled(enabled);
qcbGroupAdd->setEnabled(enabled);
qpbGroupAddAdd->setEnabled(enabled);
qpbGroupAddRemove->setEnabled(enabled);
qcbGroupInherit->setEnabled(enabled);
qcbGroupInheritable->setEnabled(enabled);
if (gp) {
qcbGroupInherit->setChecked(gp->bInherit);
qcbGroupInheritable->setChecked(gp->bInheritable);
qcbGroupInherited->setChecked(gp->bInherited);
}
}
void ACLEditor::ACLEnableCheck() {
ChanACL *as = currentACL();
bool enabled;
if (!as)
enabled = false;
else
enabled = !as->bInherited;
qpbACLRemove->setEnabled(enabled);
qpbACLUp->setEnabled(enabled);
qpbACLDown->setEnabled(enabled);
qcbACLApplyHere->setEnabled(enabled);
qcbACLApplySubs->setEnabled(enabled);
qcbACLGroup->setEnabled(enabled);
qcbACLUser->setEnabled(enabled);
for (int idx = 0; idx < qlACLAllow.count(); idx++) {
// Only enable other checkboxes if writeacl isn't set
bool enablethis = enabled
&& (qlPerms[idx] == ChanACL::Write || !(as && (as->pAllow & ChanACL::Write))
|| qlPerms[idx] == ChanACL::Speak);
qlACLAllow[idx]->setEnabled(enablethis);
qlACLDeny[idx]->setEnabled(enablethis);
}
if (as) {
qcbACLApplyHere->setChecked(as->bApplyHere);
qcbACLApplySubs->setChecked(as->bApplySubs);
for (int idx = 0; idx < qlACLAllow.count(); idx++) {
ChanACL::Perm p = qlPerms[idx];
qlACLAllow[idx]->setChecked(as->pAllow & p);
qlACLDeny[idx]->setChecked(as->pDeny & p);
}
qcbACLGroup->clear();
qcbACLGroup->addItem(QString());
qcbACLGroup->addItem(QLatin1String("all"));
qcbACLGroup->addItem(QLatin1String("auth"));
qcbACLGroup->addItem(QLatin1String("in"));
qcbACLGroup->addItem(QLatin1String("sub"));
qcbACLGroup->addItem(QLatin1String("out"));
qcbACLGroup->addItem(QLatin1String("~in"));
qcbACLGroup->addItem(QLatin1String("~sub"));
qcbACLGroup->addItem(QLatin1String("~out"));
foreach (ACLGroup *gs, qlGroups)
qcbACLGroup->addItem(gs->qsName);
if (as->iUserId == -1) {
qcbACLUser->clearEditText();
qcbACLGroup->addItem(as->qsGroup);
qcbACLGroup->setCurrentIndex(qcbACLGroup->findText(as->qsGroup, Qt::MatchExactly));
} else {
qcbACLUser->setEditText(userName(as->iUserId));
}
}
foreach (QAbstractButton *b, qdbbButtons->buttons()) {
QPushButton *qpb = qobject_cast< QPushButton * >(b);
if (qpb) {
qpb->setAutoDefault(false);
qpb->setDefault(false);
}
}
}
void ACLEditor::on_qtwTab_currentChanged(int index) {
if (index == 0) {
// Switched to property tab, update password field
updatePasswordField();
} else if (index == 2) {
// Switched to ACL tab, update ACL list
updatePasswordACL();
refillACL();
}
}
void ACLEditor::updatePasswordField() {
// Search for an ACL that represents the current password
pcaPassword = nullptr;
foreach (ChanACL *acl, qlACLs) {
if (acl->isPassword()) {
pcaPassword = acl;
}
}
if (pcaPassword)
qleChannelPassword->setText(pcaPassword->qsGroup.mid(1));
else
qleChannelPassword->clear();
}
void ACLEditor::updatePasswordACL() {
if (qleChannelPassword->text().isEmpty()) {
// Remove the password if we had one to begin with
if (pcaPassword && qlACLs.removeOne(pcaPassword)) {
delete pcaPassword;
// Search and remove the @all deny ACL
ChanACL *denyall = nullptr;
foreach (ChanACL *acl, qlACLs) {
if (acl->qsGroup == QLatin1String("all") && acl->bInherited == false && acl->bApplyHere == true
&& acl->pAllow == ChanACL::None
&& (acl->pDeny
== (ChanACL::Enter | ChanACL::Speak | ChanACL::Whisper | ChanACL::TextMessage
| ChanACL::LinkChannel)
|| // Backwards compat with old behaviour that didn't deny traverse
acl->pDeny
== (ChanACL::Enter | ChanACL::Speak | ChanACL::Whisper | ChanACL::TextMessage
| ChanACL::LinkChannel | ChanACL::Traverse))) {
denyall = acl;
}
}
if (denyall) {
qlACLs.removeOne(denyall);
delete denyall;
}
}
} else {
// Add or Update
if (!pcaPassword || !qlACLs.contains(pcaPassword)) {
pcaPassword = new ChanACL(nullptr);
pcaPassword->bApplyHere = true;
pcaPassword->bApplySubs = false;
pcaPassword->bInherited = false;
pcaPassword->pAllow = ChanACL::None;
pcaPassword->pDeny = ChanACL::Enter | ChanACL::Speak | ChanACL::Whisper | ChanACL::TextMessage
| ChanACL::LinkChannel | ChanACL::Traverse;
pcaPassword->qsGroup = QLatin1String("all");
qlACLs << pcaPassword;
pcaPassword = new ChanACL(nullptr);
pcaPassword->bApplyHere = true;
pcaPassword->bApplySubs = false;
pcaPassword->bInherited = false;
pcaPassword->pAllow = ChanACL::Enter | ChanACL::Speak | ChanACL::Whisper | ChanACL::TextMessage
| ChanACL::LinkChannel | ChanACL::Traverse;
pcaPassword->pDeny = ChanACL::None;
pcaPassword->qsGroup = QString(QLatin1String("#%1")).arg(qleChannelPassword->text());
qlACLs << pcaPassword;
} else {
pcaPassword->qsGroup = QString(QLatin1String("#%1")).arg(qleChannelPassword->text());
}
}
}
void ACLEditor::on_qlwACLs_currentRowChanged() {
ACLEnableCheck();
}
void ACLEditor::on_qpbACLAdd_clicked() {
ChanACL *as = new ChanACL(nullptr);
as->bApplyHere = true;
as->bApplySubs = true;
as->bInherited = false;
as->qsGroup = QLatin1String("all");
as->iUserId = -1;
as->pAllow = ChanACL::None;
as->pDeny = ChanACL::None;
qlACLs << as;
refillACL();
qlwACLs->setCurrentRow(qlwACLs->count() - 1);
}
void ACLEditor::on_qpbACLRemove_clicked() {
ChanACL *as = currentACL();
if (!as || as->bInherited)
return;
qlACLs.removeAll(as);
delete as;
refillACL();
}
void ACLEditor::on_qpbACLUp_clicked() {
ChanACL *as = currentACL();
if (!as || as->bInherited)
return;
int idx = qlACLs.indexOf(as);
if (idx <= numInheritACL + 1)
return;
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
qlACLs.swapItemsAt(idx - 1, idx);
#else
qlACLs.swap(idx - 1, idx);
#endif
qlwACLs->setCurrentRow(qlwACLs->currentRow() - 1);
refillACL();
}
void ACLEditor::on_qpbACLDown_clicked() {
ChanACL *as = currentACL();
if (!as || as->bInherited)
return;
int idx = qlACLs.indexOf(as) + 1;
if (idx >= qlACLs.count())
return;
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
qlACLs.swapItemsAt(idx - 1, idx);
#else
qlACLs.swap(idx - 1, idx);
#endif
qlwACLs->setCurrentRow(qlwACLs->currentRow() + 1);
refillACL();
}
void ACLEditor::on_qcbACLInherit_clicked(bool) {
refillACL();
}
void ACLEditor::on_qcbACLApplyHere_clicked(bool checked) {
ChanACL *as = currentACL();
if (!as || as->bInherited)
return;
as->bApplyHere = checked;
}
void ACLEditor::on_qcbACLApplySubs_clicked(bool checked) {
ChanACL *as = currentACL();
if (!as || as->bInherited)
return;
as->bApplySubs = checked;
}
void ACLEditor::on_qcbACLGroup_activated(const QString &text) {
ChanACL *as = currentACL();
if (!as || as->bInherited)
return;
as->iUserId = -1;
if (text.isEmpty()) {
qcbACLGroup->setCurrentIndex(1);
as->qsGroup = QLatin1String("all");
} else {
qcbACLUser->clearEditText();
as->qsGroup = text;
}
refillACL();
}
void ACLEditor::on_qcbACLUser_activated() {
QString text = qcbACLUser->currentText();
ChanACL *as = currentACL();
if (!as || as->bInherited)
return;
if (text.isEmpty()) {
as->iUserId = -1;
if (qcbACLGroup->currentIndex() == 0) {
qcbACLGroup->setCurrentIndex(1);
as->qsGroup = QLatin1String("all");
}
refillACL();
} else {
qcbACLGroup->setCurrentIndex(0);
as->iUserId = id(text);
refillACL();
}
}
void ACLEditor::ACLPermissions_clicked() {
QCheckBox *source = qobject_cast< QCheckBox * >(sender());
ChanACL *as = currentACL();
if (!as || as->bInherited)
return;
int allowed = 0;
int denied = 0;
bool enabled = true;
bool modifiedEnter = false;
for (int idx = 0; idx < qlACLAllow.count(); idx++) {
ChanACL::Perm p = qlPerms[idx];
if (qlACLAllow[idx]->isChecked() && qlACLDeny[idx]->isChecked()) {
if (source == qlACLAllow[idx])
qlACLDeny[idx]->setChecked(false);
else
qlACLAllow[idx]->setChecked(false);
}
if (p == ChanACL::Enter && (source == qlACLAllow[idx] || source == qlACLDeny[idx])) {
// Unchecking a checkbox is not counted as modifying the Enter privilege
// in this context
modifiedEnter = source->isChecked();
}
if (p == ChanACL::Listen && modifiedEnter) {
// If Enter privileges are granted, also grant Listen privilege
// and vice versa.
// This is to make sure that people don't accidentally forget to
// modify the Listen permission when they modify the enter permission.
// Especially in the case of denying enter, this could potentially lead
// to confusion if people were still able to listen to a channel they can't
// enter.
// However the user still can allow/deny the Listen permission manually after
// having changed the enter permission.
if (denied & ChanACL::Enter) {
qlACLAllow[idx]->setChecked(false);
qlACLDeny[idx]->setChecked(true);
} else {
qlACLAllow[idx]->setChecked(true);
qlACLDeny[idx]->setChecked(false);
}
}
qlACLAllow[idx]->setEnabled(enabled || p == ChanACL::Speak);
qlACLDeny[idx]->setEnabled(enabled || p == ChanACL::Speak);
if (p == ChanACL::Write && qlACLAllow[idx]->isChecked())
enabled = false;
if (qlACLAllow[idx]->isChecked())
allowed |= p;
if (qlACLDeny[idx]->isChecked())
denied |= p;
}
as->pAllow = static_cast< ChanACL::Permissions >(allowed);
as->pDeny = static_cast< ChanACL::Permissions >(denied);
}
void ACLEditor::on_qcbGroupList_activated(const QString &text) {
ACLGroup *gs = currentGroup();
if (text.isEmpty())
return;
if (!gs) {
QString name = text.toLower();
gs = new ACLGroup(name);
gs->bInherited = false;
gs->bInherit = true;
gs->bInheritable = true;
gs->qsName = name;
qlGroups << gs;
}
refillGroupNames();
refillGroupAdd();
refillGroupRemove();
refillGroupInherit();
groupEnableCheck();
qpbGroupAdd->setEnabled(false);
}
void ACLEditor::on_qcbGroupList_editTextChanged(const QString &text) {
qpbGroupAdd->setEnabled(!text.isEmpty());
}
void ACLEditor::on_qpbGroupAdd_clicked() {
on_qcbGroupList_activated(qcbGroupList->currentText());
}
void ACLEditor::on_qpbGroupRemove_clicked() {
ACLGroup *gs = currentGroup();
if (!gs)
return;
if (gs->bInherited) {
gs->bInheritable = true;
gs->bInherit = true;
gs->qsAdd.clear();
gs->qsRemove.clear();
} else {
qlGroups.removeAll(gs);
delete gs;
}
refillGroupNames();
refillGroupAdd();
refillGroupRemove();
refillGroupInherit();
groupEnableCheck();
}
void ACLEditor::on_qcbGroupInherit_clicked(bool checked) {
ACLGroup *gs = currentGroup();
if (!gs)
return;
gs->bInherit = checked;
groupEnableCheck();
}
void ACLEditor::on_qcbGroupInheritable_clicked(bool checked) {
ACLGroup *gs = currentGroup();
if (!gs)
return;
gs->bInheritable = checked;
}
void ACLEditor::on_qpbGroupAddAdd_clicked() {
ACLGroup *gs = currentGroup();
QString text = qcbGroupAdd->currentText();
if (!gs)
return;
if (text.isEmpty())
return;
gs->qsAdd << id(text);
refillGroupAdd();
qcbGroupAdd->clearEditText();
}
void ACLEditor::on_qpbGroupAddRemove_clicked() {
ACLGroup *gs = currentGroup();
if (!gs)
return;
QListWidgetItem *item = qlwGroupAdd->currentItem();
if (!item)
return;
gs->qsAdd.remove(item->data(Qt::UserRole).toInt());
refillGroupAdd();
qcbGroupRemove->clearEditText();
}
void ACLEditor::on_qpbGroupRemoveAdd_clicked() {
QString text = qcbGroupRemove->currentText();
ACLGroup *gs = currentGroup();
if (!gs)
return;
if (text.isEmpty())
return;
gs->qsRemove << id(text);
refillGroupRemove();
}
void ACLEditor::on_qpbGroupRemoveRemove_clicked() {
ACLGroup *gs = currentGroup();
if (!gs)
return;
QListWidgetItem *item = qlwGroupRemove->currentItem();
if (!item)
return;
gs->qsRemove.remove(item->data(Qt::UserRole).toInt());
refillGroupRemove();
}
void ACLEditor::on_qpbGroupInheritRemove_clicked() {
ACLGroup *gs = currentGroup();
if (!gs)
return;
QListWidgetItem *item = qlwGroupInherit->currentItem();
if (!item)
return;
gs->qsRemove.insert(item->data(Qt::UserRole).toInt());
refillGroupRemove();
}