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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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. event.replacedUsers = it.users.map(ChannelUser::nickname).toTypedArray()
  69. if (client.behaviour.requestModesOnJoin && !it.modesDiscovered) {
  70. client.sendModeRequest(it.name)
  71. }
  72. }
  73. }
  74. private fun handleTopicDiscovered(client: IrcClient, event: ChannelTopicDiscovered) {
  75. client.channelState[event.target]?.let {
  76. if (!it.topicDiscovered) {
  77. it.topic = ChannelTopic(event.topic)
  78. if (event.topic == null) {
  79. it.topicDiscovered = true
  80. }
  81. }
  82. }
  83. }
  84. private fun handleTopicMetadata(client: IrcClient, event: ChannelTopicMetadataDiscovered) {
  85. client.channelState[event.target]?.let {
  86. if (!it.topicDiscovered) {
  87. it.topic = ChannelTopic(it.topic.topic, event.user, event.setTime)
  88. it.topicDiscovered = true
  89. }
  90. }
  91. }
  92. private fun handleTopicChanged(client: IrcClient, event: ChannelTopicChanged) {
  93. client.channelState[event.target]?.let {
  94. it.topic = ChannelTopic(event.topic, event.user, event.metadata.time)
  95. }
  96. }
  97. private fun handleModeChanged(client: IrcClient, event: ModeChanged) {
  98. val chan = client.channelState[event.target] ?: return
  99. if (event.discovered) {
  100. chan.modesDiscovered = true
  101. chan.modes.clear()
  102. }
  103. var adding = true
  104. var argumentOffset = 0
  105. for (char in event.modes) {
  106. when (char) {
  107. '+' -> adding = true
  108. '-' -> adding = false
  109. else -> argumentOffset += if (client.serverState.isChannelUserMode(char)) {
  110. adjustUserMode(client, chan, char, adding, event.arguments[argumentOffset])
  111. } else {
  112. adjustMode(client, chan, char, event.arguments, argumentOffset, adding)
  113. }
  114. }
  115. }
  116. }
  117. private fun adjustMode(client: IrcClient, chan: ChannelState, mode: Char, arguments: Array<String>, argumentOffset: Int, adding: Boolean): Int {
  118. val type = client.serverState.channelModeType(mode)
  119. val takesParam = if (adding) type.needsParameterToSet else type.needsParameterToUnset
  120. val param = if (takesParam) arguments[argumentOffset] else ""
  121. if (adding) {
  122. chan.modes[mode] = param
  123. } else {
  124. chan.modes.remove(mode)
  125. }
  126. return if (takesParam) 1 else 0
  127. }
  128. private fun adjustUserMode(client: IrcClient, chan: ChannelState, mode: Char, adding: Boolean, user: String): Int {
  129. chan.users[user]?.let { channelUser ->
  130. // Filter from the master list of mode prefixes so that ordering is consistent
  131. channelUser.modes = client.serverState.channelModePrefixes.modes.filter {
  132. if (adding) {
  133. it == mode || it in channelUser.modes
  134. } else {
  135. it != mode && it in channelUser.modes
  136. }
  137. }
  138. }
  139. return 1
  140. }
  141. private fun handleQuit(client: IrcClient, event: ChannelQuit) {
  142. client.channelState[event.target]?.let {
  143. it.users -= event.user.nickname
  144. }
  145. }
  146. private fun handleNickChanged(client: IrcClient, event: ChannelNickChanged) {
  147. client.channelState[event.target]?.let {
  148. it.users[event.user.nickname]?.let { chanUser ->
  149. chanUser.nickname = event.newNick
  150. }
  151. }
  152. }
  153. }