mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-31 08:37:26 +00:00
commit
0317cf2663
@ -1,18 +1,33 @@
|
|||||||
#include "analthread.h"
|
#include "analthread.h"
|
||||||
|
#include "qrcore.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include "mainwindow.h"
|
|
||||||
|
|
||||||
AnalThread::AnalThread(MainWindow *w, QWidget *parent) :
|
AnalThread::AnalThread(QWidget *parent) :
|
||||||
QThread(parent)
|
QThread(parent),
|
||||||
|
core(nullptr),
|
||||||
|
level(2)
|
||||||
{
|
{
|
||||||
// Radare core found in:
|
}
|
||||||
this->w = w;
|
|
||||||
//this->level = 2;
|
AnalThread::~AnalThread()
|
||||||
|
{
|
||||||
|
if (isRunning()) {
|
||||||
|
quit();
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalThread::start(QRCore *core, int level)
|
||||||
|
{
|
||||||
|
this->core = core;
|
||||||
|
this->level = level;
|
||||||
|
|
||||||
|
QThread::start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// run() will be called when a thread starts
|
// run() will be called when a thread starts
|
||||||
void AnalThread::run()
|
void AnalThread::run()
|
||||||
{
|
{
|
||||||
//qDebug() << "Anal level: " << this->level;
|
//qDebug() << "Anal level: " << this->level;
|
||||||
this->w->core->analyze(this->level);
|
core->analyze(this->level);
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,25 @@
|
|||||||
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
class MainWindow;
|
class QRCore;
|
||||||
|
|
||||||
class AnalThread : public QThread
|
class AnalThread : public QThread
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit AnalThread(MainWindow *w, QWidget *parent = 0);
|
explicit AnalThread(QWidget *parent = 0);
|
||||||
|
~AnalThread();
|
||||||
|
|
||||||
|
void start(QRCore *core, int level);
|
||||||
|
|
||||||
|
protected:
|
||||||
void run();
|
void run();
|
||||||
int level;
|
|
||||||
|
using QThread::start;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QRCore *core;
|
||||||
MainWindow *w;
|
int level;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ANALTHREAD_H
|
#endif // ANALTHREAD_H
|
||||||
|
@ -11,7 +11,6 @@ createNewDialog::createNewDialog(QWidget *parent) :
|
|||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||||
w = new MainWindow(nullptr);
|
w = new MainWindow(nullptr);
|
||||||
w->core = new QRCore ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createNewDialog::~createNewDialog()
|
createNewDialog::~createNewDialog()
|
||||||
|
@ -60,10 +60,12 @@ static void appendRow(QTreeWidget *tw, const QString &str, const QString &str2=N
|
|||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) :
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
ui(new Ui::MainWindow)
|
core(new QRCore()),
|
||||||
|
ui(new Ui::MainWindow),
|
||||||
|
webserverThread(core, this)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
this->core = NULL;
|
|
||||||
doLock = false;
|
doLock = false;
|
||||||
|
|
||||||
// Add custom font
|
// Add custom font
|
||||||
@ -237,18 +239,27 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
QShortcut* commands_shortcut = new QShortcut(QKeySequence(Qt::Key_Colon), this);
|
QShortcut* commands_shortcut = new QShortcut(QKeySequence(Qt::Key_Colon), this);
|
||||||
connect(commands_shortcut, SIGNAL(activated()), this->omnibar, SLOT(showCommands()));
|
connect(commands_shortcut, SIGNAL(activated()), this->omnibar, SLOT(showCommands()));
|
||||||
|
|
||||||
|
connect(&webserverThread, SIGNAL(finished()), this, SLOT(webserverThreadFinished()));
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow() {
|
||||||
|
delete ui;
|
||||||
|
delete core;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::start_web_server() {
|
void MainWindow::start_web_server() {
|
||||||
// To be removed
|
|
||||||
static WebServerThread thread;
|
|
||||||
// Start web server
|
// Start web server
|
||||||
thread.core = core;
|
webserverThread.startServer();
|
||||||
thread.start();
|
|
||||||
QThread::sleep (1);
|
|
||||||
if (core->core->http_up == R_FALSE) {
|
|
||||||
eprintf ("FAILED TO LAUNCH\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::webserverThreadFinished()
|
||||||
|
{
|
||||||
|
core->core->http_up = webserverThread.isStarted() ? R_TRUE : R_FALSE;
|
||||||
|
|
||||||
|
// this is not true anymore, cause the webserver might have been stopped
|
||||||
|
//if (core->core->http_up == R_FALSE) {
|
||||||
|
// eprintf("FAILED TO LAUNCH\n");
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::adjustColumns(QTreeWidget *tw) {
|
void MainWindow::adjustColumns(QTreeWidget *tw) {
|
||||||
@ -275,6 +286,20 @@ void MainWindow::appendRow(QTreeWidget *tw, const QString &str, const QString &s
|
|||||||
tw->insertTopLevelItem(0, tempItem);
|
tw->insertTopLevelItem(0, tempItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::setWebServerState(bool start)
|
||||||
|
{
|
||||||
|
if (start) {
|
||||||
|
webserverThread.startServer();
|
||||||
|
|
||||||
|
// Open web interface on default browser
|
||||||
|
// ballessay: well isn't this possible with =H&
|
||||||
|
//QString link = "http://localhost:9090/";
|
||||||
|
//QDesktopServices::openUrl(QUrl(link));
|
||||||
|
} else {
|
||||||
|
webserverThread.stopServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::hideDummyColumns() {
|
void MainWindow::hideDummyColumns() {
|
||||||
// UGLY, should be a loop over all treewidgets...
|
// UGLY, should be a loop over all treewidgets...
|
||||||
this->functionsDock->functionsTreeWidget->setColumnHidden(0, true);
|
this->functionsDock->functionsTreeWidget->setColumnHidden(0, true);
|
||||||
@ -362,10 +387,6 @@ void MainWindow::def_theme() {
|
|||||||
settings.setValue("dark", false);
|
settings.setValue("dark", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow() {
|
|
||||||
delete ui;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Refresh widget functions
|
* Refresh widget functions
|
||||||
*/
|
*/
|
||||||
@ -739,6 +760,7 @@ void MainWindow::on_consoleInputLineEdit_returnPressed()
|
|||||||
QCompleter *completer = ui->consoleInputLineEdit->completer();
|
QCompleter *completer = ui->consoleInputLineEdit->completer();
|
||||||
/*
|
/*
|
||||||
* TODO: FIXME: Crashed the fucking app
|
* TODO: FIXME: Crashed the fucking app
|
||||||
|
* ballessay: yes this will crash if no completer is set -> nullptr
|
||||||
*/
|
*/
|
||||||
//QStringListModel *completerModel = (QStringListModel*)(completer->model());
|
//QStringListModel *completerModel = (QStringListModel*)(completer->model());
|
||||||
//completerModel->setStringList(completerModel->stringList() << input);
|
//completerModel->setStringList(completerModel->stringList() << input);
|
||||||
@ -840,24 +862,7 @@ void MainWindow::on_consoleExecButton_clicked()
|
|||||||
|
|
||||||
void MainWindow::on_actionStart_Web_Server_triggered()
|
void MainWindow::on_actionStart_Web_Server_triggered()
|
||||||
{
|
{
|
||||||
static WebServerThread thread;
|
setWebServerState(ui->actionStart_Web_Server->isChecked());
|
||||||
if (ui->actionStart_Web_Server->isChecked()) {
|
|
||||||
// Start web server
|
|
||||||
thread.core = core;
|
|
||||||
thread.start();
|
|
||||||
QThread::sleep (1);
|
|
||||||
if (core->core->http_up==R_FALSE) {
|
|
||||||
eprintf ("FAILED TO LAUNCH\n");
|
|
||||||
}
|
|
||||||
// Open web interface on default browser
|
|
||||||
//QString link = "http://localhost:9090/";
|
|
||||||
//QDesktopServices::openUrl(QUrl(link));
|
|
||||||
} else {
|
|
||||||
core->core->http_up= R_FALSE;
|
|
||||||
// call something to kill the webserver!!
|
|
||||||
thread.exit(0);
|
|
||||||
// Stop web server
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionConsoleSync_with_core_triggered()
|
void MainWindow::on_actionConsoleSync_with_core_triggered()
|
||||||
@ -970,7 +975,7 @@ void MainWindow::add_debug_output(QString msg)
|
|||||||
|
|
||||||
void MainWindow::on_actionNew_triggered()
|
void MainWindow::on_actionNew_triggered()
|
||||||
{
|
{
|
||||||
qApp->quit();
|
close();
|
||||||
on_actionLoad_triggered();
|
on_actionLoad_triggered();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1018,10 +1023,9 @@ void MainWindow::on_actionSDB_browser_triggered()
|
|||||||
|
|
||||||
void MainWindow::on_actionLoad_triggered()
|
void MainWindow::on_actionLoad_triggered()
|
||||||
{
|
{
|
||||||
QProcess* process = new QProcess(this);
|
QProcess process(this);
|
||||||
process->setProgram(qApp->applicationFilePath());
|
process.setEnvironment(QProcess::systemEnvironment());
|
||||||
process->setEnvironment(QProcess::systemEnvironment());
|
process.startDetached(qApp->applicationFilePath());
|
||||||
process->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionShow_Hide_mainsidebar_triggered()
|
void MainWindow::on_actionShow_Hide_mainsidebar_triggered()
|
||||||
|
@ -57,13 +57,14 @@ public:
|
|||||||
bool responsive;
|
bool responsive;
|
||||||
|
|
||||||
explicit MainWindow(QWidget *parent = 0);
|
explicit MainWindow(QWidget *parent = 0);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
void start_web_server();
|
void start_web_server();
|
||||||
void closeEvent(QCloseEvent *event);
|
void closeEvent(QCloseEvent *event);
|
||||||
void readSettings();
|
void readSettings();
|
||||||
void setFilename(QString fn);
|
void setFilename(QString fn);
|
||||||
void setCore(QRCore *core);
|
void setCore(QRCore *core);
|
||||||
void seek(const QString& offset, const QString& name=NULL);
|
void seek(const QString& offset, const QString& name=NULL);
|
||||||
~MainWindow();
|
|
||||||
void updateFrames();
|
void updateFrames();
|
||||||
void refreshFunctions();
|
void refreshFunctions();
|
||||||
void refreshComments();
|
void refreshComments();
|
||||||
@ -76,6 +77,8 @@ public:
|
|||||||
void appendRow(QTreeWidget *tw, const QString &str, const QString &str2=NULL,
|
void appendRow(QTreeWidget *tw, const QString &str, const QString &str2=NULL,
|
||||||
const QString &str3=NULL, const QString &str4=NULL, const QString &str5=NULL);
|
const QString &str3=NULL, const QString &str4=NULL, const QString &str5=NULL);
|
||||||
|
|
||||||
|
void setWebServerState(bool start);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void dark();
|
void dark();
|
||||||
@ -186,6 +189,8 @@ private slots:
|
|||||||
|
|
||||||
void on_actionReset_settings_triggered();
|
void on_actionReset_settings_triggered();
|
||||||
|
|
||||||
|
void webserverThreadFinished();
|
||||||
|
|
||||||
void on_actionQuit_triggered();
|
void on_actionQuit_triggered();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -215,6 +220,7 @@ private:
|
|||||||
QLineEdit *gotoEntry;
|
QLineEdit *gotoEntry;
|
||||||
SdbDock *sdbDock;
|
SdbDock *sdbDock;
|
||||||
QAction *sidebar_action;
|
QAction *sidebar_action;
|
||||||
|
WebServerThread webserverThread;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
|
|
||||||
OptionsDialog::OptionsDialog(QWidget *parent):
|
OptionsDialog::OptionsDialog(QWidget *parent):
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::OptionsDialog)
|
ui(new Ui::OptionsDialog),
|
||||||
|
analThread(this)
|
||||||
{
|
{
|
||||||
this->core = new QRCore();
|
this->core = new QRCore();
|
||||||
this->anal_level = 0;
|
this->anal_level = 0;
|
||||||
@ -39,6 +40,8 @@ OptionsDialog::OptionsDialog(QWidget *parent):
|
|||||||
|
|
||||||
// Add this so the dialog resizes when widgets are shown/hidden
|
// Add this so the dialog resizes when widgets are shown/hidden
|
||||||
//this->layout()->setSizeConstraint(QLayout::SetFixedSize);
|
//this->layout()->setSizeConstraint(QLayout::SetFixedSize);
|
||||||
|
|
||||||
|
connect(&analThread, SIGNAL(finished()), this, SLOT(anal_finished()));
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionsDialog::~OptionsDialog()
|
OptionsDialog::~OptionsDialog()
|
||||||
@ -169,18 +172,14 @@ void OptionsDialog::on_okButton_clicked()
|
|||||||
ui->statusLabel->setText("Analysis in progress");
|
ui->statusLabel->setText("Analysis in progress");
|
||||||
|
|
||||||
// Threads stuff
|
// Threads stuff
|
||||||
// create an instance of MyThread
|
|
||||||
this->analThread = new AnalThread(w);
|
|
||||||
|
|
||||||
// connect signal/slot
|
// connect signal/slot
|
||||||
connect(analThread, SIGNAL(finished()), this, SLOT(anal_finished()));
|
|
||||||
//analThread->level = anal_level;
|
int level = 0;
|
||||||
if (anal_level == true) {
|
if (anal_level == true) {
|
||||||
analThread->level = ui->analSlider->value();
|
level = ui->analSlider->value();
|
||||||
} else {
|
|
||||||
analThread->level = 0;
|
|
||||||
}
|
}
|
||||||
analThread->start();
|
|
||||||
|
analThread.start(core, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OptionsDialog::anal_finished()
|
void OptionsDialog::anal_finished()
|
||||||
|
@ -43,7 +43,7 @@ private:
|
|||||||
QString filename;
|
QString filename;
|
||||||
QString shortfn;
|
QString shortfn;
|
||||||
Ui::OptionsDialog *ui;
|
Ui::OptionsDialog *ui;
|
||||||
AnalThread *analThread;
|
AnalThread analThread;
|
||||||
MainWindow *w;
|
MainWindow *w;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,14 +1,78 @@
|
|||||||
#include "webserverthread.h"
|
#include "webserverthread.h"
|
||||||
|
#include "qrcore.h"
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
WebServerThread::WebServerThread(QObject *parent) :
|
WebServerThread::WebServerThread(QRCore *core, QObject *parent) :
|
||||||
QThread(parent)
|
QThread(parent),
|
||||||
|
core(core),
|
||||||
|
started(false)
|
||||||
{
|
{
|
||||||
// MEOW
|
// MEOW
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WebServerThread::~WebServerThread()
|
||||||
|
{
|
||||||
|
if (isRunning()) {
|
||||||
|
quit();
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebServerThread::startServer()
|
||||||
|
{
|
||||||
|
assert(nullptr != core);
|
||||||
|
|
||||||
|
if (!isRunning() && !started) {
|
||||||
|
QThread::start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebServerThread::stopServer()
|
||||||
|
{
|
||||||
|
assert(nullptr != core);
|
||||||
|
|
||||||
|
if (!isRunning() && started)
|
||||||
|
{
|
||||||
|
QThread::start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebServerThread::isStarted() const
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
|
return started;
|
||||||
|
}
|
||||||
|
|
||||||
void WebServerThread::run() {
|
void WebServerThread::run() {
|
||||||
if (core == NULL)
|
QMutexLocker locker(&mutex);
|
||||||
|
|
||||||
|
if (core == nullptr)
|
||||||
return;
|
return;
|
||||||
//eprintf ("Starting webserver!");
|
//eprintf ("Starting webserver!");
|
||||||
core->cmd ("=h");
|
|
||||||
|
toggleWebServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebServerThread::toggleWebServer()
|
||||||
|
{
|
||||||
|
// access already locked
|
||||||
|
|
||||||
|
// see libr/core/rtr.c
|
||||||
|
// "=h", " port", "listen for http connections (r2 -qc=H /bin/ls)",
|
||||||
|
// "=h-", "", "stop background webserver",
|
||||||
|
// "=h*", "", "restart current webserver",
|
||||||
|
// "=h&", " port", "start http server in background)",
|
||||||
|
|
||||||
|
if (started) {
|
||||||
|
// after this the only reaction to this commands is:
|
||||||
|
// sandbox: connect disabled
|
||||||
|
// and the webserver is still running
|
||||||
|
// TODO: find out why
|
||||||
|
core->cmd("=h-");
|
||||||
|
} else {
|
||||||
|
core->cmd("=h&");
|
||||||
|
}
|
||||||
|
|
||||||
|
// cmd has no usefull return value for this commands, so just toogle the state
|
||||||
|
started = !started;
|
||||||
}
|
}
|
||||||
|
@ -2,20 +2,32 @@
|
|||||||
#define WEBSERVERTHREAD_H
|
#define WEBSERVERTHREAD_H
|
||||||
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include "qrcore.h"
|
#include <QMutex>
|
||||||
|
|
||||||
|
class QRCore;
|
||||||
|
|
||||||
class WebServerThread : public QThread
|
class WebServerThread : public QThread
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
QRCore *core;
|
|
||||||
explicit WebServerThread(QObject *parent = 0);
|
|
||||||
|
|
||||||
signals:
|
explicit WebServerThread(QRCore *core, QObject *parent = 0);
|
||||||
|
~WebServerThread();
|
||||||
|
|
||||||
|
void startServer();
|
||||||
|
void stopServer();
|
||||||
|
|
||||||
|
bool isStarted() const;
|
||||||
|
|
||||||
public slots:
|
|
||||||
private:
|
private:
|
||||||
void run();
|
void run();
|
||||||
|
using QThread::start;
|
||||||
|
|
||||||
|
void toggleWebServer();
|
||||||
|
|
||||||
|
mutable QMutex mutex;
|
||||||
|
QRCore *core;
|
||||||
|
bool started;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WEBSERVERTHREAD_H
|
#endif // WEBSERVERTHREAD_H
|
||||||
|
@ -5,15 +5,14 @@
|
|||||||
|
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
||||||
SideBar::SideBar(MainWindow *main, QWidget *parent) :
|
SideBar::SideBar(MainWindow *main) :
|
||||||
QWidget(parent),
|
QWidget(main),
|
||||||
ui(new Ui::SideBar)
|
ui(new Ui::SideBar),
|
||||||
|
// Radare core found in:
|
||||||
|
main(main)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
// Radare core found in:
|
|
||||||
this->main = main;
|
|
||||||
|
|
||||||
QSettings settings("iaito", "iaito");
|
QSettings settings("iaito", "iaito");
|
||||||
if (settings.value("responsive").toBool()) {
|
if (settings.value("responsive").toBool()) {
|
||||||
ui->respButton->setChecked(true);
|
ui->respButton->setChecked(true);
|
||||||
@ -44,24 +43,7 @@ void SideBar::on_consoleButton_clicked()
|
|||||||
|
|
||||||
void SideBar::on_webServerButton_clicked()
|
void SideBar::on_webServerButton_clicked()
|
||||||
{
|
{
|
||||||
static WebServerThread thread;
|
main->setWebServerState(ui->webServerButton->isChecked());
|
||||||
if (ui->webServerButton->isChecked()) {
|
|
||||||
// Start web server
|
|
||||||
thread.core = this->main->core;
|
|
||||||
thread.start();
|
|
||||||
QThread::sleep (1);
|
|
||||||
if (this->main->core->core->http_up==R_FALSE) {
|
|
||||||
eprintf ("FAILED TO LAUNCH\n");
|
|
||||||
}
|
|
||||||
// Open web interface on default browser
|
|
||||||
//QString link = "http://localhost:9090/";
|
|
||||||
//QDesktopServices::openUrl(QUrl(link));
|
|
||||||
} else {
|
|
||||||
this->main->core->core->http_up= R_FALSE;
|
|
||||||
// call something to kill the webserver!!
|
|
||||||
thread.exit(0);
|
|
||||||
// Stop web server
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SideBar::on_lockButton_clicked()
|
void SideBar::on_lockButton_clicked()
|
||||||
|
@ -14,7 +14,7 @@ class SideBar : public QWidget
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SideBar(MainWindow *main, QWidget *parent = 0);
|
explicit SideBar(MainWindow *main);
|
||||||
~SideBar();
|
~SideBar();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
Loading…
Reference in New Issue
Block a user