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.
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/c9151745631
@ -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
|
||||
|
@ -1,7 +1,6 @@
|
||||
#!sh
|
||||
|
||||
alias fm=FileManager
|
||||
alias irc=IRCClient
|
||||
alias mag=Magnifier
|
||||
alias ms=Minesweeper
|
||||
alias sh=Shell
|
||||
|
@ -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
|
@ -28,4 +28,3 @@ directory=/bin/FileManager
|
||||
gemini=/bin/Browser
|
||||
http=/bin/Browser
|
||||
https=/bin/Browser
|
||||
irc=/bin/IRCClient
|
||||
|
@ -1,7 +0,0 @@
|
||||
[App]
|
||||
Name=IRC Client
|
||||
Executable=/bin/IRCClient
|
||||
Category=Internet
|
||||
|
||||
[Launcher]
|
||||
Protocols=irc
|
Before Width: | Height: | Size: 197 B |
Before Width: | Height: | Size: 470 B |
Before Width: | Height: | Size: 422 B |
Before Width: | Height: | Size: 424 B |
Before Width: | Height: | Size: 436 B |
Before Width: | Height: | Size: 470 B |
Before Width: | Height: | Size: 461 B |
Before Width: | Height: | Size: 516 B |
Before Width: | Height: | Size: 576 B |
Before Width: | Height: | Size: 485 B |
Before Width: | Height: | Size: 353 B |
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
@ -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);
|
||||
}
|
@ -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;
|
||||
};
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 };
|
||||
};
|
@ -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();
|
||||
}
|
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
@ -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();
|
||||
}
|
@ -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;
|
||||
};
|
@ -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);
|
||||
}
|
@ -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;
|
||||
};
|
@ -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;
|
||||
}
|
@ -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 };
|
||||
};
|
@ -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 {};
|
||||
}
|
@ -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;
|
||||
};
|
@ -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();
|
||||
}
|
@ -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;
|
||||
|