mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Add CI workflow to check line endings of all source files (#2082)
In addition, all found errors (formatting & line ending) have been fixed in this PR.
This commit is contained in:
parent
4199a01b96
commit
f191de2514
17 changed files with 959 additions and 934 deletions
13
.github/workflows/check-formatting.yml
vendored
13
.github/workflows/check-formatting.yml
vendored
|
@ -8,18 +8,19 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
check:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-20.04
|
||||||
container:
|
|
||||||
image: ubuntu:19.10
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2.3.3
|
- uses: actions/checkout@v2.3.3
|
||||||
- name: apt-get update
|
- name: apt-get update
|
||||||
run: apt-get update
|
run: sudo apt-get update
|
||||||
|
|
||||||
- name: Install clang-format
|
- name: Install clang-format
|
||||||
run: apt-get -y install clang-format
|
run: sudo apt-get -y install clang-format dos2unix
|
||||||
|
|
||||||
- name: Check formatting
|
- name: Check formatting
|
||||||
run: ./tools/check-format.sh
|
run: ./tools/check-format.sh
|
||||||
|
|
||||||
|
- name: Check line-endings
|
||||||
|
run: ./tools/check-line-endings.sh
|
||||||
|
|
|
@ -41,7 +41,7 @@ git submodule update --init --recursive
|
||||||
The code is formatted using clang format in Qt Creator. [.clang-format](src/.clang-format) contains the style file for clang format.
|
The code is formatted using clang format in Qt Creator. [.clang-format](src/.clang-format) contains the style file for clang format.
|
||||||
|
|
||||||
### Get it automated with QT Creator + Beautifier + Clang Format
|
### Get it automated with QT Creator + Beautifier + Clang Format
|
||||||
1. Download LLVM: https://releases.llvm.org/9.0.0/LLVM-9.0.0-win64.exe
|
1. Download LLVM: https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/LLVM-11.0.0-win64.exe
|
||||||
2. During the installation, make sure to add it to your path
|
2. During the installation, make sure to add it to your path
|
||||||
3. In QT Creator, select `Help` > `About Plugins` > `C++` > `Beautifier` to enable the plugin
|
3. In QT Creator, select `Help` > `About Plugins` > `C++` > `Beautifier` to enable the plugin
|
||||||
4. Restart QT Creator
|
4. Restart QT Creator
|
||||||
|
|
|
@ -1,72 +1,72 @@
|
||||||
#include "ChannelChatters.hpp"
|
#include "ChannelChatters.hpp"
|
||||||
|
|
||||||
#include "messages/Message.hpp"
|
#include "messages/Message.hpp"
|
||||||
#include "messages/MessageBuilder.hpp"
|
#include "messages/MessageBuilder.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
ChannelChatters::ChannelChatters(Channel &channel)
|
ChannelChatters::ChannelChatters(Channel &channel)
|
||||||
: channel_(channel)
|
: channel_(channel)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AccessGuard<const UsernameSet> ChannelChatters::accessChatters() const
|
AccessGuard<const UsernameSet> ChannelChatters::accessChatters() const
|
||||||
{
|
{
|
||||||
return this->chatters_.accessConst();
|
return this->chatters_.accessConst();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelChatters::addRecentChatter(const QString &user)
|
void ChannelChatters::addRecentChatter(const QString &user)
|
||||||
{
|
{
|
||||||
this->chatters_.access()->insert(user);
|
this->chatters_.access()->insert(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelChatters::addJoinedUser(const QString &user)
|
void ChannelChatters::addJoinedUser(const QString &user)
|
||||||
{
|
{
|
||||||
auto joinedUsers = this->joinedUsers_.access();
|
auto joinedUsers = this->joinedUsers_.access();
|
||||||
joinedUsers->append(user);
|
joinedUsers->append(user);
|
||||||
|
|
||||||
if (!this->joinedUsersMergeQueued_)
|
if (!this->joinedUsersMergeQueued_)
|
||||||
{
|
{
|
||||||
this->joinedUsersMergeQueued_ = true;
|
this->joinedUsersMergeQueued_ = true;
|
||||||
|
|
||||||
QTimer::singleShot(500, &this->lifetimeGuard_, [this] {
|
QTimer::singleShot(500, &this->lifetimeGuard_, [this] {
|
||||||
auto joinedUsers = this->joinedUsers_.access();
|
auto joinedUsers = this->joinedUsers_.access();
|
||||||
|
|
||||||
MessageBuilder builder(systemMessage,
|
MessageBuilder builder(systemMessage,
|
||||||
"Users joined: " + joinedUsers->join(", "));
|
"Users joined: " + joinedUsers->join(", "));
|
||||||
builder->flags.set(MessageFlag::Collapsed);
|
builder->flags.set(MessageFlag::Collapsed);
|
||||||
joinedUsers->clear();
|
joinedUsers->clear();
|
||||||
this->channel_.addMessage(builder.release());
|
this->channel_.addMessage(builder.release());
|
||||||
this->joinedUsersMergeQueued_ = false;
|
this->joinedUsersMergeQueued_ = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChannelChatters::addPartedUser(const QString &user)
|
void ChannelChatters::addPartedUser(const QString &user)
|
||||||
{
|
{
|
||||||
auto partedUsers = this->partedUsers_.access();
|
auto partedUsers = this->partedUsers_.access();
|
||||||
partedUsers->append(user);
|
partedUsers->append(user);
|
||||||
|
|
||||||
if (!this->partedUsersMergeQueued_)
|
if (!this->partedUsersMergeQueued_)
|
||||||
{
|
{
|
||||||
this->partedUsersMergeQueued_ = true;
|
this->partedUsersMergeQueued_ = true;
|
||||||
|
|
||||||
QTimer::singleShot(500, &this->lifetimeGuard_, [this] {
|
QTimer::singleShot(500, &this->lifetimeGuard_, [this] {
|
||||||
auto partedUsers = this->partedUsers_.access();
|
auto partedUsers = this->partedUsers_.access();
|
||||||
|
|
||||||
MessageBuilder builder(systemMessage,
|
MessageBuilder builder(systemMessage,
|
||||||
"Users parted: " + partedUsers->join(", "));
|
"Users parted: " + partedUsers->join(", "));
|
||||||
builder->flags.set(MessageFlag::Collapsed);
|
builder->flags.set(MessageFlag::Collapsed);
|
||||||
this->channel_.addMessage(builder.release());
|
this->channel_.addMessage(builder.release());
|
||||||
partedUsers->clear();
|
partedUsers->clear();
|
||||||
|
|
||||||
this->partedUsersMergeQueued_ = false;
|
this->partedUsersMergeQueued_ = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void ChannelChatters::setChatters(UsernameSet &&set)
|
void ChannelChatters::setChatters(UsernameSet &&set)
|
||||||
{
|
{
|
||||||
*this->chatters_.access() = set;
|
*this->chatters_.access() = set;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,37 +1,37 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/Channel.hpp"
|
#include "common/Channel.hpp"
|
||||||
#include "common/UniqueAccess.hpp"
|
#include "common/UniqueAccess.hpp"
|
||||||
#include "common/UsernameSet.hpp"
|
#include "common/UsernameSet.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
class ChannelChatters
|
class ChannelChatters
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ChannelChatters(Channel &channel);
|
ChannelChatters(Channel &channel);
|
||||||
virtual ~ChannelChatters() = default; // add vtable
|
virtual ~ChannelChatters() = default; // add vtable
|
||||||
|
|
||||||
AccessGuard<const UsernameSet> accessChatters() const;
|
AccessGuard<const UsernameSet> accessChatters() const;
|
||||||
|
|
||||||
void addRecentChatter(const QString &user);
|
void addRecentChatter(const QString &user);
|
||||||
void addJoinedUser(const QString &user);
|
void addJoinedUser(const QString &user);
|
||||||
void addPartedUser(const QString &user);
|
void addPartedUser(const QString &user);
|
||||||
void setChatters(UsernameSet &&set);
|
void setChatters(UsernameSet &&set);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Channel &channel_;
|
Channel &channel_;
|
||||||
|
|
||||||
// maps 2 char prefix to set of names
|
// maps 2 char prefix to set of names
|
||||||
UniqueAccess<UsernameSet> chatters_;
|
UniqueAccess<UsernameSet> chatters_;
|
||||||
|
|
||||||
// combines multiple joins/parts into one message
|
// combines multiple joins/parts into one message
|
||||||
UniqueAccess<QStringList> joinedUsers_;
|
UniqueAccess<QStringList> joinedUsers_;
|
||||||
bool joinedUsersMergeQueued_ = false;
|
bool joinedUsersMergeQueued_ = false;
|
||||||
UniqueAccess<QStringList> partedUsers_;
|
UniqueAccess<QStringList> partedUsers_;
|
||||||
bool partedUsersMergeQueued_ = false;
|
bool partedUsersMergeQueued_ = false;
|
||||||
|
|
||||||
QObject lifetimeGuard_;
|
QObject lifetimeGuard_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,235 +1,235 @@
|
||||||
#include "Credentials.hpp"
|
#include "Credentials.hpp"
|
||||||
|
|
||||||
#include "debug/AssertInGuiThread.hpp"
|
#include "debug/AssertInGuiThread.hpp"
|
||||||
#include "keychain.h"
|
#include "keychain.h"
|
||||||
#include "singletons/Paths.hpp"
|
#include "singletons/Paths.hpp"
|
||||||
#include "singletons/Settings.hpp"
|
#include "singletons/Settings.hpp"
|
||||||
#include "util/CombinePath.hpp"
|
#include "util/CombinePath.hpp"
|
||||||
#include "util/Overloaded.hpp"
|
#include "util/Overloaded.hpp"
|
||||||
|
|
||||||
#include <QSaveFile>
|
#include <QSaveFile>
|
||||||
#include <boost/variant.hpp>
|
#include <boost/variant.hpp>
|
||||||
|
|
||||||
#define FORMAT_NAME \
|
#define FORMAT_NAME \
|
||||||
([&] { \
|
([&] { \
|
||||||
assert(!provider.contains(":")); \
|
assert(!provider.contains(":")); \
|
||||||
return QString("chatterino:%1:%2").arg(provider).arg(name_); \
|
return QString("chatterino:%1:%2").arg(provider).arg(name_); \
|
||||||
})()
|
})()
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
bool useKeyring()
|
bool useKeyring()
|
||||||
{
|
{
|
||||||
if (getPaths()->isPortable())
|
if (getPaths()->isPortable())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
return getSettings()->useKeyring;
|
return getSettings()->useKeyring;
|
||||||
#else
|
#else
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insecure storage:
|
// Insecure storage:
|
||||||
QString insecurePath()
|
QString insecurePath()
|
||||||
{
|
{
|
||||||
return combinePath(getPaths()->settingsDirectory, "credentials.json");
|
return combinePath(getPaths()->settingsDirectory, "credentials.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonDocument loadInsecure()
|
QJsonDocument loadInsecure()
|
||||||
{
|
{
|
||||||
QFile file(insecurePath());
|
QFile file(insecurePath());
|
||||||
file.open(QIODevice::ReadOnly);
|
file.open(QIODevice::ReadOnly);
|
||||||
return QJsonDocument::fromJson(file.readAll());
|
return QJsonDocument::fromJson(file.readAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
void storeInsecure(const QJsonDocument &doc)
|
void storeInsecure(const QJsonDocument &doc)
|
||||||
{
|
{
|
||||||
QSaveFile file(insecurePath());
|
QSaveFile file(insecurePath());
|
||||||
file.open(QIODevice::WriteOnly);
|
file.open(QIODevice::WriteOnly);
|
||||||
file.write(doc.toJson());
|
file.write(doc.toJson());
|
||||||
file.commit();
|
file.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonDocument &insecureInstance()
|
QJsonDocument &insecureInstance()
|
||||||
{
|
{
|
||||||
static auto store = loadInsecure();
|
static auto store = loadInsecure();
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
void queueInsecureSave()
|
void queueInsecureSave()
|
||||||
{
|
{
|
||||||
static bool isQueued = false;
|
static bool isQueued = false;
|
||||||
|
|
||||||
if (!isQueued)
|
if (!isQueued)
|
||||||
{
|
{
|
||||||
isQueued = true;
|
isQueued = true;
|
||||||
QTimer::singleShot(200, qApp, [] {
|
QTimer::singleShot(200, qApp, [] {
|
||||||
storeInsecure(insecureInstance());
|
storeInsecure(insecureInstance());
|
||||||
isQueued = false;
|
isQueued = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// QKeychain runs jobs asyncronously, so we have to assure that set/erase
|
// QKeychain runs jobs asyncronously, so we have to assure that set/erase
|
||||||
// jobs gets executed in order.
|
// jobs gets executed in order.
|
||||||
struct SetJob {
|
struct SetJob {
|
||||||
QString name;
|
QString name;
|
||||||
QString credential;
|
QString credential;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EraseJob {
|
struct EraseJob {
|
||||||
QString name;
|
QString name;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Job = boost::variant<SetJob, EraseJob>;
|
using Job = boost::variant<SetJob, EraseJob>;
|
||||||
|
|
||||||
static std::queue<Job> &jobQueue()
|
static std::queue<Job> &jobQueue()
|
||||||
{
|
{
|
||||||
static std::queue<Job> jobs;
|
static std::queue<Job> jobs;
|
||||||
return jobs;
|
return jobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void runNextJob()
|
static void runNextJob()
|
||||||
{
|
{
|
||||||
auto &&queue = jobQueue();
|
auto &&queue = jobQueue();
|
||||||
|
|
||||||
if (!queue.empty())
|
if (!queue.empty())
|
||||||
{
|
{
|
||||||
// we were gonna use std::visit here but macos is shit
|
// we were gonna use std::visit here but macos is shit
|
||||||
|
|
||||||
auto &&item = queue.front();
|
auto &&item = queue.front();
|
||||||
|
|
||||||
if (item.which() == 0) // set job
|
if (item.which() == 0) // set job
|
||||||
{
|
{
|
||||||
auto set = boost::get<SetJob>(item);
|
auto set = boost::get<SetJob>(item);
|
||||||
auto job = new QKeychain::WritePasswordJob("chatterino");
|
auto job = new QKeychain::WritePasswordJob("chatterino");
|
||||||
job->setAutoDelete(true);
|
job->setAutoDelete(true);
|
||||||
job->setKey(set.name);
|
job->setKey(set.name);
|
||||||
job->setTextData(set.credential);
|
job->setTextData(set.credential);
|
||||||
QObject::connect(job, &QKeychain::Job::finished, qApp,
|
QObject::connect(job, &QKeychain::Job::finished, qApp,
|
||||||
[](auto) { runNextJob(); });
|
[](auto) { runNextJob(); });
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
else // erase job
|
else // erase job
|
||||||
{
|
{
|
||||||
auto erase = boost::get<EraseJob>(item);
|
auto erase = boost::get<EraseJob>(item);
|
||||||
auto job = new QKeychain::DeletePasswordJob("chatterino");
|
auto job = new QKeychain::DeletePasswordJob("chatterino");
|
||||||
job->setAutoDelete(true);
|
job->setAutoDelete(true);
|
||||||
job->setKey(erase.name);
|
job->setKey(erase.name);
|
||||||
QObject::connect(job, &QKeychain::Job::finished, qApp,
|
QObject::connect(job, &QKeychain::Job::finished, qApp,
|
||||||
[](auto) { runNextJob(); });
|
[](auto) { runNextJob(); });
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.pop();
|
queue.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void queueJob(Job &&job)
|
static void queueJob(Job &&job)
|
||||||
{
|
{
|
||||||
auto &&queue = jobQueue();
|
auto &&queue = jobQueue();
|
||||||
|
|
||||||
queue.push(std::move(job));
|
queue.push(std::move(job));
|
||||||
if (queue.size() == 1)
|
if (queue.size() == 1)
|
||||||
{
|
{
|
||||||
runNextJob();
|
runNextJob();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Credentials &Credentials::instance()
|
Credentials &Credentials::instance()
|
||||||
{
|
{
|
||||||
static Credentials creds;
|
static Credentials creds;
|
||||||
return creds;
|
return creds;
|
||||||
}
|
}
|
||||||
|
|
||||||
Credentials::Credentials()
|
Credentials::Credentials()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Credentials::get(const QString &provider, const QString &name_,
|
void Credentials::get(const QString &provider, const QString &name_,
|
||||||
QObject *receiver,
|
QObject *receiver,
|
||||||
std::function<void(const QString &)> &&onLoaded)
|
std::function<void(const QString &)> &&onLoaded)
|
||||||
{
|
{
|
||||||
assertInGuiThread();
|
assertInGuiThread();
|
||||||
|
|
||||||
auto name = FORMAT_NAME;
|
auto name = FORMAT_NAME;
|
||||||
|
|
||||||
if (useKeyring())
|
if (useKeyring())
|
||||||
{
|
{
|
||||||
auto job = new QKeychain::ReadPasswordJob("chatterino");
|
auto job = new QKeychain::ReadPasswordJob("chatterino");
|
||||||
job->setAutoDelete(true);
|
job->setAutoDelete(true);
|
||||||
job->setKey(name);
|
job->setKey(name);
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
job, &QKeychain::Job::finished, receiver,
|
job, &QKeychain::Job::finished, receiver,
|
||||||
[job, onLoaded = std::move(onLoaded)](auto) mutable {
|
[job, onLoaded = std::move(onLoaded)](auto) mutable {
|
||||||
onLoaded(job->textData());
|
onLoaded(job->textData());
|
||||||
},
|
},
|
||||||
Qt::DirectConnection);
|
Qt::DirectConnection);
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto &instance = insecureInstance();
|
auto &instance = insecureInstance();
|
||||||
|
|
||||||
onLoaded(instance.object().find(name).value().toString());
|
onLoaded(instance.object().find(name).value().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Credentials::set(const QString &provider, const QString &name_,
|
void Credentials::set(const QString &provider, const QString &name_,
|
||||||
const QString &credential)
|
const QString &credential)
|
||||||
{
|
{
|
||||||
assertInGuiThread();
|
assertInGuiThread();
|
||||||
|
|
||||||
/// On linux, we try to use a keychain but show a message to disable it when it fails.
|
/// On linux, we try to use a keychain but show a message to disable it when it fails.
|
||||||
/// XXX: add said message
|
/// XXX: add said message
|
||||||
|
|
||||||
auto name = FORMAT_NAME;
|
auto name = FORMAT_NAME;
|
||||||
|
|
||||||
if (useKeyring())
|
if (useKeyring())
|
||||||
{
|
{
|
||||||
queueJob(SetJob{name, credential});
|
queueJob(SetJob{name, credential});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto &instance = insecureInstance();
|
auto &instance = insecureInstance();
|
||||||
|
|
||||||
auto obj = instance.object();
|
auto obj = instance.object();
|
||||||
obj[name] = credential;
|
obj[name] = credential;
|
||||||
instance.setObject(obj);
|
instance.setObject(obj);
|
||||||
|
|
||||||
queueInsecureSave();
|
queueInsecureSave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Credentials::erase(const QString &provider, const QString &name_)
|
void Credentials::erase(const QString &provider, const QString &name_)
|
||||||
{
|
{
|
||||||
assertInGuiThread();
|
assertInGuiThread();
|
||||||
|
|
||||||
auto name = FORMAT_NAME;
|
auto name = FORMAT_NAME;
|
||||||
|
|
||||||
if (useKeyring())
|
if (useKeyring())
|
||||||
{
|
{
|
||||||
queueJob(EraseJob{name});
|
queueJob(EraseJob{name});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto &instance = insecureInstance();
|
auto &instance = insecureInstance();
|
||||||
|
|
||||||
if (auto it = instance.object().find(name);
|
if (auto it = instance.object().find(name);
|
||||||
it != instance.object().end())
|
it != instance.object().end())
|
||||||
{
|
{
|
||||||
instance.object().erase(it);
|
instance.object().erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
queueInsecureSave();
|
queueInsecureSave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
class Credentials
|
class Credentials
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static Credentials &instance();
|
static Credentials &instance();
|
||||||
|
|
||||||
void get(const QString &provider, const QString &name, QObject *receiver,
|
void get(const QString &provider, const QString &name, QObject *receiver,
|
||||||
std::function<void(const QString &)> &&onLoaded);
|
std::function<void(const QString &)> &&onLoaded);
|
||||||
void set(const QString &provider, const QString &name,
|
void set(const QString &provider, const QString &name,
|
||||||
const QString &credential);
|
const QString &credential);
|
||||||
void erase(const QString &provider, const QString &name);
|
void erase(const QString &provider, const QString &name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Credentials();
|
Credentials();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,260 +1,260 @@
|
||||||
#include "Irc2.hpp"
|
#include "Irc2.hpp"
|
||||||
|
|
||||||
#include <pajlada/serialize.hpp>
|
#include <pajlada/serialize.hpp>
|
||||||
#include "common/Credentials.hpp"
|
#include "common/Credentials.hpp"
|
||||||
#include "common/SignalVectorModel.hpp"
|
#include "common/SignalVectorModel.hpp"
|
||||||
#include "singletons/Paths.hpp"
|
#include "singletons/Paths.hpp"
|
||||||
#include "util/CombinePath.hpp"
|
#include "util/CombinePath.hpp"
|
||||||
#include "util/RapidjsonHelpers.hpp"
|
#include "util/RapidjsonHelpers.hpp"
|
||||||
#include "util/StandardItemHelper.hpp"
|
#include "util/StandardItemHelper.hpp"
|
||||||
|
|
||||||
#include <QSaveFile>
|
#include <QSaveFile>
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
QString configPath()
|
QString configPath()
|
||||||
{
|
{
|
||||||
return combinePath(getPaths()->settingsDirectory, "irc.json");
|
return combinePath(getPaths()->settingsDirectory, "irc.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
class Model : public SignalVectorModel<IrcServerData>
|
class Model : public SignalVectorModel<IrcServerData>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Model(QObject *parent)
|
Model(QObject *parent)
|
||||||
: SignalVectorModel<IrcServerData>(6, parent)
|
: SignalVectorModel<IrcServerData>(6, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// turn a vector item into a model row
|
// turn a vector item into a model row
|
||||||
IrcServerData getItemFromRow(std::vector<QStandardItem *> &row,
|
IrcServerData getItemFromRow(std::vector<QStandardItem *> &row,
|
||||||
const IrcServerData &original)
|
const IrcServerData &original)
|
||||||
{
|
{
|
||||||
return IrcServerData{
|
return IrcServerData{
|
||||||
row[0]->data(Qt::EditRole).toString(), // host
|
row[0]->data(Qt::EditRole).toString(), // host
|
||||||
row[1]->data(Qt::EditRole).toInt(), // port
|
row[1]->data(Qt::EditRole).toInt(), // port
|
||||||
row[2]->data(Qt::CheckStateRole).toBool(), // ssl
|
row[2]->data(Qt::CheckStateRole).toBool(), // ssl
|
||||||
row[3]->data(Qt::EditRole).toString(), // user
|
row[3]->data(Qt::EditRole).toString(), // user
|
||||||
row[4]->data(Qt::EditRole).toString(), // nick
|
row[4]->data(Qt::EditRole).toString(), // nick
|
||||||
row[5]->data(Qt::EditRole).toString(), // real
|
row[5]->data(Qt::EditRole).toString(), // real
|
||||||
original.authType, // authType
|
original.authType, // authType
|
||||||
original.connectCommands, // connectCommands
|
original.connectCommands, // connectCommands
|
||||||
original.id, // id
|
original.id, // id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// turns a row in the model into a vector item
|
// turns a row in the model into a vector item
|
||||||
void getRowFromItem(const IrcServerData &item,
|
void getRowFromItem(const IrcServerData &item,
|
||||||
std::vector<QStandardItem *> &row)
|
std::vector<QStandardItem *> &row)
|
||||||
{
|
{
|
||||||
setStringItem(row[0], item.host, false);
|
setStringItem(row[0], item.host, false);
|
||||||
setStringItem(row[1], QString::number(item.port));
|
setStringItem(row[1], QString::number(item.port));
|
||||||
setBoolItem(row[2], item.ssl);
|
setBoolItem(row[2], item.ssl);
|
||||||
setStringItem(row[3], item.user);
|
setStringItem(row[3], item.user);
|
||||||
setStringItem(row[4], item.nick);
|
setStringItem(row[4], item.nick);
|
||||||
setStringItem(row[5], item.real);
|
setStringItem(row[5], item.real);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
inline QString escape(QString str)
|
inline QString escape(QString str)
|
||||||
{
|
{
|
||||||
return str.replace(":", "::");
|
return str.replace(":", "::");
|
||||||
}
|
}
|
||||||
|
|
||||||
// This returns a unique id for every server which is understandeable in the systems credential manager.
|
// This returns a unique id for every server which is understandeable in the systems credential manager.
|
||||||
inline QString getCredentialName(const IrcServerData &data)
|
inline QString getCredentialName(const IrcServerData &data)
|
||||||
{
|
{
|
||||||
return escape(QString::number(data.id)) + ":" + escape(data.user) + "@" +
|
return escape(QString::number(data.id)) + ":" + escape(data.user) + "@" +
|
||||||
escape(data.host);
|
escape(data.host);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrcServerData::getPassword(
|
void IrcServerData::getPassword(
|
||||||
QObject *receiver, std::function<void(const QString &)> &&onLoaded) const
|
QObject *receiver, std::function<void(const QString &)> &&onLoaded) const
|
||||||
{
|
{
|
||||||
Credentials::instance().get("irc", getCredentialName(*this), receiver,
|
Credentials::instance().get("irc", getCredentialName(*this), receiver,
|
||||||
std::move(onLoaded));
|
std::move(onLoaded));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrcServerData::setPassword(const QString &password)
|
void IrcServerData::setPassword(const QString &password)
|
||||||
{
|
{
|
||||||
Credentials::instance().set("irc", getCredentialName(*this), password);
|
Credentials::instance().set("irc", getCredentialName(*this), password);
|
||||||
}
|
}
|
||||||
|
|
||||||
Irc::Irc()
|
Irc::Irc()
|
||||||
{
|
{
|
||||||
this->connections.itemInserted.connect([this](auto &&args) {
|
this->connections.itemInserted.connect([this](auto &&args) {
|
||||||
// make sure only one id can only exist for one server
|
// make sure only one id can only exist for one server
|
||||||
assert(this->servers_.find(args.item.id) == this->servers_.end());
|
assert(this->servers_.find(args.item.id) == this->servers_.end());
|
||||||
|
|
||||||
// add new server
|
// add new server
|
||||||
if (auto ab = this->abandonedChannels_.find(args.item.id);
|
if (auto ab = this->abandonedChannels_.find(args.item.id);
|
||||||
ab != this->abandonedChannels_.end())
|
ab != this->abandonedChannels_.end())
|
||||||
{
|
{
|
||||||
auto server = std::make_unique<IrcServer>(args.item, ab->second);
|
auto server = std::make_unique<IrcServer>(args.item, ab->second);
|
||||||
|
|
||||||
// set server of abandoned channels
|
// set server of abandoned channels
|
||||||
for (auto weak : ab->second)
|
for (auto weak : ab->second)
|
||||||
if (auto shared = weak.lock())
|
if (auto shared = weak.lock())
|
||||||
if (auto ircChannel =
|
if (auto ircChannel =
|
||||||
dynamic_cast<IrcChannel *>(shared.get()))
|
dynamic_cast<IrcChannel *>(shared.get()))
|
||||||
ircChannel->setServer(server.get());
|
ircChannel->setServer(server.get());
|
||||||
|
|
||||||
// add new server with abandoned channels
|
// add new server with abandoned channels
|
||||||
this->servers_.emplace(args.item.id, std::move(server));
|
this->servers_.emplace(args.item.id, std::move(server));
|
||||||
this->abandonedChannels_.erase(ab);
|
this->abandonedChannels_.erase(ab);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// add new server
|
// add new server
|
||||||
this->servers_.emplace(args.item.id,
|
this->servers_.emplace(args.item.id,
|
||||||
std::make_unique<IrcServer>(args.item));
|
std::make_unique<IrcServer>(args.item));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this->connections.itemRemoved.connect([this](auto &&args) {
|
this->connections.itemRemoved.connect([this](auto &&args) {
|
||||||
// restore
|
// restore
|
||||||
if (auto server = this->servers_.find(args.item.id);
|
if (auto server = this->servers_.find(args.item.id);
|
||||||
server != this->servers_.end())
|
server != this->servers_.end())
|
||||||
{
|
{
|
||||||
auto abandoned = server->second->getChannels();
|
auto abandoned = server->second->getChannels();
|
||||||
|
|
||||||
// set server of abandoned servers to nullptr
|
// set server of abandoned servers to nullptr
|
||||||
for (auto weak : abandoned)
|
for (auto weak : abandoned)
|
||||||
if (auto shared = weak.lock())
|
if (auto shared = weak.lock())
|
||||||
if (auto ircChannel =
|
if (auto ircChannel =
|
||||||
dynamic_cast<IrcChannel *>(shared.get()))
|
dynamic_cast<IrcChannel *>(shared.get()))
|
||||||
ircChannel->setServer(nullptr);
|
ircChannel->setServer(nullptr);
|
||||||
|
|
||||||
this->abandonedChannels_[args.item.id] = abandoned;
|
this->abandonedChannels_[args.item.id] = abandoned;
|
||||||
this->servers_.erase(server);
|
this->servers_.erase(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.caller != Irc::noEraseCredentialCaller)
|
if (args.caller != Irc::noEraseCredentialCaller)
|
||||||
{
|
{
|
||||||
Credentials::instance().erase("irc", getCredentialName(args.item));
|
Credentials::instance().erase("irc", getCredentialName(args.item));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this->connections.delayedItemsChanged.connect([this] { this->save(); });
|
this->connections.delayedItemsChanged.connect([this] { this->save(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
QAbstractTableModel *Irc::newConnectionModel(QObject *parent)
|
QAbstractTableModel *Irc::newConnectionModel(QObject *parent)
|
||||||
{
|
{
|
||||||
auto model = new Model(parent);
|
auto model = new Model(parent);
|
||||||
model->initialize(&this->connections);
|
model->initialize(&this->connections);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelPtr Irc::getOrAddChannel(int id, QString name)
|
ChannelPtr Irc::getOrAddChannel(int id, QString name)
|
||||||
{
|
{
|
||||||
if (auto server = this->servers_.find(id); server != this->servers_.end())
|
if (auto server = this->servers_.find(id); server != this->servers_.end())
|
||||||
{
|
{
|
||||||
return server->second->getOrAddChannel(name);
|
return server->second->getOrAddChannel(name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto channel = std::make_shared<IrcChannel>(name, nullptr);
|
auto channel = std::make_shared<IrcChannel>(name, nullptr);
|
||||||
|
|
||||||
this->abandonedChannels_[id].push_back(channel);
|
this->abandonedChannels_[id].push_back(channel);
|
||||||
|
|
||||||
return std::move(channel);
|
return std::move(channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Irc &Irc::instance()
|
Irc &Irc::instance()
|
||||||
{
|
{
|
||||||
static Irc irc;
|
static Irc irc;
|
||||||
return irc;
|
return irc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Irc::uniqueId()
|
int Irc::uniqueId()
|
||||||
{
|
{
|
||||||
int i = this->currentId_ + 1;
|
int i = this->currentId_ + 1;
|
||||||
auto it = this->servers_.find(i);
|
auto it = this->servers_.find(i);
|
||||||
auto it2 = this->abandonedChannels_.find(i);
|
auto it2 = this->abandonedChannels_.find(i);
|
||||||
|
|
||||||
while (it != this->servers_.end() || it2 != this->abandonedChannels_.end())
|
while (it != this->servers_.end() || it2 != this->abandonedChannels_.end())
|
||||||
{
|
{
|
||||||
i++;
|
i++;
|
||||||
it = this->servers_.find(i);
|
it = this->servers_.find(i);
|
||||||
it2 = this->abandonedChannels_.find(i);
|
it2 = this->abandonedChannels_.find(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (this->currentId_ = i);
|
return (this->currentId_ = i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Irc::save()
|
void Irc::save()
|
||||||
{
|
{
|
||||||
QJsonDocument doc;
|
QJsonDocument doc;
|
||||||
QJsonObject root;
|
QJsonObject root;
|
||||||
QJsonArray servers;
|
QJsonArray servers;
|
||||||
|
|
||||||
for (auto &&conn : this->connections)
|
for (auto &&conn : this->connections)
|
||||||
{
|
{
|
||||||
QJsonObject obj;
|
QJsonObject obj;
|
||||||
obj.insert("host", conn.host);
|
obj.insert("host", conn.host);
|
||||||
obj.insert("port", conn.port);
|
obj.insert("port", conn.port);
|
||||||
obj.insert("ssl", conn.ssl);
|
obj.insert("ssl", conn.ssl);
|
||||||
obj.insert("username", conn.user);
|
obj.insert("username", conn.user);
|
||||||
obj.insert("nickname", conn.nick);
|
obj.insert("nickname", conn.nick);
|
||||||
obj.insert("realname", conn.real);
|
obj.insert("realname", conn.real);
|
||||||
obj.insert("connectCommands",
|
obj.insert("connectCommands",
|
||||||
QJsonArray::fromStringList(conn.connectCommands));
|
QJsonArray::fromStringList(conn.connectCommands));
|
||||||
obj.insert("id", conn.id);
|
obj.insert("id", conn.id);
|
||||||
obj.insert("authType", int(conn.authType));
|
obj.insert("authType", int(conn.authType));
|
||||||
|
|
||||||
servers.append(obj);
|
servers.append(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
root.insert("servers", servers);
|
root.insert("servers", servers);
|
||||||
doc.setObject(root);
|
doc.setObject(root);
|
||||||
|
|
||||||
QSaveFile file(configPath());
|
QSaveFile file(configPath());
|
||||||
file.open(QIODevice::WriteOnly);
|
file.open(QIODevice::WriteOnly);
|
||||||
file.write(doc.toJson());
|
file.write(doc.toJson());
|
||||||
file.commit();
|
file.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Irc::load()
|
void Irc::load()
|
||||||
{
|
{
|
||||||
if (this->loaded_)
|
if (this->loaded_)
|
||||||
return;
|
return;
|
||||||
this->loaded_ = true;
|
this->loaded_ = true;
|
||||||
|
|
||||||
QString config = configPath();
|
QString config = configPath();
|
||||||
QFile file(configPath());
|
QFile file(configPath());
|
||||||
file.open(QIODevice::ReadOnly);
|
file.open(QIODevice::ReadOnly);
|
||||||
auto object = QJsonDocument::fromJson(file.readAll()).object();
|
auto object = QJsonDocument::fromJson(file.readAll()).object();
|
||||||
|
|
||||||
std::unordered_set<int> ids;
|
std::unordered_set<int> ids;
|
||||||
|
|
||||||
// load servers
|
// load servers
|
||||||
for (auto server : object.value("servers").toArray())
|
for (auto server : object.value("servers").toArray())
|
||||||
{
|
{
|
||||||
auto obj = server.toObject();
|
auto obj = server.toObject();
|
||||||
IrcServerData data;
|
IrcServerData data;
|
||||||
data.host = obj.value("host").toString(data.host);
|
data.host = obj.value("host").toString(data.host);
|
||||||
data.port = obj.value("port").toInt(data.port);
|
data.port = obj.value("port").toInt(data.port);
|
||||||
data.ssl = obj.value("ssl").toBool(data.ssl);
|
data.ssl = obj.value("ssl").toBool(data.ssl);
|
||||||
data.user = obj.value("username").toString(data.user);
|
data.user = obj.value("username").toString(data.user);
|
||||||
data.nick = obj.value("nickname").toString(data.nick);
|
data.nick = obj.value("nickname").toString(data.nick);
|
||||||
data.real = obj.value("realname").toString(data.real);
|
data.real = obj.value("realname").toString(data.real);
|
||||||
data.connectCommands =
|
data.connectCommands =
|
||||||
obj.value("connectCommands").toVariant().toStringList();
|
obj.value("connectCommands").toVariant().toStringList();
|
||||||
data.id = obj.value("id").toInt(data.id);
|
data.id = obj.value("id").toInt(data.id);
|
||||||
data.authType =
|
data.authType =
|
||||||
IrcAuthType(obj.value("authType").toInt(int(data.authType)));
|
IrcAuthType(obj.value("authType").toInt(int(data.authType)));
|
||||||
|
|
||||||
// duplicate id's are not allowed :(
|
// duplicate id's are not allowed :(
|
||||||
if (ids.find(data.id) == ids.end())
|
if (ids.find(data.id) == ids.end())
|
||||||
{
|
{
|
||||||
ids.insert(data.id);
|
ids.insert(data.id);
|
||||||
|
|
||||||
this->connections.append(data);
|
this->connections.append(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,67 +1,67 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <rapidjson/rapidjson.h>
|
#include <rapidjson/rapidjson.h>
|
||||||
#include <common/SignalVector.hpp>
|
#include <common/SignalVector.hpp>
|
||||||
|
|
||||||
#include "providers/irc/IrcChannel2.hpp"
|
#include "providers/irc/IrcChannel2.hpp"
|
||||||
#include "providers/irc/IrcServer.hpp"
|
#include "providers/irc/IrcServer.hpp"
|
||||||
|
|
||||||
class QAbstractTableModel;
|
class QAbstractTableModel;
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
enum class IrcAuthType { Anonymous, Custom, Pass, Sasl };
|
enum class IrcAuthType { Anonymous, Custom, Pass, Sasl };
|
||||||
|
|
||||||
struct IrcServerData {
|
struct IrcServerData {
|
||||||
QString host;
|
QString host;
|
||||||
int port = 6697;
|
int port = 6697;
|
||||||
bool ssl = true;
|
bool ssl = true;
|
||||||
|
|
||||||
QString user;
|
QString user;
|
||||||
QString nick;
|
QString nick;
|
||||||
QString real;
|
QString real;
|
||||||
|
|
||||||
IrcAuthType authType = IrcAuthType::Anonymous;
|
IrcAuthType authType = IrcAuthType::Anonymous;
|
||||||
void getPassword(QObject *receiver,
|
void getPassword(QObject *receiver,
|
||||||
std::function<void(const QString &)> &&onLoaded) const;
|
std::function<void(const QString &)> &&onLoaded) const;
|
||||||
void setPassword(const QString &password);
|
void setPassword(const QString &password);
|
||||||
|
|
||||||
QStringList connectCommands;
|
QStringList connectCommands;
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Irc
|
class Irc
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Irc();
|
Irc();
|
||||||
|
|
||||||
static Irc &instance();
|
static Irc &instance();
|
||||||
|
|
||||||
static inline void *const noEraseCredentialCaller =
|
static inline void *const noEraseCredentialCaller =
|
||||||
reinterpret_cast<void *>(1);
|
reinterpret_cast<void *>(1);
|
||||||
|
|
||||||
SignalVector<IrcServerData> connections;
|
SignalVector<IrcServerData> connections;
|
||||||
QAbstractTableModel *newConnectionModel(QObject *parent);
|
QAbstractTableModel *newConnectionModel(QObject *parent);
|
||||||
|
|
||||||
ChannelPtr getOrAddChannel(int serverId, QString name);
|
ChannelPtr getOrAddChannel(int serverId, QString name);
|
||||||
|
|
||||||
void save();
|
void save();
|
||||||
void load();
|
void load();
|
||||||
|
|
||||||
int uniqueId();
|
int uniqueId();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int currentId_{};
|
int currentId_{};
|
||||||
bool loaded_{};
|
bool loaded_{};
|
||||||
|
|
||||||
// Servers have a unique id.
|
// Servers have a unique id.
|
||||||
// When a server gets changed it gets removed and then added again.
|
// When a server gets changed it gets removed and then added again.
|
||||||
// So we store the channels of that server in abandonedChannels_ temporarily.
|
// So we store the channels of that server in abandonedChannels_ temporarily.
|
||||||
// Or if the server got removed permanently then it's still stored there.
|
// Or if the server got removed permanently then it's still stored there.
|
||||||
std::unordered_map<int, std::unique_ptr<IrcServer>> servers_;
|
std::unordered_map<int, std::unique_ptr<IrcServer>> servers_;
|
||||||
std::unordered_map<int, std::vector<std::weak_ptr<Channel>>>
|
std::unordered_map<int, std::vector<std::weak_ptr<Channel>>>
|
||||||
abandonedChannels_;
|
abandonedChannels_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,76 +1,76 @@
|
||||||
#include "IrcCommands.hpp"
|
#include "IrcCommands.hpp"
|
||||||
|
|
||||||
#include "messages/MessageBuilder.hpp"
|
#include "messages/MessageBuilder.hpp"
|
||||||
#include "providers/irc/IrcChannel2.hpp"
|
#include "providers/irc/IrcChannel2.hpp"
|
||||||
#include "providers/irc/IrcServer.hpp"
|
#include "providers/irc/IrcServer.hpp"
|
||||||
#include "util/Overloaded.hpp"
|
#include "util/Overloaded.hpp"
|
||||||
#include "util/QStringHash.hpp"
|
#include "util/QStringHash.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
Outcome invokeIrcCommand(const QString &commandName, const QString &allParams,
|
Outcome invokeIrcCommand(const QString &commandName, const QString &allParams,
|
||||||
IrcChannel &channel)
|
IrcChannel &channel)
|
||||||
{
|
{
|
||||||
if (!channel.server())
|
if (!channel.server())
|
||||||
{
|
{
|
||||||
return Failure;
|
return Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
// STATIC MESSAGES
|
// STATIC MESSAGES
|
||||||
static auto staticMessages = std::unordered_map<QString, QString>{
|
static auto staticMessages = std::unordered_map<QString, QString>{
|
||||||
{"join", "/join is not supported. Press ctrl+r to change the "
|
{"join", "/join is not supported. Press ctrl+r to change the "
|
||||||
"channel. If required use /raw JOIN #channel."},
|
"channel. If required use /raw JOIN #channel."},
|
||||||
{"part", "/part is not supported. Press ctrl+r to change the "
|
{"part", "/part is not supported. Press ctrl+r to change the "
|
||||||
"channel. If required use /raw PART #channel."},
|
"channel. If required use /raw PART #channel."},
|
||||||
};
|
};
|
||||||
auto cmd = commandName.toLower();
|
auto cmd = commandName.toLower();
|
||||||
|
|
||||||
if (auto it = staticMessages.find(cmd); it != staticMessages.end())
|
if (auto it = staticMessages.find(cmd); it != staticMessages.end())
|
||||||
{
|
{
|
||||||
channel.addMessage(makeSystemMessage(it->second));
|
channel.addMessage(makeSystemMessage(it->second));
|
||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CUSTOM COMMANDS
|
// CUSTOM COMMANDS
|
||||||
auto params = allParams.split(' ');
|
auto params = allParams.split(' ');
|
||||||
auto paramsAfter = [&](int i) { return params.mid(i + 1).join(' '); };
|
auto paramsAfter = [&](int i) { return params.mid(i + 1).join(' '); };
|
||||||
|
|
||||||
auto sendRaw = [&](QString str) { channel.server()->sendRawMessage(str); };
|
auto sendRaw = [&](QString str) { channel.server()->sendRawMessage(str); };
|
||||||
|
|
||||||
if (cmd == "msg")
|
if (cmd == "msg")
|
||||||
{
|
{
|
||||||
sendRaw("PRIVMSG " + params[0] + " :" + paramsAfter(0));
|
sendRaw("PRIVMSG " + params[0] + " :" + paramsAfter(0));
|
||||||
}
|
}
|
||||||
else if (cmd == "away")
|
else if (cmd == "away")
|
||||||
{
|
{
|
||||||
sendRaw("AWAY" + params[0] + " :" + paramsAfter(0));
|
sendRaw("AWAY" + params[0] + " :" + paramsAfter(0));
|
||||||
}
|
}
|
||||||
else if (cmd == "knock")
|
else if (cmd == "knock")
|
||||||
{
|
{
|
||||||
sendRaw("KNOCK #" + params[0] + " " + paramsAfter(0));
|
sendRaw("KNOCK #" + params[0] + " " + paramsAfter(0));
|
||||||
}
|
}
|
||||||
else if (cmd == "kick")
|
else if (cmd == "kick")
|
||||||
{
|
{
|
||||||
if (paramsAfter(1).isEmpty())
|
if (paramsAfter(1).isEmpty())
|
||||||
sendRaw("KICK " + params[0] + " " + params[1]);
|
sendRaw("KICK " + params[0] + " " + params[1]);
|
||||||
else
|
else
|
||||||
sendRaw("KICK " + params[0] + " " + params[1] + " :" +
|
sendRaw("KICK " + params[0] + " " + params[1] + " :" +
|
||||||
paramsAfter(1));
|
paramsAfter(1));
|
||||||
}
|
}
|
||||||
else if (cmd == "wallops")
|
else if (cmd == "wallops")
|
||||||
{
|
{
|
||||||
sendRaw("WALLOPS :" + allParams);
|
sendRaw("WALLOPS :" + allParams);
|
||||||
}
|
}
|
||||||
else if (cmd == "raw")
|
else if (cmd == "raw")
|
||||||
{
|
{
|
||||||
sendRaw(allParams);
|
sendRaw(allParams);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sendRaw(cmd.toUpper() + " " + allParams);
|
sendRaw(cmd.toUpper() + " " + allParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/Outcome.hpp"
|
#include "common/Outcome.hpp"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
class IrcChannel;
|
class IrcChannel;
|
||||||
|
|
||||||
Outcome invokeIrcCommand(const QString &command, const QString ¶ms,
|
Outcome invokeIrcCommand(const QString &command, const QString ¶ms,
|
||||||
IrcChannel &channel);
|
IrcChannel &channel);
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "IrcMessageHandler.hpp"
|
#include "IrcMessageHandler.hpp"
|
||||||
|
|
||||||
#include "Application.hpp"
|
#include "Application.hpp"
|
||||||
#include "controllers/accounts/AccountController.hpp"
|
#include "controllers/accounts/AccountController.hpp"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/Aliases.hpp"
|
#include "common/Aliases.hpp"
|
||||||
#include "common/Outcome.hpp"
|
#include "common/Outcome.hpp"
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
template <class... Ts>
|
template <class... Ts>
|
||||||
struct Overloaded : Ts... {
|
struct Overloaded : Ts... {
|
||||||
using Ts::operator()...;
|
using Ts::operator()...;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class... Ts>
|
template <class... Ts>
|
||||||
Overloaded(Ts...)->Overloaded<Ts...>;
|
Overloaded(Ts...) -> Overloaded<Ts...>;
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,97 +1,97 @@
|
||||||
#include "IrcConnectionEditor.hpp"
|
#include "IrcConnectionEditor.hpp"
|
||||||
#include "ui_IrcConnectionEditor.h"
|
#include "ui_IrcConnectionEditor.h"
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
IrcConnectionEditor::IrcConnectionEditor(const IrcServerData &data, bool isAdd,
|
IrcConnectionEditor::IrcConnectionEditor(const IrcServerData &data, bool isAdd,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
|
|
||||||
: QDialog(parent, Qt::WindowStaysOnTopHint)
|
: QDialog(parent, Qt::WindowStaysOnTopHint)
|
||||||
, ui_(new Ui::IrcConnectionEditor)
|
, ui_(new Ui::IrcConnectionEditor)
|
||||||
, data_(data)
|
, data_(data)
|
||||||
{
|
{
|
||||||
this->ui_->setupUi(this);
|
this->ui_->setupUi(this);
|
||||||
|
|
||||||
this->setWindowTitle(QString(isAdd ? "Add " : "Edit ") + "Irc Connection");
|
this->setWindowTitle(QString(isAdd ? "Add " : "Edit ") + "Irc Connection");
|
||||||
|
|
||||||
QObject::connect(this->ui_->userNameLineEdit, &QLineEdit::textChanged, this,
|
QObject::connect(this->ui_->userNameLineEdit, &QLineEdit::textChanged, this,
|
||||||
[this](const QString &text) {
|
[this](const QString &text) {
|
||||||
this->ui_->nickNameLineEdit->setPlaceholderText(text);
|
this->ui_->nickNameLineEdit->setPlaceholderText(text);
|
||||||
this->ui_->realNameLineEdit->setPlaceholderText(text);
|
this->ui_->realNameLineEdit->setPlaceholderText(text);
|
||||||
});
|
});
|
||||||
|
|
||||||
this->ui_->serverLineEdit->setText(data.host);
|
this->ui_->serverLineEdit->setText(data.host);
|
||||||
this->ui_->portSpinBox->setValue(data.port);
|
this->ui_->portSpinBox->setValue(data.port);
|
||||||
this->ui_->securityCheckBox->setChecked(data.ssl);
|
this->ui_->securityCheckBox->setChecked(data.ssl);
|
||||||
this->ui_->userNameLineEdit->setText(data.user);
|
this->ui_->userNameLineEdit->setText(data.user);
|
||||||
this->ui_->nickNameLineEdit->setText(data.nick);
|
this->ui_->nickNameLineEdit->setText(data.nick);
|
||||||
this->ui_->realNameLineEdit->setText(data.real);
|
this->ui_->realNameLineEdit->setText(data.real);
|
||||||
this->ui_->connectCommandsEditor->setPlainText(
|
this->ui_->connectCommandsEditor->setPlainText(
|
||||||
data.connectCommands.join('\n'));
|
data.connectCommands.join('\n'));
|
||||||
|
|
||||||
data.getPassword(this, [this](const QString &password) {
|
data.getPassword(this, [this](const QString &password) {
|
||||||
this->ui_->passwordLineEdit->setText(password);
|
this->ui_->passwordLineEdit->setText(password);
|
||||||
});
|
});
|
||||||
|
|
||||||
this->ui_->loginMethodComboBox->setCurrentIndex([&] {
|
this->ui_->loginMethodComboBox->setCurrentIndex([&] {
|
||||||
switch (data.authType)
|
switch (data.authType)
|
||||||
{
|
{
|
||||||
case IrcAuthType::Custom:
|
case IrcAuthType::Custom:
|
||||||
return 1;
|
return 1;
|
||||||
case IrcAuthType::Pass:
|
case IrcAuthType::Pass:
|
||||||
return 2;
|
return 2;
|
||||||
case IrcAuthType::Sasl:
|
case IrcAuthType::Sasl:
|
||||||
return 3;
|
return 3;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
|
||||||
QObject::connect(this->ui_->loginMethodComboBox,
|
QObject::connect(this->ui_->loginMethodComboBox,
|
||||||
qOverload<int>(&QComboBox::currentIndexChanged), this,
|
qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||||
[this](int index) {
|
[this](int index) {
|
||||||
if (index == 1) // Custom
|
if (index == 1) // Custom
|
||||||
{
|
{
|
||||||
this->ui_->connectCommandsEditor->setFocus();
|
this->ui_->connectCommandsEditor->setFocus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
QFont font("Monospace");
|
QFont font("Monospace");
|
||||||
font.setStyleHint(QFont::TypeWriter);
|
font.setStyleHint(QFont::TypeWriter);
|
||||||
this->ui_->connectCommandsEditor->setFont(font);
|
this->ui_->connectCommandsEditor->setFont(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
IrcConnectionEditor::~IrcConnectionEditor()
|
IrcConnectionEditor::~IrcConnectionEditor()
|
||||||
{
|
{
|
||||||
delete ui_;
|
delete ui_;
|
||||||
}
|
}
|
||||||
|
|
||||||
IrcServerData IrcConnectionEditor::data()
|
IrcServerData IrcConnectionEditor::data()
|
||||||
{
|
{
|
||||||
auto data = this->data_;
|
auto data = this->data_;
|
||||||
data.host = this->ui_->serverLineEdit->text();
|
data.host = this->ui_->serverLineEdit->text();
|
||||||
data.port = this->ui_->portSpinBox->value();
|
data.port = this->ui_->portSpinBox->value();
|
||||||
data.ssl = this->ui_->securityCheckBox->isChecked();
|
data.ssl = this->ui_->securityCheckBox->isChecked();
|
||||||
data.user = this->ui_->userNameLineEdit->text();
|
data.user = this->ui_->userNameLineEdit->text();
|
||||||
data.nick = this->ui_->nickNameLineEdit->text();
|
data.nick = this->ui_->nickNameLineEdit->text();
|
||||||
data.real = this->ui_->realNameLineEdit->text();
|
data.real = this->ui_->realNameLineEdit->text();
|
||||||
data.connectCommands =
|
data.connectCommands =
|
||||||
this->ui_->connectCommandsEditor->toPlainText().split('\n');
|
this->ui_->connectCommandsEditor->toPlainText().split('\n');
|
||||||
data.setPassword(this->ui_->passwordLineEdit->text());
|
data.setPassword(this->ui_->passwordLineEdit->text());
|
||||||
data.authType = [this] {
|
data.authType = [this] {
|
||||||
switch (this->ui_->loginMethodComboBox->currentIndex())
|
switch (this->ui_->loginMethodComboBox->currentIndex())
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
return IrcAuthType::Custom;
|
return IrcAuthType::Custom;
|
||||||
case 2:
|
case 2:
|
||||||
return IrcAuthType::Pass;
|
return IrcAuthType::Pass;
|
||||||
case 3:
|
case 3:
|
||||||
return IrcAuthType::Sasl;
|
return IrcAuthType::Sasl;
|
||||||
default:
|
default:
|
||||||
return IrcAuthType::Anonymous;
|
return IrcAuthType::Anonymous;
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
#include "providers/irc/Irc2.hpp"
|
#include "providers/irc/Irc2.hpp"
|
||||||
#include "widgets/BaseWindow.hpp"
|
#include "widgets/BaseWindow.hpp"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class IrcConnectionEditor;
|
class IrcConnectionEditor;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
struct IrcServerData;
|
struct IrcServerData;
|
||||||
|
|
||||||
class IrcConnectionEditor : public QDialog
|
class IrcConnectionEditor : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit IrcConnectionEditor(const IrcServerData &data, bool isAdd = false,
|
explicit IrcConnectionEditor(const IrcServerData &data, bool isAdd = false,
|
||||||
QWidget *parent = nullptr);
|
QWidget *parent = nullptr);
|
||||||
~IrcConnectionEditor();
|
~IrcConnectionEditor();
|
||||||
|
|
||||||
IrcServerData data();
|
IrcServerData data();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::IrcConnectionEditor *ui_;
|
Ui::IrcConnectionEditor *ui_;
|
||||||
IrcServerData data_;
|
IrcServerData data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -4,12 +4,14 @@ set -eu
|
||||||
|
|
||||||
fail="0"
|
fail="0"
|
||||||
|
|
||||||
|
clang-format --version
|
||||||
|
|
||||||
while read -r file; do
|
while read -r file; do
|
||||||
if ! diff -u <(cat "$file") <(clang-format "$file"); then
|
if ! diff -u <(cat "$file") <(clang-format "$file"); then
|
||||||
echo "$file differs!!!!!!!"
|
echo "$file differs!!!!!!!"
|
||||||
fail="1"
|
fail="1"
|
||||||
fi
|
fi
|
||||||
done < <(find src/ \( -iname "*.hpp" -o -iname "*.cpp" \))
|
done < <(find src/ -type f \( -iname "*.hpp" -o -iname "*.cpp" \))
|
||||||
|
|
||||||
if [ "$fail" = "1" ]; then
|
if [ "$fail" = "1" ]; then
|
||||||
echo "At least one file is poorly formatted - check the output above"
|
echo "At least one file is poorly formatted - check the output above"
|
||||||
|
|
22
tools/check-line-endings.sh
Executable file
22
tools/check-line-endings.sh
Executable file
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
fail="0"
|
||||||
|
|
||||||
|
dos2unix --version
|
||||||
|
|
||||||
|
while read -r file; do
|
||||||
|
num_dos_line_endings=$(dos2unix -id "$file" | awk '/[0-9]+/{print $(NF-1)}')
|
||||||
|
if [ "$num_dos_line_endings" -gt "0" ]; then
|
||||||
|
>&2 echo "File '$file' contains $num_dos_line_endings DOS line-endings, it should only be using unix line-endings!"
|
||||||
|
fail="1"
|
||||||
|
fi
|
||||||
|
done < <(find src/ -type f \( -iname "*.hpp" -o -iname "*.cpp" \))
|
||||||
|
|
||||||
|
if [ "$fail" = "1" ]; then
|
||||||
|
>&2 echo "At least one file is not using unix line-endings - check the output above"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
>&2 echo "Every file seems to be using unix line-endings. Good job!"
|
Loading…
Reference in a new issue