Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Banning users that are no longer connected to the server. #5895

Open
MarioPL98 opened this issue Sep 19, 2022 · 10 comments
Open

Banning users that are no longer connected to the server. #5895

MarioPL98 opened this issue Sep 19, 2022 · 10 comments
Labels
client feature-request This issue or PR deals with a new feature good first issue Good for first-time contributors server

Comments

@MarioPL98
Copy link

MarioPL98 commented Sep 19, 2022

Context

Banning users that are no longer connected to the server.

Description

Currently Mumble has no way to ban users that have left the server. Client should locally store all required info of users that are in chat history (including auto announcements like someone joining channel) to allow right click ban option. Currently nothing happens if you right click someone's nickname after the left the server. This should change.

Mumble component

Both

OS-specific?

No

Additional information

No response

@MarioPL98 MarioPL98 added feature-request This issue or PR deals with a new feature triage This issue is waiting to be triaged by one of the project members labels Sep 19, 2022
@MarioPL98 MarioPL98 changed the title Banning users that left the server. Banning users that are no longer connected to the server. Sep 19, 2022
@Krzmbrzl Krzmbrzl added client server good first issue Good for first-time contributors and removed triage This issue is waiting to be triaged by one of the project members labels Sep 20, 2022
@BryantArias
Copy link

I'm an undergrad student looking to contribute to my first open source project. Would I be able to try implementing this?

@Krzmbrzl
Copy link
Member

Yes, I would think so. i was thinking that essentially the client needs to keep a liftoff recently disconnected users and use that to provide the required functionality.
Do you want me to give you some pointers as to where the relevant code parts are located?

@BryantArias
Copy link

@Krzmbrzl Yes, I would appreciate that. Thank you!

@Krzmbrzl
Copy link
Member

