From: Janne Mareike Koschinski Date: Tue, 23 Feb 2021 20:25:03 +0000 (+0100) Subject: ircv3: Add support for weird tag names, per the spec X-Git-Tag: 0.14-rc2~26 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=c33c05dbcb7c0c9a51dc3d9d85334e2482d5e18e ircv3: Add support for weird tag names, per the spec IRCv3 currently does not specify (or recommend specifying) any tag names which would contain multiple slashes, but IRCv3 does recommend clients should gracefully handle any possible tag, ideally treating it as opaque string. We’d like to avoid that, but also want to ensure even after a roundtrip through our core, tags we don’t support are still in identical condition. --- diff --git a/src/common/ircdecoder.cpp b/src/common/ircdecoder.cpp index cadefbf7..5eb0e6d1 100644 --- a/src/common/ircdecoder.cpp +++ b/src/common/ircdecoder.cpp @@ -54,9 +54,11 @@ QString IrcDecoder::parseTagValue(const QString& value) result.append(*it); } escaped = false; - } else if (it->unicode() == '\\') { + } + else if (it->unicode() == '\\') { escaped = true; - } else { + } + else { result.append(*it); } } @@ -125,9 +127,15 @@ QHash IrcDecoder::parseTags(const std::function splitByVendorAndKey = rawKey.split('/'); - if (!splitByVendorAndKey.isEmpty()) key.key = splitByVendorAndKey.takeLast(); - if (!splitByVendorAndKey.isEmpty()) key.vendor = splitByVendorAndKey.takeLast(); + + int splitIndex = rawKey.lastIndexOf('/'); + if (splitIndex > 0 && splitIndex + 1 < rawKey.length()) { + key.key = rawKey.mid(splitIndex + 1); + key.vendor = rawKey.left(splitIndex); + } + else { + key.key = rawKey; + } tags[key] = parseTagValue(rawValue); } return tags; @@ -155,7 +163,12 @@ QByteArray IrcDecoder::parseParameter(const QByteArray& raw, int& start) } } -void IrcDecoder::parseMessage(const std::function& decode, const QByteArray& rawMsg, QHash& tags, QString& prefix, QString& command, QList& parameters) +void IrcDecoder::parseMessage(const std::function& decode, + const QByteArray& rawMsg, + QHash& tags, + QString& prefix, + QString& command, + QList& parameters) { int start = 0; skipEmptyParts(rawMsg, start); @@ -170,7 +183,6 @@ void IrcDecoder::parseMessage(const std::function& d QByteArray param = parseParameter(rawMsg, start); skipEmptyParts(rawMsg, start); params.append(param); - } parameters = params; } diff --git a/tests/common/ircdecodertest.cpp b/tests/common/ircdecodertest.cpp index 09363366..380a038f 100644 --- a/tests/common/ircdecodertest.cpp +++ b/tests/common/ircdecodertest.cpp @@ -150,6 +150,30 @@ TEST(IrcDecoderTest, with_tags) {IrcTagKey("rt"), "ql7"}}, "", "foo")); + + EXPECT_EQ(parse("@a=b foo"), + IrcMessage( + {{IrcTagKey("a"), "b"}}, + "", + "foo")); + + EXPECT_EQ(parse("@example.com/a=b foo"), + IrcMessage( + {{IrcTagKey("example.com", "a"), "b"}}, + "", + "foo")); + + EXPECT_EQ(parse("@example.com/subfolder/to/a=b foo"), + IrcMessage( + {{IrcTagKey("example.com/subfolder/to", "a"), "b"}}, + "", + "foo")); + + EXPECT_EQ(parse("@v\\/e\\/n\\/d\\/o\\/r/tag=b foo"), + IrcMessage( + {{IrcTagKey("v\\/e\\/n\\/d\\/o\\/r", "tag"), "b"}}, + "", + "foo")); } TEST(IrcDecoderTest, with_escaped_tags) diff --git a/tests/common/ircencodertest.cpp b/tests/common/ircencodertest.cpp index 38b50e0e..e723ae0a 100644 --- a/tests/common/ircencodertest.cpp +++ b/tests/common/ircencodertest.cpp @@ -208,6 +208,34 @@ TEST(IrcEncoderTest, tags_with_no_value_and_space_filled_trailing) {"bar", "baz", " "})).data()); } +TEST(IrcEncoderTest, tags_with_invalid_vendor) +{ + EXPECT_STRCASEEQ( + "@a=b foo", + write(IrcMessage( + {{IrcTagKey("a"), "b"}}, + "", + "foo")).data()); + EXPECT_STRCASEEQ( + "@example.com/a=b foo", + write(IrcMessage( + {{IrcTagKey("example.com", "a"), "b"}}, + "", + "foo")).data()); + EXPECT_STRCASEEQ( + "@example.com/subfolder/to/a=b foo", + write(IrcMessage( + {{IrcTagKey("example.com/subfolder/to", "a"), "b"}}, + "", + "foo")).data()); + EXPECT_STRCASEEQ( + "@v\\/e\\/n\\/d\\/o\\/r/tag=b foo", + write(IrcMessage( + {{IrcTagKey("v\\/e\\/n\\/d\\/o\\/r", "tag"), "b"}}, + "", + "foo")).data()); +} + TEST(IrcEncoderTest, tags_with_escaped_values) { std::vector expected{