--- a/libpurple/protocols/ircv3/README.md Fri Feb 10 03:03:39 2023 -0600
+++ b/libpurple/protocols/ircv3/README.md Thu Feb 16 08:13:28 2023 -0600
@@ -16,5 +16,6 @@
keep this list up to date, but if you notice we've missed something please let
* sasl (right now just PLAIN works)
--- a/libpurple/protocols/ircv3/purpleircv3capabilities.c Fri Feb 10 03:03:39 2023 -0600
+++ b/libpurple/protocols/ircv3/purpleircv3capabilities.c Thu Feb 16 08:13:28 2023 -0600
@@ -108,7 +108,6 @@
PurpleAccount *account = NULL;
PurpleConnection *purple_connection = NULL;
- gboolean found = FALSE;
purple_connection = PURPLE_CONNECTION(capabilities->connection);
account = purple_connection_get_account(purple_connection);
@@ -117,7 +116,10 @@
* require-password option.
if(purple_account_get_require_password(account)) {
+ gboolean found = FALSE; purple_ircv3_capabilities_lookup(capabilities, "sasl", &found);
purple_ircv3_sasl_request(capabilities);
@@ -126,10 +128,12 @@
/* cap-notify is implied when we use CAP LS 302, so this is really just to
* make sure it's requested.
- purple_ircv3_capabilities_lookup(capabilities, "cap-notify", &found);
- purple_ircv3_capabilities_request(capabilities, "cap-notify");
+ purple_ircv3_capabilities_lookup_and_request(capabilities, "cap-notify"); + /* message-tags is used for a lot of stuff so we need to tell everyone we + * do in fact support it. + purple_ircv3_capabilities_lookup_and_request(capabilities, "message-tags"); /******************************************************************************
@@ -616,6 +620,23 @@
+purple_ircv3_capabilities_lookup_and_request(PurpleIRCv3Capabilities *capabilities, + gboolean found = FALSE; + g_return_val_if_fail(PURPLE_IRCV3_IS_CAPABILITIES(capabilities), FALSE); + g_return_val_if_fail(name != NULL, FALSE); + purple_ircv3_capabilities_lookup(capabilities, name, &found); + purple_ircv3_capabilities_request(capabilities, name); purple_ircv3_capabilities_add_wait(PurpleIRCv3Capabilities *capabilities) {
g_return_if_fail(PURPLE_IRCV3_IS_CAPABILITIES(capabilities));
--- a/libpurple/protocols/ircv3/purpleircv3capabilities.h Fri Feb 10 03:03:39 2023 -0600
+++ b/libpurple/protocols/ircv3/purpleircv3capabilities.h Thu Feb 16 08:13:28 2023 -0600
@@ -85,6 +85,26 @@
const char *purple_ircv3_capabilities_lookup(PurpleIRCv3Capabilities *capabilities, const char *name, gboolean *found);
+ * purple_ircv3_capabilities_lookup_and_request: + * @capabilities: The instance. + * @name: The name of the capability to look for. + * A helper function to call [method@PurpleIRCv3.Capabilities.Lookup] and if + * found, call [method@PurpleIRCv3.Capabilities.Request]. + * This method ignores the advertised value, so to get that you'll need to call + * [method@PurpleIRCv3.Capabilities.Lookup] yourself. + * Also if you need to do something when the server ACK's or NAK's your + * request, you're probably better off just using the methods yourself. + * Returns: %TRUE if @name was found and requested, %FALSE otherwise. +gboolean purple_ircv3_capabilities_lookup_and_request(PurpleIRCv3Capabilities *capabilities, const char *name); * purple_ircv3_capabilties_add_wait:
* @capabilities: The instance.
--- a/libpurple/protocols/ircv3/purpleircv3parser.c Fri Feb 10 03:03:39 2023 -0600
+++ b/libpurple/protocols/ircv3/purpleircv3parser.c Thu Feb 16 08:13:28 2023 -0600
@@ -267,8 +267,11 @@
g_assert(parser->regex_message != NULL);
- parser->regex_tags = g_regex_new("(?:(?<key>[A-Za-z0-9-\\/]+)"
- "(?:=(?<value>[^\\r\\n;]*))?(?:;|$))",
+ parser->regex_tags = g_regex_new("(?<key>(?<client_prefix>\\+?)" + "(?:(?<vendor>[A-Za-z0-9-\\.]+)\\/)?" + "(?<key_name>[A-Za-z0-9-]+)" + "(?:=(?<value>[^\r\n;]*))?(?:;|$)", g_assert(parser->regex_tags != NULL);
--- a/libpurple/protocols/ircv3/tests/test_ircv3_parser.c Fri Feb 10 03:03:39 2023 -0600
+++ b/libpurple/protocols/ircv3/tests/test_ircv3_parser.c Thu Feb 16 08:13:28 2023 -0600
@@ -594,6 +594,85 @@
/******************************************************************************
+ * Message tags examples + *****************************************************************************/ +test_purple_ircv3_parser_message_tags_none(void) { + TestPurpleIRCv3ParserData data = { + .source = "nick!ident@host.com", + .params = {"me", "Hello"}, + const char *msg = NULL; + msg = ":nick!ident@host.com PRIVMSG me :Hello"; + test_purple_ircv3_parser(msg, &data); +test_purple_ircv3_parser_message_tags_3_tags(void) { + TestPurpleIRCv3ParserData data = { + .source = "nick!ident@host.com", + .params = {"me", "Hello"}, + const char *msg = NULL; + data.tags = g_hash_table_new(g_str_hash, g_str_equal); + g_hash_table_insert(data.tags, "aaa", "bbb"); + g_hash_table_insert(data.tags, "ccc", ""); + g_hash_table_insert(data.tags, "example.com/ddd", "eee"); + msg = "@aaa=bbb;ccc;example.com/ddd=eee :nick!ident@host.com PRIVMSG me " + test_purple_ircv3_parser(msg, &data); +test_purple_ircv3_parser_message_tags_client_only(void) { + TestPurpleIRCv3ParserData data = { + .source = "url_bot!bot@example.com", + .params = {"#channel", "Example.com: A News Story"}, + const char *msg = NULL; + data.tags = g_hash_table_new(g_str_hash, g_str_equal); + g_hash_table_insert(data.tags, "+icon", "https://example.com/favicon.png"); + msg = "@+icon=https://example.com/favicon.png :url_bot!bot@example.com " + "PRIVMSG #channel :Example.com: A News Story"; + test_purple_ircv3_parser(msg, &data); +test_purple_ircv3_parser_message_tags_labeled_response(void) { + TestPurpleIRCv3ParserData data = { + .source = "nick!user@example.com", + .params = {"#channel"}, + const char *msg = NULL; + data.tags = g_hash_table_new(g_str_hash, g_str_equal); + g_hash_table_insert(data.tags, "label", "123"); + g_hash_table_insert(data.tags, "msgid", "abc"); + g_hash_table_insert(data.tags, "+example-client-tag", "example-value"); + msg = "@label=123;msgid=abc;+example-client-tag=example-value " + ":nick!user@example.com TAGMSG #channel"; + test_purple_ircv3_parser(msg, &data); +/****************************************************************************** *****************************************************************************/
@@ -686,5 +765,17 @@
g_test_add_func("/ircv3/parser/special-mode-2",
test_purple_ircv3_special_mode_2);
+ /* These tests are the examples from the message-tags specification, + * https://ircv3.net/specs/extensions/message-tags.html. + g_test_add_func("/ircv3/parser/message-tags/none", + test_purple_ircv3_parser_message_tags_none); + g_test_add_func("/ircv3/parser/message-tags/3-tags", + test_purple_ircv3_parser_message_tags_3_tags); + g_test_add_func("/ircv3/parser/message-tags/client-only", + test_purple_ircv3_parser_message_tags_client_only); + g_test_add_func("/ircv3/parser/message-tags/labeled-message", + test_purple_ircv3_parser_message_tags_labeled_response);