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.

monitor.go 6.0KB

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