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.7KB

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