chat_nav.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package server
  2. import (
  3. "errors"
  4. "github.com/google/uuid"
  5. "github.com/mkaminski/goaim/oscar"
  6. "io"
  7. "time"
  8. )
  9. type ChatNavHandler interface {
  10. CreateRoomHandler(sess *Session, cr *ChatRegistry, newChatRoom ChatRoomFactory, snacPayloadIn oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (XMessage, error)
  11. RequestChatRightsHandler() XMessage
  12. RequestRoomInfoHandler(cr *ChatRegistry, snacPayloadIn oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (XMessage, error)
  13. }
  14. func NewChatNavRouter() ChatNavRouter {
  15. return ChatNavRouter{
  16. ChatNavHandler: ChatNavService{},
  17. }
  18. }
  19. type ChatNavRouter struct {
  20. ChatNavHandler
  21. }
  22. func (rt *ChatNavRouter) RouteChatNav(sess *Session, cr *ChatRegistry, SNACFrame oscar.SnacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
  23. switch SNACFrame.SubGroup {
  24. case oscar.ChatNavRequestChatRights:
  25. outSNAC := rt.RequestChatRightsHandler()
  26. return writeOutSNAC(SNACFrame, outSNAC.snacFrame, outSNAC.snacOut, sequence, w)
  27. case oscar.ChatNavRequestRoomInfo:
  28. inSNAC := oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo{}
  29. if err := oscar.Unmarshal(&inSNAC, r); err != nil {
  30. return err
  31. }
  32. outSNAC, err := rt.RequestRoomInfoHandler(cr, inSNAC)
  33. if err != nil {
  34. return err
  35. }
  36. return writeOutSNAC(SNACFrame, outSNAC.snacFrame, outSNAC.snacOut, sequence, w)
  37. case oscar.ChatNavCreateRoom:
  38. snacPayloadIn := oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{}
  39. if err := oscar.Unmarshal(&snacPayloadIn, r); err != nil {
  40. return err
  41. }
  42. outSNAC, err := rt.CreateRoomHandler(sess, cr, NewChatRoom, snacPayloadIn)
  43. if err != nil {
  44. return err
  45. }
  46. return writeOutSNAC(SNACFrame, outSNAC.snacFrame, outSNAC.snacOut, sequence, w)
  47. default:
  48. return ErrUnsupportedSubGroup
  49. }
  50. }
  51. type ChatNavService struct {
  52. }
  53. type ChatCookie struct {
  54. Cookie []byte `len_prefix:"uint16"`
  55. SessID string `len_prefix:"uint16"`
  56. }
  57. func (s ChatNavService) RequestChatRightsHandler() XMessage {
  58. return XMessage{
  59. snacFrame: oscar.SnacFrame{
  60. FoodGroup: oscar.CHAT_NAV,
  61. SubGroup: oscar.ChatNavNavInfo,
  62. },
  63. snacOut: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
  64. TLVRestBlock: oscar.TLVRestBlock{
  65. TLVList: oscar.TLVList{
  66. oscar.NewTLV(0x02, uint8(10)),
  67. oscar.NewTLV(0x03, oscar.SNAC_0x0D_0x09_TLVExchangeInfo{
  68. Identifier: 4,
  69. TLVBlock: oscar.TLVBlock{
  70. TLVList: oscar.TLVList{
  71. oscar.NewTLV(0x0002, uint16(0x0010)),
  72. oscar.NewTLV(0x00c9, uint16(15)),
  73. oscar.NewTLV(0x00d3, "default Exchange"),
  74. oscar.NewTLV(0x00d5, uint8(2)),
  75. oscar.NewTLV(0xd6, "us-ascii"),
  76. oscar.NewTLV(0xd7, "en"),
  77. oscar.NewTLV(0xd8, "us-ascii"),
  78. oscar.NewTLV(0xd9, "en"),
  79. },
  80. },
  81. }),
  82. },
  83. },
  84. },
  85. }
  86. }
  87. func NewChatRoom() ChatRoom {
  88. return ChatRoom{
  89. Cookie: uuid.New().String(),
  90. CreateTime: time.Now(),
  91. SessionManager: NewSessionManager(),
  92. }
  93. }
  94. type ChatRoomFactory func() ChatRoom
  95. func (s ChatNavService) CreateRoomHandler(sess *Session, cr *ChatRegistry, newChatRoom ChatRoomFactory, snacPayloadIn oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (XMessage, error) {
  96. name, hasName := snacPayloadIn.GetString(oscar.ChatTLVRoomName)
  97. if !hasName {
  98. return XMessage{}, errors.New("unable to find chat name")
  99. }
  100. room := newChatRoom()
  101. room.DetailLevel = snacPayloadIn.DetailLevel
  102. room.Exchange = snacPayloadIn.Exchange
  103. room.InstanceNumber = snacPayloadIn.InstanceNumber
  104. room.Name = name
  105. cr.Register(room)
  106. // add user to chat room
  107. room.NewSessionWithSN(sess.ID, sess.ScreenName)
  108. return XMessage{
  109. snacFrame: oscar.SnacFrame{
  110. FoodGroup: oscar.CHAT_NAV,
  111. SubGroup: oscar.ChatNavNavInfo,
  112. },
  113. snacOut: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
  114. TLVRestBlock: oscar.TLVRestBlock{
  115. TLVList: oscar.TLVList{
  116. oscar.NewTLV(oscar.ChatNavTLVRoomInfo, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
  117. Exchange: snacPayloadIn.Exchange,
  118. Cookie: room.Cookie,
  119. InstanceNumber: snacPayloadIn.InstanceNumber,
  120. DetailLevel: snacPayloadIn.DetailLevel,
  121. TLVBlock: oscar.TLVBlock{
  122. TLVList: room.TLVList(),
  123. },
  124. }),
  125. },
  126. },
  127. },
  128. }, nil
  129. }
  130. func (s ChatNavService) RequestRoomInfoHandler(cr *ChatRegistry, snacPayloadIn oscar.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (XMessage, error) {
  131. room, err := cr.Retrieve(string(snacPayloadIn.Cookie))
  132. if err != nil {
  133. return XMessage{}, err
  134. }
  135. return XMessage{
  136. snacFrame: oscar.SnacFrame{
  137. FoodGroup: oscar.CHAT_NAV,
  138. SubGroup: oscar.ChatNavNavInfo,
  139. },
  140. snacOut: oscar.SNAC_0x0D_0x09_ChatNavNavInfo{
  141. TLVRestBlock: oscar.TLVRestBlock{
  142. TLVList: oscar.TLVList{
  143. oscar.NewTLV(0x04, oscar.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
  144. Exchange: 4,
  145. Cookie: room.Cookie,
  146. InstanceNumber: 100,
  147. DetailLevel: 2,
  148. TLVBlock: oscar.TLVBlock{
  149. TLVList: room.TLVList(),
  150. },
  151. }),
  152. },
  153. },
  154. },
  155. }, nil
  156. }