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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. package irc
  4. import (
  5. "strconv"
  6. "strings"
  7. "github.com/goshuirc/irc-go/ircmsg"
  8. )
  9. // alertMonitors alerts everyone monitoring us that we're online.
  10. func (client *Client) alertMonitors() {
  11. // alert monitors
  12. for _, mClient := range client.server.monitoring[client.nickCasefolded] {
  13. // don't have to notify ourselves
  14. if mClient != client {
  15. mClient.SendFromClient("", client, nil, RPL_MONONLINE, mClient.nick, client.nickMaskString)
  16. }
  17. }
  18. }
  19. // clearMonitorList clears our MONITOR list.
  20. func (client *Client) clearMonitorList() {
  21. for name := range client.monitoring {
  22. // just removes current client from the list
  23. orig := client.server.monitoring[name]
  24. var index int
  25. for i, cli := range orig {
  26. if cli == client {
  27. index = i
  28. break
  29. }
  30. }
  31. client.server.monitoring[name] = append(orig[:index], orig[index+1:]...)
  32. }
  33. client.monitoring = make(map[string]bool)
  34. }
  35. var (
  36. metadataSubcommands = map[string]func(server *Server, client *Client, msg ircmsg.IrcMessage) bool{
  37. "-": monitorRemoveHandler,
  38. "+": monitorAddHandler,
  39. "c": monitorClearHandler,
  40. "l": monitorListHandler,
  41. "s": monitorStatusHandler,
  42. }
  43. )
  44. func monitorHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  45. handler, exists := metadataSubcommands[strings.ToLower(msg.Params[0])]
  46. if !exists {
  47. client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "MONITOR", msg.Params[0], "Unknown subcommand")
  48. return false
  49. }
  50. return handler(server, client, msg)
  51. }
  52. func monitorRemoveHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  53. if len(msg.Params) < 2 {
  54. client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nick, msg.Command, "Not enough parameters")
  55. return false
  56. }
  57. targets := strings.Split(msg.Params[1], ",")
  58. for len(targets) > 0 {
  59. // check name length
  60. if len(targets[0]) < 1 {
  61. targets = targets[1:]
  62. continue
  63. }
  64. // remove target
  65. casefoldedTarget, err := CasefoldName(targets[0])
  66. if err != nil {
  67. // skip silently I guess
  68. targets = targets[1:]
  69. continue
  70. }
  71. if client.monitoring[casefoldedTarget] {
  72. // just removes current client from the list
  73. orig := server.monitoring[casefoldedTarget]
  74. var index int
  75. for i, cli := range orig {
  76. if cli == client {
  77. index = i
  78. break
  79. }
  80. }
  81. server.monitoring[casefoldedTarget] = append(orig[:index], orig[index+1:]...)
  82. delete(client.monitoring, casefoldedTarget)
  83. }
  84. // remove first element of targets list
  85. targets = targets[1:]
  86. }
  87. return false
  88. }
  89. func monitorAddHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  90. if len(msg.Params) < 2 {
  91. client.Send(nil, server.name, ERR_NEEDMOREPARAMS, client.nick, msg.Command, "Not enough parameters")
  92. return false
  93. }
  94. var online []string
  95. var offline []string
  96. targets := strings.Split(msg.Params[1], ",")
  97. for len(targets) > 0 {
  98. // check name length
  99. if len(targets[0]) < 1 || len(targets[0]) > server.limits.NickLen {
  100. targets = targets[1:]
  101. continue
  102. }
  103. // check the monitor list length
  104. if len(client.monitoring) >= server.limits.MonitorEntries {
  105. client.Send(nil, server.name, ERR_MONLISTFULL, client.nick, strconv.Itoa(server.limits.MonitorEntries), strings.Join(targets, ","))
  106. break
  107. }
  108. // add target
  109. casefoldedTarget, err := CasefoldName(targets[0])
  110. if err != nil {
  111. // skip silently I guess
  112. targets = targets[1:]
  113. continue
  114. }
  115. if !client.monitoring[casefoldedTarget] {
  116. client.monitoring[casefoldedTarget] = true
  117. orig := server.monitoring[casefoldedTarget]
  118. server.monitoring[casefoldedTarget] = append(orig, client)
  119. }
  120. // add to online / offline lists
  121. target := server.clients.Get(casefoldedTarget)
  122. if target == nil {
  123. offline = append(offline, targets[0])
  124. } else {
  125. online = append(online, target.nickMaskString)
  126. }
  127. // remove first element of targets list
  128. targets = targets[1:]
  129. }
  130. if len(online) > 0 {
  131. client.Send(nil, server.name, RPL_MONONLINE, client.nick, strings.Join(online, ","))
  132. }
  133. if len(offline) > 0 {
  134. client.Send(nil, server.name, RPL_MONOFFLINE, client.nick, strings.Join(offline, ","))
  135. }
  136. return false
  137. }
  138. func monitorClearHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  139. client.clearMonitorList()
  140. return false
  141. }
  142. func monitorListHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  143. var monitorList []string
  144. for name := range client.monitoring {
  145. monitorList = append(monitorList, name)
  146. }
  147. for _, line := range argsToStrings(maxLastArgLength, monitorList, ",") {
  148. client.Send(nil, server.name, RPL_MONLIST, client.nick, line)
  149. }
  150. return false
  151. }
  152. func monitorStatusHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  153. var online []string
  154. var offline []string
  155. for name := range client.monitoring {
  156. target := server.clients.Get(name)
  157. if target == nil {
  158. offline = append(offline, name)
  159. } else {
  160. online = append(online, target.nickMaskString)
  161. }
  162. }
  163. if len(online) > 0 {
  164. for _, line := range argsToStrings(maxLastArgLength, online, ",") {
  165. client.Send(nil, server.name, RPL_MONONLINE, client.nick, line)
  166. }
  167. }
  168. if len(offline) > 0 {
  169. for _, line := range argsToStrings(maxLastArgLength, offline, ",") {
  170. client.Send(nil, server.name, RPL_MONOFFLINE, client.nick, line)
  171. }
  172. }
  173. return false
  174. }