diff --git a/src/main/kotlin/io/zachbr/dis4irc/bridge/ConfigurationData.kt b/src/main/kotlin/io/zachbr/dis4irc/bridge/ConfigurationData.kt index cd30c8b..1e95605 100644 --- a/src/main/kotlin/io/zachbr/dis4irc/bridge/ConfigurationData.kt +++ b/src/main/kotlin/io/zachbr/dis4irc/bridge/ConfigurationData.kt @@ -47,6 +47,7 @@ data class IrcConfiguration ( val userName: String, val realName: String, val antiPing: Boolean, + val discriminator: Boolean, val noPrefixRegex: Pattern?, val announceForwardedCommands: Boolean, val discordReplyContextLimit: Int, @@ -63,6 +64,7 @@ data class IrcConfiguration ( "userName='$userName', " + "realName='$realName', " + "antiPing=$antiPing, " + + "includeDiscriminator=$discriminator, " + "noPrefixRegex=$noPrefixRegex, " + "announceForwardedCommands=$announceForwardedCommands, " + "discordReplyContextLimit=$discordReplyContextLimit, " + diff --git a/src/main/kotlin/io/zachbr/dis4irc/bridge/message/Sender.kt b/src/main/kotlin/io/zachbr/dis4irc/bridge/message/Sender.kt index c4299c6..642e90f 100644 --- a/src/main/kotlin/io/zachbr/dis4irc/bridge/message/Sender.kt +++ b/src/main/kotlin/io/zachbr/dis4irc/bridge/message/Sender.kt @@ -8,13 +8,17 @@ package io.zachbr.dis4irc.bridge.message -internal val BOT_SENDER = Sender("Bridge", null, null) +internal val BOT_SENDER = Sender("Bridge", "Bridge", null, null) data class Sender( /** * User's display name, this is *not* guaranteed to be unique or secure */ val displayName: String, + /** + * User's tag name, this is guaranteed to be unique + */ + val tagName: String, /** * User's discord snowflake id, or null if the message originated from Discord */ diff --git a/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/discord/DiscordPier.kt b/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/discord/DiscordPier.kt index 2f042a3..cc3e9cf 100644 --- a/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/discord/DiscordPier.kt +++ b/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/discord/DiscordPier.kt @@ -102,7 +102,13 @@ class DiscordPier(private val bridge: Bridge) : Pier { val webhook = webhookMap[targetChan] val guild = channel.guild - // convert name use to proper mentions + // convert a user tag to proper mentions + for (member in guild.memberCache) { + val mentionTrigger = "@${member.user.asTag}" // require @ prefix + msg.contents = replaceTarget(msg.contents, mentionTrigger, member.asMention) + } + + // convert effective nick name to proper mentions for (member in guild.memberCache) { val mentionTrigger = "@${member.effectiveName}" // require @ prefix msg.contents = replaceTarget(msg.contents, mentionTrigger, member.asMention) diff --git a/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/discord/Extensions.kt b/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/discord/Extensions.kt index 4778875..6db694a 100644 --- a/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/discord/Extensions.kt +++ b/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/discord/Extensions.kt @@ -79,7 +79,8 @@ fun Message.toBridgeMsg(logger: Logger, receiveTimestamp: Long = System.nanoTime } val displayName = guildMember?.effectiveName ?: this.author.name // webhooks won't have an effective name - val sender = Sender(displayName, this.author.idLong, null) + val tagName = guildMember?.user?.asTag ?: this.author.name // webhooks won't hav a tag + val sender = Sender(displayName, tagName, this.author.idLong, null) return io.zachbr.dis4irc.bridge.message.Message( messageText, sender, diff --git a/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/irc/Extensions.kt b/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/irc/Extensions.kt index c6cbe3c..c002cfa 100644 --- a/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/irc/Extensions.kt +++ b/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/irc/Extensions.kt @@ -16,5 +16,5 @@ import org.kitteh.irc.client.library.element.User import java.util.Optional fun Channel.asBridgeSource(): Source = Source(this.name, null, PlatformType.IRC) -fun User.asBridgeSender(): Sender = Sender(this.nick, null, this.account.toNullable()) +fun User.asBridgeSender(): Sender = Sender(this.nick, this.realName.orElse(this.nick), null, this.account.toNullable()) fun Optional.toNullable(): T? = this.orElse(null) diff --git a/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/irc/IrcPier.kt b/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/irc/IrcPier.kt index f5be36d..dc1b0fe 100644 --- a/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/irc/IrcPier.kt +++ b/src/main/kotlin/io/zachbr/dis4irc/bridge/pier/irc/IrcPier.kt @@ -11,6 +11,7 @@ package io.zachbr.dis4irc.bridge.pier.irc import io.netty.handler.ssl.util.InsecureTrustManagerFactory import io.zachbr.dis4irc.bridge.Bridge import io.zachbr.dis4irc.bridge.message.Message +import io.zachbr.dis4irc.bridge.message.Sender import io.zachbr.dis4irc.bridge.pier.Pier import org.kitteh.irc.client.library.Client import org.kitteh.irc.client.library.Client.Builder.Server.SecurityType @@ -27,6 +28,7 @@ class IrcPier(private val bridge: Bridge) : Pier { internal val logger: Logger = bridge.logger private lateinit var ircConn: Client private var antiPing: Boolean = false + private var discriminator: Boolean = true private var noPrefix: Pattern? = null private var referenceLengthLimit: Int = 90 @@ -66,6 +68,7 @@ class IrcPier(private val bridge: Bridge) : Pier { noPrefix = bridge.config.irc.noPrefixRegex antiPing = bridge.config.irc.antiPing + discriminator = bridge.config.irc.discriminator referenceLengthLimit = bridge.config.irc.discordReplyContextLimit } @@ -99,9 +102,9 @@ class IrcPier(private val bridge: Bridge) : Pier { context = context.substring(0, referenceLengthLimit - 1) + "..." } - var refSender = msg.referencedMessage.sender.displayName + var refSender = generateName(msg.referencedMessage.sender) // do not ping yourself if you reply to your own messages - if (refSender == msg.sender.displayName) { + if (refSender.contains(msg.sender.displayName)) { refSender = rebuildWithAntiPing(refSender) } @@ -145,9 +148,20 @@ class IrcPier(private val bridge: Bridge) : Pier { if (msg.originatesFromBridgeItself()) { return "" } + return "<${generateName(msg.sender)}>" + } - val nameDisplay = generateColoredName(msg.sender.displayName) - return "<$nameDisplay>" + private fun generateName(sender: Sender): String { + var nameDisplay = generateColoredName(sender.displayName) + if (discriminator) { + if (sender.tagName.startsWith(sender.displayName + "#")) { + nameDisplay += "${Format.DARK_GRAY}${sender.tagName.substring(sender.displayName.length)}" + } else { + val tag = if (antiPing) rebuildWithAntiPing(sender.tagName) else sender.tagName + nameDisplay += "${Format.DARK_GRAY} ($tag)" + } + } + return nameDisplay + Format.RESET } // https://github.com/korobi/Web/blob/master/src/Korobi/WebBundle/IRC/Parser/NickColours.php diff --git a/src/main/kotlin/io/zachbr/dis4irc/config/ConfigurationUtils.kt b/src/main/kotlin/io/zachbr/dis4irc/config/ConfigurationUtils.kt index 918d296..b6edaeb 100644 --- a/src/main/kotlin/io/zachbr/dis4irc/config/ConfigurationUtils.kt +++ b/src/main/kotlin/io/zachbr/dis4irc/config/ConfigurationUtils.kt @@ -59,6 +59,10 @@ fun CommentedConfigurationNode.makeDefaultNode() { val ircAntiPing = ircBaseNode.node("anti-ping") ircAntiPing.set(true) + val ircDiscriminator = ircBaseNode.node("discriminator") + ircDiscriminator.set(true) + ircDiscriminator.comment("Include the discriminator or the full tag if a nickname is set") + val announceForwards = ircBaseNode.node("announce-forwarded-messages-sender") announceForwards.set(false) @@ -123,6 +127,7 @@ fun CommentedConfigurationNode.toBridgeConfiguration(): BridgeConfiguration { val ircUserName = getStringNonNull("IRC username cannot be null in $bridgeName!", "irc", "username") val ircRealName = getStringNonNull("IRC realname cannot be null in $bridgeName!", "irc", "realname") val ircAntiPing = this.node("irc", "anti-ping").boolean + val ircDiscriminator = this.node("irc", "discriminator").boolean val ircNoPrefix = this.node("irc", "no-prefix-regex").string // nullable val ircAnnounceForwards = this.node("irc", "announce-forwarded-messages-sender").boolean val ircDiscordReplyContextLimit = this.node("irc", "discord-reply-context-limit").int @@ -190,7 +195,7 @@ fun CommentedConfigurationNode.toBridgeConfiguration(): BridgeConfiguration { val discordConfig = DiscordConfiguration(discordApiKey, webhookMappings) val ircConfig = IrcConfiguration(ircHost, ircPass, ircPort, ircUseSsl, ircAllowBadSsl, ircNickName, ircUserName, - ircRealName, ircAntiPing, ircNoPrefixPattern, ircAnnounceForwards, ircDiscordReplyContextLimit, ircCommandsList) + ircRealName, ircAntiPing, ircDiscriminator, ircNoPrefixPattern, ircAnnounceForwards, ircDiscordReplyContextLimit, ircCommandsList) return BridgeConfiguration( bridgeName, diff --git a/src/test/kotlin/io/zachbr/dis4irc/bridge/message/MessageTest.kt b/src/test/kotlin/io/zachbr/dis4irc/bridge/message/MessageTest.kt index a29206e..3ac7179 100644 --- a/src/test/kotlin/io/zachbr/dis4irc/bridge/message/MessageTest.kt +++ b/src/test/kotlin/io/zachbr/dis4irc/bridge/message/MessageTest.kt @@ -15,7 +15,7 @@ import org.junit.jupiter.api.Test class MessageTest { @Test fun testShouldSendTo() { - val sender = Sender("SomeSender", null, null) + val sender = Sender("SomeSender", "SomeSender#1234", null, null) // test from IRC val ircSource = Source("#some-channel", null, PlatformType.IRC) diff --git a/src/test/kotlin/io/zachbr/dis4irc/bridge/mutator/mutators/TranslateFormattingTest.kt b/src/test/kotlin/io/zachbr/dis4irc/bridge/mutator/mutators/TranslateFormattingTest.kt index 8f910c7..e4ef6db 100644 --- a/src/test/kotlin/io/zachbr/dis4irc/bridge/mutator/mutators/TranslateFormattingTest.kt +++ b/src/test/kotlin/io/zachbr/dis4irc/bridge/mutator/mutators/TranslateFormattingTest.kt @@ -44,14 +44,14 @@ class TranslateFormattingTest { } private fun testIrcToDiscord(expected: String, string: String) { - val message = Message(string, Sender("Test", null, null), Source("#test", null, PlatformType.IRC), System.nanoTime()) + val message = Message(string, Sender("Test", "Test", null, null), Source("#test", null, PlatformType.IRC), System.nanoTime()) val mutator = TranslateFormatting() mutator.mutate(message) assertEquals(expected, message.contents) } private fun testDiscordToIrc(expected: String, input: String) { - val message = Message(input, Sender("Test", null, null), Source("#test", null, PlatformType.DISCORD), System.nanoTime()) + val message = Message(input, Sender("Test", "Test#1234", null, null), Source("#test", null, PlatformType.DISCORD), System.nanoTime()) val mutator = TranslateFormatting() mutator.mutate(message) assertEquals(expected, message.contents)