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

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