1 #pragma once 2 3 #include <irc/irc_message.hpp> 4 #include <irc/irc_channel.hpp> 5 #include <irc/capability.hpp> 6 7 #include "biboumi.h" 8 9 #ifdef WITH_SASL 10 # include <irc/sasl.hpp> 11 #endif 12 #include <irc/iid.hpp> 13 14 #include <bridge/history_limit.hpp> 15 16 #include <network/tcp_client_socket_handler.hpp> 17 #include <network/resolver.hpp> 18 19 #include <unordered_map> 20 #include <utility> 21 #include <memory> 22 #include <vector> 23 #include <string> 24 #include <stack> 25 #include <deque> 26 #include <map> 27 #include <set> 28 #include <utils/tokens_bucket.hpp> 29 30 class IrcClient; 31 32 using MessageCallback = std::function<void(const IrcClient*, const IrcMessage&)>; 33 34 class Bridge; 35 36 /** 37 * Represent one IRC client, i.e. an endpoint connected to a single IRC 38 * server, through a TCP socket, receiving and sending commands to it. 39 */ 40 class IrcClient: public TCPClientSocketHandler 41 { 42 public: 43 explicit IrcClient(std::shared_ptr<Poller>& poller, std::string hostname, 44 std::string nickname, std::string username, 45 std::string realname, std::string user_hostname, 46 Bridge& bridge); 47 ~IrcClient(); 48 49 IrcClient(const IrcClient&) = delete; 50 IrcClient(IrcClient&&) = delete; 51 IrcClient& operator=(const IrcClient&) = delete; 52 IrcClient& operator=(IrcClient&&) = delete; 53 54 /** 55 * Connect to the IRC server 56 */ 57 void start(); 58 /** 59 * Called when the connection to the server cannot be established 60 */ 61 void on_connection_failed(const std::string& reason) override final; 62 /** 63 * Called when successfully connected to the server 64 */ 65 void on_connected() override final; 66 /** 67 * Close the connection, remove us from the poller 68 */ 69 void on_connection_close(const std::string& error_msg) override final; 70 /** 71 * Parse the data we have received so far and try to get one or more 72 * complete messages from it. 73 */ 74 void parse_in_buffer(const size_t) override final; 75 #ifdef BOTAN_FOUND 76 virtual bool abort_on_invalid_cert() const override final; 77 #endif 78 /** 79 * Return the channel with this name, create it if it does not yet exist 80 */ 81 IrcChannel* get_channel(const std::string& name); 82 /** 83 * Return the channel with this name. Nullptr if it is not found 84 */ 85 const IrcChannel* find_channel(const std::string& name) const; 86 /** 87 * Returns true if the channel is joined 88 */ 89 bool is_channel_joined(const std::string& name); 90 /** 91 * Return our own nick 92 */ 93 std::string get_own_nick() const; 94 /** 95 * Serialize the given message into a line, and send that into the socket 96 * (actually, into our out_buf and signal the poller that we want to wach 97 * for send events to be ready) 98 */ 99 void send_message(IrcMessage message, MessageCallback callback={}, bool throttle=true); 100 void send_raw(const std::string& txt); 101 void actual_send(std::pair<IrcMessage, MessageCallback>&& message_pair); 102 /** 103 * Send the PONG irc command 104 */ 105 void send_pong_command(const IrcMessage& message); 106 /** 107 * Do nothing when we receive a PONG command (but also do not log that no 108 * handler exist) 109 */ 110 void on_pong(const IrcMessage& message); 111 void send_ping_command(); 112 /** 113 * Send the USER irc command 114 */ 115 void send_user_command(const std::string& username, const std::string& realname); 116 /** 117 * Send the NICK irc command 118 */ 119 void send_nick_command(const std::string& username); 120 void send_pass_command(const std::string& password); 121 void send_webirc_command(const std::string& password, const std::string& user_ip); 122 /** 123 * Send the JOIN irc command. 124 */ 125 void send_join_command(const std::string& chan_name, const std::string& password); 126 /** 127 * Send a PRIVMSG command for a channel 128 * Return true if the message was actually sent 129 */ 130 bool send_channel_message(const std::string& chan_name, const std::string& body, 131 MessageCallback callback); 132 /** 133 * Send a PRIVMSG command for an user 134 */ 135 void send_private_message(const std::string& username, const std::string& body, const std::string& type); 136 /** 137 * Send the PART irc command 138 */ 139 void send_part_command(const std::string& chan_name, const std::string& status_message); 140 /** 141 * Send the MODE irc command 142 */ 143 void send_mode_command(const std::string& chan_name, const std::vector<std::string>& arguments); 144 /** 145 * Send the KICK irc command 146 */ 147 void send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason); 148 /** 149 * Send the LIST irc command 150 */ 151 void send_list_command(); 152 void send_invitation(const std::string& chan_name, const std::string& nick); 153 void send_topic_command(const std::string& chan_name, const std::string& topic); 154 /** 155 * Send the QUIT irc command 156 */ 157 void send_quit_command(const std::string& reason); 158 /** 159 * Send a message to the gateway user, not generated by the IRC server, 160 * but that might be useful because we want to be verbose (for example we 161 * might want to notify the user about the connexion state) 162 */ 163 void send_gateway_message(const std::string& message, const std::string& from=""); 164 /** 165 * Forward the server message received from IRC to the XMPP component 166 */ 167 void forward_server_message(const IrcMessage& message); 168 /** 169 * When receiving the isupport informations. See 170 * http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt 171 */ 172 void on_isupport_message(const IrcMessage& message); 173 /** 174 * Does nothing yet. Isn’t that duplicating features from 005? 175 */ 176 void on_server_myinfo(const IrcMessage& message); 177 /** 178 * Just empty the motd we kept as a string 179 */ 180 void empty_motd(const IrcMessage& message); 181 /** 182 * Send the MOTD string as one single "big" message 183 */ 184 void send_motd(const IrcMessage& message); 185 /** 186 * Append this line to the MOTD 187 */ 188 void on_motd_line(const IrcMessage& message); 189 /** 190 * Forward the join of an other user into an IRC channel, and save the 191 * IrcUsers in the IrcChannel 192 */ 193 void set_and_forward_user_list(const IrcMessage& message); 194 /** 195 * Signal the start of the LIST response. The RFC says its obsolete and 196 * “not used”, but I we receive it on some servers, so just ignore it. 197 */ 198 void on_rpl_liststart(const IrcMessage& message); 199 /** 200 * A single LIST response line (one channel) 201 * 202 * The command is handled in a wait_irc callback. This general handler is 203 * empty and just used to avoid sending a message stanza for each received 204 * channel. 205 */ 206 void on_rpl_list(const IrcMessage& message); 207 /** 208 * Signal the end of the LIST response, ignore. 209 */ 210 void on_rpl_listend(const IrcMessage& message); 211 /** 212 * Remember our nick and host, when we are joined to the channel. The list 213 * of user comes after so we do not send the self-presence over XMPP yet. 214 */ 215 void on_channel_join(const IrcMessage& message); 216 /** 217 * When a channel message is received 218 */ 219 void on_channel_message(const IrcMessage& message); 220 /** 221 * A notice is received 222 */ 223 void on_notice(const IrcMessage& message); 224 /** 225 * Save the topic in the IrcChannel 226 */ 227 void on_topic_received(const IrcMessage& message); 228 /** 229 * Save the topic author in the IrcChannel 230 */ 231 void on_topic_who_time_received(const IrcMessage& message); 232 /** 233 * Empty the topic 234 */ 235 void on_empty_topic(const IrcMessage& message); 236 /** 237 * The IRC server is confirming that the invitation has been forwarded 238 */ 239 void on_invited(const IrcMessage& message); 240 /** 241 * The IRC server sends a CAP message, as part of capabilities negociation. It could be a ACK, 242 * NACK, or something else 243 */ 244 void on_cap(const IrcMessage& message); 245 private: 246 void cap_end(); 247 public: 248 #ifdef WITH_SASL 249 void on_authenticate(const IrcMessage& message); 250 void on_sasl_login(const IrcMessage& message); 251 void on_sasl_success(const IrcMessage& message); 252 void on_sasl_failure(const IrcMessage& message); 253 #endif 254 /** 255 * The channel has been completely joined (self presence, topic, all names 256 * received etc), send the self presence and topic to the XMPP user. 257 */ 258 void on_channel_completely_joined(const IrcMessage& message); 259 void on_banlist(const IrcMessage& message); 260 void on_banlist_end(const IrcMessage& message); 261 /** 262 * Save our own host, as reported by the server 263 */ 264 void on_own_host_received(const IrcMessage& message); 265 /** 266 * We tried to set an invalid nickname 267 */ 268 void on_erroneous_nickname(const IrcMessage& message); 269 /** 270 * When the IRC servers denies our nickname because of a conflict. Send a 271 * presence conflict from all channels, because the name is server-wide. 272 */ 273 void on_nickname_conflict(const IrcMessage& message); 274 /** 275 * Idem, but for when the user changes their nickname too quickly 276 */ 277 void on_nickname_change_too_fast(const IrcMessage& message); 278 /** 279 * An error when we try to invite a user already in the channel 280 */ 281 void on_useronchannel(const IrcMessage& message); 282 /** 283 * Handles most errors from the server by just forwarding the message to the user. 284 */ 285 void on_generic_error(const IrcMessage& message); 286 /** 287 * When a message 001 is received, join the rooms we wanted to join, and set our actual nickname 288 */ 289 void on_welcome_message(const IrcMessage& message); 290 void on_part(const IrcMessage& message); 291 void on_error(const IrcMessage& message); 292 void on_invite(const IrcMessage& message); 293 void on_nick(const IrcMessage& message); 294 void on_kick(const IrcMessage& message); 295 void on_mode(const IrcMessage& message); 296 void on_channel_bad_key(const IrcMessage& message); 297 /** 298 * A mode towards our own user is received (note, that is different from a 299 * channel mode towards or own nick, see 300 * http://tools.ietf.org/html/rfc2812#section-3.1.5 VS #section-3.2.3) 301 */ 302 void on_user_mode(const IrcMessage& message); 303 /** 304 * A mode towards a channel. Note that this can change the mode of the 305 * channel itself or an IrcUser in it. 306 */ 307 void on_channel_mode(const IrcMessage& message); 308 void on_quit(const IrcMessage& message); 309 void on_unknown_message(const IrcMessage& message); 310 /** 311 * Return the number of joined channels 312 */ 313 size_t number_of_joined_channels() const; 314 get_hostname() const315 const std::string& get_hostname() const { return this->hostname; } get_nick() const316 std::string get_nick() const { return this->current_nick; } is_welcomed() const317 bool is_welcomed() const { return this->welcomed; } 318 get_resolver() const319 const Resolver& get_resolver() const { return this->dns_resolver; } 320 get_sorted_user_modes() const321 const std::vector<char>& get_sorted_user_modes() const { return this->sorted_user_modes; } 322 get_chantypes() const323 std::set<char> get_chantypes() const { return this->chantypes; } 324 void set_throttle_limit(long int limit); 325 /** 326 * Store the history limit that the client asked when joining this room. 327 */ 328 HistoryLimit history_limit; 329 private: 330 /** 331 * The hostname of the server we are connected to. 332 */ 333 const std::string hostname; 334 /** 335 * Our own host, as reported by the IRC server. 336 * By default (and if it is not overridden by the server), it is a 337 * meaningless string, with the maximum allowed size 338 */ 339 std::string own_host{63, '*'}; 340 /** 341 * The hostname of the user. This is used in the USER and the WEBIRC 342 * commands, but only the one in WEBIRC will be used by the IRC server. 343 */ 344 const std::string user_hostname; 345 /** 346 * The username used in the USER irc command 347 */ 348 std::string username; 349 /** 350 * The realname used in the USER irc command 351 */ 352 std::string realname; 353 /** 354 * Our current nickname on the server 355 */ 356 std::string current_nick; 357 /** 358 * To communicate back with the bridge 359 */ 360 Bridge& bridge; 361 /** 362 * Where messaged are stored when they are throttled. 363 */ 364 std::deque<std::pair<IrcMessage, MessageCallback>> message_queue{}; 365 /** 366 * The list of joined channels, indexed by name 367 */ 368 std::unordered_map<std::string, std::unique_ptr<IrcChannel>> channels; 369 /** 370 * A list of chan we want to join (tuples with the channel name and the 371 * password, if any), but we need a response 001 from the server before 372 * sending the actual JOIN commands. So we just keep the channel names in 373 * a list, and send the JOIN commands for each of them whenever the 374 * WELCOME message is received. 375 */ 376 std::vector<std::tuple<std::string, std::string>> channels_to_join; 377 /** 378 * This flag indicates that the server is completely joined (connection 379 * has been established, we are authentified and we have a nick) 380 */ 381 bool welcomed; 382 #ifdef WITH_SASL 383 /** 384 * Whether or not we are trying to authenticate using sasl. If this is true we need to wait for a 385 * successful auth 386 */ 387 SaslState sasl_state{SaslState::unneeded}; 388 #endif 389 std::map<std::string, Capability> capabilities; 390 /** 391 * See http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt section 3.3 392 * We store the possible chanmodes in this object. 393 * chanmodes[0] contains modes of type A, [1] of type B etc 394 */ 395 std::vector<std::string> chanmodes; 396 /** 397 * See http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt 398 * section 3.5 399 */ 400 std::set<char> chantypes; 401 /** 402 * Each motd line received is appended to this string, which we send when 403 * the motd is completely received 404 */ 405 std::string motd; 406 /** 407 * See http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt section 3.14 408 * The example given would be transformed into 409 * modes_to_prefix = {{'&', 'a'}, {'*', 'b'}} 410 */ 411 std::map<char, char> prefix_to_mode; 412 /** 413 * Available user modes, sorted from most significant to least significant 414 * (for example 'ahov' is a common order). 415 */ 416 std::vector<char> sorted_user_modes; 417 /** 418 * A list of ports to which we will try to connect, in reverse. Each port 419 * is associated with a boolean telling if we should use TLS or not if the 420 * connection succeeds on that port. 421 */ 422 std::stack<std::pair<std::string, bool>> ports_to_try; 423 /** 424 * A set of (lowercase) nicknames to which we sent a private message. 425 */ 426 std::set<std::string> nicks_to_treat_as_private; 427 /** 428 * DNS resolver, used to resolve the hostname of the user if we are using 429 * the WebIRC protocole. 430 */ 431 Resolver dns_resolver; 432 TokensBucket tokens_bucket; 433 long int get_throttle_limit() const; 434 }; 435 436 437