diff --git a/chatterino.pro b/chatterino.pro index 0e0440690..14129b318 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -133,6 +133,7 @@ SOURCES += \ src/providers/irc/Irc2.cpp \ src/providers/irc/IrcAccount.cpp \ src/providers/irc/IrcChannel2.cpp \ + src/providers/irc/IrcCommands.cpp \ src/providers/irc/IrcConnection2.cpp \ src/providers/irc/IrcServer.cpp \ src/providers/LinkResolver.cpp \ @@ -302,6 +303,7 @@ HEADERS += \ src/providers/irc/Irc2.hpp \ src/providers/irc/IrcAccount.hpp \ src/providers/irc/IrcChannel2.hpp \ + src/providers/irc/IrcCommands.hpp \ src/providers/irc/IrcConnection2.hpp \ src/providers/irc/IrcServer.hpp \ src/providers/LinkResolver.hpp \ diff --git a/src/providers/irc/IrcChannel2.cpp b/src/providers/irc/IrcChannel2.cpp index 13c9d11b8..fd6cc82d4 100644 --- a/src/providers/irc/IrcChannel2.cpp +++ b/src/providers/irc/IrcChannel2.cpp @@ -2,6 +2,7 @@ #include "debug/AssertInGuiThread.hpp" #include "messages/MessageBuilder.hpp" +#include "providers/irc/IrcCommands.hpp" #include "providers/irc/IrcServer.hpp" namespace chatterino { @@ -17,15 +18,26 @@ void IrcChannel::sendMessage(const QString &message) { assertInGuiThread(); - if (this->server()) - this->server()->sendMessage(this->getName(), message); + if (message.startsWith("/")) + { + int index = message.indexOf(' ', 1); + QString command = message.mid(1, index - 1); + QString params = index == -1 ? "" : message.mid(index + 1); - MessageBuilder builder; - builder.emplace(); - builder.emplace(this->server()->nick() + ":", - MessageElementFlag::Username); - builder.emplace(message, MessageElementFlag::Text); - this->addMessage(builder.release()); + invokeIrcCommand(command, params, *this); + } + else + { + if (this->server()) + this->server()->sendMessage(this->getName(), message); + + MessageBuilder builder; + builder.emplace(); + builder.emplace(this->server()->nick() + ":", + MessageElementFlag::Username); + builder.emplace(message, MessageElementFlag::Text); + this->addMessage(builder.release()); + } } IrcServer *IrcChannel::server() diff --git a/src/providers/irc/IrcCommands.cpp b/src/providers/irc/IrcCommands.cpp new file mode 100644 index 000000000..87d07c8d9 --- /dev/null +++ b/src/providers/irc/IrcCommands.cpp @@ -0,0 +1,76 @@ +#include "IrcCommands.hpp" + +#include "messages/MessageBuilder.hpp" +#include "providers/irc/IrcChannel2.hpp" +#include "providers/irc/IrcServer.hpp" +#include "util/Overloaded.hpp" +#include "util/QStringHash.hpp" + +namespace chatterino { + +Outcome invokeIrcCommand(const QString &commandName, const QString &allParams, + IrcChannel &channel) +{ + if (!channel.server()) + { + return Failure; + } + + // STATIC MESSAGES + static auto staticMessages = std::unordered_map{ + {"join", "/join is not supported. Press ctrl+r to change the " + "channel. If required use /raw JOIN #channel."}, + {"part", "/part is not supported. Press ctrl+r to change the " + "channel. If required use /raw PART #channel."}, + }; + auto cmd = commandName.toLower(); + + if (auto it = staticMessages.find(cmd); it != staticMessages.end()) + { + channel.addMessage(makeSystemMessage(it->second)); + return Success; + } + + // CUSTOM COMMANDS + auto params = allParams.split(' '); + auto paramsAfter = [&](int i) { return params.mid(i + 1).join(' '); }; + + auto sendRaw = [&](QString str) { channel.server()->sendRawMessage(str); }; + + if (cmd == "msg") + { + sendRaw("PRIVMSG " + params[0] + " :" + paramsAfter(0)); + } + else if (cmd == "away") + { + sendRaw("AWAY" + params[0] + " :" + paramsAfter(0)); + } + else if (cmd == "knock") + { + sendRaw("KNOCK #" + params[0] + " " + paramsAfter(0)); + } + else if (cmd == "kick") + { + if (paramsAfter(1).isEmpty()) + sendRaw("KICK " + params[0] + " " + params[1]); + else + sendRaw("KICK " + params[0] + " " + params[1] + " :" + + paramsAfter(1)); + } + else if (cmd == "wallops") + { + sendRaw("WALLOPS :" + allParams); + } + else if (cmd == "raw") + { + sendRaw(allParams); + } + else + { + sendRaw(cmd.toUpper() + " " + allParams); + } + + return Success; +} + +} // namespace chatterino diff --git a/src/providers/irc/IrcCommands.hpp b/src/providers/irc/IrcCommands.hpp new file mode 100644 index 000000000..ffdbde023 --- /dev/null +++ b/src/providers/irc/IrcCommands.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "common/Outcome.hpp" + +namespace chatterino { + +class IrcChannel; + +Outcome invokeIrcCommand(const QString &command, const QString ¶ms, + IrcChannel &channel); + +} // namespace chatterino diff --git a/src/providers/irc/IrcServer.cpp b/src/providers/irc/IrcServer.cpp index 928796128..66e9d3f8b 100644 --- a/src/providers/irc/IrcServer.cpp +++ b/src/providers/irc/IrcServer.cpp @@ -107,6 +107,25 @@ void IrcServer::initializeConnection(IrcConnection *connection, this, [](const QString &reserved, QString *result) { *result = reserved + (std::rand() % 100); }); + + QObject::connect(connection, &Communi::IrcConnection::noticeMessageReceived, + this, [this](Communi::IrcNoticeMessage *message) { + MessageBuilder builder; + + builder.emplace(); + builder.emplace( + message->nick(), MessageElementFlag::Username); + builder.emplace( + "-> you:", MessageElementFlag::Username); + builder.emplace(message->content(), + MessageElementFlag::Text); + + auto msg = builder.release(); + + for (auto &&weak : this->channels) + if (auto shared = weak.lock()) + shared->addMessage(msg); + }); } std::shared_ptr IrcServer::createChannel(const QString &channelName) @@ -211,6 +230,7 @@ void IrcServer::readConnectionMessageReceived(Communi::IrcMessage *message) } case Communi::IrcMessage::Pong: + case Communi::IrcMessage::Notice: return; default:; diff --git a/src/widgets/dialogs/SelectChannelDialog.cpp b/src/widgets/dialogs/SelectChannelDialog.cpp index 91e9ef50e..627de694a 100644 --- a/src/widgets/dialogs/SelectChannelDialog.cpp +++ b/src/widgets/dialogs/SelectChannelDialog.cpp @@ -294,6 +294,8 @@ void SelectChannelDialog::setSelectedChannel(IndirectChannel _channel) } } } + + this->ui_.irc.channel->setFocus(); } break; default: