Mirror of github.com/gissleh/irc
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.

1186 lines
26 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. package irc
  2. import (
  3. "bufio"
  4. "context"
  5. "crypto/rand"
  6. "crypto/tls"
  7. "encoding/binary"
  8. "encoding/hex"
  9. "errors"
  10. "fmt"
  11. mathRand "math/rand"
  12. "net"
  13. "strconv"
  14. "strings"
  15. "sync"
  16. "time"
  17. "git.aiterp.net/gisle/irc/ircutil"
  18. "git.aiterp.net/gisle/irc/isupport"
  19. "git.aiterp.net/gisle/irc/list"
  20. )
  21. var supportedCaps = []string{
  22. "server-time",
  23. "cap-notify",
  24. "multi-prefix",
  25. "userhost-in-names",
  26. "account-notify",
  27. "away-notify",
  28. "extended-join",
  29. "chghost",
  30. "account-tag",
  31. }
  32. // ErrNoConnection is returned if you try to do something requiring a connection,
  33. // but there is none.
  34. var ErrNoConnection = errors.New("irc: no connection")
  35. // ErrTargetAlreadyAdded is returned by Client.AddTarget if that target has already been
  36. // added to the client.
  37. var ErrTargetAlreadyAdded = errors.New("irc: target already added")
  38. // ErrTargetConflict is returned by Clinet.AddTarget if there already exists a target
  39. // matching the name and kind.
  40. var ErrTargetConflict = errors.New("irc: target name and kind match existing target")
  41. // ErrTargetNotFound is returned by Clinet.RemoveTarget if the target is not part of
  42. // the client's target list
  43. var ErrTargetNotFound = errors.New("irc: target not found")
  44. // ErrTargetIsStatus is returned by Clinet.RemoveTarget if the target is the client's
  45. // status target
  46. var ErrTargetIsStatus = errors.New("irc: cannot remove status target")
  47. // A Client is an IRC client. You need to use New to construct it
  48. type Client struct {
  49. id string
  50. config Config
  51. mutex sync.RWMutex
  52. conn net.Conn
  53. ctx context.Context
  54. cancel context.CancelFunc
  55. events chan *Event
  56. sends chan string
  57. lastSend time.Time
  58. capEnabled map[string]bool
  59. capData map[string]string
  60. capsRequested []string
  61. nick string
  62. user string
  63. host string
  64. quit bool
  65. isupport isupport.ISupport
  66. values map[string]interface{}
  67. status *Status
  68. targets []Target
  69. targteIds map[Target]string
  70. }
  71. // New creates a new client. The context can be context.Background if you want manually to
  72. // tear down clients upon quitting.
  73. func New(ctx context.Context, config Config) *Client {
  74. client := &Client{
  75. id: generateClientID(),
  76. values: make(map[string]interface{}),
  77. events: make(chan *Event, 64),
  78. sends: make(chan string, 64),
  79. capEnabled: make(map[string]bool),
  80. capData: make(map[string]string),
  81. config: config.WithDefaults(),
  82. targteIds: make(map[Target]string, 16),
  83. status: &Status{},
  84. }
  85. client.AddTarget(client.status)
  86. client.ctx, client.cancel = context.WithCancel(ctx)
  87. go client.handleEventLoop()
  88. go client.handleSendLoop()
  89. return client
  90. }
  91. // Context gets the client's context. It's cancelled if the parent context used
  92. // in New is, or Destroy is called.
  93. func (client *Client) Context() context.Context {
  94. return client.ctx
  95. }
  96. // ID gets the unique identifier for the client, which could be used in data structures
  97. func (client *Client) ID() string {
  98. client.mutex.RLock()
  99. defer client.mutex.RUnlock()
  100. return client.id
  101. }
  102. // Nick gets the nick of the client
  103. func (client *Client) Nick() string {
  104. client.mutex.RLock()
  105. defer client.mutex.RUnlock()
  106. return client.nick
  107. }
  108. // User gets the user/ident of the client
  109. func (client *Client) User() string {
  110. client.mutex.RLock()
  111. defer client.mutex.RUnlock()
  112. return client.user
  113. }
  114. // Host gets the hostname of the client
  115. func (client *Client) Host() string {
  116. client.mutex.RLock()
  117. defer client.mutex.RUnlock()
  118. return client.host
  119. }
  120. // ISupport gets the client's ISupport. This is mutable, and changes to it
  121. // *will* affect the client.
  122. func (client *Client) ISupport() *isupport.ISupport {
  123. return &client.isupport
  124. }
  125. // Connect connects to the server by addr.
  126. func (client *Client) Connect(addr string, ssl bool) (err error) {
  127. var conn net.Conn
  128. if client.Connected() {
  129. client.Disconnect()
  130. }
  131. client.isupport.Reset()
  132. client.mutex.Lock()
  133. client.quit = false
  134. client.mutex.Unlock()
  135. client.EmitSync(context.Background(), NewEvent("client", "connecting"))
  136. if ssl {
  137. conn, err = tls.Dial("tcp", addr, &tls.Config{
  138. InsecureSkipVerify: client.config.SkipSSLVerification,
  139. })
  140. if err != nil {
  141. return err
  142. }
  143. } else {
  144. conn, err = net.Dial("tcp", addr)
  145. if err != nil {
  146. return err
  147. }
  148. }
  149. client.Emit(NewEvent("client", "connect"))
  150. go func() {
  151. reader := bufio.NewReader(conn)
  152. replacer := strings.NewReplacer("\r", "", "\n", "")
  153. for {
  154. line, err := reader.ReadString('\n')
  155. if err != nil {
  156. break
  157. }
  158. line = replacer.Replace(line)
  159. event, err := ParsePacket(line)
  160. if err != nil {
  161. continue
  162. }
  163. client.Emit(event)
  164. }
  165. client.mutex.Lock()
  166. client.conn = nil
  167. client.mutex.Unlock()
  168. client.Emit(NewEvent("client", "disconnect"))
  169. }()
  170. client.mutex.Lock()
  171. client.conn = conn
  172. client.mutex.Unlock()
  173. return nil
  174. }
  175. // Disconnect disconnects from the server. It will either return the
  176. // close error, or ErrNoConnection if there is no connection
  177. func (client *Client) Disconnect() error {
  178. client.mutex.Lock()
  179. defer client.mutex.Unlock()
  180. if client.conn == nil {
  181. return ErrNoConnection
  182. }
  183. client.quit = true
  184. err := client.conn.Close()
  185. return err
  186. }
  187. // Connected returns true if the client has a connection
  188. func (client *Client) Connected() bool {
  189. client.mutex.RLock()
  190. defer client.mutex.RUnlock()
  191. return client.conn != nil
  192. }
  193. // Send sends a line to the server. A line-feed will be automatically added if one
  194. // is not provided.
  195. func (client *Client) Send(line string) error {
  196. client.mutex.RLock()
  197. conn := client.conn
  198. client.mutex.RUnlock()
  199. if conn == nil {
  200. return ErrNoConnection
  201. }
  202. if !strings.HasSuffix(line, "\n") {
  203. line += "\r\n"
  204. }
  205. _, err := conn.Write([]byte(line))
  206. if err != nil {
  207. client.EmitNonBlocking(NewErrorEvent("network", err.Error()))
  208. client.Disconnect()
  209. }
  210. return err
  211. }
  212. // Sendf is Send with a fmt.Sprintf
  213. func (client *Client) Sendf(format string, a ...interface{}) error {
  214. return client.Send(fmt.Sprintf(format, a...))
  215. }
  216. // SendQueued appends a message to a queue that will only send 2 messages
  217. // per second to avoid flooding. If the queue is ull, a goroutine will be
  218. // spawned to queue it, so this function will always return immediately.
  219. // Order may not be guaranteed, however, but if you're sending 64 messages
  220. // at once that may not be your greatest concern.
  221. //
  222. // Failed sends will be discarded quietly to avoid a backup from being
  223. // thrown on a new connection.
  224. func (client *Client) SendQueued(line string) {
  225. select {
  226. case client.sends <- line:
  227. default:
  228. go func() { client.sends <- line }()
  229. }
  230. }
  231. // SendQueuedf is SendQueued with a fmt.Sprintf
  232. func (client *Client) SendQueuedf(format string, a ...interface{}) {
  233. client.SendQueued(fmt.Sprintf(format, a...))
  234. }
  235. // SendCTCP sends a queued message with the following CTCP verb and text. If reply is true,
  236. // it will use a NOTICE instead of PRIVMSG.
  237. func (client *Client) SendCTCP(verb, targetName string, reply bool, text string) {
  238. ircVerb := "PRIVMSG"
  239. if reply {
  240. ircVerb = "NOTICE"
  241. }
  242. client.SendQueuedf("%s %s :\x01%s %s\x01", ircVerb, targetName, verb, text)
  243. }
  244. // SendCTCPf is SendCTCP with a fmt.Sprintf
  245. func (client *Client) SendCTCPf(verb, targetName string, reply bool, format string, a ...interface{}) {
  246. client.SendCTCP(verb, targetName, reply, fmt.Sprintf(format, a...))
  247. }
  248. // Emit sends an event through the client's event, and it will return immediately
  249. // unless the internal channel is filled up. The returned context can be used to
  250. // wait for the event, or the client's destruction.
  251. func (client *Client) Emit(event Event) context.Context {
  252. event.ctx, event.cancel = context.WithCancel(client.ctx)
  253. client.events <- &event
  254. return event.ctx
  255. }
  256. // EmitNonBlocking is just like emit, but it will spin off a goroutine if the channel is full.
  257. // This lets it be called from other handlers without ever blocking. See Emit for what the
  258. // returned context is for.
  259. func (client *Client) EmitNonBlocking(event Event) context.Context {
  260. event.ctx, event.cancel = context.WithCancel(client.ctx)
  261. select {
  262. case client.events <- &event:
  263. default:
  264. go func() { client.events <- &event }()
  265. }
  266. return event.ctx
  267. }
  268. // EmitSync emits an event and waits for either its context to complete or the one
  269. // passed to it (e.g. a request's context). It's a shorthand for Emit with its
  270. // return value used in a `select` along with a passed context.
  271. func (client *Client) EmitSync(ctx context.Context, event Event) (err error) {
  272. eventCtx := client.Emit(event)
  273. select {
  274. case <-eventCtx.Done():
  275. {
  276. if err := eventCtx.Err(); err != context.Canceled {
  277. return err
  278. }
  279. return nil
  280. }
  281. case <-ctx.Done():
  282. {
  283. return ctx.Err()
  284. }
  285. }
  286. }
  287. // EmitInput emits an input event parsed from the line.
  288. func (client *Client) EmitInput(line string, target Target) context.Context {
  289. event := ParseInput(line)
  290. if target != nil {
  291. client.mutex.RLock()
  292. event.targets = append(event.targets, target)
  293. event.targetIds[target] = client.targteIds[target]
  294. client.mutex.RUnlock()
  295. } else {
  296. client.mutex.RLock()
  297. event.targets = append(event.targets, client.status)
  298. event.targetIds[client.status] = client.targteIds[client.status]
  299. client.mutex.RUnlock()
  300. }
  301. return client.Emit(event)
  302. }
  303. // Value gets a client value.
  304. func (client *Client) Value(key string) interface{} {
  305. client.mutex.RLock()
  306. defer client.mutex.RUnlock()
  307. return client.values[key]
  308. }
  309. // SetValue sets a client value.
  310. func (client *Client) SetValue(key string, value interface{}) {
  311. client.mutex.Lock()
  312. client.values[key] = value
  313. client.mutex.Unlock()
  314. }
  315. // Destroy destroys the client, which will lead to a disconnect. Cancelling the
  316. // parent context will do the same.
  317. func (client *Client) Destroy() {
  318. client.Disconnect()
  319. client.cancel()
  320. close(client.sends)
  321. close(client.events)
  322. }
  323. // Destroyed returns true if the client has been destroyed, either by
  324. // Destroy or the parent context.
  325. func (client *Client) Destroyed() bool {
  326. select {
  327. case <-client.ctx.Done():
  328. return true
  329. default:
  330. return false
  331. }
  332. }
  333. // PrivmsgOverhead returns the overhead on a privmsg to the target. If `action` is true,
  334. // it will also count the extra overhead of a CTCP ACTION.
  335. func (client *Client) PrivmsgOverhead(targetName string, action bool) int {
  336. client.mutex.RLock()
  337. defer client.mutex.RUnlock()
  338. // Return a really safe estimate if user or host is missing.
  339. if client.user == "" || client.host == "" {
  340. return 200
  341. }
  342. return ircutil.MessageOverhead(client.nick, client.user, client.host, targetName, action)
  343. }
  344. // Join joins one or more channels without a key.
  345. func (client *Client) Join(channels ...string) error {
  346. return client.Sendf("JOIN %s", strings.Join(channels, ","))
  347. }
  348. // Part parts one or more channels.
  349. func (client *Client) Part(channels ...string) error {
  350. return client.Sendf("PART %s", strings.Join(channels, ","))
  351. }
  352. // Target gets a target by kind and name
  353. func (client *Client) Target(kind string, name string) Target {
  354. client.mutex.RLock()
  355. defer client.mutex.RUnlock()
  356. for _, target := range client.targets {
  357. if target.Kind() == kind && target.Name() == name {
  358. return target
  359. }
  360. }
  361. return nil
  362. }
  363. // Targets gets all targets of the given kinds.
  364. func (client *Client) Targets(kinds ...string) []Target {
  365. if len(kinds) == 0 {
  366. client.mutex.Lock()
  367. targets := make([]Target, len(client.targets))
  368. copy(targets, client.targets)
  369. client.mutex.Unlock()
  370. return targets
  371. }
  372. client.mutex.Lock()
  373. targets := make([]Target, 0, len(client.targets))
  374. for _, target := range client.targets {
  375. for _, kind := range kinds {
  376. if target.Kind() == kind {
  377. targets = append(targets, target)
  378. break
  379. }
  380. }
  381. }
  382. client.mutex.Unlock()
  383. return targets
  384. }
  385. // Status gets the client's status target.
  386. func (client *Client) Status() *Status {
  387. return client.status
  388. }
  389. // Channel is a shorthand for getting a channel target and type asserting it.
  390. func (client *Client) Channel(name string) *Channel {
  391. target := client.Target("channel", name)
  392. if target == nil {
  393. return nil
  394. }
  395. return target.(*Channel)
  396. }
  397. // Channels gets all channel targets the client has.
  398. func (client *Client) Channels() []*Channel {
  399. targets := client.Targets("channel")
  400. channels := make([]*Channel, len(targets))
  401. for i := range targets {
  402. channels[i] = targets[i].(*Channel)
  403. }
  404. return channels
  405. }
  406. // Query is a shorthand for getting a query target and type asserting it.
  407. func (client *Client) Query(name string) *Query {
  408. target := client.Target("query", name)
  409. if target == nil {
  410. return nil
  411. }
  412. return target.(*Query)
  413. }
  414. // AddTarget adds a target to the client, generating a unique ID for it.
  415. func (client *Client) AddTarget(target Target) (id string, err error) {
  416. client.mutex.Lock()
  417. defer client.mutex.Unlock()
  418. for i := range client.targets {
  419. if target == client.targets[i] {
  420. err = ErrTargetAlreadyAdded
  421. return
  422. } else if target.Kind() == client.targets[i].Kind() && target.Name() == client.targets[i].Name() {
  423. err = ErrTargetConflict
  424. return
  425. }
  426. }
  427. id = generateClientID()
  428. client.targets = append(client.targets, target)
  429. client.targteIds[target] = id
  430. return
  431. }
  432. // RemoveTarget removes a target to the client
  433. func (client *Client) RemoveTarget(target Target) (id string, err error) {
  434. if target == client.status {
  435. return "", ErrTargetIsStatus
  436. }
  437. client.mutex.Lock()
  438. defer client.mutex.Unlock()
  439. for i := range client.targets {
  440. if target == client.targets[i] {
  441. id = client.targteIds[target]
  442. client.targets[i] = client.targets[len(client.targets)-1]
  443. client.targets = client.targets[:len(client.targets)-1]
  444. delete(client.targteIds, target)
  445. // Ensure the channel has been parted
  446. if channel, ok := target.(*Channel); ok && !channel.parted {
  447. client.SendQueuedf("/part %s", channel.Name())
  448. }
  449. return
  450. }
  451. }
  452. err = ErrTargetNotFound
  453. return
  454. }
  455. // FindUser checks each channel to find user info about a user.
  456. func (client *Client) FindUser(nick string) (u list.User, ok bool) {
  457. client.mutex.RLock()
  458. defer client.mutex.RUnlock()
  459. for _, target := range client.targets {
  460. channel, ok := target.(*Channel)
  461. if !ok {
  462. continue
  463. }
  464. user, ok := channel.UserList().User(nick)
  465. if !ok {
  466. continue
  467. }
  468. return user, true
  469. }
  470. return list.User{}, false
  471. }
  472. func (client *Client) handleEventLoop() {
  473. ticker := time.NewTicker(time.Second * 30)
  474. for {
  475. select {
  476. case event, ok := <-client.events:
  477. {
  478. if !ok {
  479. goto end
  480. }
  481. client.handleEvent(event)
  482. emit(event, client)
  483. // Turn an unhandled input into a raw command.
  484. if event.kind == "input" && !event.preventedDefault {
  485. client.SendQueued(strings.ToUpper(event.verb) + " " + event.Text)
  486. }
  487. event.cancel()
  488. }
  489. case <-ticker.C:
  490. {
  491. event := NewEvent("client", "tick")
  492. event.ctx, event.cancel = context.WithCancel(client.ctx)
  493. client.handleEvent(&event)
  494. emit(&event, client)
  495. event.cancel()
  496. }
  497. case <-client.ctx.Done():
  498. {
  499. goto end
  500. }
  501. }
  502. }
  503. end:
  504. ticker.Stop()
  505. client.Disconnect()
  506. event := NewEvent("client", "destroy")
  507. event.ctx, event.cancel = context.WithCancel(client.ctx)
  508. client.handleEvent(&event)
  509. emit(&event, client)
  510. event.cancel()
  511. }
  512. func (client *Client) handleSendLoop() {
  513. lastRefresh := time.Time{}
  514. queue := client.config.SendRate
  515. for line := range client.sends {
  516. now := time.Now()
  517. deltaTime := now.Sub(lastRefresh)
  518. if deltaTime < time.Second {
  519. queue--
  520. if queue <= 0 {
  521. time.Sleep(time.Second - deltaTime)
  522. lastRefresh = now
  523. queue = client.config.SendRate - 1
  524. }
  525. } else {
  526. lastRefresh = now
  527. queue = client.config.SendRate - 1
  528. }
  529. client.Send(line)
  530. }
  531. }
  532. // handleEvent is always first and gets to break a few rules.
  533. func (client *Client) handleEvent(event *Event) {
  534. // IRCv3 `server-time`
  535. if timeTag, ok := event.Tags["time"]; ok {
  536. serverTime, err := time.Parse(time.RFC3339Nano, timeTag)
  537. if err == nil && serverTime.Year() > 2000 {
  538. event.Time = serverTime
  539. }
  540. }
  541. // For events that were created with targets, handle them now there now.
  542. for _, target := range event.targets {
  543. target.Handle(event, client)
  544. }
  545. switch event.name {
  546. // Ping Pong
  547. case "hook.tick":
  548. {
  549. client.mutex.RLock()
  550. lastSend := time.Since(client.lastSend)
  551. client.mutex.RUnlock()
  552. if lastSend > time.Second*120 {
  553. client.Sendf("PING :%x%x%x", mathRand.Int63(), mathRand.Int63(), mathRand.Int63())
  554. }
  555. }
  556. case "packet.ping":
  557. {
  558. message := "PONG"
  559. for _, arg := range event.Args {
  560. message += " " + arg
  561. }
  562. if event.Text != "" {
  563. message += " :" + event.Text
  564. }
  565. client.Send(message)
  566. }
  567. // Client Registration
  568. case "client.connect":
  569. {
  570. client.Send("CAP LS 302")
  571. if client.config.Password != "" {
  572. client.Sendf("PASS :%s", client.config.Password)
  573. }
  574. nick := client.config.Nick
  575. client.mutex.RLock()
  576. if client.nick != "" {
  577. nick = client.nick
  578. }
  579. client.mutex.RUnlock()
  580. client.Sendf("NICK %s", nick)
  581. client.Sendf("USER %s 8 * :%s", client.config.User, client.config.RealName)
  582. }
  583. case "packet.001":
  584. {
  585. client.mutex.Lock()
  586. client.nick = event.Args[0]
  587. client.mutex.Unlock()
  588. client.Sendf("WHO %s", event.Args[0])
  589. }
  590. case "packet.443":
  591. {
  592. client.mutex.RLock()
  593. hasRegistered := client.nick != ""
  594. client.mutex.RUnlock()
  595. if !hasRegistered {
  596. nick := event.Args[1]
  597. // "AltN" -> "AltN+1", ...
  598. prev := client.config.Nick
  599. sent := false
  600. for _, alt := range client.config.Alternatives {
  601. if nick == prev {
  602. client.Sendf("NICK %s", alt)
  603. sent = true
  604. break
  605. }
  606. prev = alt
  607. }
  608. if !sent {
  609. // "LastAlt" -> "Nick23962"
  610. client.Sendf("NICK %s%05d", client.config.Nick, mathRand.Int31n(99999))
  611. }
  612. }
  613. }
  614. case "packet.nick":
  615. {
  616. client.handleInTargets(event.Nick, event)
  617. if event.Nick == client.nick {
  618. client.SetValue("nick", event.Arg(0))
  619. }
  620. }
  621. // Handle ISupport
  622. case "packet.005":
  623. {
  624. for _, token := range event.Args[1:] {
  625. kvpair := strings.Split(token, "=")
  626. if len(kvpair) == 2 {
  627. client.isupport.Set(kvpair[0], kvpair[1])
  628. } else {
  629. client.isupport.Set(kvpair[0], "")
  630. }
  631. }
  632. }
  633. // Capability negotiation
  634. case "packet.cap":
  635. {
  636. capCommand := event.Args[1]
  637. capTokens := strings.Split(event.Text, " ")
  638. switch capCommand {
  639. case "LS":
  640. {
  641. for _, token := range capTokens {
  642. split := strings.SplitN(token, "=", 2)
  643. key := split[0]
  644. if len(key) == 0 {
  645. continue
  646. }
  647. if len(split) == 2 {
  648. client.capData[key] = split[1]
  649. }
  650. for i := range supportedCaps {
  651. if supportedCaps[i] == token {
  652. client.mutex.Lock()
  653. client.capsRequested = append(client.capsRequested, token)
  654. client.mutex.Unlock()
  655. break
  656. }
  657. }
  658. }
  659. if len(event.Args) < 3 || event.Args[2] != "*" {
  660. client.mutex.RLock()
  661. requestedCount := len(client.capsRequested)
  662. client.mutex.RUnlock()
  663. if requestedCount > 0 {
  664. client.mutex.RLock()
  665. requestedCaps := strings.Join(client.capsRequested, " ")
  666. client.mutex.RUnlock()
  667. client.Send("CAP REQ :" + requestedCaps)
  668. } else {
  669. client.Send("CAP END")
  670. }
  671. }
  672. }
  673. case "ACK":
  674. {
  675. for _, token := range capTokens {
  676. client.mutex.Lock()
  677. if client.capEnabled[token] {
  678. client.capEnabled[token] = true
  679. }
  680. client.mutex.Unlock()
  681. }
  682. client.Send("CAP END")
  683. }
  684. case "NAK":
  685. {
  686. // Remove offenders
  687. for _, token := range capTokens {
  688. client.mutex.Lock()
  689. for i := range client.capsRequested {
  690. if token == client.capsRequested[i] {
  691. client.capsRequested = append(client.capsRequested[:i], client.capsRequested[i+1:]...)
  692. break
  693. }
  694. }
  695. client.mutex.Unlock()
  696. }
  697. client.mutex.RLock()
  698. requestedCaps := strings.Join(client.capsRequested, " ")
  699. client.mutex.RUnlock()
  700. client.Send("CAP REQ :" + requestedCaps)
  701. }
  702. case "NEW":
  703. {
  704. requests := make([]string, 0, len(capTokens))
  705. for _, token := range capTokens {
  706. for i := range supportedCaps {
  707. if supportedCaps[i] == token {
  708. requests = append(requests, token)
  709. }
  710. }
  711. }
  712. if len(requests) > 0 {
  713. client.Send("CAP REQ :" + strings.Join(requests, " "))
  714. }
  715. }
  716. case "DEL":
  717. {
  718. for _, token := range capTokens {
  719. client.mutex.Lock()
  720. if client.capEnabled[token] {
  721. client.capEnabled[token] = false
  722. }
  723. client.mutex.Unlock()
  724. }
  725. }
  726. }
  727. }
  728. // User/host detection
  729. case "packet.352": // WHO reply
  730. {
  731. // Example args: test * ~irce 127.0.0.1 localhost.localnetwork Gissleh H :0 ...
  732. nick := event.Args[5]
  733. user := event.Args[2]
  734. host := event.Args[3]
  735. if nick == client.nick {
  736. client.mutex.Lock()
  737. client.user = user
  738. client.host = host
  739. client.mutex.Unlock()
  740. }
  741. }
  742. case "packet.chghost":
  743. {
  744. if event.Nick == client.nick {
  745. client.mutex.Lock()
  746. client.user = event.Args[1]
  747. client.host = event.Args[2]
  748. client.mutex.Unlock()
  749. }
  750. // This may be relevant in channels where the client resides.
  751. client.handleInTargets(event.Nick, event)
  752. }
  753. // Channel join/leave/mode handling
  754. case "packet.join":
  755. {
  756. var channel *Channel
  757. if event.Nick == client.nick {
  758. channel = &Channel{name: event.Arg(0), userlist: list.New(&client.isupport)}
  759. client.AddTarget(channel)
  760. } else {
  761. channel = client.Channel(event.Arg(0))
  762. }
  763. client.handleInTarget(channel, event)
  764. if channel != nil {
  765. channel.Handle(event, client)
  766. }
  767. }
  768. case "packet.part":
  769. {
  770. channel := client.Channel(event.Arg(0))
  771. if channel == nil {
  772. break
  773. }
  774. channel.Handle(event, client)
  775. if event.Nick == client.nick {
  776. client.RemoveTarget(channel)
  777. } else {
  778. client.handleInTarget(channel, event)
  779. }
  780. }
  781. case "packet.quit":
  782. {
  783. client.handleInTargets(event.Nick, event)
  784. }
  785. case "packet.353": // NAMES
  786. {
  787. channel := client.Channel(event.Arg(2))
  788. if channel != nil {
  789. client.handleInTarget(channel, event)
  790. }
  791. }
  792. case "packet.366": // End of NAMES
  793. {
  794. channel := client.Channel(event.Arg(1))
  795. if channel != nil {
  796. client.handleInTarget(channel, event)
  797. }
  798. }
  799. case "packet.mode":
  800. {
  801. targetName := event.Arg(0)
  802. if client.isupport.IsChannel(targetName) {
  803. channel := client.Channel(targetName)
  804. if channel != nil {
  805. client.handleInTarget(channel, event)
  806. }
  807. }
  808. }
  809. // Message parsing
  810. case "packet.privmsg", "ctcp.action":
  811. {
  812. // Target the mssage
  813. target := Target(client.status)
  814. spawned := false
  815. targetName := event.Arg(0)
  816. if targetName == client.nick {
  817. target := client.Target("query", targetName)
  818. if target == nil {
  819. query := &Query{user: list.User{
  820. Nick: event.Nick,
  821. User: event.User,
  822. Host: event.Host,
  823. }}
  824. client.AddTarget(query)
  825. spawned = true
  826. target = query
  827. }
  828. } else {
  829. channel := client.Channel(targetName)
  830. if channel != nil {
  831. if user, ok := channel.UserList().User(event.Nick); ok {
  832. event.RenderTags["prefixedNick"] = user.PrefixedNick
  833. }
  834. target = channel
  835. } else {
  836. target = client.status
  837. }
  838. }
  839. client.handleInTarget(target, event)
  840. if spawned {
  841. // TODO: Message has higher importance // 0:Normal, 1:Important, 2:Highlight
  842. }
  843. }
  844. case "packet.notice":
  845. {
  846. // Find channel target
  847. targetName := event.Arg(0)
  848. if client.isupport.IsChannel(targetName) {
  849. channel := client.Channel(targetName)
  850. if channel != nil {
  851. if user, ok := channel.UserList().User(event.Nick); ok {
  852. event.RenderTags["prefixedNick"] = user.PrefixedNick
  853. }
  854. client.handleInTarget(channel, event)
  855. }
  856. } else {
  857. // Try to target by mentioned channel name
  858. for _, token := range strings.Fields(event.Text) {
  859. if client.isupport.IsChannel(token) {
  860. channel := client.Channel(token)
  861. if channel == nil {
  862. continue
  863. }
  864. if user, ok := channel.UserList().User(event.Nick); ok {
  865. event.RenderTags["prefixedNick"] = user.PrefixedNick
  866. }
  867. client.handleInTarget(channel, event)
  868. break
  869. }
  870. }
  871. }
  872. // Otherwise, it belongs in the status target
  873. if len(event.targets) == 0 {
  874. client.status.Handle(event, client)
  875. client.handleInTarget(client.status, event)
  876. }
  877. }
  878. // account-notify
  879. case "packet.account":
  880. {
  881. client.handleInTargets(event.Nick, event)
  882. }
  883. // away-notify
  884. case "packet.away":
  885. {
  886. client.handleInTargets(event.Nick, event)
  887. }
  888. // Auto-rejoin
  889. case "packet.376", "packet.422":
  890. {
  891. client.mutex.RLock()
  892. channels := make([]string, 0, len(client.targets))
  893. rejoinEvent := NewEvent("info", "rejoin")
  894. for _, target := range client.targets {
  895. if channel, ok := target.(*Channel); ok {
  896. channels = append(channels, channel.Name())
  897. rejoinEvent.targets = append(rejoinEvent.targets, target)
  898. rejoinEvent.targetIds[target] = client.targteIds[target]
  899. }
  900. }
  901. client.mutex.RUnlock()
  902. if len(channels) > 0 {
  903. client.Sendf("JOIN %s", strings.Join(channels, ","))
  904. client.EmitNonBlocking(rejoinEvent)
  905. }
  906. client.EmitNonBlocking(NewEvent("hook", "ready"))
  907. }
  908. }
  909. if len(event.targets) == 0 {
  910. client.handleInTarget(client.status, event)
  911. }
  912. }
  913. func (client *Client) handleInTargets(nick string, event *Event) {
  914. client.mutex.RLock()
  915. for i := range client.targets {
  916. switch target := client.targets[i].(type) {
  917. case *Channel:
  918. {
  919. if nick != "" {
  920. if _, ok := target.UserList().User(event.Nick); !ok {
  921. continue
  922. }
  923. }
  924. target.Handle(event, client)
  925. event.targets = append(event.targets, target)
  926. event.targetIds[target] = client.targteIds[target]
  927. }
  928. case *Query:
  929. {
  930. if target.user.Nick == nick {
  931. target.Handle(event, client)
  932. event.targets = append(event.targets, target)
  933. event.targetIds[target] = client.targteIds[target]
  934. }
  935. }
  936. case *Status:
  937. {
  938. if client.nick == event.Nick {
  939. target.Handle(event, client)
  940. event.targets = append(event.targets, target)
  941. event.targetIds[target] = client.targteIds[target]
  942. }
  943. }
  944. }
  945. }
  946. client.mutex.RUnlock()
  947. }
  948. func (client *Client) handleInTarget(target Target, event *Event) {
  949. client.mutex.RLock()
  950. target.Handle(event, client)
  951. event.targets = append(event.targets, target)
  952. event.targetIds[target] = client.targteIds[target]
  953. client.mutex.RUnlock()
  954. }
  955. func generateClientID() string {
  956. bytes := make([]byte, 12)
  957. _, err := rand.Read(bytes)
  958. // Ugly fallback if crypto rand doesn't work.
  959. if err != nil {
  960. rng := mathRand.NewSource(time.Now().UnixNano())
  961. result := strconv.FormatInt(rng.Int63(), 16)
  962. for len(result) < 24 {
  963. result += strconv.FormatInt(rng.Int63(), 16)
  964. }
  965. return result[:24]
  966. }
  967. binary.BigEndian.PutUint32(bytes[4:], uint32(time.Now().Unix()))
  968. return hex.EncodeToString(bytes)
  969. }