You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ChannelStateHandler.kt 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package com.dmdirc.ktirc.handlers
  2. import com.dmdirc.ktirc.IrcClient
  3. import com.dmdirc.ktirc.events.*
  4. import com.dmdirc.ktirc.model.ChannelState
  5. import com.dmdirc.ktirc.model.ChannelTopic
  6. import com.dmdirc.ktirc.model.ChannelUser
  7. import com.dmdirc.ktirc.util.logger
  8. internal class ChannelStateHandler : EventHandler {
  9. private val log by logger()
  10. override fun processEvent(client: IrcClient, event: IrcEvent): List<IrcEvent> {
  11. when (event) {
  12. is ChannelJoined -> handleJoin(client, event)
  13. is ChannelParted -> handlePart(client, event)
  14. is ChannelNamesReceived -> handleNamesReceived(client, event)
  15. is ChannelNamesFinished -> handleNamesFinished(client, event)
  16. is ChannelUserKicked -> handleKick(client, event)
  17. is ChannelTopicDiscovered -> handleTopicDiscovered(client, event)
  18. is ChannelTopicMetadataDiscovered -> handleTopicMetadata(client, event)
  19. is ChannelTopicChanged -> handleTopicChanged(client, event)
  20. is ModeChanged -> handleModeChanged(client, event)
  21. is UserQuit -> return handleQuit(client, event)
  22. is UserNickChanged -> return handleNickChanged(client, event)
  23. }
  24. return emptyList()
  25. }
  26. private fun handleJoin(client: IrcClient, event: ChannelJoined) {
  27. if (client.isLocalUser(event.user)) {
  28. log.info { "Joined new channel: ${event.channel}" }
  29. client.channelState += ChannelState(event.channel) { client.caseMapping }
  30. }
  31. client.channelState[event.channel]?.let { it.users += ChannelUser(event.user.nickname) }
  32. }
  33. private fun handlePart(client: IrcClient, event: ChannelParted) {
  34. if (client.isLocalUser(event.user)) {
  35. log.info { "Left channel: ${event.channel}" }
  36. client.channelState -= event.channel
  37. } else {
  38. client.channelState[event.channel]?.let {
  39. it.users -= event.user.nickname
  40. }
  41. }
  42. }
  43. private fun handleKick(client: IrcClient, event: ChannelUserKicked) {
  44. if (client.isLocalUser(event.victim)) {
  45. log.info { "Kicked from channel: ${event.channel}" }
  46. client.channelState -= event.channel
  47. } else {
  48. client.channelState[event.channel]?.let {
  49. it.users -= event.victim
  50. }
  51. }
  52. }
  53. private fun handleNamesReceived(client: IrcClient, event: ChannelNamesReceived) {
  54. val channel = client.channelState[event.channel] ?: return
  55. if (!channel.receivingUserList) {
  56. log.finer { "Started receiving names list for ${channel.name}" }
  57. channel.users.clear()
  58. channel.receivingUserList = true
  59. }
  60. event.toModesAndUsers(client).forEach { (modes, user) ->
  61. channel.users += ChannelUser(user.nickname, modes)
  62. }
  63. }
  64. private fun handleNamesFinished(client: IrcClient, event: ChannelNamesFinished) {
  65. client.channelState[event.channel]?.let {
  66. it.receivingUserList = false
  67. log.finest { "Finished receiving names in ${event.channel}. Users: ${it.users.toList()}" }
  68. }
  69. }
  70. private fun handleTopicDiscovered(client: IrcClient, event: ChannelTopicDiscovered) {
  71. client.channelState[event.channel]?.let {
  72. if (!it.topicDiscovered) {
  73. it.topic = ChannelTopic(event.topic)
  74. if (event.topic == null) {
  75. it.topicDiscovered = true
  76. }
  77. }
  78. }
  79. }
  80. private fun handleTopicMetadata(client: IrcClient, event: ChannelTopicMetadataDiscovered) {
  81. client.channelState[event.channel]?.let {
  82. if (!it.topicDiscovered) {
  83. it.topic = ChannelTopic(it.topic.topic, event.user, event.setTime)
  84. it.topicDiscovered = true
  85. }
  86. }
  87. }
  88. private fun handleTopicChanged(client: IrcClient, event: ChannelTopicChanged) {
  89. client.channelState[event.channel]?.let {
  90. it.topic = ChannelTopic(event.topic, event.user, event.time)
  91. }
  92. }
  93. private fun handleModeChanged(client: IrcClient, event: ModeChanged) {
  94. val chan = client.channelState[event.target] ?: return
  95. if (event.discovered) {
  96. chan.modesDiscovered = true
  97. chan.modes.clear()
  98. }
  99. var adding = true
  100. var argumentOffset = 0
  101. for (char in event.modes) {
  102. when (char) {
  103. '+' -> adding = true
  104. '-' -> adding = false
  105. else -> argumentOffset += if (client.serverState.isChannelUserMode(char)) {
  106. adjustUserMode(client, chan, char, adding, event.arguments[argumentOffset])
  107. } else {
  108. adjustMode(client, chan, char, event.arguments, argumentOffset, adding)
  109. }
  110. }
  111. }
  112. }
  113. private fun adjustMode(client: IrcClient, chan: ChannelState, mode: Char, arguments: Array<String>, argumentOffset: Int, adding: Boolean): Int {
  114. val type = client.serverState.channelModeType(mode)
  115. val takesParam = if (adding) type.needsParameterToSet else type.needsParameterToUnset
  116. val param = if (takesParam) arguments[argumentOffset] else ""
  117. if (adding) {
  118. chan.modes[mode] = param
  119. } else {
  120. chan.modes.remove(mode)
  121. }
  122. return if (takesParam) 1 else 0
  123. }
  124. private fun adjustUserMode(client: IrcClient, chan: ChannelState, mode: Char, adding: Boolean, user: String): Int {
  125. chan.users[user]?.let { channelUser ->
  126. // Filter from the master list of mode prefixes so that ordering is consistent
  127. channelUser.modes = client.serverState.channelModePrefixes.modes.filter {
  128. if (adding) {
  129. it == mode || it in channelUser.modes
  130. } else {
  131. it != mode && it in channelUser.modes
  132. }
  133. }
  134. }
  135. return 1
  136. }
  137. private fun handleQuit(client: IrcClient, event: UserQuit) = sequence {
  138. client.channelState.forEach {
  139. if (it.users.contains(event.user.nickname)) {
  140. it.users -= event.user.nickname
  141. yield(ChannelQuit(event.time, event.user, it.name, event.reason))
  142. }
  143. }
  144. }.toList()
  145. private fun handleNickChanged(client: IrcClient, event: UserNickChanged) = sequence {
  146. client.channelState.forEach {
  147. it.users[event.user.nickname]?.let { chanUser ->
  148. chanUser.nickname = event.newNick
  149. yield(ChannelNickChanged(event.time, event.user, it.name, event.newNick))
  150. }
  151. }
  152. }.toList()
  153. }