Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package irc
  2. import (
  3. "fmt"
  4. "net"
  5. "time"
  6. )
  7. const (
  8. LOGIN_TIMEOUT = time.Minute / 2 // how long the client has to login
  9. IDLE_TIMEOUT = time.Minute // how long before a client is considered idle
  10. QUIT_TIMEOUT = time.Minute // how long after idle before a client is kicked
  11. )
  12. type Client struct {
  13. atime time.Time
  14. authorized bool
  15. awayMessage Text
  16. capabilities CapabilitySet
  17. capState CapState
  18. channels ChannelSet
  19. commands chan Command
  20. ctime time.Time
  21. flags map[UserMode]bool
  22. hasQuit bool
  23. hops uint
  24. hostname Name
  25. idleTimer *time.Timer
  26. loginTimer *time.Timer
  27. nick Name
  28. quitTimer *time.Timer
  29. realname Text
  30. registered bool
  31. server *Server
  32. socket *Socket
  33. username Name
  34. }
  35. func NewClient(server *Server, conn net.Conn) *Client {
  36. now := time.Now()
  37. client := &Client{
  38. atime: now,
  39. authorized: server.password == nil,
  40. capState: CapNone,
  41. capabilities: make(CapabilitySet),
  42. channels: make(ChannelSet),
  43. commands: make(chan Command),
  44. ctime: now,
  45. flags: make(map[UserMode]bool),
  46. server: server,
  47. }
  48. client.socket = NewSocket(conn, client.commands)
  49. client.loginTimer = time.AfterFunc(LOGIN_TIMEOUT, client.connectionTimeout)
  50. go client.run()
  51. return client
  52. }
  53. //
  54. // command goroutine
  55. //
  56. func (client *Client) run() {
  57. for command := range client.commands {
  58. if checkPass, ok := command.(checkPasswordCommand); ok {
  59. checkPass.LoadPassword(client.server)
  60. // Block the client thread while handling a potentially expensive
  61. // password bcrypt operation. Since the server is single-threaded
  62. // for commands, we don't want the server to perform the bcrypt,
  63. // blocking anyone else from sending commands until it
  64. // completes. This could be a form of DoS if handled naively.
  65. checkPass.CheckPassword()
  66. }
  67. command.SetClient(client)
  68. client.server.commands <- command
  69. }
  70. }
  71. func (client *Client) connectionTimeout() {
  72. client.commands <- &QuitCommand{
  73. message: "connection timeout",
  74. }
  75. }
  76. //
  77. // idle timer goroutine
  78. //
  79. func (client *Client) connectionIdle() {
  80. client.server.idle <- client
  81. }
  82. //
  83. // server goroutine
  84. //
  85. func (client *Client) Active() {
  86. client.atime = time.Now()
  87. }
  88. func (client *Client) Touch() {
  89. if client.quitTimer != nil {
  90. client.quitTimer.Stop()
  91. }
  92. if client.idleTimer == nil {
  93. client.idleTimer = time.AfterFunc(IDLE_TIMEOUT, client.connectionIdle)
  94. } else {
  95. client.idleTimer.Reset(IDLE_TIMEOUT)
  96. }
  97. }
  98. func (client *Client) Idle() {
  99. client.Reply(RplPing(client))
  100. if client.quitTimer == nil {
  101. client.quitTimer = time.AfterFunc(QUIT_TIMEOUT, client.connectionTimeout)
  102. } else {
  103. client.quitTimer.Reset(QUIT_TIMEOUT)
  104. }
  105. }
  106. func (client *Client) Register() {
  107. if client.registered {
  108. return
  109. }
  110. client.registered = true
  111. client.loginTimer.Stop()
  112. client.Touch()
  113. }
  114. func (client *Client) destroy() {
  115. // clean up channels
  116. for channel := range client.channels {
  117. channel.Quit(client)
  118. }
  119. // clean up server
  120. client.server.clients.Remove(client)
  121. // clean up self
  122. if client.loginTimer != nil {
  123. client.loginTimer.Stop()
  124. }
  125. if client.idleTimer != nil {
  126. client.idleTimer.Stop()
  127. }
  128. if client.quitTimer != nil {
  129. client.quitTimer.Stop()
  130. }
  131. client.socket.Close()
  132. Log.debug.Printf("%s: destroyed", client)
  133. }
  134. func (client *Client) IdleTime() time.Duration {
  135. return time.Since(client.atime)
  136. }
  137. func (client *Client) SignonTime() int64 {
  138. return client.ctime.Unix()
  139. }
  140. func (client *Client) IdleSeconds() uint64 {
  141. return uint64(client.IdleTime().Seconds())
  142. }
  143. func (client *Client) HasNick() bool {
  144. return client.nick != ""
  145. }
  146. func (client *Client) HasUsername() bool {
  147. return client.username != ""
  148. }
  149. // <mode>
  150. func (c *Client) ModeString() (str string) {
  151. for flag := range c.flags {
  152. str += flag.String()
  153. }
  154. if len(str) > 0 {
  155. str = "+" + str
  156. }
  157. return
  158. }
  159. func (c *Client) UserHost() Name {
  160. username := "*"
  161. if c.HasUsername() {
  162. username = c.username.String()
  163. }
  164. return Name(fmt.Sprintf("%s!%s@%s", c.Nick(), username, c.hostname))
  165. }
  166. func (c *Client) Nick() Name {
  167. if c.HasNick() {
  168. return c.nick
  169. }
  170. return Name("*")
  171. }
  172. func (c *Client) Id() Name {
  173. return c.UserHost()
  174. }
  175. func (c *Client) String() string {
  176. return c.Id().String()
  177. }
  178. func (client *Client) Friends() ClientSet {
  179. friends := make(ClientSet)
  180. friends.Add(client)
  181. for channel := range client.channels {
  182. for member := range channel.members {
  183. friends.Add(member)
  184. }
  185. }
  186. return friends
  187. }
  188. func (client *Client) SetNickname(nickname Name) {
  189. if client.HasNick() {
  190. Log.error.Printf("%s nickname already set!", client)
  191. return
  192. }
  193. client.nick = nickname
  194. client.server.clients.Add(client)
  195. }
  196. func (client *Client) ChangeNickname(nickname Name) {
  197. // Make reply before changing nick to capture original source id.
  198. reply := RplNick(client, nickname)
  199. client.server.clients.Remove(client)
  200. client.server.whoWas.Append(client)
  201. client.nick = nickname
  202. client.server.clients.Add(client)
  203. for friend := range client.Friends() {
  204. friend.Reply(reply)
  205. }
  206. }
  207. func (client *Client) Reply(reply string, args ...interface{}) {
  208. if len(args) > 0 {
  209. reply = fmt.Sprintf(reply, args...)
  210. }
  211. client.socket.Write(reply)
  212. }
  213. func (client *Client) Quit(message Text) {
  214. if client.hasQuit {
  215. return
  216. }
  217. client.hasQuit = true
  218. client.Reply(RplError("quit"))
  219. client.server.whoWas.Append(client)
  220. friends := client.Friends()
  221. friends.Remove(client)
  222. client.destroy()
  223. if len(friends) > 0 {
  224. reply := RplQuit(client, message)
  225. for friend := range friends {
  226. friend.Reply(reply)
  227. }
  228. }
  229. }