Serenity Operating System
at hosted 221 lines 9.0 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#pragma once 28 29#include "IRCLogBuffer.h" 30#include "IRCWindow.h" 31#include <AK/CircularQueue.h> 32#include <AK/Function.h> 33#include <AK/HashMap.h> 34#include <AK/String.h> 35#include <LibCore/ConfigFile.h> 36#include <LibCore/TCPSocket.h> 37 38class IRCChannel; 39class IRCQuery; 40class IRCWindowListModel; 41 42class IRCClient final : public Core::Object { 43 C_OBJECT(IRCClient) 44 friend class IRCChannel; 45 friend class IRCQuery; 46 47public: 48 virtual ~IRCClient() override; 49 50 void set_server(const String& hostname, int port = 6667); 51 52 bool connect(); 53 54 String hostname() const { return m_hostname; } 55 int port() const { return m_port; } 56 57 String nickname() const { return m_nickname; } 58 59 String ctcp_version_reply() const { return m_ctcp_version_reply; } 60 String ctcp_userinfo_reply() const { return m_ctcp_userinfo_reply; } 61 String ctcp_finger_reply() const { return m_ctcp_finger_reply; } 62 63 void join_channel(const String&); 64 void part_channel(const String&); 65 void change_nick(const String&); 66 67 static bool is_nick_prefix(char); 68 static bool is_channel_prefix(char); 69 String nick_without_prefix(const String& nick); 70 71 IRCWindow* current_window() { return aid_get_active_window(); } 72 const IRCWindow* current_window() const { return aid_get_active_window(); } 73 74 Function<void()> on_disconnect; 75 Function<void()> on_server_message; 76 Function<void(const String&)> on_nickname_changed; 77 Function<void(IRCChannel&)> on_part_from_channel; 78 79 Function<NonnullRefPtr<IRCWindow>(void*, IRCWindow::Type, const String&)> aid_create_window; 80 Function<IRCWindow*()> aid_get_active_window; 81 Function<void()> aid_update_window_list; 82 83 void register_subwindow(IRCWindow&); 84 void unregister_subwindow(IRCWindow&); 85 86 IRCWindowListModel* client_window_list_model() { return m_client_window_list_model.ptr(); } 87 const IRCWindowListModel* client_window_list_model() const { return m_client_window_list_model.ptr(); } 88 89 int window_count() const { return m_windows.size(); } 90 const IRCWindow& window_at(int index) const { return *m_windows.at(index); } 91 IRCWindow& window_at(int index) { return *m_windows.at(index); } 92 93 size_t window_index(const IRCWindow& window) const 94 { 95 for (size_t i = 0; i < m_windows.size(); ++i) { 96 if (m_windows[i] == &window) 97 return i; 98 } 99 ASSERT_NOT_REACHED(); 100 } 101 102 void did_part_from_channel(Badge<IRCChannel>, IRCChannel&); 103 104 void handle_user_input_in_channel(const String& channel_name, const String&); 105 void handle_user_input_in_query(const String& query_name, const String&); 106 void handle_user_input_in_server(const String&); 107 108 void handle_list_channels_action(); 109 void handle_whois_action(const String& nick); 110 void handle_open_query_action(const String&); 111 void handle_close_query_action(const String&); 112 void handle_join_action(const String& channel_name); 113 void handle_part_action(const String& channel_name); 114 void handle_cycle_channel_action(const String& channel_name); 115 void handle_change_nick_action(const String& nick); 116 void handle_change_topic_action(const String& channel_name, const String&); 117 void handle_invite_user_action(const String& channel_name, const String& nick); 118 void handle_banlist_action(const String& channel_name); 119 void handle_voice_user_action(const String& channel_name, const String& nick); 120 void handle_devoice_user_action(const String& channel_name, const String& nick); 121 void handle_hop_user_action(const String& channel_name, const String& nick); 122 void handle_dehop_user_action(const String& channel_name, const String& nick); 123 void handle_op_user_action(const String& channel_name, const String& nick); 124 void handle_deop_user_action(const String& channel_name, const String& nick); 125 void handle_kick_user_action(const String& channel_name, const String& nick, const String&); 126 127 IRCQuery* query_with_name(const String&); 128 IRCQuery& ensure_query(const String& name); 129 IRCChannel& ensure_channel(const String& name); 130 131 void add_server_message(const String&, Color = Color::Black); 132 133private: 134 IRCClient(); 135 136 struct Message { 137 String prefix; 138 String command; 139 Vector<String> arguments; 140 }; 141 142 enum class PrivmsgOrNotice { 143 Privmsg, 144 Notice, 145 }; 146 147 void receive_from_server(); 148 void send(const String&); 149 void send_user(); 150 void send_nick(); 151 void send_pong(const String& server); 152 void send_privmsg(const String& target, const String&); 153 void send_notice(const String& target, const String&); 154 void send_topic(const String& channel_name, const String&); 155 void send_invite(const String& channel_name, const String& nick); 156 void send_banlist(const String& channel_name); 157 void send_voice_user(const String& channel_name, const String& nick); 158 void send_devoice_user(const String& channel_name, const String& nick); 159 void send_hop_user(const String& channel_name, const String& nick); 160 void send_dehop_user(const String& channel_name, const String& nick); 161 void send_op_user(const String& channel_name, const String& nick); 162 void send_deop_user(const String& channel_name, const String& nick); 163 void send_kick(const String& channel_name, const String& nick, const String&); 164 void send_list(); 165 void send_whois(const String&); 166 void process_line(ByteBuffer&&); 167 void handle_join(const Message&); 168 void handle_part(const Message&); 169 void handle_quit(const Message&); 170 void handle_ping(const Message&); 171 void handle_topic(const Message&); 172 void handle_rpl_topic(const Message&); 173 void handle_rpl_whoisuser(const Message&); 174 void handle_rpl_whoisserver(const Message&); 175 void handle_rpl_whoisoperator(const Message&); 176 void handle_rpl_whoisidle(const Message&); 177 void handle_rpl_endofwho(const Message&); 178 void handle_rpl_endofwhois(const Message&); 179 void handle_rpl_endofwhowas(const Message&); 180 void handle_rpl_endofmotd(const Message&); 181 void handle_rpl_whoischannels(const Message&); 182 void handle_rpl_topicwhotime(const Message&); 183 void handle_rpl_endofnames(const Message&); 184 void handle_rpl_endofbanlist(const Message&); 185 void handle_rpl_namreply(const Message&); 186 void handle_rpl_banlist(const Message&); 187 void handle_err_nosuchnick(const Message&); 188 void handle_err_unknowncommand(const Message&); 189 void handle_err_nicknameinuse(const Message&); 190 void handle_privmsg_or_notice(const Message&, PrivmsgOrNotice); 191 void handle_nick(const Message&); 192 void handle(const Message&); 193 void handle_user_command(const String&); 194 void handle_ctcp_request(const StringView& peer, const StringView& payload); 195 void handle_ctcp_response(const StringView& peer, const StringView& payload); 196 void send_ctcp_response(const StringView& peer, const StringView& payload); 197 198 void on_socket_connected(); 199 200 String m_hostname; 201 int m_port { 6667 }; 202 203 RefPtr<Core::TCPSocket> m_socket; 204 205 String m_nickname; 206 RefPtr<Core::Notifier> m_notifier; 207 HashMap<String, RefPtr<IRCChannel>, CaseInsensitiveStringTraits> m_channels; 208 HashMap<String, RefPtr<IRCQuery>, CaseInsensitiveStringTraits> m_queries; 209 210 String m_ctcp_version_reply; 211 String m_ctcp_userinfo_reply; 212 String m_ctcp_finger_reply; 213 214 Vector<IRCWindow*> m_windows; 215 216 IRCWindow* m_server_subwindow { nullptr }; 217 218 NonnullRefPtr<IRCWindowListModel> m_client_window_list_model; 219 NonnullRefPtr<IRCLogBuffer> m_log; 220 NonnullRefPtr<Core::ConfigFile> m_config; 221};