qulogic/pidgin

IRCv3: Implement basic CTCP support

5 months ago, Gary Kramlich
55b30ce86f17
Parents f00a798a38a6
Children 82fffff36df6
IRCv3: Implement basic CTCP support

This is just the scaffolding for it and doesn't implement any actual commands.

Testing Done:
Sent some `CTCP VERSION`'s to an IRCv3 account. Also manually sent `CTCP VERSION`'s to users and channel via temporary code in when the connection was fully established.

Reviewed at https://reviews.imfreedom.org/r/2854/
--- a/libpurple/protocols/ircv3/meson.build Thu Nov 30 22:18:04 2023 -0600
+++ b/libpurple/protocols/ircv3/meson.build Thu Nov 30 22:38:54 2023 -0600
@@ -2,6 +2,7 @@
'purpleircv3capabilities.c',
'purpleircv3connection.c',
'purpleircv3core.c',
+ 'purpleircv3ctcp.c',
'purpleircv3formatting.c',
'purpleircv3message.c',
'purpleircv3messagehandlers.c',
@@ -17,6 +18,7 @@
'purpleircv3connection.h',
'purpleircv3constants.h',
'purpleircv3core.h',
+ 'purpleircv3ctcp.h',
'purpleircv3formatting.h',
'purpleircv3message.h',
'purpleircv3messagehandlers.h',
--- a/libpurple/protocols/ircv3/purpleircv3connection.c Thu Nov 30 22:18:04 2023 -0600
+++ b/libpurple/protocols/ircv3/purpleircv3connection.c Thu Nov 30 22:38:54 2023 -0600
@@ -36,6 +36,8 @@
enum {
SIG_REGISTRATION_COMPLETE,
+ SIG_CTCP_REQUEST,
+ SIG_CTCP_RESPONSE,
N_SIGNALS,
};
static guint signals[N_SIGNALS] = {0, };
@@ -606,6 +608,52 @@
NULL,
G_TYPE_NONE,
0);
+
+ /**
+ * PurpleIRCv3Connection::ctcp-request:
+ * @connection: The instance.
+ * @command: The CTCP command.
+ * @params: (nullable): The CTCP parameters.
+ *
+ * This signal is emitted after a CTCP request has been received.
+ *
+ * Since: 3.0.0
+ */
+ signals[SIG_CTCP_REQUEST] = g_signal_new_class_handler(
+ "ctcp-request",
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ /**
+ * PurpleIRCv3Connection::ctcp-response:
+ * @connection: The instance.
+ * @command: The CTCP command.
+ * @params: (nullable): The CTCP parameters.
+ *
+ * This signal is emitted after a CTCP response has been received.
+ *
+ * Since: 3.0.0
+ */
+ signals[SIG_CTCP_RESPONSE] = g_signal_new_class_handler(
+ "ctcp-response",
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
}
/******************************************************************************
@@ -639,6 +687,30 @@
return priv->cancellable;
}
+void
+purple_ircv3_connection_emit_ctcp_request(PurpleIRCv3Connection *connection,
+ const char *command,
+ const char *parameters)
+{
+ g_return_if_fail(PURPLE_IRCV3_IS_CONNECTION(connection));
+ g_return_if_fail(!purple_strempty(command));
+
+ g_signal_emit(connection, signals[SIG_CTCP_REQUEST], 0, command,
+ parameters);
+}
+
+void
+purple_ircv3_connection_emit_ctcp_response(PurpleIRCv3Connection *connection,
+ const char *command,
+ const char *parameters)
+{
+ g_return_if_fail(PURPLE_IRCV3_IS_CONNECTION(connection));
+ g_return_if_fail(!purple_strempty(command));
+
+ g_signal_emit(connection, signals[SIG_CTCP_RESPONSE], 0, command,
+ parameters);
+}
+
/******************************************************************************
* Public API
*****************************************************************************/
--- a/libpurple/protocols/ircv3/purpleircv3connection.h Thu Nov 30 22:18:04 2023 -0600
+++ b/libpurple/protocols/ircv3/purpleircv3connection.h Thu Nov 30 22:38:54 2023 -0600
@@ -75,6 +75,32 @@
G_GNUC_INTERNAL GCancellable *purple_ircv3_connection_get_cancellable(PurpleIRCv3Connection *connection);
/**
+ * purple_ircv3_connection_emit_ctcp_request:
+ * @connection: The instance.
+ * @command: The CTCP command.
+ * @parameters: (nullable): The CTCP parameters.
+ *
+ * Emits the [signal@Connection:ctcp-request] signal with the given @command
+ * and @parameters.
+ *
+ * Since: 3.0.0
+ */
+G_GNUC_INTERNAL void purple_ircv3_connection_emit_ctcp_request(PurpleIRCv3Connection *connection, const char *command, const char *parameters);
+
+/**
+ * purple_ircv3_connection_emit_ctcp_response:
+ * @connection: The instance.
+ * @command: The CTCP command.
+ * @parameters: (nullable): The CTCP parameters.
+ *
+ * Emits the [signal@Connection:ctcp-response] signal with the given @command
+ * and @parameters.
+ *
+ * Since: 3.0.0
+ */
+G_GNUC_INTERNAL void purple_ircv3_connection_emit_ctcp_response(PurpleIRCv3Connection *connection, const char *command, const char *parameters);
+
+/**
* purple_ircv3_connection_writef:
* @connection: The instance.
* @format: The format string.
--- a/libpurple/protocols/ircv3/purpleircv3constants.h Thu Nov 30 22:18:04 2023 -0600
+++ b/libpurple/protocols/ircv3/purpleircv3constants.h Thu Nov 30 22:38:54 2023 -0600
@@ -24,6 +24,15 @@
#define PURPLE_IRCV3_CONSTANTS_H
/**
+ * PURPLE_IRCV3_CTCP_DELIMITER:
+ *
+ * The delimiter used for CTCP messages.
+ *
+ * Since: 3.0.0
+ */
+#define PURPLE_IRCV3_CTCP_DELIMITER (0x1) PURPLE_IRCV3_AVAILABLE_MACRO_IN_3_0
+
+/**
* PURPLE_IRCV3_ERR_NICKLOCKED:
*
* A constant for the IRC %NICKLOCKED error.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/ircv3/purpleircv3ctcp.c Thu Nov 30 22:38:54 2023 -0600
@@ -0,0 +1,103 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n-lib.h>
+
+#include "purpleircv3ctcp.h"
+
+#include "purpleircv3constants.h"
+
+/******************************************************************************
+ * Internal API
+ *****************************************************************************/
+void
+purple_ircv3_ctcp_handle(PurpleIRCv3Connection *connection,
+ PurpleMessage *message)
+{
+ const char *contents = NULL;
+
+ g_return_if_fail(PURPLE_IRCV3_IS_CONNECTION(connection));
+ g_return_if_fail(PURPLE_IS_MESSAGE(message));
+
+ contents = purple_message_get_contents(message);
+ if(contents != NULL && contents[0] == PURPLE_IRCV3_CTCP_DELIMITER) {
+ PurpleMessageFlags flags;
+ char *command = NULL;
+ char *contents = NULL;
+ char *params = NULL;
+ char *ptr = NULL;
+
+ /* Move past the delimiter. */
+ contents += 1;
+
+ /* Find the delimiter for the command. */
+ ptr = g_strstr_len(contents, -1, " ");
+
+ /* If we don't have a space, then we have no parameters. */
+ if(ptr == NULL) {
+ size_t len = strlen(contents);
+
+ command = g_strdup(contents);
+ if(command[len - 1] == PURPLE_IRCV3_CTCP_DELIMITER) {
+ command[len - 1] = '\0';
+ }
+ } else {
+ size_t len = 0;
+
+ command = g_strndup(contents, ptr - contents);
+
+ params = g_strdup(ptr + 1);
+ len = strlen(params);
+ if(params[len - 1] == PURPLE_IRCV3_CTCP_DELIMITER) {
+ params[len - 1] = '\0';
+ }
+ }
+
+ flags = purple_message_get_flags(message);
+ if(flags & PURPLE_MESSAGE_NOTIFY) {
+ if(!purple_strempty(params)) {
+ contents = g_strdup_printf(_("CTCP %s response: %s"), command,
+ params);
+ } else {
+ contents = g_strdup_printf(_("CTCP %s response was empty"),
+ command);
+ }
+
+ purple_ircv3_connection_emit_ctcp_response(connection, command,
+ params);
+ } else {
+ if(!purple_strempty(params)) {
+ contents = g_strdup_printf(_("requested CTCP %s: %s"), command,
+ params);
+ } else {
+ contents = g_strdup_printf(_("requested CTCP %s"), command);
+ }
+
+ purple_ircv3_connection_emit_ctcp_request(connection, command,
+ params);
+ }
+
+ if(!purple_strempty(contents)) {
+ purple_message_set_contents(message, contents);
+ }
+
+ g_clear_pointer(&contents, g_free);
+ g_clear_pointer(&command, g_free);
+ g_clear_pointer(&params, g_free);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/ircv3/purpleircv3ctcp.h Thu Nov 30 22:38:54 2023 -0600
@@ -0,0 +1,49 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+#if !defined(PURPLE_IRCV3_GLOBAL_HEADER_INSIDE) && \
+ !defined(PURPLE_IRCV3_COMPILATION)
+# error "only <libpurple/protocols/ircv3.h> may be included directly"
+#endif
+
+#ifndef PURPLE_IRCV3_CTCP_H
+#define PURPLE_IRCV3_CTCP_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <purple.h>
+
+#include "purpleircv3connection.h"
+
+G_BEGIN_DECLS
+
+/**
+ * purple_ircv3_ctcp_handle: (skip)
+ * @connection: The connection instance.
+ * @message: The message instance.
+ *
+ * Check if @message is a CTCP message and handles it accordingly.
+ *
+ * Since: 3.0.0
+ */
+G_GNUC_INTERNAL
+void purple_ircv3_ctcp_handle(PurpleIRCv3Connection *connection, PurpleMessage *message);
+
+G_END_DECLS
+
+#endif /* PURPLE_IRCV3_CTCP_H */
--- a/libpurple/protocols/ircv3/purpleircv3messagehandlers.c Thu Nov 30 22:18:04 2023 -0600
+++ b/libpurple/protocols/ircv3/purpleircv3messagehandlers.c Thu Nov 30 22:38:54 2023 -0600
@@ -23,6 +23,7 @@
#include "purpleircv3connection.h"
#include "purpleircv3constants.h"
#include "purpleircv3core.h"
+#include "purpleircv3ctcp.h"
#include "purpleircv3formatting.h"
#include "purpleircv3source.h"
@@ -227,6 +228,9 @@
g_date_time_unref(dt);
+ /* Check if this is a CTCP message. */
+ purple_ircv3_ctcp_handle(connection, message);
+
purple_conversation_write_message(conversation, message);
g_clear_pointer(&nick, g_free);