Alright, so here's what I think might be important in this context:

  1. Here's where the context menu gets created when you right-click in the text chat ("log") area:
    void MainWindow::on_qteLog_customContextMenuRequested(const QPoint &mpos) {
    QString link = qteLog->anchorAt(mpos);
    if (!link.isEmpty()) {
    QUrl l(link);
    if (handleSpecialContextMenu(l, qteLog->mapToGlobal(mpos)))
    return;
    }
    QPoint contentPosition =
    QPoint(QApplication::isRightToLeft()
    ? (qteLog->horizontalScrollBar()->maximum() - qteLog->horizontalScrollBar()->value())
    : qteLog->horizontalScrollBar()->value(),
    qteLog->verticalScrollBar()->value());
    QMenu *menu = qteLog->createStandardContextMenu(mpos + contentPosition);
    QTextCursor cursor = qteLog->cursorForPosition(mpos);
    QTextCharFormat fmt = cursor.charFormat();
    // Work around imprecise cursor image identification
    // Apparently, the cursor is shifted half the characters width to the right on the image
    // element. This is in contrast to hyperlinks for example, which have correct edge detection.
    // For the image, we get the right half (plus the left half of the next character) for the
    // image, and have to move the cursor forward to also detect on the left half of the image
    // (plus the right half of the previous character).
    // It is unclear why we have to use NextCharacter instead of PreviousCharacter.
    if (fmt.objectType() == QTextFormat::NoObject) {
    cursor.movePosition(QTextCursor::NextCharacter);
    fmt = cursor.charFormat();
    }
    if (cursor.charFormat().isImageFormat()) {
    menu->addSeparator();
    menu->addAction(tr("Save Image As..."), this, SLOT(saveImageAs(void)));
    qtcSaveImageCursor = cursor;
    }
    menu->addSeparator();
    menu->addAction(tr("Clear"), qteLog, SLOT(clear(void)));
    menu->exec(qteLog->mapToGlobal(mpos));
    delete menu;
    }

    Note in particular
    bool MainWindow::handleSpecialContextMenu(const QUrl &url, const QPoint &pos_, bool focus) {
    if (url.scheme() == QString::fromLatin1("clientid")) {
    bool ok = false;
    QString maybeUserHash(url.host());
    if (maybeUserHash.length() == 40) {
    ClientUser *cu = pmModel->getUser(maybeUserHash);
    if (cu) {
    cuContextUser = cu;
    ok = true;
    }
    } else {
    QByteArray qbaServerDigest = QByteArray::fromBase64(url.path().remove(0, 1).toLatin1());
    cuContextUser = ClientUser::get(url.host().toInt(&ok, 10));
    ServerHandlerPtr sh = Global::get().sh;
    ok = ok && sh && (qbaServerDigest == sh->qbaDigest);
    }
    if (ok && cuContextUser) {
    if (focus) {
    qtvUsers->setCurrentIndex(pmModel->index(cuContextUser.data()));
    qteChat->setFocus();
    } else {
    qpContextPosition = QPoint();
    qmUser->exec(pos_, nullptr);
    }
    }
    cuContextUser.clear();
    } else if (url.scheme() == QString::fromLatin1("channelid")) {

    which seems to handle right-clicking on a username.
  2. Here's the part of the code that gets called when a new user connects to the same server:
    // User just connected
    if (!pDst) {
    if (!msg.has_name()) {
    return;
    }
    pDst = pmModel->addUser(msg.session(), u8(msg.name()));
    connect(pDst, &ClientUser::talkingStateChanged, Global::get().talkingUI, &TalkingUI::on_talkingStateChanged);
    connect(pDst, &ClientUser::muteDeafStateChanged, Global::get().talkingUI, &TalkingUI::on_muteDeafStateChanged);
    if (channel && channel != pDst->cChannel) {
    pmModel->moveUser(pDst, channel);
    }
    if (msg.has_hash()) {
    pmModel->setHash(pDst, u8(msg.hash()));
    }
    if (pSelf) {
    if (pDst->cChannel == pSelf->cChannel) {
    Global::get().l->log(
    Log::ChannelJoinConnect,
    tr("%1 connected and entered channel.").arg(Log::formatClientUser(pDst, Log::Source)));
    } else {
    Global::get().l->log(Log::UserJoin, tr("%1 connected.").arg(Log::formatClientUser(pDst, Log::Source)));
    }
    }
    }

    and the code that's called when a user disconnects again:
    void MainWindow::msgUserRemove(const MumbleProto::UserRemove &msg) {
    VICTIM_INIT;
    ACTOR_INIT;
    SELF_INIT;
    QString reason = u8(msg.reason()).toHtmlEscaped();
    if (pDst == pSelf) {
    bRetryServer = false;
    if (msg.ban())
    Global::get().l->log(Log::YouKicked, tr("You were kicked and banned from the server by %1: %2.")
    .arg(Log::formatClientUser(pSrc, Log::Source))
    .arg(reason));
    else
    Global::get().l->log(Log::YouKicked, tr("You were kicked from the server by %1: %2.")
    .arg(Log::formatClientUser(pSrc, Log::Source))
    .arg(reason));
    } else if (pSrc) {
    if (msg.ban())
    Global::get().l->log((pSrc == pSelf) ? Log::YouKicked : Log::UserKicked,
    tr("%3 was kicked and banned from the server by %1: %2.")
    .arg(Log::formatClientUser(pSrc, Log::Source))
    .arg(reason)
    .arg(Log::formatClientUser(pDst, Log::Target)));
    else
    Global::get().l->log((pSrc == pSelf) ? Log::YouKicked : Log::UserKicked,
    tr("%3 was kicked from the server by %1: %2.")
    .arg(Log::formatClientUser(pSrc, Log::Source))
    .arg(reason)
    .arg(Log::formatClientUser(pDst, Log::Target)));
    } else {
    if (pDst->cChannel == pSelf->cChannel || pDst->cChannel->allLinks().contains(pSelf->cChannel)) {
    Global::get().l->log(Log::ChannelLeaveDisconnect,
    tr("%1 left channel and disconnected.").arg(Log::formatClientUser(pDst, Log::Source)));
    } else {
    Global::get().l->log(Log::UserLeave, tr("%1 disconnected.").arg(Log::formatClientUser(pDst, Log::Source)));
    }
    }
    QMetaObject::invokeMethod(Global::get().talkingUI, "on_clientDisconnected", Qt::QueuedConnection,
    Q_ARG(unsigned int, pDst->uiSession));
    if (Global::get().mw->m_searchDialog) {
    QMetaObject::invokeMethod(Global::get().mw->m_searchDialog, "on_clientDisconnected", Qt::QueuedConnection,
    Q_ARG(unsigned int, pDst->uiSession));
    }
    if (pDst != pSelf)
    pmModel->removeUser(pDst);
    }

In case it might be relevant/interesting: Here's the function that formats a user's name such that it becomes clickable and interactable in the first place:

mumble/src/mumble/Log.cpp

Lines 531 to 556 in 600ffb4

QString Log::formatClientUser(ClientUser *cu, LogColorType t, const QString &displayName) {
QString className;
if (t == Log::Target) {
className = QString::fromLatin1("target");
} else if (t == Log::Source) {
className = QString::fromLatin1("source");
}
if (cu) {
QString name = (displayName.isNull() ? cu->qsName : displayName).toHtmlEscaped();
if (cu->qsHash.isEmpty()) {
return QString::fromLatin1("<a href='clientid://%2/%4' class='log-user log-%1'>%3</a>")
.arg(className)
.arg(cu->uiSession)
.arg(name)
.arg(QString::fromLatin1(Global::get().sh->qbaDigest.toBase64()));
} else {
return QString::fromLatin1("<a href='clientid://%2' class='log-user log-%1'>%3</a>")
.arg(className)
.arg(cu->qsHash)
.arg(name);
}
} else {
return QString::fromLatin1("<span class='log-server log-%1'>%2</span>").arg(className).arg(tr("the server"));
}
}


I would suggest you create a draft PR as soon as possible, so I can have a few glances at what direction you are picking and potentially give some advice early on :)

@fuushyn
Copy link

fuushyn commented Oct 8, 2022

Hi, is this issue open? I'd like to work on it

@davidebeatrici
Copy link
Member

Hi, it's indeed still open and as far as I know nobody is working on it currently.

@Krzmbrzl
Copy link
Member

Krzmbrzl commented Oct 9, 2022

Actually, @BryantArias wanted to work on this. I have not heard back from them since then though, so I'm not quite sure if that is still the case.

@BryantArias maybe you could comment on this?

@BryantArias
Copy link

Yes, unfortunately I had to drop this issue and forgot to update you. They're good to take it on if they'd like.

@fuushyn
Copy link

fuushyn commented Oct 9, 2022

Cool

@Krzmbrzl
Copy link
Member

Krzmbrzl commented Oct 9, 2022

Alright, @fuushyn then this is all yours :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
client feature-request This issue or PR deals with a new feature good first issue Good for first-time contributors server
Projects
None yet
Development

No branches or pull requests

5 participants