2018-06-26 14:09:39 +02:00
|
|
|
#include "IrcServer.hpp"
|
2018-02-05 15:11:50 +01:00
|
|
|
|
|
|
|
#include <cassert>
|
2019-09-18 08:05:51 +02:00
|
|
|
#include <cstdlib>
|
2018-02-05 15:11:50 +01:00
|
|
|
|
2019-09-18 11:11:50 +02:00
|
|
|
#include "messages/Message.hpp"
|
2019-09-10 14:46:43 +02:00
|
|
|
#include "messages/MessageBuilder.hpp"
|
2019-09-09 22:26:14 +02:00
|
|
|
#include "providers/irc/Irc2.hpp"
|
|
|
|
#include "providers/irc/IrcChannel2.hpp"
|
2019-09-18 11:11:50 +02:00
|
|
|
#include "singletons/Settings.hpp"
|
2019-09-14 20:45:01 +02:00
|
|
|
#include "util/QObjectRef.hpp"
|
2019-09-09 22:26:14 +02:00
|
|
|
|
2018-02-05 15:11:50 +01:00
|
|
|
namespace chatterino {
|
2018-06-26 16:37:59 +02:00
|
|
|
|
2019-09-11 13:51:48 +02:00
|
|
|
IrcServer::IrcServer(const IrcServerData &data)
|
|
|
|
: data_(new IrcServerData(data))
|
2019-09-09 22:26:14 +02:00
|
|
|
{
|
|
|
|
this->connect();
|
|
|
|
}
|
|
|
|
|
2019-09-11 13:51:48 +02:00
|
|
|
IrcServer::IrcServer(const IrcServerData &data,
|
2019-09-09 22:26:14 +02:00
|
|
|
const std::vector<std::weak_ptr<Channel>> &restoreChannels)
|
|
|
|
: IrcServer(data)
|
|
|
|
{
|
|
|
|
for (auto &&weak : restoreChannels)
|
|
|
|
{
|
|
|
|
if (auto shared = weak.lock())
|
|
|
|
{
|
|
|
|
this->channels[shared->getName()] = weak;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IrcServer::~IrcServer()
|
|
|
|
{
|
|
|
|
delete this->data_;
|
|
|
|
}
|
|
|
|
|
2019-09-10 14:46:43 +02:00
|
|
|
int IrcServer::id()
|
2019-09-09 22:26:14 +02:00
|
|
|
{
|
|
|
|
return this->data_->id;
|
|
|
|
}
|
|
|
|
|
2019-09-10 14:46:43 +02:00
|
|
|
const QString &IrcServer::user()
|
|
|
|
{
|
|
|
|
return this->data_->user;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QString &IrcServer::nick()
|
|
|
|
{
|
2019-09-14 20:45:01 +02:00
|
|
|
return this->data_->nick.isEmpty() ? this->data_->user : this->data_->nick;
|
2019-09-10 14:46:43 +02:00
|
|
|
}
|
|
|
|
|
2019-09-14 20:45:01 +02:00
|
|
|
void IrcServer::initializeConnection(IrcConnection *connection,
|
|
|
|
ConnectionType type)
|
2019-09-09 22:26:14 +02:00
|
|
|
{
|
2019-09-14 20:45:01 +02:00
|
|
|
assert(type == Both);
|
2019-09-09 22:26:14 +02:00
|
|
|
|
|
|
|
connection->setSecure(this->data_->ssl);
|
|
|
|
connection->setHost(this->data_->host);
|
|
|
|
connection->setPort(this->data_->port);
|
|
|
|
|
|
|
|
connection->setUserName(this->data_->user);
|
2019-09-11 13:17:36 +02:00
|
|
|
connection->setNickName(this->data_->nick.isEmpty() ? this->data_->user
|
|
|
|
: this->data_->nick);
|
|
|
|
connection->setRealName(this->data_->real.isEmpty() ? this->data_->user
|
|
|
|
: this->data_->nick);
|
2019-09-14 20:45:01 +02:00
|
|
|
|
2019-09-15 13:15:29 +02:00
|
|
|
switch (this->data_->authType)
|
2019-09-15 11:35:17 +02:00
|
|
|
{
|
2019-09-15 13:15:29 +02:00
|
|
|
case IrcAuthType::Sasl:
|
|
|
|
connection->setSaslMechanism("PLAIN");
|
|
|
|
[[fallthrough]];
|
|
|
|
case IrcAuthType::Pass:
|
|
|
|
this->data_->getPassword(
|
|
|
|
this, [conn = new QObjectRef(connection) /* can't copy */,
|
|
|
|
this](const QString &password) mutable {
|
|
|
|
if (*conn)
|
|
|
|
{
|
|
|
|
(*conn)->setPassword(password);
|
|
|
|
this->open(Both);
|
|
|
|
}
|
|
|
|
|
|
|
|
delete conn;
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
this->open(Both);
|
2019-09-15 11:35:17 +02:00
|
|
|
}
|
2019-09-18 08:05:51 +02:00
|
|
|
|
|
|
|
QObject::connect(
|
|
|
|
connection, &Communi::IrcConnection::socketError, this,
|
|
|
|
[this](QAbstractSocket::SocketError error) {
|
|
|
|
static int index =
|
|
|
|
QAbstractSocket::staticMetaObject.indexOfEnumerator(
|
|
|
|
"SocketError");
|
|
|
|
|
|
|
|
std::lock_guard lock(this->channelMutex);
|
|
|
|
|
|
|
|
for (auto &&weak : this->channels)
|
|
|
|
if (auto shared = weak.lock())
|
|
|
|
shared->addMessage(makeSystemMessage(
|
|
|
|
QStringLiteral("Socket error: ") +
|
|
|
|
QAbstractSocket::staticMetaObject.enumerator(index)
|
|
|
|
.valueToKey(error)));
|
|
|
|
});
|
|
|
|
|
|
|
|
QObject::connect(connection, &Communi::IrcConnection::nickNameRequired,
|
|
|
|
this, [](const QString &reserved, QString *result) {
|
|
|
|
*result = reserved + (std::rand() % 100);
|
|
|
|
});
|
2019-09-18 10:58:43 +02:00
|
|
|
|
|
|
|
QObject::connect(connection, &Communi::IrcConnection::noticeMessageReceived,
|
|
|
|
this, [this](Communi::IrcNoticeMessage *message) {
|
|
|
|
MessageBuilder builder;
|
|
|
|
|
|
|
|
builder.emplace<TimestampElement>();
|
|
|
|
builder.emplace<TextElement>(
|
|
|
|
message->nick(), MessageElementFlag::Username);
|
|
|
|
builder.emplace<TextElement>(
|
|
|
|
"-> you:", MessageElementFlag::Username);
|
|
|
|
builder.emplace<TextElement>(message->content(),
|
|
|
|
MessageElementFlag::Text);
|
|
|
|
|
|
|
|
auto msg = builder.release();
|
|
|
|
|
|
|
|
for (auto &&weak : this->channels)
|
|
|
|
if (auto shared = weak.lock())
|
|
|
|
shared->addMessage(msg);
|
|
|
|
});
|
2019-09-09 22:26:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<Channel> IrcServer::createChannel(const QString &channelName)
|
|
|
|
{
|
2019-09-10 14:46:43 +02:00
|
|
|
return std::make_shared<IrcChannel>(channelName, this);
|
2019-09-09 22:26:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IrcServer::hasSeparateWriteConnection() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-09-11 13:17:36 +02:00
|
|
|
void IrcServer::onReadConnected(IrcConnection *connection)
|
|
|
|
{
|
2019-09-14 18:38:09 +02:00
|
|
|
{
|
2019-09-14 20:45:01 +02:00
|
|
|
std::lock_guard lock(this->channelMutex);
|
2019-09-14 18:38:09 +02:00
|
|
|
|
2019-09-14 20:45:01 +02:00
|
|
|
for (auto &&command : this->data_->connectCommands)
|
2019-09-11 13:17:36 +02:00
|
|
|
{
|
2019-09-14 20:45:01 +02:00
|
|
|
connection->sendRaw(command + "\r\n");
|
2019-09-11 13:17:36 +02:00
|
|
|
}
|
|
|
|
}
|
2019-09-14 20:45:01 +02:00
|
|
|
|
|
|
|
AbstractIrcServer::onReadConnected(connection);
|
2019-09-11 13:17:36 +02:00
|
|
|
}
|
|
|
|
|
2019-09-10 14:46:43 +02:00
|
|
|
void IrcServer::privateMessageReceived(Communi::IrcPrivateMessage *message)
|
|
|
|
{
|
|
|
|
auto target = message->target();
|
|
|
|
target = target.startsWith('#') ? target.mid(1) : target;
|
|
|
|
|
|
|
|
if (auto channel = this->getChannelOrEmpty(target); !channel->isEmpty())
|
|
|
|
{
|
|
|
|
MessageBuilder builder;
|
|
|
|
|
2019-09-11 13:17:36 +02:00
|
|
|
builder.emplace<TimestampElement>();
|
2019-09-10 14:46:43 +02:00
|
|
|
builder.emplace<TextElement>(message->nick() + ":",
|
|
|
|
MessageElementFlag::Username);
|
|
|
|
builder.emplace<TextElement>(message->content(),
|
|
|
|
MessageElementFlag::Text);
|
|
|
|
|
|
|
|
channel->addMessage(builder.release());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IrcServer::readConnectionMessageReceived(Communi::IrcMessage *message)
|
|
|
|
{
|
2019-09-16 18:01:32 +02:00
|
|
|
AbstractIrcServer::readConnectionMessageReceived(message);
|
|
|
|
|
2019-09-18 08:05:51 +02:00
|
|
|
switch (message->type())
|
|
|
|
{
|
|
|
|
case Communi::IrcMessage::Join:
|
|
|
|
{
|
|
|
|
auto x = static_cast<Communi::IrcJoinMessage *>(message);
|
|
|
|
|
|
|
|
if (auto it =
|
|
|
|
this->channels.find(this->cleanChannelName(x->channel()));
|
|
|
|
it != this->channels.end())
|
|
|
|
{
|
|
|
|
if (auto shared = it->lock())
|
|
|
|
{
|
|
|
|
if (message->nick() == this->data_->nick)
|
|
|
|
{
|
|
|
|
shared->addMessage(
|
|
|
|
MessageBuilder(systemMessage, "joined").release());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (auto c =
|
|
|
|
dynamic_cast<ChannelChatters *>(shared.get()))
|
|
|
|
c->addJoinedUser(x->nick());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Communi::IrcMessage::Part:
|
|
|
|
{
|
|
|
|
auto x = static_cast<Communi::IrcPartMessage *>(message);
|
|
|
|
|
|
|
|
if (auto it =
|
|
|
|
this->channels.find(this->cleanChannelName(x->channel()));
|
|
|
|
it != this->channels.end())
|
|
|
|
{
|
|
|
|
if (auto shared = it->lock())
|
|
|
|
{
|
|
|
|
if (message->nick() == this->data_->nick)
|
|
|
|
{
|
|
|
|
shared->addMessage(
|
|
|
|
MessageBuilder(systemMessage, "parted").release());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (auto c =
|
|
|
|
dynamic_cast<ChannelChatters *>(shared.get()))
|
|
|
|
c->addPartedUser(x->nick());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Communi::IrcMessage::Pong:
|
2019-09-18 10:58:43 +02:00
|
|
|
case Communi::IrcMessage::Notice:
|
2019-09-18 08:05:51 +02:00
|
|
|
return;
|
|
|
|
|
2019-09-18 11:11:50 +02:00
|
|
|
default:
|
|
|
|
if (getSettings()->showUnhandledIrcMessages)
|
|
|
|
{
|
|
|
|
MessageBuilder builder;
|
2019-09-16 18:01:32 +02:00
|
|
|
|
2019-09-18 11:11:50 +02:00
|
|
|
builder.emplace<TimestampElement>();
|
|
|
|
builder.emplace<TextElement>(message->toData(),
|
|
|
|
MessageElementFlag::Text);
|
|
|
|
builder->flags.set(MessageFlag::Debug);
|
2019-09-16 18:01:32 +02:00
|
|
|
|
2019-09-18 11:11:50 +02:00
|
|
|
auto msg = builder.release();
|
2019-09-16 18:01:32 +02:00
|
|
|
|
2019-09-18 11:11:50 +02:00
|
|
|
for (auto &&weak : this->channels)
|
|
|
|
{
|
|
|
|
if (auto shared = weak.lock())
|
|
|
|
shared->addMessage(msg);
|
|
|
|
}
|
|
|
|
};
|
2019-09-16 18:01:32 +02:00
|
|
|
}
|
2019-09-10 14:46:43 +02:00
|
|
|
}
|
|
|
|
|
2018-02-05 15:11:50 +01:00
|
|
|
} // namespace chatterino
|