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.

capability.go 2.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. package irc
  2. import (
  3. "strings"
  4. )
  5. type CapSubCommand string
  6. const (
  7. CAP_LS CapSubCommand = "LS"
  8. CAP_LIST CapSubCommand = "LIST"
  9. CAP_REQ CapSubCommand = "REQ"
  10. CAP_ACK CapSubCommand = "ACK"
  11. CAP_NAK CapSubCommand = "NAK"
  12. CAP_CLEAR CapSubCommand = "CLEAR"
  13. CAP_END CapSubCommand = "END"
  14. )
  15. // Capabilities are optional features a client may request from a server.
  16. type Capability string
  17. const (
  18. MultiPrefix Capability = "multi-prefix"
  19. SASL Capability = "sasl"
  20. )
  21. var (
  22. SupportedCapabilities = CapabilitySet{
  23. MultiPrefix: true,
  24. }
  25. )
  26. func (capability Capability) String() string {
  27. return string(capability)
  28. }
  29. // CapModifiers are indicators showing the state of a capability after a REQ or
  30. // ACK.
  31. type CapModifier rune
  32. const (
  33. Ack CapModifier = '~'
  34. Disable CapModifier = '-'
  35. Sticky CapModifier = '='
  36. )
  37. func (mod CapModifier) String() string {
  38. return string(mod)
  39. }
  40. type CapState uint
  41. const (
  42. CapNone CapState = iota
  43. CapNegotiating CapState = iota
  44. CapNegotiated CapState = iota
  45. )
  46. type CapabilitySet map[Capability]bool
  47. func (set CapabilitySet) String() string {
  48. strs := make([]string, len(set))
  49. index := 0
  50. for capability := range set {
  51. strs[index] = string(capability)
  52. index += 1
  53. }
  54. return strings.Join(strs, " ")
  55. }
  56. func (set CapabilitySet) DisableString() string {
  57. parts := make([]string, len(set))
  58. index := 0
  59. for capability := range set {
  60. parts[index] = Disable.String() + capability.String()
  61. index += 1
  62. }
  63. return strings.Join(parts, " ")
  64. }
  65. func (msg *CapCommand) HandleRegServer(server *Server) {
  66. client := msg.Client()
  67. switch msg.subCommand {
  68. case CAP_LS:
  69. client.capState = CapNegotiating
  70. client.Reply(RplCap(client, CAP_LS, SupportedCapabilities))
  71. case CAP_LIST:
  72. client.Reply(RplCap(client, CAP_LIST, client.capabilities))
  73. case CAP_REQ:
  74. for capability := range msg.capabilities {
  75. if !SupportedCapabilities[capability] {
  76. client.Reply(RplCap(client, CAP_NAK, msg.capabilities))
  77. return
  78. }
  79. }
  80. for capability := range msg.capabilities {
  81. client.capabilities[capability] = true
  82. }
  83. client.Reply(RplCap(client, CAP_ACK, msg.capabilities))
  84. case CAP_CLEAR:
  85. reply := RplCap(client, CAP_ACK, client.capabilities.DisableString())
  86. client.capabilities = make(CapabilitySet)
  87. client.Reply(reply)
  88. case CAP_END:
  89. client.capState = CapNegotiated
  90. server.tryRegister(client)
  91. default:
  92. client.ErrInvalidCapCmd(msg.subCommand)
  93. }
  94. }