summaryrefslogtreecommitdiff
path: root/Applications
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-09-03 21:18:28 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-09-03 21:18:28 +0200
commit5c7ef5977d7c867069a8b2d320a3ebb99fe7c658 (patch)
treea9ba04a735d99df62bd3bbb6bb5e9ededc10f4bd /Applications
parent9ffe8feff4bdc536f92fbee16e0ce66c077e0674 (diff)
downloadserenity-5c7ef5977d7c867069a8b2d320a3ebb99fe7c658.zip
IRCClient: Handle incoming CTCP requests VERSION and PING
CTCP requests are client-to-client messages that are sent as either PRIVMSG (for requests) or NOTICE (for responses) and wrapped in ASCII character 0x01 on both sides. This patch implements responding to the very common VERSION and PING requests. We always get a VERSION request from freenode when connecting there, for instance. :^)
Diffstat (limited to 'Applications')
-rw-r--r--Applications/IRCClient/IRCClient.cpp69
-rw-r--r--Applications/IRCClient/IRCClient.h4
2 files changed, 69 insertions, 4 deletions
diff --git a/Applications/IRCClient/IRCClient.cpp b/Applications/IRCClient/IRCClient.cpp
index 8847270438..2b93fba7c3 100644
--- a/Applications/IRCClient/IRCClient.cpp
+++ b/Applications/IRCClient/IRCClient.cpp
@@ -1,10 +1,11 @@
-#include "IRCAppWindow.h"
#include "IRCClient.h"
+#include "IRCAppWindow.h"
#include "IRCChannel.h"
#include "IRCLogBuffer.h"
#include "IRCQuery.h"
#include "IRCWindow.h"
#include "IRCWindowListModel.h"
+#include <AK/StringBuilder.h>
#include <LibCore/CNotifier.h>
#include <arpa/inet.h>
#include <netinet/in.h>
@@ -291,6 +292,11 @@ void IRCClient::send_privmsg(const String& target, const String& text)
send(String::format("PRIVMSG %s :%s\r\n", target.characters(), text.characters()));
}
+void IRCClient::send_notice(const String& target, const String& text)
+{
+ send(String::format("NOTICE %s :%s\r\n", target.characters(), text.characters()));
+}
+
void IRCClient::handle_user_input_in_channel(const String& channel_name, const String& input)
{
if (input.is_empty())
@@ -330,6 +336,11 @@ bool IRCClient::is_nick_prefix(char ch) const
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)
@@ -340,9 +351,12 @@ void IRCClient::handle_privmsg_or_notice(const Message& msg, PrivmsgOrNotice typ
auto sender_nick = parts[0];
auto target = msg.arguments[0];
+ bool is_ctcp = has_ctcp_payload(msg.arguments[1]);
+
#ifdef IRC_DEBUG
- printf("handle_privmsg_or_notice: type='%s', sender_nick='%s', target='%s'\n",
+ printf("handle_privmsg_or_notice: type='%s'%s, sender_nick='%s', target='%s'\n",
type == PrivmsgOrNotice::Privmsg ? "privmsg" : "notice",
+ is_ctcp ? " (ctcp)" : "",
sender_nick.characters(),
target.characters());
#endif
@@ -356,15 +370,31 @@ void IRCClient::handle_privmsg_or_notice(const Message& msg, PrivmsgOrNotice typ
sender_nick = sender_nick.substring(1, sender_nick.length() - 1);
}
+ String message_text = msg.arguments[1];
+ auto message_color = Color::Black;
+
+ 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);
+ StringBuilder builder;
+ builder.append("(CTCP) ");
+ builder.append(ctcp_payload);
+ message_text = builder.to_string();
+ message_color = Color::Blue;
+ }
+
{
auto it = m_channels.find(target);
if (it != m_channels.end()) {
- (*it).value->add_message(sender_prefix, sender_nick, msg.arguments[1]);
+ (*it).value->add_message(sender_prefix, sender_nick, message_text, message_color);
return;
}
}
auto& query = ensure_query(sender_nick);
- query.add_message(sender_prefix, sender_nick, msg.arguments[1]);
+ query.add_message(sender_prefix, sender_nick, message_text, message_color);
}
IRCQuery& IRCClient::ensure_query(const String& name)
@@ -671,3 +701,34 @@ 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::handle_ctcp_request(const StringView& peer, const StringView& payload)
+{
+ dbg() << "handle_ctcp_request: " << payload;
+
+ if (payload == "VERSION") {
+ send_ctcp_response(peer, "VERSION IRC Client [x86] / Serenity OS");
+ return;
+ }
+
+ // FIXME: Add StringView::starts_with()
+ if (String(payload).starts_with("PING")) {
+ send_ctcp_response(peer, payload);
+ return;
+ }
+}
+
+void IRCClient::handle_ctcp_response(const StringView& peer, const StringView& payload)
+{
+ dbg() << "handle_ctcp_response(" << peer << "): " << payload;
+}
diff --git a/Applications/IRCClient/IRCClient.h b/Applications/IRCClient/IRCClient.h
index 2c1fd22d20..02891a09ff 100644
--- a/Applications/IRCClient/IRCClient.h
+++ b/Applications/IRCClient/IRCClient.h
@@ -105,6 +105,7 @@ private:
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_whois(const String&);
void process_line(ByteBuffer&&);
void handle_join(const Message&);
@@ -125,6 +126,9 @@ private:
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_response(const StringView& peer, const StringView& payload);
void on_socket_connected();