diff options
author | Andreas Kling <kling@serenityos.org> | 2021-08-24 16:19:08 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-08-24 16:37:28 +0200 |
commit | c9151745631a45e6511eab6ec41308414be8757b (patch) | |
tree | 4abf65599438a401031a8d1dc6badeb89607eb85 | |
parent | 97f53835259853a3060949a68326c25f4f617a0b (diff) | |
download | serenity-c9151745631a45e6511eab6ec41308414be8757b.zip |
Userland: Remove IRC Client
The IRC Client application made some sense while our main communication
hub was an IRC channel. Now that we've moved on, IRC is just a random
protocol with no particular relevance to this project.
This also has the benefit of removing one major client of the single-
process Web::InProcessWebView class.
38 files changed, 1 insertions, 2835 deletions
diff --git a/AK/Debug.h.in b/AK/Debug.h.in index 94b976fd29..bd51a04e95 100644 --- a/AK/Debug.h.in +++ b/AK/Debug.h.in @@ -218,10 +218,6 @@ #cmakedefine01 IMAGE_LOADER_DEBUG #endif -#ifndef IRC_DEBUG -#cmakedefine01 IRC_DEBUG -#endif - #ifndef ITEM_RECTS_DEBUG #cmakedefine01 ITEM_RECTS_DEBUG #endif diff --git a/Base/etc/shellrc b/Base/etc/shellrc index 0d9849171e..5700af0e0b 100644 --- a/Base/etc/shellrc +++ b/Base/etc/shellrc @@ -1,7 +1,6 @@ #!sh alias fm=FileManager -alias irc=IRCClient alias mag=Magnifier alias ms=Minesweeper alias sh=Shell diff --git a/Base/home/anon/.config/IRCClient.ini b/Base/home/anon/.config/IRCClient.ini deleted file mode 100644 index cc542335c6..0000000000 --- a/Base/home/anon/.config/IRCClient.ini +++ /dev/null @@ -1,20 +0,0 @@ -[User] -Nickname=anon_seren1ty - -[Connection] -Server=chat.freenode.net -Port=6667 -AutoJoinChannels= - -[CTCP] -VersionReply=IRC Client [x86] / Serenity OS -UserInfoReply=anon -FingerReply=anon - -[Messaging] -ShowJoinPartMessages=1 -ShowNickChangeMessages=1 - -[Notifications] -NotifyOnMessage=1 -NotifyOnMention=1 diff --git a/Base/home/anon/.config/LaunchServer.ini b/Base/home/anon/.config/LaunchServer.ini index 7c14d637a0..0c7910f136 100644 --- a/Base/home/anon/.config/LaunchServer.ini +++ b/Base/home/anon/.config/LaunchServer.ini @@ -28,4 +28,3 @@ directory=/bin/FileManager gemini=/bin/Browser http=/bin/Browser https=/bin/Browser -irc=/bin/IRCClient diff --git a/Base/res/apps/IRCClient.af b/Base/res/apps/IRCClient.af deleted file mode 100644 index 3b2ed41b50..0000000000 --- a/Base/res/apps/IRCClient.af +++ /dev/null @@ -1,7 +0,0 @@ -[App] -Name=IRC Client -Executable=/bin/IRCClient -Category=Internet - -[Launcher] -Protocols=irc diff --git a/Base/res/icons/16x16/app-irc-client.png b/Base/res/icons/16x16/app-irc-client.png Binary files differdeleted file mode 100644 index 82c1a5c273..0000000000 --- a/Base/res/icons/16x16/app-irc-client.png +++ /dev/null diff --git a/Base/res/icons/16x16/irc-close-query.png b/Base/res/icons/16x16/irc-close-query.png Binary files differdeleted file mode 100644 index ba2b405229..0000000000 --- a/Base/res/icons/16x16/irc-close-query.png +++ /dev/null diff --git a/Base/res/icons/16x16/irc-invite.png b/Base/res/icons/16x16/irc-invite.png Binary files differdeleted file mode 100644 index 727d88616e..0000000000 --- a/Base/res/icons/16x16/irc-invite.png +++ /dev/null diff --git a/Base/res/icons/16x16/irc-join.png b/Base/res/icons/16x16/irc-join.png Binary files differdeleted file mode 100644 index 3a86927805..0000000000 --- a/Base/res/icons/16x16/irc-join.png +++ /dev/null diff --git a/Base/res/icons/16x16/irc-list.png b/Base/res/icons/16x16/irc-list.png Binary files differdeleted file mode 100644 index 05d0eb35cc..0000000000 --- a/Base/res/icons/16x16/irc-list.png +++ /dev/null diff --git a/Base/res/icons/16x16/irc-nick.png b/Base/res/icons/16x16/irc-nick.png Binary files differdeleted file mode 100644 index e52da4d2f4..0000000000 --- a/Base/res/icons/16x16/irc-nick.png +++ /dev/null diff --git a/Base/res/icons/16x16/irc-open-query.png b/Base/res/icons/16x16/irc-open-query.png Binary files differdeleted file mode 100644 index b827be3a40..0000000000 --- a/Base/res/icons/16x16/irc-open-query.png +++ /dev/null diff --git a/Base/res/icons/16x16/irc-part.png b/Base/res/icons/16x16/irc-part.png Binary files differdeleted file mode 100644 index 6755f333e9..0000000000 --- a/Base/res/icons/16x16/irc-part.png +++ /dev/null diff --git a/Base/res/icons/16x16/irc-topic.png b/Base/res/icons/16x16/irc-topic.png Binary files differdeleted file mode 100644 index 56a8e08ebc..0000000000 --- a/Base/res/icons/16x16/irc-topic.png +++ /dev/null diff --git a/Base/res/icons/16x16/irc-whois.png b/Base/res/icons/16x16/irc-whois.png Binary files differdeleted file mode 100644 index 5dde6881a2..0000000000 --- a/Base/res/icons/16x16/irc-whois.png +++ /dev/null diff --git a/Base/res/icons/32x32/app-irc-client.png b/Base/res/icons/32x32/app-irc-client.png Binary files differdeleted file mode 100644 index 8a9abb8c1a..0000000000 --- a/Base/res/icons/32x32/app-irc-client.png +++ /dev/null diff --git a/Meta/CMake/all_the_debug_macros.cmake b/Meta/CMake/all_the_debug_macros.cmake index 0bb7a3694b..7ce59d775a 100644 --- a/Meta/CMake/all_the_debug_macros.cmake +++ b/Meta/CMake/all_the_debug_macros.cmake @@ -86,7 +86,6 @@ set(IOAPIC_DEBUG ON) set(IO_DEBUG ON) set(IPV4_DEBUG ON) set(IPV4_SOCKET_DEBUG ON) -set(IRC_DEBUG ON) set(IRQ_DEBUG ON) set(ISO9660_DEBUG ON) set(ISO9660_VERY_DEBUG ON) @@ -81,7 +81,6 @@ I'm also on [Patreon](https://www.patreon.com/serenityos) and [GitHub Sponsors]( * On-line help system (both terminal and GUI variants) * Web browser (Browser) * C++ IDE (HackStudio) -* IRC client * Desktop synthesizer (Piano) * E-mail client (Mail) * Various desktop apps & games diff --git a/Userland/Applications/CMakeLists.txt b/Userland/Applications/CMakeLists.txt index a9bed10c45..2af39f0b82 100644 --- a/Userland/Applications/CMakeLists.txt +++ b/Userland/Applications/CMakeLists.txt @@ -12,7 +12,6 @@ add_subdirectory(FileManager) add_subdirectory(FontEditor) add_subdirectory(Help) add_subdirectory(HexEditor) -add_subdirectory(IRCClient) add_subdirectory(ImageViewer) add_subdirectory(KeyboardMapper) add_subdirectory(KeyboardSettings) diff --git a/Userland/Applications/IRCClient/CMakeLists.txt b/Userland/Applications/IRCClient/CMakeLists.txt deleted file mode 100644 index 73dd4534ae..0000000000 --- a/Userland/Applications/IRCClient/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -serenity_component( - IRCClient - TARGETS IRCClient -) - -set(SOURCES - IRCAppWindow.cpp - IRCChannel.cpp - IRCChannelMemberListModel.cpp - IRCClient.cpp - IRCLogBuffer.cpp - IRCQuery.cpp - IRCWindow.cpp - IRCWindowListModel.cpp - main.cpp -) - -serenity_app(IRCClient ICON app-irc-client) -target_link_libraries(IRCClient LibWeb LibGUI) diff --git a/Userland/Applications/IRCClient/IRCAppWindow.cpp b/Userland/Applications/IRCClient/IRCAppWindow.cpp deleted file mode 100644 index ec64224a0d..0000000000 --- a/Userland/Applications/IRCClient/IRCAppWindow.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "IRCAppWindow.h" -#include "IRCChannel.h" -#include "IRCWindow.h" -#include "IRCWindowListModel.h" -#include <LibGUI/Action.h> -#include <LibGUI/Application.h> -#include <LibGUI/BoxLayout.h> -#include <LibGUI/InputBox.h> -#include <LibGUI/Menu.h> -#include <LibGUI/Menubar.h> -#include <LibGUI/Splitter.h> -#include <LibGUI/StackWidget.h> -#include <LibGUI/TableView.h> -#include <LibGUI/Toolbar.h> -#include <LibGUI/ToolbarContainer.h> - -static IRCAppWindow* s_the; - -IRCAppWindow& IRCAppWindow::the() -{ - return *s_the; -} - -IRCAppWindow::IRCAppWindow(String server, int port) - : m_client(IRCClient::construct(server, port)) -{ - VERIFY(!s_the); - s_the = this; - - set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/app-irc-client.png")); - - update_title(); - resize(600, 400); - setup_actions(); - setup_menus(); - setup_widgets(); - - setup_client(); -} - -IRCAppWindow::~IRCAppWindow() -{ -} - -void IRCAppWindow::update_title() -{ - set_title(String::formatted("{}@{}:{} - IRC Client", m_client->nickname(), m_client->hostname(), m_client->port())); -} - -void IRCAppWindow::setup_client() -{ - m_client->aid_create_window = [this](void* owner, IRCWindow::Type type, const String& name) { - return create_window(owner, type, name); - }; - m_client->aid_get_active_window = [this] { - return static_cast<IRCWindow*>(m_container->active_widget()); - }; - m_client->aid_update_window_list = [this] { - m_window_list->model()->invalidate(); - }; - m_client->on_nickname_changed = [this](const String&) { - update_title(); - }; - m_client->on_part_from_channel = [this](auto&) { - update_gui_actions(); - }; - - if (m_client->hostname().is_empty()) { - String value; - if (GUI::InputBox::show(this, value, "Enter server:", "Connect to server") == GUI::InputBox::ExecCancel) { - GUI::Application::the()->quit(); - return; - } - - m_client->set_server(value, 6667); - } - update_title(); - bool success = m_client->connect(); - VERIFY(success); -} - -void IRCAppWindow::setup_actions() -{ - m_join_action = GUI::Action::create("&Join Channel...", { Mod_Ctrl, Key_J }, Gfx::Bitmap::try_load_from_file("/res/icons/16x16/irc-join.png"), [&](auto&) { - String value; - if (GUI::InputBox::show(this, value, "Enter channel name:", "Join Channel") == GUI::InputBox::ExecOK && !value.is_empty()) - m_client->handle_join_action(value); - }); - - m_list_channels_action = GUI::Action::create("&List Channels", Gfx::Bitmap::try_load_from_file("/res/icons/16x16/irc-list.png"), [&](auto&) { - m_client->handle_list_channels_action(); - }); - - m_part_action = GUI::Action::create("&Part from Channel", { Mod_Ctrl, Key_P }, Gfx::Bitmap::try_load_from_file("/res/icons/16x16/irc-part.png"), [this](auto&) { - auto* window = m_client->current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) { - return; - } - m_client->handle_part_action(window->channel().name()); - }); - - m_whois_action = GUI::Action::create("&Whois User...", Gfx::Bitmap::try_load_from_file("/res/icons/16x16/irc-whois.png"), [&](auto&) { - String value; - if (GUI::InputBox::show(this, value, "Enter nickname:", "Whois User") == GUI::InputBox::ExecOK && !value.is_empty()) - m_client->handle_whois_action(value); - }); - - m_open_query_action = GUI::Action::create("Open &Query...", { Mod_Ctrl, Key_O }, Gfx::Bitmap::try_load_from_file("/res/icons/16x16/irc-open-query.png"), [&](auto&) { - String value; - if (GUI::InputBox::show(this, value, "Enter nickname:", "Open Query") == GUI::InputBox::ExecOK && !value.is_empty()) - m_client->handle_open_query_action(value); - }); - - m_close_query_action = GUI::Action::create("&Close Query", { Mod_Ctrl, Key_D }, Gfx::Bitmap::try_load_from_file("/res/icons/16x16/irc-close-query.png"), [](auto&) { - outln("FIXME: Implement close-query action"); - }); - - m_change_nick_action = GUI::Action::create("Change &Nickname...", Gfx::Bitmap::try_load_from_file("/res/icons/16x16/irc-nick.png"), [this](auto&) { - String value; - if (GUI::InputBox::show(this, value, "Enter nickname:", "Change Nickname") == GUI::InputBox::ExecOK && !value.is_empty()) - m_client->handle_change_nick_action(value); - }); - - m_change_topic_action = GUI::Action::create("Change &Topic...", Gfx::Bitmap::try_load_from_file("/res/icons/16x16/irc-topic.png"), [this](auto&) { - auto* window = m_client->current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) { - return; - } - String value; - if (GUI::InputBox::show(this, value, "Enter topic:", "Change Topic") == GUI::InputBox::ExecOK && !value.is_empty()) - m_client->handle_change_topic_action(window->channel().name(), value); - }); - - m_invite_user_action = GUI::Action::create("&Invite User...", Gfx::Bitmap::try_load_from_file("/res/icons/16x16/irc-invite.png"), [this](auto&) { - auto* window = m_client->current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) { - return; - } - String value; - if (GUI::InputBox::show(this, value, "Enter nick:", "Invite User") == GUI::InputBox::ExecOK && !value.is_empty()) - m_client->handle_invite_user_action(window->channel().name(), value); - }); - - m_banlist_action = GUI::Action::create("&Ban List", [this](auto&) { - auto* window = m_client->current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) { - return; - } - m_client->handle_banlist_action(window->channel().name()); - }); - - m_voice_user_action = GUI::Action::create("&Voice User...", [this](auto&) { - auto* window = m_client->current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) { - return; - } - String value; - if (GUI::InputBox::show(this, value, "Enter nick:", "Voice User") == GUI::InputBox::ExecOK && !value.is_empty()) - m_client->handle_voice_user_action(window->channel().name(), value); - }); - - m_devoice_user_action = GUI::Action::create("DeVoice User...", [this](auto&) { - auto* window = m_client->current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) { - return; - } - String value; - if (GUI::InputBox::show(this, value, "Enter nick:", "DeVoice user") == GUI::InputBox::ExecOK && !value.is_empty()) - m_client->handle_devoice_user_action(window->channel().name(), value); - }); - - m_hop_user_action = GUI::Action::create("Hop User", [this](auto&) { - auto* window = m_client->current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) { - return; - } - String value; - if (GUI::InputBox::show(this, value, "Enter nick:", "Hop User") == GUI::InputBox::ExecOK && !value.is_empty()) - m_client->handle_hop_user_action(window->channel().name(), value); - }); - - m_dehop_user_action = GUI::Action::create("DeHop User", [this](auto&) { - auto* window = m_client->current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) { - return; - } - String value; - if (GUI::InputBox::show(this, value, "Enter nick:", "DeHop User") == GUI::InputBox::ExecOK && !value.is_empty()) - m_client->handle_dehop_user_action(window->channel().name(), value); - }); - - m_op_user_action = GUI::Action::create("&Op User", [this](auto&) { - auto* window = m_client->current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) { - return; - } - String value; - if (GUI::InputBox::show(this, value, "Enter nick:", "Op User") == GUI::InputBox::ExecOK && !value.is_empty()) - m_client->handle_op_user_action(window->channel().name(), value); - }); - - m_deop_user_action = GUI::Action::create("DeOp user", [this](auto&) { - auto* window = m_client->current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) { - return; - } - String value; - if (GUI::InputBox::show(this, value, "Enter nick:", "DeOp User") == GUI::InputBox::ExecOK && !value.is_empty()) - m_client->handle_deop_user_action(window->channel().name(), value); - }); - - m_kick_user_action = GUI::Action::create("&Kick User", [this](auto&) { - auto* window = m_client->current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) { - return; - } - String nick_value; - if (GUI::InputBox::show(this, nick_value, "Enter nick:", "Kick User") != GUI::InputBox::ExecOK || nick_value.is_empty()) - return; - String reason_value; - if (GUI::InputBox::show(this, reason_value, "Enter reason:", "Reason") == GUI::InputBox::ExecOK) - m_client->handle_kick_user_action(window->channel().name(), nick_value, reason_value.characters()); - }); - - m_cycle_channel_action = GUI::Action::create("C&ycle Channel", [this](auto&) { - auto* window = m_client->current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) { - return; - } - m_client->handle_cycle_channel_action(window->channel().name()); - }); -} - -void IRCAppWindow::setup_menus() -{ - auto& file_menu = add_menu("&File"); - file_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) { - GUI::Application::the()->quit(); - })); - - auto& server_menu = add_menu("&Server"); - server_menu.add_action(*m_change_nick_action); - server_menu.add_separator(); - server_menu.add_action(*m_join_action); - server_menu.add_action(*m_list_channels_action); - server_menu.add_separator(); - server_menu.add_action(*m_whois_action); - server_menu.add_action(*m_open_query_action); - server_menu.add_action(*m_close_query_action); - - auto& channel_menu = add_menu("&Channel"); - channel_menu.add_action(*m_change_topic_action); - channel_menu.add_action(*m_invite_user_action); - channel_menu.add_action(*m_banlist_action); - - auto& channel_control_menu = channel_menu.add_submenu("Con&trol"); - channel_control_menu.add_action(*m_voice_user_action); - channel_control_menu.add_action(*m_devoice_user_action); - channel_control_menu.add_action(*m_hop_user_action); - channel_control_menu.add_action(*m_dehop_user_action); - channel_control_menu.add_action(*m_op_user_action); - channel_control_menu.add_action(*m_deop_user_action); - channel_control_menu.add_separator(); - channel_control_menu.add_action(*m_kick_user_action); - - channel_menu.add_separator(); - channel_menu.add_action(*m_cycle_channel_action); - channel_menu.add_action(*m_part_action); - - auto& help_menu = add_menu("&Help"); - help_menu.add_action(GUI::CommonActions::make_about_action("IRC Client", GUI::Icon::default_icon("app-irc-client"), this)); -} - -void IRCAppWindow::setup_widgets() -{ - auto& widget = set_main_widget<GUI::Widget>(); - widget.set_fill_with_background_color(true); - widget.set_layout<GUI::VerticalBoxLayout>(); - widget.layout()->set_spacing(0); - - auto& toolbar_container = widget.add<GUI::ToolbarContainer>(); - auto& toolbar = toolbar_container.add<GUI::Toolbar>(); - toolbar.set_has_frame(false); - toolbar.add_action(*m_change_nick_action); - toolbar.add_separator(); - toolbar.add_action(*m_join_action); - toolbar.add_action(*m_part_action); - toolbar.add_separator(); - toolbar.add_action(*m_whois_action); - toolbar.add_action(*m_open_query_action); - toolbar.add_action(*m_close_query_action); - - auto& outer_container = widget.add<GUI::Widget>(); - outer_container.set_layout<GUI::VerticalBoxLayout>(); - outer_container.layout()->set_margins({ 0, 2, 2 }); - - auto& horizontal_container = outer_container.add<GUI::HorizontalSplitter>(); - - m_window_list = horizontal_container.add<GUI::TableView>(); - m_window_list->set_column_headers_visible(false); - m_window_list->set_alternating_row_colors(false); - m_window_list->set_model(m_client->client_window_list_model()); - m_window_list->set_activates_on_selection(true); - m_window_list->set_fixed_width(100); - m_window_list->on_activation = [this](auto& index) { - set_active_window(m_client->window_at(index.row())); - }; - - m_container = horizontal_container.add<GUI::StackWidget>(); - m_container->on_active_widget_change = [this](auto*) { - update_gui_actions(); - }; - - create_window(&m_client, IRCWindow::Server, "Server"); -} - -void IRCAppWindow::set_active_window(IRCWindow& window) -{ - m_container->set_active_widget(&window); - window.clear_unread_count(); - auto index = m_window_list->model()->index(m_client->window_index(window)); - m_window_list->selection().set(index); -} - -void IRCAppWindow::update_gui_actions() -{ - auto* window = static_cast<IRCWindow*>(m_container->active_widget()); - bool is_open_channel = window && window->type() == IRCWindow::Type::Channel && window->channel().is_open(); - m_change_topic_action->set_enabled(is_open_channel); - m_invite_user_action->set_enabled(is_open_channel); - m_banlist_action->set_enabled(is_open_channel); - m_voice_user_action->set_enabled(is_open_channel); - m_devoice_user_action->set_enabled(is_open_channel); - m_hop_user_action->set_enabled(is_open_channel); - m_dehop_user_action->set_enabled(is_open_channel); - m_op_user_action->set_enabled(is_open_channel); - m_deop_user_action->set_enabled(is_open_channel); - m_kick_user_action->set_enabled(is_open_channel); - m_cycle_channel_action->set_enabled(is_open_channel); - m_part_action->set_enabled(is_open_channel); -} - -NonnullRefPtr<IRCWindow> IRCAppWindow::create_window(void* owner, IRCWindow::Type type, const String& name) -{ - return m_container->add<IRCWindow>(m_client, owner, type, name); -} diff --git a/Userland/Applications/IRCClient/IRCAppWindow.h b/Userland/Applications/IRCClient/IRCAppWindow.h deleted file mode 100644 index 79be0a0538..0000000000 --- a/Userland/Applications/IRCClient/IRCAppWindow.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "IRCClient.h" -#include "IRCWindow.h" -#include <LibGUI/Widget.h> -#include <LibGUI/Window.h> - -class IRCAppWindow : public GUI::Window { - C_OBJECT(IRCAppWindow); - -public: - virtual ~IRCAppWindow() override; - - static IRCAppWindow& the(); - - void set_active_window(IRCWindow&); - -private: - IRCAppWindow(String server, int port); - - void setup_client(); - void setup_actions(); - void setup_menus(); - void setup_widgets(); - void update_title(); - void update_gui_actions(); - - NonnullRefPtr<IRCWindow> create_window(void* owner, IRCWindow::Type, const String& name); - NonnullRefPtr<IRCClient> m_client; - RefPtr<GUI::StackWidget> m_container; - RefPtr<GUI::TableView> m_window_list; - RefPtr<GUI::Action> m_join_action; - RefPtr<GUI::Action> m_list_channels_action; - RefPtr<GUI::Action> m_part_action; - RefPtr<GUI::Action> m_cycle_channel_action; - RefPtr<GUI::Action> m_whois_action; - RefPtr<GUI::Action> m_open_query_action; - RefPtr<GUI::Action> m_close_query_action; - RefPtr<GUI::Action> m_change_nick_action; - RefPtr<GUI::Action> m_change_topic_action; - RefPtr<GUI::Action> m_invite_user_action; - RefPtr<GUI::Action> m_banlist_action; - RefPtr<GUI::Action> m_voice_user_action; - RefPtr<GUI::Action> m_devoice_user_action; - RefPtr<GUI::Action> m_hop_user_action; - RefPtr<GUI::Action> m_dehop_user_action; - RefPtr<GUI::Action> m_op_user_action; - RefPtr<GUI::Action> m_deop_user_action; - RefPtr<GUI::Action> m_kick_user_action; -}; diff --git a/Userland/Applications/IRCClient/IRCChannel.cpp b/Userland/Applications/IRCClient/IRCChannel.cpp deleted file mode 100644 index 7606b05a1f..0000000000 --- a/Userland/Applications/IRCClient/IRCChannel.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "IRCChannel.h" -#include "IRCChannelMemberListModel.h" -#include "IRCClient.h" - -IRCChannel::IRCChannel(IRCClient& client, const String& name) - : m_client(client) - , m_name(name) - , m_log(IRCLogBuffer::create()) - , m_member_model(IRCChannelMemberListModel::create(*this)) -{ - m_window = m_client.aid_create_window(this, IRCWindow::Channel, m_name); - m_window->set_log_buffer(*m_log); -} - -IRCChannel::~IRCChannel() -{ -} - -NonnullRefPtr<IRCChannel> IRCChannel::create(IRCClient& client, const String& name) -{ - return adopt_ref(*new IRCChannel(client, name)); -} - -void IRCChannel::add_member(const String& name, char prefix) -{ - for (auto& member : m_members) { - if (member.name == name) { - member.prefix = prefix; - return; - } - } - m_members.append({ name, prefix }); - m_member_model->invalidate(); -} - -void IRCChannel::remove_member(const String& name) -{ - m_members.remove_first_matching([&](auto& member) { return name == member.name; }); -} - -void IRCChannel::add_message(char prefix, const String& name, const String& text, Color color) -{ - log().add_message(prefix, name, text, color); - window().did_add_message(name, text); -} - -void IRCChannel::add_message(const String& text, Color color) -{ - log().add_message(text, color); - window().did_add_message(); -} - -void IRCChannel::say(const String& text) -{ - m_client.send_privmsg(m_name, text); - add_message(' ', m_client.nickname(), text); -} - -void IRCChannel::handle_join(const String& nick, const String& hostmask) -{ - if (nick == m_client.nickname()) { - m_open = true; - return; - } - add_member(nick, (char)0); - m_member_model->invalidate(); - if (m_client.show_join_part_messages()) - add_message(String::formatted("*** {} [{}] has joined {}", nick, hostmask, m_name), Color::MidGreen); -} - -void IRCChannel::handle_part(const String& nick, const String& hostmask) -{ - if (nick == m_client.nickname()) { - m_open = false; - m_members.clear(); - m_client.did_part_from_channel({}, *this); - } else { - remove_member(nick); - } - m_member_model->invalidate(); - if (m_client.show_join_part_messages()) - add_message(String::formatted("*** {} [{}] has parted from {}", nick, hostmask, m_name), Color::MidGreen); -} - -void IRCChannel::handle_quit(const String& nick, const String& hostmask, const String& message) -{ - if (nick == m_client.nickname()) { - m_open = false; - m_members.clear(); - m_client.did_part_from_channel({}, *this); - } else { - remove_member(nick); - } - m_member_model->invalidate(); - add_message(String::formatted("*** {} [{}] has quit ({})", nick, hostmask, message), Color::MidGreen); -} - -void IRCChannel::handle_topic(const String& nick, const String& topic) -{ - if (nick.is_null()) - add_message(String::formatted("*** Topic is \"{}\"", topic), Color::MidBlue); - else - add_message(String::formatted("*** {} set topic to \"{}\"", nick, topic), Color::MidBlue); -} - -void IRCChannel::notify_nick_changed(const String& old_nick, const String& new_nick) -{ - for (auto& member : m_members) { - if (member.name == old_nick) { - member.name = new_nick; - m_member_model->invalidate(); - if (m_client.show_nick_change_messages()) - add_message(String::formatted("~ {} changed nickname to {}", old_nick, new_nick), Color::MidMagenta); - return; - } - } -} diff --git a/Userland/Applications/IRCClient/IRCChannel.h b/Userland/Applications/IRCClient/IRCChannel.h deleted file mode 100644 index aebea43862..0000000000 --- a/Userland/Applications/IRCClient/IRCChannel.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "IRCLogBuffer.h" -#include <AK/RefCounted.h> -#include <AK/RefPtr.h> -#include <AK/String.h> -#include <AK/Vector.h> - -class IRCClient; -class IRCChannelMemberListModel; -class IRCWindow; - -class IRCChannel : public RefCounted<IRCChannel> { -public: - static NonnullRefPtr<IRCChannel> create(IRCClient&, const String&); - ~IRCChannel(); - - bool is_open() const { return m_open; } - void set_open(bool b) { m_open = b; } - - String name() const { return m_name; } - - void add_member(const String& name, char prefix); - void remove_member(const String& name); - - void add_message(char prefix, const String& name, const String& text, Color = Color::Black); - void add_message(const String& text, Color = Color::Black); - - void say(const String&); - - const IRCLogBuffer& log() const { return *m_log; } - IRCLogBuffer& log() { return *m_log; } - - IRCChannelMemberListModel* member_model() { return m_member_model.ptr(); } - const IRCChannelMemberListModel* member_model() const { return m_member_model.ptr(); } - - int member_count() const { return m_members.size(); } - String member_at(int i) { return m_members[i].name; } - - void handle_join(const String& nick, const String& hostmask); - void handle_part(const String& nick, const String& hostmask); - void handle_quit(const String& nick, const String& hostmask, const String& message); - void handle_topic(const String& nick, const String& topic); - - IRCWindow& window() { return *m_window; } - const IRCWindow& window() const { return *m_window; } - - String topic() const { return m_topic; } - - void notify_nick_changed(const String& old_nick, const String& new_nick); - -private: - IRCChannel(IRCClient&, const String&); - - IRCClient& m_client; - String m_name; - String m_topic; - struct Member { - String name; - char prefix { 0 }; - }; - Vector<Member> m_members; - bool m_open { false }; - - NonnullRefPtr<IRCLogBuffer> m_log; - NonnullRefPtr<IRCChannelMemberListModel> m_member_model; - IRCWindow* m_window { nullptr }; -}; diff --git a/Userland/Applications/IRCClient/IRCChannelMemberListModel.cpp b/Userland/Applications/IRCClient/IRCChannelMemberListModel.cpp deleted file mode 100644 index 3dbd0997d0..0000000000 --- a/Userland/Applications/IRCClient/IRCChannelMemberListModel.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "IRCChannelMemberListModel.h" -#include "IRCChannel.h" -#include <stdio.h> -#include <time.h> - -IRCChannelMemberListModel::IRCChannelMemberListModel(IRCChannel& channel) - : m_channel(channel) -{ -} - -IRCChannelMemberListModel::~IRCChannelMemberListModel() -{ -} - -int IRCChannelMemberListModel::row_count(const GUI::ModelIndex&) const -{ - return m_channel.member_count(); -} - -int IRCChannelMemberListModel::column_count(const GUI::ModelIndex&) const -{ - return 1; -} - -String IRCChannelMemberListModel::column_name(int column) const -{ - switch (column) { - case Column::Name: - return "Name"; - } - VERIFY_NOT_REACHED(); -} - -GUI::Variant IRCChannelMemberListModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const -{ - if (role == GUI::ModelRole::TextAlignment) - return Gfx::TextAlignment::CenterLeft; - if (role == GUI::ModelRole::Display) { - switch (index.column()) { - case Column::Name: - return m_channel.member_at(index.row()); - } - } - return {}; -} - -String IRCChannelMemberListModel::nick_at(const GUI::ModelIndex& index) const -{ - return data(index, GUI::ModelRole::Display).to_string(); -} diff --git a/Userland/Applications/IRCClient/IRCChannelMemberListModel.h b/Userland/Applications/IRCClient/IRCChannelMemberListModel.h deleted file mode 100644 index 12ca9ca739..0000000000 --- a/Userland/Applications/IRCClient/IRCChannelMemberListModel.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <AK/Function.h> -#include <LibGUI/Model.h> - -class IRCChannel; - -class IRCChannelMemberListModel final : public GUI::Model { -public: - enum Column { - Name - }; - static NonnullRefPtr<IRCChannelMemberListModel> create(IRCChannel& channel) { return adopt_ref(*new IRCChannelMemberListModel(channel)); } - virtual ~IRCChannelMemberListModel() override; - - virtual int row_count(const GUI::ModelIndex&) const override; - virtual int column_count(const GUI::ModelIndex&) const override; - virtual String column_name(int column) const override; - virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override; - virtual String nick_at(const GUI::ModelIndex& index) const; - -private: - explicit IRCChannelMemberListModel(IRCChannel&); - - IRCChannel& m_channel; -}; diff --git a/Userland/Applications/IRCClient/IRCClient.cpp b/Userland/Applications/IRCClient/IRCClient.cpp deleted file mode 100644 index fc92f2f7bb..0000000000 --- a/Userland/Applications/IRCClient/IRCClient.cpp +++ /dev/null @@ -1,1164 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "IRCClient.h" -#include "IRCAppWindow.h" -#include "IRCChannel.h" -#include "IRCLogBuffer.h" -#include "IRCQuery.h" -#include "IRCWindow.h" -#include "IRCWindowListModel.h" -#include <AK/Debug.h> -#include <AK/QuickSort.h> -#include <AK/StringBuilder.h> -#include <LibCore/DateTime.h> -#include <LibCore/Notifier.h> -#include <pwd.h> -#include <stdio.h> -#include <strings.h> -#include <unistd.h> - -enum IRCNumeric { - RPL_WELCOME = 1, - RPL_WHOISUSER = 311, - RPL_WHOISSERVER = 312, - RPL_WHOISOPERATOR = 313, - RPL_ENDOFWHO = 315, - RPL_WHOISIDLE = 317, - RPL_ENDOFWHOIS = 318, - RPL_WHOISCHANNELS = 319, - RPL_TOPIC = 332, - RPL_TOPICWHOTIME = 333, - RPL_NAMREPLY = 353, - RPL_ENDOFNAMES = 366, - RPL_BANLIST = 367, - RPL_ENDOFBANLIST = 368, - RPL_ENDOFWHOWAS = 369, - RPL_ENDOFMOTD = 376, - ERR_NOSUCHNICK = 401, - ERR_UNKNOWNCOMMAND = 421, - ERR_NICKNAMEINUSE = 433, -}; - -IRCClient::IRCClient(String server, int port) - : m_nickname("seren1ty") - , m_client_window_list_model(IRCWindowListModel::create(*this)) - , m_log(IRCLogBuffer::create()) - , m_config(Core::ConfigFile::open_for_app("IRCClient", Core::ConfigFile::AllowWriting::Yes)) -{ - struct passwd* user_pw = getpwuid(getuid()); - m_socket = Core::TCPSocket::construct(this); - m_nickname = m_config->read_entry("User", "Nickname", String::formatted("{}_seren1ty", user_pw->pw_name)); - - if (server.is_empty()) { - m_hostname = m_config->read_entry("Connection", "Server", ""); - m_port = m_config->read_num_entry("Connection", "Port", 6667); - } else { - m_hostname = server; - m_port = port ? port : 6667; - } - - m_show_join_part_messages = m_config->read_bool_entry("Messaging", "ShowJoinPartMessages", 1); - m_show_nick_change_messages = m_config->read_bool_entry("Messaging", "ShowNickChangeMessages", 1); - - m_notify_on_message = m_config->read_bool_entry("Notifications", "NotifyOnMessage", 1); - m_notify_on_mention = m_config->read_bool_entry("Notifications", "NotifyOnMention", 1); - - m_ctcp_version_reply = m_config->read_entry("CTCP", "VersionReply", "IRC Client [x86] / Serenity OS"); - m_ctcp_userinfo_reply = m_config->read_entry("CTCP", "UserInfoReply", user_pw->pw_name); - m_ctcp_finger_reply = m_config->read_entry("CTCP", "FingerReply", user_pw->pw_name); -} - -IRCClient::~IRCClient() -{ -} - -void IRCClient::set_server(const String& hostname, int port) -{ - m_hostname = hostname; - m_port = port; - m_config->write_entry("Connection", "Server", hostname); - m_config->write_num_entry("Connection", "Port", port); - m_config->sync(); -} - -void IRCClient::on_socket_connected() -{ - m_notifier = Core::Notifier::construct(m_socket->fd(), Core::Notifier::Read); - m_notifier->on_ready_to_read = [this] { receive_from_server(); }; - - send_user(); - send_nick(); -} - -bool IRCClient::connect() -{ - if (m_socket->is_connected()) - VERIFY_NOT_REACHED(); - - m_socket->on_connected = [this] { on_socket_connected(); }; - - return m_socket->connect(m_hostname, m_port); -} - -void IRCClient::receive_from_server() -{ - while (m_socket->can_read_line()) { - auto line = m_socket->read_line(); - if (line.is_null()) { - if (!m_socket->is_connected()) { - outln("IRCClient: Connection closed!"); - exit(1); - } - VERIFY_NOT_REACHED(); - } - process_line(line); - } -} - -void IRCClient::process_line(const String& line) -{ - Message msg; - Vector<char, 32> prefix; - Vector<char, 32> command; - Vector<char, 256> current_parameter; - enum { - Start, - InPrefix, - InCommand, - InStartOfParameter, - InParameter, - InTrailingParameter, - } state - = Start; - - for (size_t i = 0; i < line.length(); ++i) { - char ch = line[i]; - if (ch == '\r') - continue; - if (ch == '\n') - break; - switch (state) { - case Start: - if (ch == ':') { - state = InPrefix; - continue; - } - state = InCommand; - [[fallthrough]]; - case InCommand: - if (ch == ' ') { - state = InStartOfParameter; - continue; - } - command.append(ch); - continue; - case InPrefix: - if (ch == ' ') { - state = InCommand; - continue; - } - prefix.append(ch); - continue; - case InStartOfParameter: - if (ch == ':') { - state = InTrailingParameter; - continue; - } - state = InParameter; - [[fallthrough]]; - case InParameter: - if (ch == ' ') { - if (!current_parameter.is_empty()) - msg.arguments.append(String(current_parameter.data(), current_parameter.size())); - current_parameter.clear_with_capacity(); - state = InStartOfParameter; - continue; - } - current_parameter.append(ch); - continue; - case InTrailingParameter: - current_parameter.append(ch); - continue; - } - } - if (!current_parameter.is_empty()) - msg.arguments.append(String::copy(current_parameter)); - msg.prefix = String::copy(prefix); - msg.command = String::copy(command); - handle(msg); -} - -void IRCClient::send(const String& text) -{ - if (!m_socket->send(text.bytes())) { - perror("send"); - exit(1); - } -} - -void IRCClient::send_user() -{ - send(String::formatted("USER {} 0 * :{}\r\n", m_nickname, m_nickname)); -} - -void IRCClient::send_nick() -{ - send(String::formatted("NICK {}\r\n", m_nickname)); -} - -void IRCClient::send_pong(const String& server) -{ - send(String::formatted("PONG {}\r\n", server)); - sleep(1); -} - -void IRCClient::join_channel(const String& channel_name) -{ - send(String::formatted("JOIN {}\r\n", channel_name)); -} - -void IRCClient::part_channel(const String& channel_name) -{ - send(String::formatted("PART {}\r\n", channel_name)); -} - -void IRCClient::send_whois(const String& nick) -{ - send(String::formatted("WHOIS {}\r\n", nick)); -} - -void IRCClient::handle(const Message& msg) -{ - if constexpr (IRC_DEBUG) { - outln("IRCClient::execute: prefix='{}', command='{}', arguments={}", - msg.prefix, - msg.command, - msg.arguments.size()); - - size_t index = 0; - for (auto& arg : msg.arguments) - outln(" [{}]: {}", index++, arg); - } - - auto numeric = msg.command.to_uint(); - - if (numeric.has_value()) { - switch (numeric.value()) { - case RPL_WELCOME: - return handle_rpl_welcome(msg); - case RPL_WHOISCHANNELS: - return handle_rpl_whoischannels(msg); - case RPL_ENDOFWHO: - return handle_rpl_endofwho(msg); - case RPL_ENDOFWHOIS: - return handle_rpl_endofwhois(msg); - case RPL_ENDOFWHOWAS: - return handle_rpl_endofwhowas(msg); - case RPL_ENDOFMOTD: - return handle_rpl_endofmotd(msg); - case RPL_WHOISOPERATOR: - return handle_rpl_whoisoperator(msg); - case RPL_WHOISSERVER: - return handle_rpl_whoisserver(msg); - case RPL_WHOISUSER: - return handle_rpl_whoisuser(msg); - case RPL_WHOISIDLE: - return handle_rpl_whoisidle(msg); - case RPL_TOPICWHOTIME: - return handle_rpl_topicwhotime(msg); - case RPL_TOPIC: - return handle_rpl_topic(msg); - case RPL_NAMREPLY: - return handle_rpl_namreply(msg); - case RPL_ENDOFNAMES: - return handle_rpl_endofnames(msg); - case RPL_BANLIST: - return handle_rpl_banlist(msg); - case RPL_ENDOFBANLIST: - return handle_rpl_endofbanlist(msg); - case ERR_NOSUCHNICK: - return handle_err_nosuchnick(msg); - case ERR_UNKNOWNCOMMAND: - return handle_err_unknowncommand(msg); - case ERR_NICKNAMEINUSE: - return handle_err_nicknameinuse(msg); - } - } - - if (msg.command == "PING") - return handle_ping(msg); - - if (msg.command == "JOIN") - return handle_join(msg); - - if (msg.command == "PART") - return handle_part(msg); - - if (msg.command == "QUIT") - return handle_quit(msg); - - if (msg.command == "TOPIC") - return handle_topic(msg); - - if (msg.command == "PRIVMSG") - return handle_privmsg_or_notice(msg, PrivmsgOrNotice::Privmsg); - - if (msg.command == "NOTICE") - return handle_privmsg_or_notice(msg, PrivmsgOrNotice::Notice); - - if (msg.command == "NICK") - return handle_nick(msg); - - if (msg.arguments.size() >= 2) - add_server_message(String::formatted("[{}] {}", msg.command, msg.arguments[1])); -} - -void IRCClient::add_server_message(const String& text, Color color) -{ - m_log->add_message(0, "", text, color); - m_server_subwindow->did_add_message(); -} - -void IRCClient::send_topic(const String& channel_name, const String& text) -{ - send(String::formatted("TOPIC {} :{}\r\n", channel_name, text)); -} - -void IRCClient::send_invite(const String& channel_name, const String& nick) -{ - send(String::formatted("INVITE {} {}\r\n", nick, channel_name)); -} - -void IRCClient::send_banlist(const String& channel_name) -{ - send(String::formatted("MODE {} +b\r\n", channel_name)); -} - -void IRCClient::send_voice_user(const String& channel_name, const String& nick) -{ - send(String::formatted("MODE {} +v {}\r\n", channel_name, nick)); -} - -void IRCClient::send_devoice_user(const String& channel_name, const String& nick) -{ - send(String::formatted("MODE {} -v {}\r\n", channel_name, nick)); -} - -void IRCClient::send_hop_user(const String& channel_name, const String& nick) -{ - send(String::formatted("MODE {} +h {}\r\n", channel_name, nick)); -} - -void IRCClient::send_dehop_user(const String& channel_name, const String& nick) -{ - send(String::formatted("MODE {} -h {}\r\n", channel_name, nick)); -} - -void IRCClient::send_op_user(const String& channel_name, const String& nick) -{ - send(String::formatted("MODE {} +o {}\r\n", channel_name, nick)); -} - -void IRCClient::send_deop_user(const String& channel_name, const String& nick) -{ - send(String::formatted("MODE {} -o {}\r\n", channel_name, nick)); -} - -void IRCClient::send_kick(const String& channel_name, const String& nick, const String& comment) -{ - send(String::formatted("KICK {} {} :{}\r\n", channel_name, nick, comment)); -} - -void IRCClient::send_list() -{ - send("LIST\r\n"); -} - -void IRCClient::send_privmsg(const String& target, const String& text) -{ - send(String::formatted("PRIVMSG {} :{}\r\n", target, text)); -} - -void IRCClient::send_notice(const String& target, const String& text) -{ - send(String::formatted("NOTICE {} :{}\r\n", target, text)); -} - -void IRCClient::handle_user_input_in_channel(const String& channel_name, const String& input) -{ - if (input.is_empty()) - return; - if (input[0] == '/') - return handle_user_command(input); - ensure_channel(channel_name).say(input); -} - -void IRCClient::handle_user_input_in_query(const String& query_name, const String& input) -{ - if (input.is_empty()) - return; - if (input[0] == '/') - return handle_user_command(input); - ensure_query(query_name).say(input); -} - -void IRCClient::handle_user_input_in_server(const String& input) -{ - if (input.is_empty()) - return; - if (input[0] == '/') - return handle_user_command(input); -} - -String IRCClient::nick_without_prefix(const String& nick) -{ - assert(!nick.is_empty()); - if (IRCClient::is_nick_prefix(nick[0])) - return nick.substring(1, nick.length() - 1); - return nick; -} - -bool IRCClient::is_nick_prefix(char ch) -{ - switch (ch) { - case '@': - case '+': - case '~': - case '&': - case '%': - return true; - } - return false; -} - -bool IRCClient::is_channel_prefix(char ch) -{ - switch (ch) { - case '&': - case '#': - case '+': - case '!': - return true; - } - return false; -} - -static bool has_ctcp_payload(const StringView& string) -{ - return string.length() >= 2 && string[0] == 0x01 && string[string.length() - 1] == 0x01; -} - -void IRCClient::handle_privmsg_or_notice(const Message& msg, PrivmsgOrNotice type) -{ - if (msg.arguments.size() < 2) - return; - if (msg.prefix.is_empty()) - return; - auto parts = msg.prefix.split('!'); - auto sender_nick = parts[0]; - auto target = msg.arguments[0]; - - bool is_ctcp = has_ctcp_payload(msg.arguments[1]); - - outln_if(IRC_DEBUG, "handle_privmsg_or_notice: type='{}'{}, sender_nick='{}', target='{}'", - type == PrivmsgOrNotice::Privmsg ? "privmsg" : "notice", - is_ctcp ? " (ctcp)" : "", - sender_nick, - target); - - if (sender_nick.is_empty()) - return; - - char sender_prefix = 0; - if (is_nick_prefix(sender_nick[0])) { - sender_prefix = sender_nick[0]; - sender_nick = sender_nick.substring(1, sender_nick.length() - 1); - } - - String message_text = msg.arguments[1]; - auto message_color = Color::Black; - - bool insert_as_raw_message = false; - - if (is_ctcp) { - auto ctcp_payload = msg.arguments[1].substring_view(1, msg.arguments[1].length() - 2); - if (type == PrivmsgOrNotice::Privmsg) - handle_ctcp_request(sender_nick, ctcp_payload); - else - handle_ctcp_response(sender_nick, ctcp_payload); - - if (ctcp_payload.starts_with("ACTION")) { - insert_as_raw_message = true; - message_text = String::formatted("* {}{}", sender_nick, ctcp_payload.substring_view(6, ctcp_payload.length() - 6)); - message_color = Color::Magenta; - } else { - message_text = String::formatted("(CTCP) {}", ctcp_payload); - message_color = Color::Blue; - } - } - - { - auto it = m_channels.find(target); - if (it != m_channels.end()) { - if (insert_as_raw_message) - (*it).value->add_message(message_text, message_color); - else - (*it).value->add_message(sender_prefix, sender_nick, message_text, message_color); - return; - } - } - - // For NOTICE or CTCP messages, only put them in query if one already exists. - // Otherwise, put them in the server window. This seems to match other clients. - IRCQuery* query = nullptr; - if (is_ctcp || type == PrivmsgOrNotice::Notice) { - query = query_with_name(target); - } else { - query = &ensure_query(target); - } - if (query) { - if (insert_as_raw_message) - query->add_message(message_text, message_color); - else - query->add_message(sender_prefix, sender_nick, message_text, message_color); - } else { - add_server_message(String::formatted("<{}> {}", sender_nick, message_text), message_color); - } -} - -IRCQuery* IRCClient::query_with_name(const String& name) -{ - return const_cast<IRCQuery*>(m_queries.get(name).value_or(nullptr)); -} - -IRCQuery& IRCClient::ensure_query(const String& name) -{ - auto it = m_queries.find(name); - if (it != m_queries.end()) - return *(*it).value; - auto query = IRCQuery::create(*this, name); - auto& query_reference = *query; - m_queries.set(name, query); - return query_reference; -} - -IRCChannel& IRCClient::ensure_channel(const String& name) -{ - auto it = m_channels.find(name); - if (it != m_channels.end()) - return *(*it).value; - auto channel = IRCChannel::create(*this, name); - auto& channel_reference = *channel; - m_channels.set(name, channel); - return channel_reference; -} - -void IRCClient::handle_ping(const Message& msg) -{ - if (msg.arguments.size() < 1) - return; - m_log->add_message(0, "", "Ping? Pong!"); - send_pong(msg.arguments[0]); -} - -void IRCClient::handle_join(const Message& msg) -{ - if (msg.arguments.size() != 1) - return; - auto prefix_parts = msg.prefix.split('!'); - if (prefix_parts.size() < 1) - return; - auto nick = prefix_parts[0]; - auto& channel_name = msg.arguments[0]; - ensure_channel(channel_name).handle_join(nick, msg.prefix); -} - -void IRCClient::handle_part(const Message& msg) -{ - if (msg.arguments.size() < 1) - return; - auto prefix_parts = msg.prefix.split('!'); - if (prefix_parts.size() < 1) - return; - auto nick = prefix_parts[0]; - auto& channel_name = msg.arguments[0]; - ensure_channel(channel_name).handle_part(nick, msg.prefix); -} - -void IRCClient::handle_quit(const Message& msg) -{ - if (msg.arguments.size() < 1) - return; - auto prefix_parts = msg.prefix.split('!'); - if (prefix_parts.size() < 1) - return; - auto nick = prefix_parts[0]; - auto& message = msg.arguments[0]; - for (auto& it : m_channels) { - it.value->handle_quit(nick, msg.prefix, message); - } -} - -void IRCClient::handle_nick(const Message& msg) -{ - auto prefix_parts = msg.prefix.split('!'); - if (prefix_parts.size() < 1) - return; - auto old_nick = prefix_parts[0]; - if (msg.arguments.size() != 1) - return; - auto& new_nick = msg.arguments[0]; - if (old_nick == m_nickname) - m_nickname = new_nick; - if (m_show_nick_change_messages) - add_server_message(String::formatted("~ {} changed nickname to {}", old_nick, new_nick)); - if (on_nickname_changed) - on_nickname_changed(new_nick); - for (auto& it : m_channels) { - it.value->notify_nick_changed(old_nick, new_nick); - } -} - -void IRCClient::handle_topic(const Message& msg) -{ - if (msg.arguments.size() != 2) - return; - auto prefix_parts = msg.prefix.split('!'); - if (prefix_parts.size() < 1) - return; - auto nick = prefix_parts[0]; - auto& channel_name = msg.arguments[0]; - ensure_channel(channel_name).handle_topic(nick, msg.arguments[1]); -} - -void IRCClient::handle_rpl_welcome(const Message& msg) -{ - if (msg.arguments.size() < 2) - return; - auto& welcome_message = msg.arguments[1]; - add_server_message(welcome_message); - - auto channel_str = m_config->read_entry("Connection", "AutoJoinChannels", ""); - if (channel_str.is_empty()) - return; - dbgln("IRCClient: Channels to autojoin: {}", channel_str); - auto channels = channel_str.split(','); - for (auto& channel : channels) { - join_channel(channel); - dbgln("IRCClient: Auto joining channel: {}", channel); - } -} - -void IRCClient::handle_rpl_topic(const Message& msg) -{ - if (msg.arguments.size() < 3) - return; - auto& channel_name = msg.arguments[1]; - auto& topic = msg.arguments[2]; - ensure_channel(channel_name).handle_topic({}, topic); -} - -void IRCClient::handle_rpl_namreply(const Message& msg) -{ - if (msg.arguments.size() < 4) - return; - auto& channel_name = msg.arguments[2]; - auto& channel = ensure_channel(channel_name); - auto members = msg.arguments[3].split(' '); - - quick_sort(members, [](auto& a, auto& b) { - return strcasecmp(a.characters(), b.characters()) < 0; - }); - - for (auto& member : members) { - if (member.is_empty()) - continue; - char prefix = 0; - if (is_nick_prefix(member[0])) - prefix = member[0]; - channel.add_member(member, prefix); - } -} - -void IRCClient::handle_rpl_endofnames(const Message&) -{ - add_server_message("// End of NAMES"); -} - -void IRCClient::handle_rpl_banlist(const Message& msg) -{ - if (msg.arguments.size() < 5) - return; - auto& channel = msg.arguments[1]; - auto& mask = msg.arguments[2]; - auto& user = msg.arguments[3]; - auto& datestamp = msg.arguments[4]; - add_server_message(String::formatted("* {}: {} on {} by {}", channel, mask, datestamp, user)); -} - -void IRCClient::handle_rpl_endofbanlist(const Message&) -{ - add_server_message("// End of BANLIST"); -} - -void IRCClient::handle_rpl_endofwho(const Message&) -{ - add_server_message("// End of WHO"); -} - -void IRCClient::handle_rpl_endofwhois(const Message&) -{ - add_server_message("// End of WHOIS"); -} - -void IRCClient::handle_rpl_endofwhowas(const Message&) -{ - add_server_message("// End of WHOWAS"); -} - -void IRCClient::handle_rpl_endofmotd(const Message&) -{ - add_server_message("// End of MOTD"); -} - -void IRCClient::handle_rpl_whoisoperator(const Message& msg) -{ - if (msg.arguments.size() < 2) - return; - auto& nick = msg.arguments[1]; - add_server_message(String::formatted("* {} is an IRC operator", nick)); -} - -void IRCClient::handle_rpl_whoisserver(const Message& msg) -{ - if (msg.arguments.size() < 3) - return; - auto& nick = msg.arguments[1]; - auto& server = msg.arguments[2]; - add_server_message(String::formatted("* {} is using server {}", nick, server)); -} - -void IRCClient::handle_rpl_whoisuser(const Message& msg) -{ - if (msg.arguments.size() < 6) - return; - auto& nick = msg.arguments[1]; - auto& username = msg.arguments[2]; - auto& host = msg.arguments[3]; - [[maybe_unused]] auto& asterisk = msg.arguments[4]; - auto& realname = msg.arguments[5]; - add_server_message(String::formatted("* {} is {}@{}, real name: {}", nick, username, host, realname)); -} - -void IRCClient::handle_rpl_whoisidle(const Message& msg) -{ - if (msg.arguments.size() < 3) - return; - auto& nick = msg.arguments[1]; - auto& secs = msg.arguments[2]; - add_server_message(String::formatted("* {} is {} seconds idle", nick, secs)); -} - -void IRCClient::handle_rpl_whoischannels(const Message& msg) -{ - if (msg.arguments.size() < 3) - return; - auto& nick = msg.arguments[1]; - auto& channel_list = msg.arguments[2]; - add_server_message(String::formatted("* {} is in channels {}", nick, channel_list)); -} - -void IRCClient::handle_rpl_topicwhotime(const Message& msg) -{ - if (msg.arguments.size() < 4) - return; - auto& channel_name = msg.arguments[1]; - auto& nick = msg.arguments[2]; - auto setat = msg.arguments[3]; - auto setat_time = setat.to_uint(); - if (setat_time.has_value()) - setat = Core::DateTime::from_timestamp(setat_time.value()).to_string(); - ensure_channel(channel_name).add_message(String::formatted("*** (set by {} at {})", nick, setat), Color::Blue); -} - -void IRCClient::handle_err_nosuchnick(const Message& msg) -{ - if (msg.arguments.size() < 3) - return; - auto& nick = msg.arguments[1]; - auto& message = msg.arguments[2]; - add_server_message(String::formatted("* {} :{}", nick, message)); -} - -void IRCClient::handle_err_unknowncommand(const Message& msg) -{ - if (msg.arguments.size() < 2) - return; - auto& cmd = msg.arguments[1]; - add_server_message(String::formatted("* Unknown command: {}", cmd)); -} - -void IRCClient::handle_err_nicknameinuse(const Message& msg) -{ - if (msg.arguments.size() < 2) - return; - auto& nick = msg.arguments[1]; - add_server_message(String::formatted("* {} :Nickname in use", nick)); -} - -void IRCClient::register_subwindow(IRCWindow& subwindow) -{ - if (subwindow.type() == IRCWindow::Server) { - m_server_subwindow = &subwindow; - subwindow.set_log_buffer(*m_log); - } - m_windows.append(&subwindow); - m_client_window_list_model->invalidate(); -} - -void IRCClient::unregister_subwindow(IRCWindow& subwindow) -{ - if (subwindow.type() == IRCWindow::Server) { - m_server_subwindow = &subwindow; - } - for (size_t i = 0; i < m_windows.size(); ++i) { - if (m_windows.at(i) == &subwindow) { - m_windows.remove(i); - break; - } - } - m_client_window_list_model->invalidate(); -} - -void IRCClient::handle_user_command(const String& input) -{ - auto parts = input.split_view(' '); - if (parts.is_empty()) - return; - auto command = String(parts[0]).to_uppercase(); - if (command == "/RAW") { - if (parts.size() <= 1) - return; - int command_length = command.length() + 1; - StringView raw_message = input.view().substring_view(command_length, input.view().length() - command_length); - send(String::formatted("{}\r\n", raw_message)); - return; - } - if (command == "/NICK") { - if (parts.size() >= 2) - change_nick(parts[1]); - return; - } - if (command == "/JOIN") { - if (parts.size() >= 2) - join_channel(parts[1]); - return; - } - if (command == "/PART") { - if (parts.size() >= 2) { - auto channel = parts[1]; - part_channel(channel); - } else { - auto* window = current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) - return; - auto channel = window->channel().name(); - join_channel(channel); - } - return; - } - if (command == "/CYCLE") { - if (parts.size() >= 2) { - auto channel = parts[1]; - part_channel(channel); - join_channel(channel); - } else { - auto* window = current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) - return; - auto channel = window->channel().name(); - part_channel(channel); - join_channel(channel); - } - return; - } - if (command == "/BANLIST") { - if (parts.size() >= 2) { - auto channel = parts[1]; - send_banlist(channel); - } else { - auto* window = current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) - return; - auto channel = window->channel().name(); - send_banlist(channel); - } - return; - } - if (command == "/ME") { - if (parts.size() < 2) - return; - - auto* window = current_window(); - if (!window) - return; - - auto emote = input.view().substring_view_starting_after_substring(parts[0]); - auto action_string = String::formatted("ACTION{}", emote); - String peer; - if (window->type() == IRCWindow::Type::Channel) { - peer = window->channel().name(); - window->channel().add_message(String::formatted("* {}{}", m_nickname, emote), Gfx::Color::Magenta); - } else if (window->type() == IRCWindow::Type::Query) { - peer = window->query().name(); - window->query().add_message(String::formatted("* {}{}", m_nickname, emote), Gfx::Color::Magenta); - } else { - return; - } - - send_ctcp_request(peer, action_string); - return; - } - if (command == "/TOPIC") { - if (parts.size() < 2) - return; - if (parts[1].is_empty()) - return; - - if (is_channel_prefix(parts[1][0])) { - if (parts.size() < 3) - return; - auto channel = parts[1]; - auto topic = input.view().substring_view_starting_after_substring(channel); - send_topic(channel, topic); - } else { - auto* window = current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) - return; - auto channel = window->channel().name(); - auto topic = input.view().substring_view_starting_after_substring(parts[0]); - send_topic(channel, topic); - } - return; - } - if (command == "/KICK") { - if (parts.size() < 2) - return; - if (parts[1].is_empty()) - return; - - if (is_channel_prefix(parts[1][0])) { - if (parts.size() < 3) - return; - auto channel = parts[1]; - auto nick = parts[2]; - auto reason = input.view().substring_view_starting_after_substring(nick); - send_kick(channel, nick, reason); - } else { - auto* window = current_window(); - if (!window || window->type() != IRCWindow::Type::Channel) - return; - auto channel = window->channel().name(); - auto nick = parts[1]; - auto reason = input.view().substring_view_starting_after_substring(nick); - send_kick(channel, nick, reason); - } - return; - } - if (command == "/LIST") { - send_list(); - return; - } - if (command == "/QUERY") { - if (parts.size() >= 2) { - auto& query = ensure_query(parts[1]); - IRCAppWindow::the().set_active_window(query.window()); - } - return; - } - if (command == "/MSG") { - if (parts.size() < 3) - return; - auto nick = parts[1]; - auto& query = ensure_query(nick); - IRCAppWindow::the().set_active_window(query.window()); - query.say(input.view().substring_view_starting_after_substring(nick)); - return; - } - if (command == "/WHOIS") { - if (parts.size() >= 2) - send_whois(parts[1]); - return; - } -} - -void IRCClient::change_nick(const String& nick) -{ - send(String::formatted("NICK {}\r\n", nick)); -} - -void IRCClient::handle_list_channels_action() -{ - send_list(); -} - -void IRCClient::handle_whois_action(const String& nick) -{ - send_whois(nick); -} - -void IRCClient::handle_ctcp_user_action(const String& nick, const String& message) -{ - send_ctcp_request(nick, message); -} - -void IRCClient::handle_open_query_action(const String& nick) -{ - ensure_query(nick); -} - -void IRCClient::handle_change_nick_action(const String& nick) -{ - change_nick(nick); -} - -void IRCClient::handle_change_topic_action(const String& channel, const String& topic) -{ - send_topic(channel, topic); -} - -void IRCClient::handle_invite_user_action(const String& channel, const String& nick) -{ - send_invite(channel, nick); -} - -void IRCClient::handle_banlist_action(const String& channel) -{ - send_banlist(channel); -} - -void IRCClient::handle_voice_user_action(const String& channel, const String& nick) -{ - send_voice_user(channel, nick); -} - -void IRCClient::handle_devoice_user_action(const String& channel, const String& nick) -{ - send_devoice_user(channel, nick); -} - -void IRCClient::handle_hop_user_action(const String& channel, const String& nick) -{ - send_hop_user(channel, nick); -} - -void IRCClient::handle_dehop_user_action(const String& channel, const String& nick) -{ - send_dehop_user(channel, nick); -} - -void IRCClient::handle_op_user_action(const String& channel, const String& nick) -{ - send_op_user(channel, nick); -} - -void IRCClient::handle_deop_user_action(const String& channel, const String& nick) -{ - send_deop_user(channel, nick); -} - -void IRCClient::handle_kick_user_action(const String& channel, const String& nick, const String& message) -{ - send_kick(channel, nick, message); -} - -void IRCClient::handle_close_query_action(const String& nick) -{ - m_queries.remove(nick); - m_client_window_list_model->invalidate(); -} - -void IRCClient::handle_join_action(const String& channel) -{ - join_channel(channel); -} - -void IRCClient::handle_part_action(const String& channel) -{ - part_channel(channel); -} - -void IRCClient::handle_cycle_channel_action(const String& channel) -{ - part_channel(channel); - join_channel(channel); -} - -void IRCClient::did_part_from_channel(Badge<IRCChannel>, IRCChannel& channel) -{ - if (on_part_from_channel) - on_part_from_channel(channel); -} - -void IRCClient::send_ctcp_response(const StringView& peer, const StringView& payload) -{ - StringBuilder builder; - builder.append(0x01); - builder.append(payload); - builder.append(0x01); - auto message = builder.to_string(); - send_notice(peer, message); -} - -void IRCClient::send_ctcp_request(const StringView& peer, const StringView& payload) -{ - StringBuilder builder; - builder.append(0x01); - builder.append(payload); - builder.append(0x01); - auto message = builder.to_string(); - send_privmsg(peer, message); -} - -void IRCClient::handle_ctcp_request(const StringView& peer, const StringView& payload) -{ - dbgln("handle_ctcp_request: {}", payload); - - if (payload == "VERSION") { - auto version = ctcp_version_reply(); - if (version.is_empty()) - return; - send_ctcp_response(peer, String::formatted("VERSION {}", version)); - return; - } - - if (payload == "USERINFO") { - auto userinfo = ctcp_userinfo_reply(); - if (userinfo.is_empty()) - return; - send_ctcp_response(peer, String::formatted("USERINFO {}", userinfo)); - return; - } - - if (payload == "FINGER") { - auto finger = ctcp_finger_reply(); - if (finger.is_empty()) - return; - send_ctcp_response(peer, String::formatted("FINGER {}", finger)); - return; - } - - if (payload.starts_with("PING")) { - send_ctcp_response(peer, payload); - return; - } -} - -void IRCClient::handle_ctcp_response(const StringView& peer, const StringView& payload) -{ - dbgln("handle_ctcp_response({}): {}", peer, payload); -} diff --git a/Userland/Applications/IRCClient/IRCClient.h b/Userland/Applications/IRCClient/IRCClient.h deleted file mode 100644 index 15f3e7c223..0000000000 --- a/Userland/Applications/IRCClient/IRCClient.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "IRCLogBuffer.h" -#include "IRCWindow.h" -#include <AK/CircularQueue.h> -#include <AK/Function.h> -#include <AK/HashMap.h> -#include <AK/String.h> -#include <LibCore/ConfigFile.h> -#include <LibCore/TCPSocket.h> - -class IRCChannel; -class IRCQuery; -class IRCWindowListModel; - -class IRCClient final : public Core::Object { - C_OBJECT(IRCClient) - friend class IRCChannel; - friend class IRCQuery; - -public: - virtual ~IRCClient() override; - - void set_server(const String& hostname, int port = 6667); - - bool connect(); - - String hostname() const { return m_hostname; } - int port() const { return m_port; } - - String nickname() const { return m_nickname; } - - String ctcp_version_reply() const { return m_ctcp_version_reply; } - String ctcp_userinfo_reply() const { return m_ctcp_userinfo_reply; } - String ctcp_finger_reply() const { return m_ctcp_finger_reply; } - - bool show_join_part_messages() const { return m_show_join_part_messages; } - bool show_nick_change_messages() const { return m_show_nick_change_messages; } - - bool notify_on_message() const { return m_notify_on_message; } - bool notify_on_mention() const { return m_notify_on_mention; } - - void join_channel(const String&); - void part_channel(const String&); - void change_nick(const String&); - - static bool is_nick_prefix(char); - static bool is_channel_prefix(char); - String nick_without_prefix(const String& nick); - - IRCWindow* current_window() { return aid_get_active_window(); } - const IRCWindow* current_window() const { return aid_get_active_window(); } - - Function<void()> on_disconnect; - Function<void()> on_server_message; - Function<void(const String&)> on_nickname_changed; - Function<void(IRCChannel&)> on_part_from_channel; - - Function<NonnullRefPtr<IRCWindow>(void*, IRCWindow::Type, const String&)> aid_create_window; - Function<IRCWindow*()> aid_get_active_window; - Function<void()> aid_update_window_list; - - void register_subwindow(IRCWindow&); - void unregister_subwindow(IRCWindow&); - - IRCWindowListModel* client_window_list_model() { return m_client_window_list_model.ptr(); } - const IRCWindowListModel* client_window_list_model() const { return m_client_window_list_model.ptr(); } - - int window_count() const { return m_windows.size(); } - const IRCWindow& window_at(int index) const { return *m_windows.at(index); } - IRCWindow& window_at(int index) { return *m_windows.at(index); } - - size_t window_index(const IRCWindow& window) const - { - for (size_t i = 0; i < m_windows.size(); ++i) { - if (m_windows[i] == &window) - return i; - } - VERIFY_NOT_REACHED(); - } - - void did_part_from_channel(Badge<IRCChannel>, IRCChannel&); - - void handle_user_input_in_channel(const String& channel_name, const String&); - void handle_user_input_in_query(const String& query_name, const String&); - void handle_user_input_in_server(const String&); - - void handle_list_channels_action(); - void handle_whois_action(const String& nick); - void handle_ctcp_user_action(const String& nick, const String& message); - void handle_open_query_action(const String&); - void handle_close_query_action(const String&); - void handle_join_action(const String& channel_name); - void handle_part_action(const String& channel_name); - void handle_cycle_channel_action(const String& channel_name); - void handle_change_nick_action(const String& nick); - void handle_change_topic_action(const String& channel_name, const String&); - void handle_invite_user_action(const String& channel_name, const String& nick); - void handle_banlist_action(const String& channel_name); - void handle_voice_user_action(const String& channel_name, const String& nick); - void handle_devoice_user_action(const String& channel_name, const String& nick); - void handle_hop_user_action(const String& channel_name, const String& nick); - void handle_dehop_user_action(const String& channel_name, const String& nick); - void handle_op_user_action(const String& channel_name, const String& nick); - void handle_deop_user_action(const String& channel_name, const String& nick); - void handle_kick_user_action(const String& channel_name, const String& nick, const String&); - - IRCQuery* query_with_name(const String&); - IRCQuery& ensure_query(const String& name); - IRCChannel& ensure_channel(const String& name); - - void add_server_message(const String&, Color = Color::Black); - -private: - IRCClient(String server, int port); - - struct Message { - String prefix; - String command; - Vector<String> arguments; - }; - - enum class PrivmsgOrNotice { - Privmsg, - Notice, - }; - - void receive_from_server(); - void send(const String&); - void send_user(); - void send_nick(); - void send_pong(const String& server); - void send_privmsg(const String& target, const String&); - void send_notice(const String& target, const String&); - void send_topic(const String& channel_name, const String&); - void send_invite(const String& channel_name, const String& nick); - void send_banlist(const String& channel_name); - void send_voice_user(const String& channel_name, const String& nick); - void send_devoice_user(const String& channel_name, const String& nick); - void send_hop_user(const String& channel_name, const String& nick); - void send_dehop_user(const String& channel_name, const String& nick); - void send_op_user(const String& channel_name, const String& nick); - void send_deop_user(const String& channel_name, const String& nick); - void send_kick(const String& channel_name, const String& nick, const String&); - void send_list(); - void send_whois(const String&); - void process_line(const String&); - void handle_join(const Message&); - void handle_part(const Message&); - void handle_quit(const Message&); - void handle_ping(const Message&); - void handle_topic(const Message&); - void handle_rpl_welcome(const Message&); - void handle_rpl_topic(const Message&); - void handle_rpl_whoisuser(const Message&); - void handle_rpl_whoisserver(const Message&); - void handle_rpl_whoisoperator(const Message&); - void handle_rpl_whoisidle(const Message&); - void handle_rpl_endofwho(const Message&); - void handle_rpl_endofwhois(const Message&); - void handle_rpl_endofwhowas(const Message&); - void handle_rpl_endofmotd(const Message&); - void handle_rpl_whoischannels(const Message&); - void handle_rpl_topicwhotime(const Message&); - void handle_rpl_endofnames(const Message&); - void handle_rpl_endofbanlist(const Message&); - void handle_rpl_namreply(const Message&); - void handle_rpl_banlist(const Message&); - void handle_err_nosuchnick(const Message&); - void handle_err_unknowncommand(const Message&); - void handle_err_nicknameinuse(const Message&); - void handle_privmsg_or_notice(const Message&, PrivmsgOrNotice); - void handle_nick(const Message&); - void handle(const Message&); - void handle_user_command(const String&); - void handle_ctcp_request(const StringView& peer, const StringView& payload); - void handle_ctcp_response(const StringView& peer, const StringView& payload); - void send_ctcp_request(const StringView& peer, const StringView& payload); - void send_ctcp_response(const StringView& peer, const StringView& payload); - - void on_socket_connected(); - - String m_hostname; - int m_port { 6667 }; - - RefPtr<Core::TCPSocket> m_socket; - - String m_nickname; - RefPtr<Core::Notifier> m_notifier; - HashMap<String, RefPtr<IRCChannel>, CaseInsensitiveStringTraits> m_channels; - HashMap<String, RefPtr<IRCQuery>, CaseInsensitiveStringTraits> m_queries; - - bool m_show_join_part_messages { 1 }; - bool m_show_nick_change_messages { 1 }; - - bool m_notify_on_message { 1 }; - bool m_notify_on_mention { 1 }; - - String m_ctcp_version_reply; - String m_ctcp_userinfo_reply; - String m_ctcp_finger_reply; - - Vector<IRCWindow*> m_windows; - - IRCWindow* m_server_subwindow { nullptr }; - - NonnullRefPtr<IRCWindowListModel> m_client_window_list_model; - NonnullRefPtr<IRCLogBuffer> m_log; - NonnullRefPtr<Core::ConfigFile> m_config; -}; diff --git a/Userland/Applications/IRCClient/IRCLogBuffer.cpp b/Userland/Applications/IRCClient/IRCLogBuffer.cpp deleted file mode 100644 index 9ac766d05b..0000000000 --- a/Userland/Applications/IRCClient/IRCLogBuffer.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "IRCLogBuffer.h" -#include <LibWeb/DOM/DocumentFragment.h> -#include <LibWeb/DOM/DocumentType.h> -#include <LibWeb/DOM/ElementFactory.h> -#include <LibWeb/DOM/Text.h> -#include <time.h> - -NonnullRefPtr<IRCLogBuffer> IRCLogBuffer::create() -{ - return adopt_ref(*new IRCLogBuffer); -} - -IRCLogBuffer::IRCLogBuffer() -{ - m_document = Web::DOM::Document::create(); - m_document->append_child(adopt_ref(*new Web::DOM::DocumentType(document()))); - auto html_element = m_document->create_element("html"); - m_document->append_child(html_element); - auto head_element = m_document->create_element("head"); - html_element->append_child(head_element); - auto style_element = m_document->create_element("style"); - style_element->append_child(adopt_ref(*new Web::DOM::Text(document(), "div { font-family: Csilla; font-weight: lighter; }"))); - head_element->append_child(style_element); - auto body_element = m_document->create_element("body"); - html_element->append_child(body_element); - m_container_element = body_element; -} - -IRCLogBuffer::~IRCLogBuffer() -{ -} - -static String timestamp_string() -{ - auto now = time(nullptr); - auto* tm = localtime(&now); - return String::formatted("{:02}:{:02}:{:02} ", tm->tm_hour, tm->tm_min, tm->tm_sec); -} - -void IRCLogBuffer::add_message(char prefix, const String& name, const String& text, Color color) -{ - auto nick_string = String::formatted("<{}{}> ", prefix ? prefix : ' ', name.characters()); - auto html = String::formatted( - "<span>{}</span>" - "<b>{}</b>" - "<span>{}</span>", - timestamp_string(), - escape_html_entities(nick_string), - escape_html_entities(text)); - - auto wrapper = m_document->create_element(Web::HTML::TagNames::div); - wrapper->set_attribute(Web::HTML::AttributeNames::style, String::formatted("color: {}", color.to_string())); - wrapper->set_inner_html(html); - m_container_element->append_child(wrapper); - m_document->force_layout(); -} - -void IRCLogBuffer::add_message(const String& text, Color color) -{ - auto html = String::formatted( - "<span>{}</span>" - "<span>{}</span>", - timestamp_string(), - escape_html_entities(text)); - auto wrapper = m_document->create_element(Web::HTML::TagNames::div); - wrapper->set_attribute(Web::HTML::AttributeNames::style, String::formatted("color: {}", color.to_string())); - wrapper->set_inner_html(html); - m_container_element->append_child(wrapper); - m_document->force_layout(); -} diff --git a/Userland/Applications/IRCClient/IRCLogBuffer.h b/Userland/Applications/IRCClient/IRCLogBuffer.h deleted file mode 100644 index 5afe118da1..0000000000 --- a/Userland/Applications/IRCClient/IRCLogBuffer.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <AK/RefCounted.h> -#include <AK/RefPtr.h> -#include <AK/String.h> -#include <LibGfx/Color.h> -#include <LibWeb/DOM/Document.h> - -class IRCLogBuffer : public RefCounted<IRCLogBuffer> { -public: - static NonnullRefPtr<IRCLogBuffer> create(); - ~IRCLogBuffer(); - - struct Message { - time_t timestamp { 0 }; - char prefix { 0 }; - String sender; - String text; - Color color { Color::Black }; - }; - - void add_message(char prefix, const String& name, const String& text, Color = Color::Black); - void add_message(const String& text, Color = Color::Black); - - const Web::DOM::Document& document() const { return *m_document; } - Web::DOM::Document& document() { return *m_document; } - -private: - IRCLogBuffer(); - RefPtr<Web::DOM::Document> m_document; - RefPtr<Web::DOM::Element> m_container_element; -}; diff --git a/Userland/Applications/IRCClient/IRCQuery.cpp b/Userland/Applications/IRCClient/IRCQuery.cpp deleted file mode 100644 index 553ad36d1e..0000000000 --- a/Userland/Applications/IRCClient/IRCQuery.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "IRCQuery.h" -#include "IRCClient.h" - -IRCQuery::IRCQuery(IRCClient& client, const String& name) - : m_client(client) - , m_name(name) - , m_log(IRCLogBuffer::create()) -{ - m_window = m_client->aid_create_window(this, IRCWindow::Query, m_name); - m_window->set_log_buffer(*m_log); -} - -IRCQuery::~IRCQuery() -{ -} - -NonnullRefPtr<IRCQuery> IRCQuery::create(IRCClient& client, const String& name) -{ - return adopt_ref(*new IRCQuery(client, name)); -} - -void IRCQuery::add_message(char prefix, const String& name, const String& text, Color color) -{ - log().add_message(prefix, name, text, color); - window().did_add_message(name, text); -} - -void IRCQuery::add_message(const String& text, Color color) -{ - log().add_message(text, color); - window().did_add_message(); -} - -void IRCQuery::say(const String& text) -{ - m_client->send_privmsg(m_name, text); - add_message(' ', m_client->nickname(), text); -} diff --git a/Userland/Applications/IRCClient/IRCQuery.h b/Userland/Applications/IRCClient/IRCQuery.h deleted file mode 100644 index dd4d054478..0000000000 --- a/Userland/Applications/IRCClient/IRCQuery.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "IRCLogBuffer.h" -#include <AK/CircularQueue.h> -#include <AK/RefCounted.h> -#include <AK/RefPtr.h> -#include <AK/String.h> -#include <AK/Vector.h> - -class IRCClient; -class IRCWindow; - -class IRCQuery : public RefCounted<IRCQuery> { -public: - static NonnullRefPtr<IRCQuery> create(IRCClient&, const String& name); - ~IRCQuery(); - - String name() const { return m_name; } - void add_message(char prefix, const String& name, const String& text, Color = Color::Black); - void add_message(const String& text, Color = Color::Black); - - const IRCLogBuffer& log() const { return *m_log; } - IRCLogBuffer& log() { return *m_log; } - - void say(const String&); - - IRCWindow& window() { return *m_window; } - const IRCWindow& window() const { return *m_window; } - -private: - IRCQuery(IRCClient&, const String& name); - - NonnullRefPtr<IRCClient> m_client; - String m_name; - RefPtr<IRCWindow> m_window; - - NonnullRefPtr<IRCLogBuffer> m_log; -}; diff --git a/Userland/Applications/IRCClient/IRCWindow.cpp b/Userland/Applications/IRCClient/IRCWindow.cpp deleted file mode 100644 index de822d6f8d..0000000000 --- a/Userland/Applications/IRCClient/IRCWindow.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "IRCWindow.h" -#include "IRCChannel.h" -#include "IRCChannelMemberListModel.h" -#include "IRCClient.h" -#include <AK/StringBuilder.h> -#include <LibGUI/Action.h> -#include <LibGUI/BoxLayout.h> -#include <LibGUI/InputBox.h> -#include <LibGUI/Menu.h> -#include <LibGUI/Notification.h> -#include <LibGUI/Splitter.h> -#include <LibGUI/TableView.h> -#include <LibGUI/TextBox.h> -#include <LibGUI/TextEditor.h> -#include <LibGUI/Window.h> -#include <LibWeb/InProcessWebView.h> - -IRCWindow::IRCWindow(IRCClient& client, void* owner, Type type, const String& name) - : m_client(client) - , m_owner(owner) - , m_type(type) - , m_name(name) -{ - set_layout<GUI::VerticalBoxLayout>(); - - // Make a container for the log buffer view + (optional) member list. - auto& container = add<GUI::HorizontalSplitter>(); - - m_page_view = container.add<Web::InProcessWebView>(); - - if (m_type == Channel) { - auto& member_view = container.add<GUI::TableView>(); - member_view.set_column_headers_visible(false); - member_view.set_fixed_width(100); - member_view.set_alternating_row_colors(false); - member_view.set_model(channel().member_model()); - member_view.set_activates_on_selection(true); - member_view.on_activation = [&](auto& index) { - if (!index.is_valid()) - return; - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_open_query_action(m_client->nick_without_prefix(nick.characters())); - }; - member_view.on_context_menu_request = [&](const GUI::ModelIndex& index, const GUI::ContextMenuEvent& event) { - if (!index.is_valid()) - return; - - m_context_menu = GUI::Menu::construct(); - - m_context_menu->add_action(GUI::Action::create("Open &Query", Gfx::Bitmap::try_load_from_file("/res/icons/16x16/irc-open-query.png"), [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_open_query_action(m_client->nick_without_prefix(nick.characters())); - })); - - m_context_menu->add_action(GUI::Action::create("Whois", Gfx::Bitmap::try_load_from_file("/res/icons/16x16/irc-whois.png"), [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_whois_action(m_client->nick_without_prefix(nick.characters())); - })); - - auto& context_control_menu = m_context_menu->add_submenu("Control"); - - context_control_menu.add_action(GUI::Action::create("&Voice", [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_voice_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters())); - })); - - context_control_menu.add_action(GUI::Action::create("DeVoice", [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_devoice_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters())); - })); - - context_control_menu.add_action(GUI::Action::create("Hop", [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_hop_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters())); - })); - - context_control_menu.add_action(GUI::Action::create("DeHop", [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_dehop_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters())); - })); - - context_control_menu.add_action(GUI::Action::create("&Op", [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_op_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters())); - })); - - context_control_menu.add_action(GUI::Action::create("DeOp", [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_deop_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters())); - })); - - context_control_menu.add_separator(); - - context_control_menu.add_action(GUI::Action::create("&Kick", [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - if (IRCClient::is_nick_prefix(nick[0])) - nick = nick.substring(1, nick.length() - 1); - String value; - if (GUI::InputBox::show(window(), value, "Enter reason:", "Reason") == GUI::InputBox::ExecOK) - m_client->handle_kick_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters()), value); - })); - - auto& context_ctcp_menu = m_context_menu->add_submenu("CTCP"); - - context_ctcp_menu.add_action(GUI::Action::create("&User Info", [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_ctcp_user_action(m_client->nick_without_prefix(nick.characters()), "USERINFO"); - })); - - context_ctcp_menu.add_action(GUI::Action::create("&Finger", [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_ctcp_user_action(m_client->nick_without_prefix(nick.characters()), "FINGER"); - })); - - context_ctcp_menu.add_action(GUI::Action::create("&Time", [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_ctcp_user_action(m_client->nick_without_prefix(nick.characters()), "TIME"); - })); - - context_ctcp_menu.add_action(GUI::Action::create("&Version", [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_ctcp_user_action(m_client->nick_without_prefix(nick.characters()), "VERSION"); - })); - - context_ctcp_menu.add_action(GUI::Action::create("&Client Info", [&](const GUI::Action&) { - auto nick = channel().member_model()->nick_at(member_view.selection().first()); - if (nick.is_empty()) - return; - m_client->handle_ctcp_user_action(m_client->nick_without_prefix(nick.characters()), "CLIENTINFO"); - })); - - m_context_menu->popup(event.screen_position()); - }; - } - - m_text_box = add<GUI::TextBox>(); - m_text_box->set_fixed_height(19); - m_text_box->on_return_pressed = [this] { - if (m_type == Channel) - m_client->handle_user_input_in_channel(m_name, m_text_box->text()); - else if (m_type == Query) - m_client->handle_user_input_in_query(m_name, m_text_box->text()); - else if (m_type == Server) - m_client->handle_user_input_in_server(m_text_box->text()); - m_text_box->add_current_text_to_history(); - m_text_box->clear(); - }; - m_text_box->set_history_enabled(true); - m_text_box->set_placeholder("Message"); - - m_client->register_subwindow(*this); -} - -IRCWindow::~IRCWindow() -{ - m_client->unregister_subwindow(*this); -} - -void IRCWindow::set_log_buffer(const IRCLogBuffer& log_buffer) -{ - m_log_buffer = &log_buffer; - m_page_view->set_document(const_cast<Web::DOM::Document*>(&log_buffer.document())); -} - -bool IRCWindow::is_active() const -{ - return m_client->current_window() == this; -} - -void IRCWindow::post_notification_if_needed(const String& name, const String& message) -{ - if (name.is_null() || message.is_null()) - return; - if (is_active() && window()->is_active()) - return; - - auto notification = GUI::Notification::construct(); - - if (type() == Type::Channel) { - if (!m_client->notify_on_mention()) - return; - if (!message.contains(m_client->nickname())) - return; - - StringBuilder builder; - builder.append(name); - builder.append(" in "); - builder.append(m_name); - notification->set_title(builder.to_string()); - } else { - if (!m_client->notify_on_message()) - return; - notification->set_title(name); - } - - notification->set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/32x32/app-irc-client.png")); - notification->set_text(message); - notification->show(); -} - -void IRCWindow::did_add_message(const String& name, const String& message) -{ - post_notification_if_needed(name, message); - - if (!is_active()) { - ++m_unread_count; - m_client->aid_update_window_list(); - return; - } - m_page_view->scroll_to_bottom(); -} - -void IRCWindow::clear_unread_count() -{ - if (!m_unread_count) - return; - m_unread_count = 0; - m_client->aid_update_window_list(); -} - -int IRCWindow::unread_count() const -{ - return m_unread_count; -} diff --git a/Userland/Applications/IRCClient/IRCWindow.h b/Userland/Applications/IRCClient/IRCWindow.h deleted file mode 100644 index 0be13eb5f7..0000000000 --- a/Userland/Applications/IRCClient/IRCWindow.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <LibGUI/Widget.h> -#include <LibWeb/Forward.h> - -class IRCChannel; -class IRCClient; -class IRCQuery; -class IRCLogBuffer; - -class IRCWindow : public GUI::Widget { - C_OBJECT(IRCWindow) -public: - enum Type { - Server, - Channel, - Query, - }; - - virtual ~IRCWindow() override; - - String name() const { return m_name; } - void set_name(const String& name) { m_name = name; } - - Type type() const { return m_type; } - - void set_log_buffer(const IRCLogBuffer&); - - bool is_active() const; - - int unread_count() const; - void clear_unread_count(); - - void did_add_message(const String& name = {}, const String& message = {}); - - IRCChannel& channel() { return *(IRCChannel*)m_owner; } - const IRCChannel& channel() const { return *(const IRCChannel*)m_owner; } - - IRCQuery& query() { return *(IRCQuery*)m_owner; } - const IRCQuery& query() const { return *(const IRCQuery*)m_owner; } - -private: - IRCWindow(IRCClient&, void* owner, Type, const String& name); - - void post_notification_if_needed(const String& name, const String& message); - - NonnullRefPtr<IRCClient> m_client; - void* m_owner { nullptr }; - Type m_type; - String m_name; - RefPtr<Web::InProcessWebView> m_page_view; - RefPtr<GUI::TextBox> m_text_box; - RefPtr<IRCLogBuffer> m_log_buffer; - RefPtr<GUI::Menu> m_context_menu; - int m_unread_count { 0 }; -}; diff --git a/Userland/Applications/IRCClient/IRCWindowListModel.cpp b/Userland/Applications/IRCClient/IRCWindowListModel.cpp deleted file mode 100644 index 76ef9623f9..0000000000 --- a/Userland/Applications/IRCClient/IRCWindowListModel.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "IRCWindowListModel.h" -#include "IRCChannel.h" -#include "IRCClient.h" - -IRCWindowListModel::IRCWindowListModel(IRCClient& client) - : m_client(client) -{ -} - -IRCWindowListModel::~IRCWindowListModel() -{ -} - -int IRCWindowListModel::row_count(const GUI::ModelIndex&) const -{ - return m_client->window_count(); -} - -int IRCWindowListModel::column_count(const GUI::ModelIndex&) const -{ - return 1; -} - -String IRCWindowListModel::column_name(int column) const -{ - switch (column) { - case Column::Name: - return "Name"; - } - VERIFY_NOT_REACHED(); -} - -GUI::Variant IRCWindowListModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const -{ - if (role == GUI::ModelRole::TextAlignment) - return Gfx::TextAlignment::CenterLeft; - if (role == GUI::ModelRole::Display) { - switch (index.column()) { - case Column::Name: { - auto& window = m_client->window_at(index.row()); - if (window.unread_count()) - return String::formatted("{} ({})", window.name(), window.unread_count()); - return window.name(); - } - } - } - if (role == GUI::ModelRole::ForegroundColor) { - switch (index.column()) { - case Column::Name: { - auto& window = m_client->window_at(index.row()); - if (window.unread_count()) - return Color(Color::Red); - if (!window.channel().is_open()) - return Color(Color::WarmGray); - return Color(Color::Black); - } - } - } - return {}; -} diff --git a/Userland/Applications/IRCClient/IRCWindowListModel.h b/Userland/Applications/IRCClient/IRCWindowListModel.h deleted file mode 100644 index 8de806cbcc..0000000000 --- a/Userland/Applications/IRCClient/IRCWindowListModel.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <AK/Function.h> -#include <LibGUI/Model.h> - -class IRCClient; -class IRCWindow; - -class IRCWindowListModel final : public GUI::Model { -public: - enum Column { - Name, - }; - - static NonnullRefPtr<IRCWindowListModel> create(IRCClient& client) { return adopt_ref(*new IRCWindowListModel(client)); } - virtual ~IRCWindowListModel() override; - - virtual int row_count(const GUI::ModelIndex&) const override; - virtual int column_count(const GUI::ModelIndex&) const override; - virtual String column_name(int column) const override; - virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override; - -private: - explicit IRCWindowListModel(IRCClient&); - - NonnullRefPtr<IRCClient> m_client; -}; diff --git a/Userland/Applications/IRCClient/main.cpp b/Userland/Applications/IRCClient/main.cpp deleted file mode 100644 index 1249632f0d..0000000000 --- a/Userland/Applications/IRCClient/main.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "IRCAppWindow.h" -#include "IRCClient.h" -#include <LibCore/StandardPaths.h> -#include <LibGUI/Application.h> -#include <LibGUI/MessageBox.h> -#include <stdio.h> -#include <unistd.h> - -int main(int argc, char** argv) -{ - if (pledge("stdio inet unix recvfd sendfd cpath rpath wpath", nullptr) < 0) { - perror("pledge"); - return 1; - } - - if (getuid() == 0) { - warnln("Refusing to run as root"); - return 1; - } - - auto app = GUI::Application::construct(argc, argv); - - if (unveil("/tmp/portal/lookup", "rw") < 0) { - perror("unveil"); - return 1; - } - - if (unveil("/tmp/portal/notify", "rw") < 0) { - perror("unveil"); - return 1; - } - - if (unveil("/etc/passwd", "r") < 0) { - perror("unveil"); - return 1; - } - - if (unveil(Core::StandardPaths::home_directory().characters(), "rwc") < 0) { - perror("unveil"); - return 1; - } - - if (unveil("/res", "r") < 0) { - perror("unveil"); - return 1; - } - - if (unveil(nullptr, nullptr) < 0) { - perror("unveil"); - return 1; - } - - URL url = ""; - if (app->args().size() >= 1) { - url = URL::create_with_url_or_path(app->args()[0]); - - if (url.protocol().to_lowercase() == "ircs") { - warnln("Secure IRC over SSL/TLS (ircs) is not supported"); - return 1; - } - - if (url.protocol().to_lowercase() != "irc") { - warnln("Unsupported protocol"); - return 1; - } - - if (url.host().is_empty()) { - warnln("Invalid URL"); - return 1; - } - - if (!url.port() || url.port() == 80) - url.set_port(6667); - } - - auto app_window = IRCAppWindow::construct(url.host(), url.port()); - app_window->show(); - return app->exec(); -} diff --git a/Userland/Demos/WidgetGallery/GalleryWidget.cpp b/Userland/Demos/WidgetGallery/GalleryWidget.cpp index 662057d8e3..badda01419 100644 --- a/Userland/Demos/WidgetGallery/GalleryWidget.cpp +++ b/Userland/Demos/WidgetGallery/GalleryWidget.cpp @@ -131,7 +131,7 @@ GalleryWidget::GalleryWidget() }; m_msgbox_button = basics_tab.find_descendant_of_type_named<GUI::Button>("msgbox_button"); - m_msgbox_button->set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/app-irc-client.png")); + m_msgbox_button->set_icon(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/app-browser.png")); m_msgbox_type = GUI::MessageBox::Type::None; m_msgbox_input_type = GUI::MessageBox::InputType::OK; |