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.

1296 lines
29 KiB

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