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.

client.go 4.9KB

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