1 // Copyright 2005-2019 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5
6 #include "mumble_pch.hpp"
7
8 #include "ACLEditor.h"
9
10 #include "ACL.h"
11 #include "Channel.h"
12 #include "ClientUser.h"
13 #include "Database.h"
14 #include "Log.h"
15 #include "ServerHandler.h"
16 #include "User.h"
17
18 // We define a global macro called 'g'. This can lead to issues when included code uses 'g' as a type or parameter name (like protobuf 3.7 does). As such, for now, we have to make this our last include.
19 #include "Global.h"
20
ACLGroup(const QString & name)21 ACLGroup::ACLGroup(const QString &name) : Group(NULL, name) {
22 bInherited = false;
23 }
24
ACLEditor(int channelparentid,QWidget * p)25 ACLEditor::ACLEditor(int channelparentid, QWidget *p) : QDialog(p) {
26 // Simple constructor for add channel menu
27 bAddChannelMode = true;
28 iChannel = channelparentid;
29
30 setupUi(this);
31
32 qsbChannelPosition->setRange(INT_MIN, INT_MAX);
33
34 setWindowTitle(tr("Mumble - Add channel"));
35 qtwTab->removeTab(2);
36 qtwTab->removeTab(1);
37
38 // Until I come around implementing it hide the password fields
39 qleChannelPassword->hide();
40 qlChannelPassword->hide();
41
42 if (g.sh->uiVersion >= 0x010300) {
43 qsbChannelMaxUsers->setRange(0, INT_MAX);
44 qsbChannelMaxUsers->setValue(0);
45 qsbChannelMaxUsers->setSpecialValueText(tr("Default server value"));
46 } else {
47 qlChannelMaxUsers->hide();
48 qsbChannelMaxUsers->hide();
49 }
50
51 qlChannelID->hide();
52
53 qleChannelName->setFocus();
54
55 pcaPassword = NULL;
56 adjustSize();
57 }
58
ACLEditor(int channelid,const MumbleProto::ACL & mea,QWidget * p)59 ACLEditor::ACLEditor(int channelid, const MumbleProto::ACL &mea, QWidget *p) : QDialog(p) {
60 QLabel *l;
61
62 bAddChannelMode = false;
63
64 iChannel = channelid;
65 Channel *pChannel = Channel::get(iChannel);
66 if (pChannel == NULL) {
67 g.l->log(Log::Warning, tr("Failed: Invalid channel"));
68 QDialog::reject();
69 return;
70 }
71
72 msg = mea;
73
74 setupUi(this);
75
76 qcbChannelTemporary->hide();
77
78 iId = mea.channel_id();
79 setWindowTitle(tr("Mumble - Edit %1").arg(Channel::get(iId)->qsName));
80
81 qlChannelID->setText(tr("ID: %1").arg(iId));
82
83 qleChannelName->setText(pChannel->qsName);
84 if (channelid == 0)
85 qleChannelName->setEnabled(false);
86
87 rteChannelDescription->setText(pChannel->qsDesc);
88
89 qsbChannelPosition->setRange(INT_MIN, INT_MAX);
90 qsbChannelPosition->setValue(pChannel->iPosition);
91
92 if (g.sh->uiVersion >= 0x010300) {
93 qsbChannelMaxUsers->setRange(0, INT_MAX);
94 qsbChannelMaxUsers->setValue(pChannel->uiMaxUsers);
95 qsbChannelMaxUsers->setSpecialValueText(tr("Default server value"));
96 } else {
97 qlChannelMaxUsers->hide();
98 qsbChannelMaxUsers->hide();
99 }
100
101 QGridLayout *grid = new QGridLayout(qgbACLpermissions);
102
103 l = new QLabel(tr("Deny"), qgbACLpermissions);
104 grid->addWidget(l, 0, 1);
105 l = new QLabel(tr("Allow"), qgbACLpermissions);
106 grid->addWidget(l, 0, 2);
107
108 int idx = 1;
109 for (int i = 0; i < ((iId == 0) ? 30 : 16); ++i) {
110 ChanACL::Perm perm = static_cast<ChanACL::Perm>(1 << i);
111 QString name = ChanACL::permName(perm);
112
113 if (! name.isEmpty()) {
114 QCheckBox *qcb;
115 l = new QLabel(name, qgbACLpermissions);
116 grid->addWidget(l, idx, 0);
117 qcb = new QCheckBox(qgbACLpermissions);
118 qcb->setToolTip(tr("Deny %1").arg(name));
119 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)));
120 connect(qcb, SIGNAL(clicked(bool)), this, SLOT(ACLPermissions_clicked()));
121 grid->addWidget(qcb, idx, 1);
122
123 qlACLDeny << qcb;
124
125 qcb = new QCheckBox(qgbACLpermissions);
126 qcb->setToolTip(tr("Allow %1").arg(name));
127 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)));
128 connect(qcb, SIGNAL(clicked(bool)), this, SLOT(ACLPermissions_clicked()));
129 grid->addWidget(qcb, idx, 2);
130
131 qlACLAllow << qcb;
132
133 qlPerms << perm;
134
135 ++idx;
136 }
137 }
138 QSpacerItem *si = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
139 grid->addItem(si, idx, 0);
140
141 connect(qcbGroupAdd->lineEdit(), SIGNAL(returnPressed()), qpbGroupAddAdd, SLOT(animateClick()));
142 connect(qcbGroupRemove->lineEdit(), SIGNAL(returnPressed()), qpbGroupRemoveAdd, SLOT(animateClick()));
143
144 foreach(User *u, ClientUser::c_qmUsers) {
145 if (u->iId >= 0) {
146 qhNameCache.insert(u->iId, u->qsName);
147 qhIDCache.insert(u->qsName.toLower(), u->iId);
148 }
149 }
150
151 ChanACL *def = new ChanACL(NULL);
152
153 def->bApplyHere = true;
154 def->bApplySubs = true;
155 def->bInherited = true;
156 def->iUserId = -1;
157 def->qsGroup = QLatin1String("all");
158 def->pAllow = ChanACL::Traverse | ChanACL::Enter | ChanACL::Speak | ChanACL::Whisper | ChanACL::TextMessage;
159 def->pDeny = (~def->pAllow) & ChanACL::All;
160
161 qlACLs << def;
162
163 for (int i = 0; i < mea.acls_size(); ++i) {
164 const MumbleProto::ACL_ChanACL &as = mea.acls(i);
165
166 ChanACL *acl = new ChanACL(NULL);
167 acl->bApplyHere = as.apply_here();
168 acl->bApplySubs = as.apply_subs();
169 acl->bInherited = as.inherited();
170 acl->iUserId = -1;
171 if (as.has_user_id())
172 acl->iUserId = as.user_id();
173 else
174 acl->qsGroup = u8(as.group());
175 acl->pAllow = static_cast<ChanACL::Permissions>(as.grant());
176 acl->pDeny = static_cast<ChanACL::Permissions>(as.deny());
177
178 qlACLs << acl;
179 }
180
181 for (int i = 0; i < mea.groups_size(); ++i) {
182 const MumbleProto::ACL_ChanGroup &gs = mea.groups(i);
183
184 ACLGroup *gp = new ACLGroup(u8(gs.name()));
185 gp->bInherit = gs.inherit();
186 gp->bInherited = gs.inherited();
187 gp->bInheritable = gs.inheritable();
188 for (int j = 0; j < gs.add_size(); ++j)
189 gp->qsAdd.insert(gs.add(j));
190 for (int j = 0; j < gs.remove_size(); ++j)
191 gp->qsRemove.insert(gs.remove(j));
192 for (int j = 0; j < gs.inherited_members_size(); ++j)
193 gp->qsTemporary.insert(gs.inherited_members(j));
194
195 qlGroups << gp;
196 }
197
198 iUnknown = -2;
199
200 numInheritACL = -1;
201
202 bInheritACL = mea.inherit_acls();
203 qcbACLInherit->setChecked(bInheritACL);
204
205 foreach(ChanACL *acl, qlACLs) {
206 if (acl->bInherited)
207 numInheritACL++;
208 }
209
210 refill(GroupAdd);
211 refill(GroupRemove);
212 refill(GroupInherit);
213 refill(ACLList);
214 refillGroupNames();
215
216 ACLEnableCheck();
217 groupEnableCheck();
218
219 updatePasswordField();
220
221 qleChannelName->setFocus();
222 adjustSize();
223 }
224
~ACLEditor()225 ACLEditor::~ACLEditor() {
226 foreach(ChanACL *acl, qlACLs) {
227 delete acl;
228 }
229 foreach(ACLGroup *gp, qlGroups) {
230 delete gp;
231 }
232 }
233
showEvent(QShowEvent * evt)234 void ACLEditor::showEvent(QShowEvent *evt) {
235 ACLEnableCheck();
236 QDialog::showEvent(evt);
237 }
238
accept()239 void ACLEditor::accept() {
240 Channel *pChannel = Channel::get(iChannel);
241 if (pChannel == NULL) {
242 // Channel gone while editing
243 g.l->log(Log::Warning, tr("Failed: Invalid channel"));
244 QDialog::reject();
245 return;
246 }
247
248 if (qleChannelName->text().isEmpty()) {
249 // Empty channel name
250 QMessageBox::warning(this, QLatin1String("Mumble"), tr("Channel must have a name"), QMessageBox::Ok);
251 qleChannelName->setFocus();
252 return;
253 }
254
255 // Update channel state
256 if (bAddChannelMode) {
257 g.sh->createChannel(iChannel, qleChannelName->text(), rteChannelDescription->text(), qsbChannelPosition->value(), qcbChannelTemporary->isChecked(), qsbChannelMaxUsers->value());
258 } else {
259 bool needs_update = false;
260
261 updatePasswordACL();
262
263 MumbleProto::ChannelState mpcs;
264 mpcs.set_channel_id(pChannel->iId);
265 if (pChannel->qsName != qleChannelName->text()) {
266 mpcs.set_name(u8(qleChannelName->text()));
267 needs_update = true;
268 }
269 if (rteChannelDescription->isModified() && (pChannel->qsDesc != rteChannelDescription->text())) {
270 const QString &descriptionText = rteChannelDescription->text();
271 mpcs.set_description(u8(descriptionText));
272 needs_update = true;
273 g.db->setBlob(sha1(descriptionText), descriptionText.toUtf8());
274 }
275 if (pChannel->iPosition != qsbChannelPosition->value()) {
276 mpcs.set_position(qsbChannelPosition->value());
277 needs_update = true;
278 }
279 if (pChannel->uiMaxUsers != static_cast<unsigned int>(qsbChannelMaxUsers->value())) {
280 mpcs.set_max_users(qsbChannelMaxUsers->value());
281 needs_update = true;
282 }
283 if (needs_update)
284 g.sh->sendMessage(mpcs);
285
286 // Update ACL
287 msg.set_inherit_acls(bInheritACL);
288 msg.clear_acls();
289 msg.clear_groups();
290
291 foreach(ChanACL *acl, qlACLs) {
292 if (acl->bInherited || (acl->iUserId < -1))
293 continue;
294 MumbleProto::ACL_ChanACL *mpa = msg.add_acls();
295 mpa->set_apply_here(acl->bApplyHere);
296 mpa->set_apply_subs(acl->bApplySubs);
297 if (acl->iUserId != -1)
298 mpa->set_user_id(acl->iUserId);
299 else
300 mpa->set_group(u8(acl->qsGroup));
301 mpa->set_grant(acl->pAllow);
302 mpa->set_deny(acl->pDeny);
303 }
304
305 foreach(ACLGroup *gp, qlGroups) {
306 if (gp->bInherited && gp->bInherit && gp->bInheritable && (gp->qsAdd.count() == 0) && (gp->qsRemove.count() == 0))
307 continue;
308 MumbleProto::ACL_ChanGroup *mpg = msg.add_groups();
309 mpg->set_name(u8(gp->qsName));
310 mpg->set_inherit(gp->bInherit);
311 mpg->set_inheritable(gp->bInheritable);
312 foreach(int pid, gp->qsAdd)
313 if (pid >= 0)
314 mpg->add_add(pid);
315 foreach(int pid, gp->qsRemove)
316 if (pid >= 0)
317 mpg->add_remove(pid);
318 }
319 g.sh->sendMessage(msg);
320 }
321 QDialog::accept();
322 }
323
324
userName(int pid)325 const QString ACLEditor::userName(int pid) {
326 if (qhNameCache.contains(pid))
327 return qhNameCache.value(pid);
328 else
329 return QString::fromLatin1("#%1").arg(pid);
330 }
331
id(const QString & uname)332 int ACLEditor::id(const QString &uname) {
333 QString name = uname.toLower();
334 if (qhIDCache.contains(name)) {
335 return qhIDCache.value(name);
336 } else {
337 if (! qhNameWait.contains(name)) {
338 MumbleProto::QueryUsers mpuq;
339 mpuq.add_names(u8(name));
340 g.sh->sendMessage(mpuq);
341
342 iUnknown--;
343 qhNameWait.insert(name, iUnknown);
344 qhNameCache.insert(iUnknown, name);
345 }
346 return qhNameWait.value(name);
347 }
348 }
349
returnQuery(const MumbleProto::QueryUsers & mqu)350 void ACLEditor::returnQuery(const MumbleProto::QueryUsers &mqu) {
351 if (mqu.names_size() != mqu.ids_size())
352 return;
353
354 for (int i = 0; i < mqu.names_size(); ++i) {
355 int pid = mqu.ids(i);
356 QString name = u8(mqu.names(i));
357 QString lname = name.toLower();
358 qhIDCache.insert(lname, pid);
359 qhNameCache.insert(pid, name);
360
361 if (qhNameWait.contains(lname)) {
362 int tid = qhNameWait.take(lname);
363
364 foreach(ChanACL *acl, qlACLs)
365 if (acl->iUserId == tid)
366 acl->iUserId = pid;
367 foreach(ACLGroup *gp, qlGroups) {
368 if (gp->qsAdd.remove(tid))
369 gp->qsAdd.insert(pid);
370 if (gp->qsRemove.remove(tid))
371 gp->qsRemove.insert(pid);
372 }
373 qhNameCache.remove(tid);
374 }
375 }
376 refillGroupInherit();
377 refillGroupRemove();
378 refillGroupAdd();
379 refillComboBoxes();
380 refillACL();
381 }
382
refill(WaitID wid)383 void ACLEditor::refill(WaitID wid) {
384 switch (wid) {
385 case ACLList:
386 refillACL();
387 break;
388 case GroupInherit:
389 refillGroupInherit();
390 break;
391 case GroupRemove:
392 refillGroupRemove();
393 break;
394 case GroupAdd:
395 refillGroupAdd();
396 break;
397 }
398 }
399
refillComboBoxes()400 void ACLEditor::refillComboBoxes() {
401 QList<QComboBox *> ql;
402 ql << qcbGroupAdd;
403 ql << qcbGroupRemove;
404 ql << qcbACLUser;
405
406 QStringList names = qhNameCache.values();
407 names.sort();
408
409 foreach(QComboBox *qcb, ql) {
410 qcb->clear();
411 qcb->addItems(names);
412 qcb->clearEditText();
413 }
414 }
415
refillACL()416 void ACLEditor::refillACL() {
417 int idx = qlwACLs->currentRow();
418 bool previousinherit = bInheritACL;
419 bInheritACL = qcbACLInherit->isChecked();
420
421 qlwACLs->clear();
422
423 bool first = true;
424
425 foreach(ChanACL *acl, qlACLs) {
426 if (first)
427 first = false;
428 else if (! bInheritACL && acl->bInherited)
429 continue;
430 QString text;
431 if (acl->iUserId == -1)
432 text = QString::fromLatin1("@%1").arg(acl->qsGroup);
433 else
434 text = userName(acl->iUserId);
435 QListWidgetItem *item = new QListWidgetItem(text, qlwACLs);
436 if (acl->bInherited) {
437 QFont f = item->font();
438 f.setItalic(true);
439 item->setFont(f);
440 }
441 }
442 if (bInheritACL && ! previousinherit && (idx != 0))
443 idx += numInheritACL;
444 if (! bInheritACL && previousinherit)
445 idx -= numInheritACL;
446
447 qlwACLs->setCurrentRow(idx);
448 }
449
refillGroupNames()450 void ACLEditor::refillGroupNames() {
451 QString text = qcbGroupList->currentText().toLower();
452 QStringList qsl;
453
454 foreach(ACLGroup *gp, qlGroups) {
455 qsl << gp->qsName;
456 }
457 qsl.sort();
458
459 qcbGroupList->clear();
460
461 foreach(QString name, qsl) {
462 qcbGroupList->addItem(name);
463 }
464
465 int wantindex = qcbGroupList->findText(text, Qt::MatchFixedString);
466 qcbGroupList->setCurrentIndex(wantindex);
467 }
468
currentGroup()469 ACLGroup *ACLEditor::currentGroup() {
470 QString group = qcbGroupList->currentText();
471
472 foreach(ACLGroup *gp, qlGroups)
473 if (gp->qsName == group)
474 return gp;
475
476 group = group.toLower();
477
478 foreach(ACLGroup *gp, qlGroups)
479 if (gp->qsName == group)
480 return gp;
481
482 return NULL;
483 }
484
currentACL()485 ChanACL *ACLEditor::currentACL() {
486 int idx = qlwACLs->currentRow();
487 if (idx < 0)
488 return NULL;
489
490 if (idx && ! bInheritACL)
491 idx += numInheritACL;
492 return qlACLs[idx];
493 }
494
fillWidgetFromSet(QListWidget * qlw,const QSet<int> & qs)495 void ACLEditor::fillWidgetFromSet(QListWidget *qlw, const QSet<int> &qs) {
496 qlw->clear();
497
498 QList<idname> ql;
499 foreach(int pid, qs) {
500 ql << idname(userName(pid), pid);
501 }
502 qStableSort(ql);
503 foreach(idname i, ql) {
504 QListWidgetItem *qlwi = new QListWidgetItem(i.first, qlw);
505 qlwi->setData(Qt::UserRole, i.second);
506 if (i.second < 0) {
507 QFont f = qlwi->font();
508 f.setItalic(true);
509 qlwi->setFont(f);
510 }
511 }
512 }
513
refillGroupAdd()514 void ACLEditor::refillGroupAdd() {
515 ACLGroup *gp = currentGroup();
516
517 if (! gp)
518 return;
519
520 fillWidgetFromSet(qlwGroupAdd, gp->qsAdd);
521 }
522
refillGroupRemove()523 void ACLEditor::refillGroupRemove() {
524 ACLGroup *gp = currentGroup();
525 if (! gp)
526 return;
527
528 fillWidgetFromSet(qlwGroupRemove, gp->qsRemove);
529 }
530
refillGroupInherit()531 void ACLEditor::refillGroupInherit() {
532 ACLGroup *gp = currentGroup();
533
534 if (! gp)
535 return;
536
537 fillWidgetFromSet(qlwGroupInherit, gp->qsTemporary);
538 }
539
groupEnableCheck()540 void ACLEditor::groupEnableCheck() {
541 ACLGroup *gp = currentGroup();
542
543 bool enabled;
544 if (! gp)
545 enabled = false;
546 else
547 enabled = gp->bInherit;
548
549 qlwGroupRemove->setEnabled(enabled);
550 qlwGroupInherit->setEnabled(enabled);
551 qcbGroupRemove->setEnabled(enabled);
552 qpbGroupRemoveAdd->setEnabled(enabled);
553 qpbGroupRemoveRemove->setEnabled(enabled);
554 qpbGroupInheritRemove->setEnabled(enabled);
555
556 enabled = (gp != NULL);
557 qlwGroupAdd->setEnabled(enabled);
558 qcbGroupAdd->setEnabled(enabled);
559 qpbGroupAddAdd->setEnabled(enabled);
560 qpbGroupAddRemove->setEnabled(enabled);
561 qcbGroupInherit->setEnabled(enabled);
562 qcbGroupInheritable->setEnabled(enabled);
563
564 if (gp) {
565 qcbGroupInherit->setChecked(gp->bInherit);
566 qcbGroupInheritable->setChecked(gp->bInheritable);
567 qcbGroupInherited->setChecked(gp->bInherited);
568 }
569 }
570
ACLEnableCheck()571 void ACLEditor::ACLEnableCheck() {
572 ChanACL *as = currentACL();
573
574 bool enabled;
575 if (! as)
576 enabled = false;
577 else
578 enabled = ! as->bInherited;
579
580 qpbACLRemove->setEnabled(enabled);
581 qpbACLUp->setEnabled(enabled);
582 qpbACLDown->setEnabled(enabled);
583 qcbACLApplyHere->setEnabled(enabled);
584 qcbACLApplySubs->setEnabled(enabled);
585 qcbACLGroup->setEnabled(enabled);
586 qcbACLUser->setEnabled(enabled);
587
588 for (int idx = 0; idx < qlACLAllow.count(); idx++) {
589 // Only enable other checkboxes if writeacl isn't set
590 bool enablethis = enabled && (qlPerms[idx] == ChanACL::Write || !(as && (as->pAllow & ChanACL::Write)) || qlPerms[idx] == ChanACL::Speak);
591 qlACLAllow[idx]->setEnabled(enablethis);
592 qlACLDeny[idx]->setEnabled(enablethis);
593 }
594
595 if (as) {
596 qcbACLApplyHere->setChecked(as->bApplyHere);
597 qcbACLApplySubs->setChecked(as->bApplySubs);
598
599 for (int idx = 0; idx < qlACLAllow.count(); idx++) {
600 ChanACL::Perm p = qlPerms[idx];
601 qlACLAllow[idx]->setChecked(as->pAllow & p);
602 qlACLDeny[idx]->setChecked(as->pDeny & p);
603 }
604
605 qcbACLGroup->clear();
606 qcbACLGroup->addItem(QString());
607 qcbACLGroup->addItem(QLatin1String("all"));
608 qcbACLGroup->addItem(QLatin1String("auth"));
609 qcbACLGroup->addItem(QLatin1String("in"));
610 qcbACLGroup->addItem(QLatin1String("sub"));
611 qcbACLGroup->addItem(QLatin1String("out"));
612 qcbACLGroup->addItem(QLatin1String("~in"));
613 qcbACLGroup->addItem(QLatin1String("~sub"));
614 qcbACLGroup->addItem(QLatin1String("~out"));
615
616 foreach(ACLGroup *gs, qlGroups)
617 qcbACLGroup->addItem(gs->qsName);
618
619 if (as->iUserId == -1) {
620 qcbACLUser->clearEditText();
621 qcbACLGroup->addItem(as->qsGroup);
622 qcbACLGroup->setCurrentIndex(qcbACLGroup->findText(as->qsGroup, Qt::MatchExactly));
623 } else {
624 qcbACLUser->setEditText(userName(as->iUserId));
625 }
626 }
627 foreach(QAbstractButton *b, qdbbButtons->buttons()) {
628 QPushButton *qpb = qobject_cast<QPushButton *>(b);
629 if (qpb) {
630 qpb->setAutoDefault(false);
631 qpb->setDefault(false);
632 }
633 }
634 }
635
on_qtwTab_currentChanged(int index)636 void ACLEditor::on_qtwTab_currentChanged(int index) {
637 if (index == 0) {
638 // Switched to property tab, update password field
639 updatePasswordField();
640 } else if (index == 2) {
641 // Switched to ACL tab, update ACL list
642 updatePasswordACL();
643 refillACL();
644 }
645 }
646
updatePasswordField()647 void ACLEditor::updatePasswordField() {
648 pcaPassword = NULL;
649 foreach(ChanACL *acl, qlACLs) {
650 // Check for sth that applies to '#<something>' AND grants 'Enter' AND may grant 'Speak', 'Whisper',
651 // 'TextMessage', 'Link' but NOTHING else AND does not deny anything, then '<something>' is the password.
652 if (acl->qsGroup.startsWith(QLatin1Char('#')) &&
653 acl->bApplyHere &&
654 !acl->bInherited &&
655 (acl->pAllow & ChanACL::Enter) &&
656 (acl->pAllow == (ChanACL::Enter | ChanACL::Speak | ChanACL::Whisper | ChanACL::TextMessage | ChanACL::LinkChannel) || // Backwards compat with old behaviour that didn't deny traverse
657 acl->pAllow == (ChanACL::Enter | ChanACL::Speak | ChanACL::Whisper | ChanACL::TextMessage | ChanACL::LinkChannel | ChanACL::Traverse)) &&
658 acl->pDeny == ChanACL::None) {
659 pcaPassword = acl;
660 }
661 }
662 if (pcaPassword)
663 qleChannelPassword->setText(pcaPassword->qsGroup.mid(1));
664 else
665 qleChannelPassword->clear();
666
667 }
668
updatePasswordACL()669 void ACLEditor::updatePasswordACL() {
670 if (qleChannelPassword->text().isEmpty()) {
671 // Remove the password if we had one to begin with
672 if (pcaPassword && qlACLs.removeOne(pcaPassword)) {
673 delete pcaPassword;
674
675 // Search and remove the @all deny ACL
676 ChanACL *denyall = NULL;
677 foreach(ChanACL *acl, qlACLs) {
678 if (acl->qsGroup == QLatin1String("all") &&
679 acl->bInherited == false &&
680 acl->bApplyHere == true &&
681 acl->pAllow == ChanACL::None &&
682 (acl->pDeny == (ChanACL::Enter | ChanACL::Speak | ChanACL::Whisper | ChanACL::TextMessage | ChanACL::LinkChannel) || // Backwards compat with old behaviour that didn't deny traverse
683 acl->pDeny == (ChanACL::Enter | ChanACL::Speak | ChanACL::Whisper | ChanACL::TextMessage | ChanACL::LinkChannel | ChanACL::Traverse))) {
684 denyall = acl;
685 }
686 }
687 if (denyall) {
688 qlACLs.removeOne(denyall);
689 delete denyall;
690 }
691 }
692 } else {
693 // Add or Update
694 if (pcaPassword == NULL || !qlACLs.contains(pcaPassword)) {
695 pcaPassword = new ChanACL(NULL);
696 pcaPassword->bApplyHere = true;
697 pcaPassword->bApplySubs = false;
698 pcaPassword->bInherited = false;
699 pcaPassword->pAllow = ChanACL::None;
700 pcaPassword->pDeny = ChanACL::Enter | ChanACL::Speak | ChanACL::Whisper | ChanACL::TextMessage | ChanACL::LinkChannel | ChanACL::Traverse;
701 pcaPassword->qsGroup = QLatin1String("all");
702 qlACLs << pcaPassword;
703
704 pcaPassword = new ChanACL(NULL);
705 pcaPassword->bApplyHere = true;
706 pcaPassword->bApplySubs = false;
707 pcaPassword->bInherited = false;
708 pcaPassword->pAllow = ChanACL::Enter | ChanACL::Speak | ChanACL::Whisper | ChanACL::TextMessage | ChanACL::LinkChannel | ChanACL::Traverse;
709 pcaPassword->pDeny = ChanACL::None;
710 pcaPassword->qsGroup = QString(QLatin1String("#%1")).arg(qleChannelPassword->text());
711 qlACLs << pcaPassword;
712 } else {
713 pcaPassword->qsGroup = QString(QLatin1String("#%1")).arg(qleChannelPassword->text());
714 }
715 }
716 }
717
on_qlwACLs_currentRowChanged()718 void ACLEditor::on_qlwACLs_currentRowChanged() {
719 ACLEnableCheck();
720 }
721
on_qpbACLAdd_clicked()722 void ACLEditor::on_qpbACLAdd_clicked() {
723 ChanACL *as = new ChanACL(NULL);
724 as->bApplyHere = true;
725 as->bApplySubs = true;
726 as->bInherited = false;
727 as->qsGroup = QLatin1String("all");
728 as->iUserId = -1;
729 as->pAllow = ChanACL::None;
730 as->pDeny = ChanACL::None;
731 qlACLs << as;
732 refillACL();
733 qlwACLs->setCurrentRow(qlwACLs->count() - 1);
734 }
735
on_qpbACLRemove_clicked()736 void ACLEditor::on_qpbACLRemove_clicked() {
737 ChanACL *as = currentACL();
738 if (! as || as->bInherited)
739 return;
740
741 qlACLs.removeAll(as);
742 delete as;
743 refillACL();
744 }
745
on_qpbACLUp_clicked()746 void ACLEditor::on_qpbACLUp_clicked() {
747 ChanACL *as = currentACL();
748 if (! as || as->bInherited)
749 return;
750
751 int idx = qlACLs.indexOf(as);
752 if (idx <= numInheritACL + 1)
753 return;
754
755 qlACLs.swap(idx - 1, idx);
756 qlwACLs->setCurrentRow(qlwACLs->currentRow() - 1);
757 refillACL();
758 }
759
on_qpbACLDown_clicked()760 void ACLEditor::on_qpbACLDown_clicked() {
761 ChanACL *as = currentACL();
762 if (! as || as->bInherited)
763 return;
764
765 int idx = qlACLs.indexOf(as) + 1;
766 if (idx >= qlACLs.count())
767 return;
768
769 qlACLs.swap(idx - 1, idx);
770 qlwACLs->setCurrentRow(qlwACLs->currentRow() + 1);
771 refillACL();
772 }
773
on_qcbACLInherit_clicked(bool)774 void ACLEditor::on_qcbACLInherit_clicked(bool) {
775 refillACL();
776 }
777
on_qcbACLApplyHere_clicked(bool checked)778 void ACLEditor::on_qcbACLApplyHere_clicked(bool checked) {
779 ChanACL *as = currentACL();
780 if (! as || as->bInherited)
781 return;
782
783 as->bApplyHere = checked;
784 }
785
on_qcbACLApplySubs_clicked(bool checked)786 void ACLEditor::on_qcbACLApplySubs_clicked(bool checked) {
787 ChanACL *as = currentACL();
788 if (! as || as->bInherited)
789 return;
790
791 as->bApplySubs = checked;
792 }
793
on_qcbACLGroup_activated(const QString & text)794 void ACLEditor::on_qcbACLGroup_activated(const QString &text) {
795 ChanACL *as = currentACL();
796 if (! as || as->bInherited)
797 return;
798
799 as->iUserId = -1;
800
801 if (text.isEmpty()) {
802 qcbACLGroup->setCurrentIndex(1);
803 as->qsGroup = QLatin1String("all");
804 } else {
805 qcbACLUser->clearEditText();
806 as->qsGroup = text;
807 }
808 refillACL();
809 }
810
on_qcbACLUser_activated()811 void ACLEditor::on_qcbACLUser_activated() {
812 QString text = qcbACLUser->currentText();
813
814 ChanACL *as = currentACL();
815 if (! as || as->bInherited)
816 return;
817
818 if (text.isEmpty()) {
819 as->iUserId = -1;
820 if (qcbACLGroup->currentIndex() == 0) {
821 qcbACLGroup->setCurrentIndex(1);
822 as->qsGroup = QLatin1String("all");
823 }
824 refillACL();
825 } else {
826 qcbACLGroup->setCurrentIndex(0);
827 as->iUserId = id(text);
828 refillACL();
829 }
830 }
831
ACLPermissions_clicked()832 void ACLEditor::ACLPermissions_clicked() {
833 QCheckBox *source = qobject_cast<QCheckBox *>(sender());
834
835 ChanACL *as = currentACL();
836 if (! as || as->bInherited)
837 return;
838
839 int allowed = 0;
840 int denied = 0;
841
842 bool enabled = true;
843 for (int idx = 0; idx < qlACLAllow.count(); idx++) {
844 ChanACL::Perm p = qlPerms[idx];
845 if (qlACLAllow[idx]->isChecked() && qlACLDeny[idx]->isChecked()) {
846 if (source == qlACLAllow[idx])
847 qlACLDeny[idx]->setChecked(false);
848 else
849 qlACLAllow[idx]->setChecked(false);
850 }
851
852 qlACLAllow[idx]->setEnabled(enabled || p == ChanACL::Speak);
853 qlACLDeny[idx]->setEnabled(enabled || p == ChanACL::Speak);
854
855 if (p == ChanACL::Write && qlACLAllow[idx]->isChecked())
856 enabled = false;
857
858 if (qlACLAllow[idx]->isChecked())
859 allowed |= p;
860 if (qlACLDeny[idx]->isChecked())
861 denied |= p;
862 }
863
864 as->pAllow = static_cast<ChanACL::Permissions>(allowed);
865 as->pDeny = static_cast<ChanACL::Permissions>(denied);
866 }
867
on_qcbGroupList_activated(const QString & text)868 void ACLEditor::on_qcbGroupList_activated(const QString &text) {
869 ACLGroup *gs = currentGroup();
870 if (text.isEmpty())
871 return;
872 if (! gs) {
873 QString name = text.toLower();
874 gs = new ACLGroup(name);
875 gs->bInherited = false;
876 gs->bInherit = true;
877 gs->bInheritable = true;
878 gs->qsName = name;
879 qlGroups << gs;
880 }
881
882 refillGroupNames();
883 refillGroupAdd();
884 refillGroupRemove();
885 refillGroupInherit();
886 groupEnableCheck();
887 qpbGroupAdd->setEnabled(false);
888 }
889
on_qcbGroupList_editTextChanged(const QString & text)890 void ACLEditor::on_qcbGroupList_editTextChanged(const QString & text) {
891 qpbGroupAdd->setEnabled(!text.isEmpty());
892 }
893
on_qpbGroupAdd_clicked()894 void ACLEditor::on_qpbGroupAdd_clicked() {
895 on_qcbGroupList_activated(qcbGroupList->currentText());
896 }
897
on_qpbGroupRemove_clicked()898 void ACLEditor::on_qpbGroupRemove_clicked() {
899 ACLGroup *gs = currentGroup();
900 if (! gs)
901 return;
902
903 if (gs->bInherited) {
904 gs->bInheritable = true;
905 gs->bInherit = true;
906 gs->qsAdd.clear();
907 gs->qsRemove.clear();
908 } else {
909 qlGroups.removeAll(gs);
910 delete gs;
911 }
912 refillGroupNames();
913 refillGroupAdd();
914 refillGroupRemove();
915 refillGroupInherit();
916 groupEnableCheck();
917 }
918
on_qcbGroupInherit_clicked(bool checked)919 void ACLEditor::on_qcbGroupInherit_clicked(bool checked) {
920 ACLGroup *gs = currentGroup();
921 if (! gs)
922 return;
923
924 gs->bInherit = checked;
925 groupEnableCheck();
926 }
927
on_qcbGroupInheritable_clicked(bool checked)928 void ACLEditor::on_qcbGroupInheritable_clicked(bool checked) {
929 ACLGroup *gs = currentGroup();
930 if (! gs)
931 return;
932
933 gs->bInheritable = checked;
934 }
935
on_qpbGroupAddAdd_clicked()936 void ACLEditor::on_qpbGroupAddAdd_clicked() {
937 ACLGroup *gs = currentGroup();
938 QString text = qcbGroupAdd->currentText();
939
940 if (! gs)
941 return;
942
943 if (text.isEmpty())
944 return;
945
946 gs->qsAdd << id(text);
947 refillGroupAdd();
948 qcbGroupAdd->clearEditText();
949 }
950
on_qpbGroupAddRemove_clicked()951 void ACLEditor::on_qpbGroupAddRemove_clicked() {
952 ACLGroup *gs = currentGroup();
953 if (! gs)
954 return;
955
956 QListWidgetItem *item = qlwGroupAdd->currentItem();
957 if (! item)
958 return;
959
960 gs->qsAdd.remove(item->data(Qt::UserRole).toInt());
961 refillGroupAdd();
962 qcbGroupRemove->clearEditText();
963 }
964
on_qpbGroupRemoveAdd_clicked()965 void ACLEditor::on_qpbGroupRemoveAdd_clicked() {
966 QString text = qcbGroupRemove->currentText();
967
968 ACLGroup *gs = currentGroup();
969 if (! gs)
970 return;
971
972 if (text.isEmpty())
973 return;
974
975 gs->qsRemove << id(text);
976 refillGroupRemove();
977 }
978
on_qpbGroupRemoveRemove_clicked()979 void ACLEditor::on_qpbGroupRemoveRemove_clicked() {
980 ACLGroup *gs = currentGroup();
981 if (! gs)
982 return;
983
984 QListWidgetItem *item = qlwGroupRemove->currentItem();
985 if (! item)
986 return;
987
988 gs->qsRemove.remove(item->data(Qt::UserRole).toInt());
989 refillGroupRemove();
990 }
991
on_qpbGroupInheritRemove_clicked()992 void ACLEditor::on_qpbGroupInheritRemove_clicked() {
993 ACLGroup *gs = currentGroup();
994 if (! gs)
995 return;
996
997 QListWidgetItem *item = qlwGroupInherit->currentItem();
998 if (! item)
999 return;
1000
1001 gs->qsRemove.insert(item->data(Qt::UserRole).toInt());
1002 refillGroupRemove();
1003 }
1004