chat.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package state
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/url"
  6. "time"
  7. "github.com/mk6i/retro-aim-server/wire"
  8. )
  9. const (
  10. // PrivateExchange is the ID of the exchange that hosts non-public created
  11. // by users.
  12. PrivateExchange uint16 = 4
  13. // PublicExchange is the ID of the exchange that hosts public chat rooms
  14. // created by the server operator exclusively.
  15. PublicExchange uint16 = 5
  16. )
  17. // ErrChatRoomNotFound indicates that a chat room lookup failed.
  18. var (
  19. ErrChatRoomNotFound = errors.New("chat room not found")
  20. ErrDupChatRoom = errors.New("chat room already exists")
  21. )
  22. // NewChatRoom creates a new ChatRoom instance.
  23. func NewChatRoom(name string, creator IdentScreenName, exchange uint16) ChatRoom {
  24. return ChatRoom{
  25. name: name,
  26. creator: creator,
  27. exchange: exchange,
  28. }
  29. }
  30. // ChatRoom represents of a chat room.
  31. type ChatRoom struct {
  32. createTime time.Time
  33. creator IdentScreenName
  34. exchange uint16
  35. name string
  36. }
  37. // Creator returns the screen name of the user who created the chat room.
  38. func (c ChatRoom) Creator() IdentScreenName {
  39. return c.creator
  40. }
  41. // Exchange returns which exchange the chat room belongs to.
  42. func (c ChatRoom) Exchange() uint16 {
  43. return c.exchange
  44. }
  45. // Name returns the chat room name.
  46. func (c ChatRoom) Name() string {
  47. return c.name
  48. }
  49. // InstanceNumber returns which instance chatroom exists in. Overflow chat
  50. // rooms do not exist yet, so all chats happen in the same instance.
  51. func (c ChatRoom) InstanceNumber() uint16 {
  52. return 0
  53. }
  54. // CreateTime returns when the chat room was inserted in the database.
  55. func (c ChatRoom) CreateTime() time.Time {
  56. return c.createTime
  57. }
  58. // DetailLevel returns the detail level of the chat room (whatever that means).
  59. func (c ChatRoom) DetailLevel() uint8 {
  60. return 0x02 // Pidgin 2.13.0 expects value 0x02
  61. }
  62. // Cookie returns the chat room unique identifier.
  63. func (c ChatRoom) Cookie() string {
  64. // According to Pidgin, the chat cookie is a 3-part identifier. The third
  65. // segment is the chat name, which is shown explicitly in the Pidgin code.
  66. // We can assume that the first two parts were the exchange and instance
  67. // number. As of now, Pidgin is the only client that cares about the cookie
  68. // format, and it only cares about the chat name segment.
  69. return fmt.Sprintf("%d-%d-%s", c.exchange, c.InstanceNumber(), c.name)
  70. }
  71. // URL creates a URL that can be used to join a chat room.
  72. func (c ChatRoom) URL() *url.URL {
  73. // macOS client v4.0.9 requires the `roomname` param to precede `exchange`
  74. // param. Create the path using string concatenation rather than url.Values
  75. // because url.Values sorts the params alphabetically.
  76. opaque := fmt.Sprintf("gochat?roomname=%s&exchange=%d", url.QueryEscape(c.name), c.exchange)
  77. return &url.URL{
  78. Scheme: "aim",
  79. Opaque: opaque,
  80. }
  81. }
  82. // TLVList returns a TLV list of chat room metadata.
  83. func (c ChatRoom) TLVList() []wire.TLV {
  84. return []wire.TLV{
  85. // From protocols/oscar/family_chatnav.c in lib purple, these are the
  86. // room creation flags:
  87. // - 1 Evilable
  88. // - 2 Nav Only
  89. // - 4 Instancing Allowed
  90. // - 8 Occupant Peek Allowed
  91. // It's unclear what effect they actually have.
  92. wire.NewTLVBE(wire.ChatRoomTLVFlags, uint16(15)),
  93. wire.NewTLVBE(wire.ChatRoomTLVCreateTime, uint32(c.createTime.Unix())),
  94. wire.NewTLVBE(wire.ChatRoomTLVMaxMsgLen, uint16(1024)),
  95. wire.NewTLVBE(wire.ChatRoomTLVMaxOccupancy, uint16(100)),
  96. // From protocols/oscar/family_chatnav.c in lib purple, these are the
  97. // room creation permission values:
  98. // - 0 creation not allowed
  99. // - 1 room creation allowed
  100. // - 2 exchange creation allowed
  101. // It's unclear what effect they actually have.
  102. wire.NewTLVBE(wire.ChatRoomTLVNavCreatePerms, uint8(2)),
  103. wire.NewTLVBE(wire.ChatRoomTLVFullyQualifiedName, c.name),
  104. wire.NewTLVBE(wire.ChatRoomTLVRoomName, c.name),
  105. wire.NewTLVBE(wire.ChatRoomTLVMaxMsgVisLen, uint16(1024)),
  106. }
  107. }