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.

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