permit_deny.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package foodgroup
  2. import (
  3. "context"
  4. "github.com/mk6i/open-oscar-server/state"
  5. "github.com/mk6i/open-oscar-server/wire"
  6. )
  7. // NewPermitDenyService creates an instance of PermitDenyService.
  8. func NewPermitDenyService(
  9. bartItemManager BARTItemManager,
  10. relationshipFetcher RelationshipFetcher,
  11. clientSideBuddyListManager ClientSideBuddyListManager,
  12. messageRelayer MessageRelayer,
  13. sessionRetriever SessionRetriever,
  14. ) PermitDenyService {
  15. return PermitDenyService{
  16. buddyBroadcaster: newBuddyNotifier(bartItemManager, relationshipFetcher, messageRelayer, sessionRetriever),
  17. clientSideBuddyListManager: clientSideBuddyListManager,
  18. }
  19. }
  20. // PermitDenyService provides functionality for the PermitDeny (PD) food group.
  21. // The PD food group manages settings for permit/deny (allow/block) for
  22. // pre-feedbag (sever-side buddy list) AIM clients.
  23. type PermitDenyService struct {
  24. buddyBroadcaster buddyBroadcaster
  25. clientSideBuddyListManager ClientSideBuddyListManager
  26. }
  27. // AddDenyListEntries adds users to your block list and sets your visibility
  28. // mode to "deny some". If your screen name is passed as a single element in
  29. // the input payload, your visibility mode is set to "permit all" instead.
  30. // Your buddy list and your relations' buddy lists are updated to reflect the
  31. // current mode.
  32. func (s PermitDenyService) AddDenyListEntries(ctx context.Context, instance *state.SessionInstance, inBody wire.SNAC_0x09_0x07_PermitDenyAddDenyListEntries) error {
  33. if len(inBody.Users) == 1 {
  34. sn := state.NewIdentScreenName(inBody.Users[0].ScreenName)
  35. if sn.String() == instance.IdentScreenName().String() {
  36. if err := s.clientSideBuddyListManager.SetPDMode(ctx, instance.IdentScreenName(), wire.FeedbagPDModePermitAll); err != nil {
  37. return err
  38. }
  39. return s.maybeBroadcastVisibility(ctx, instance, nil)
  40. }
  41. }
  42. if err := s.clientSideBuddyListManager.SetPDMode(ctx, instance.IdentScreenName(), wire.FeedbagPDModeDenySome); err != nil {
  43. return err
  44. }
  45. for _, user := range inBody.Users {
  46. sn := state.NewIdentScreenName(user.ScreenName)
  47. if err := s.clientSideBuddyListManager.DenyBuddy(ctx, instance.IdentScreenName(), sn); err != nil {
  48. return err
  49. }
  50. }
  51. // don't filter users so that users permitted as a result of this
  52. // visibility change get properly notified
  53. return s.maybeBroadcastVisibility(ctx, instance, nil)
  54. }
  55. // AddPermListEntries adds users to your permit list and sets your visibility
  56. // mode to "permit some". If your screen name is passed as a single element in
  57. // the input payload, your visibility mode is set to "deny all" instead. Your
  58. // buddy list and your relations' buddy lists are updated to reflect the
  59. // current mode.
  60. func (s PermitDenyService) AddPermListEntries(ctx context.Context, instance *state.SessionInstance, inBody wire.SNAC_0x09_0x05_PermitDenyAddPermListEntries) error {
  61. if len(inBody.Users) == 1 {
  62. sn := state.NewIdentScreenName(inBody.Users[0].ScreenName)
  63. if sn.String() == instance.IdentScreenName().String() {
  64. if err := s.clientSideBuddyListManager.SetPDMode(ctx, instance.IdentScreenName(), wire.FeedbagPDModeDenyAll); err != nil {
  65. return err
  66. }
  67. return s.maybeBroadcastVisibility(ctx, instance, nil)
  68. }
  69. }
  70. if err := s.clientSideBuddyListManager.SetPDMode(ctx, instance.IdentScreenName(), wire.FeedbagPDModePermitSome); err != nil {
  71. return err
  72. }
  73. for _, user := range inBody.Users {
  74. sn := state.NewIdentScreenName(user.ScreenName)
  75. if err := s.clientSideBuddyListManager.PermitBuddy(ctx, instance.IdentScreenName(), sn); err != nil {
  76. return err
  77. }
  78. }
  79. // don't filter users so that users blocked as a result of this visibility
  80. // change get properly notified
  81. return s.maybeBroadcastVisibility(ctx, instance, nil)
  82. }
  83. // DelDenyListEntries removes users from your deny list. Your buddy list and
  84. // your relations' buddy lists are updated to reflect the list update.
  85. func (s PermitDenyService) DelDenyListEntries(ctx context.Context, instance *state.SessionInstance, inBody wire.SNAC_0x09_0x08_PermitDenyDelDenyListEntries) error {
  86. if len(inBody.Users) == 0 {
  87. return nil
  88. }
  89. for _, user := range inBody.Users {
  90. sn := state.NewIdentScreenName(user.ScreenName)
  91. if err := s.clientSideBuddyListManager.RemoveDenyBuddy(ctx, instance.IdentScreenName(), sn); err != nil {
  92. return err
  93. }
  94. }
  95. return s.maybeBroadcastVisibility(ctx, instance, inBody.Users)
  96. }
  97. // DelPermListEntries removes users from your permit list. Your buddy list and
  98. // your relations' buddy lists are updated to reflect the list update.
  99. func (s PermitDenyService) DelPermListEntries(ctx context.Context, instance *state.SessionInstance, inBody wire.SNAC_0x09_0x06_PermitDenyDelPermListEntries) error {
  100. if len(inBody.Users) == 0 {
  101. return nil
  102. }
  103. for _, user := range inBody.Users {
  104. sn := state.NewIdentScreenName(user.ScreenName)
  105. if err := s.clientSideBuddyListManager.RemovePermitBuddy(ctx, instance.IdentScreenName(), sn); err != nil {
  106. return err
  107. }
  108. }
  109. return s.maybeBroadcastVisibility(ctx, instance, inBody.Users)
  110. }
  111. // maybeBroadcastVisibility broadcasts visibility changes to a list users only
  112. // if the client has finished signing in, which prevents duplicate arrival
  113. // notifications, which are ultimately sent at the end of the sign on flow.
  114. func (s PermitDenyService) maybeBroadcastVisibility(ctx context.Context, instance *state.SessionInstance, body []struct {
  115. ScreenName string `oscar:"len_prefix=uint8"`
  116. }) error {
  117. if !instance.SignonComplete() {
  118. return nil
  119. }
  120. var filter []state.IdentScreenName
  121. if len(body) > 0 {
  122. filter = make([]state.IdentScreenName, 0, len(body))
  123. for _, user := range body {
  124. filter = append(filter, state.NewIdentScreenName(user.ScreenName))
  125. }
  126. }
  127. return s.buddyBroadcaster.BroadcastVisibility(ctx, instance, filter, true)
  128. }
  129. // RightsQuery returns settings for the PermitDeny food group. It returns SNAC
  130. // wire.PermitDenyRightsReply. The values in the return SNAC were arbitrarily
  131. // chosen.
  132. func (s PermitDenyService) RightsQuery(ctx context.Context, inFrame wire.SNACFrame) wire.SNACMessage {
  133. return wire.SNACMessage{
  134. Frame: wire.SNACFrame{
  135. FoodGroup: wire.PermitDeny,
  136. SubGroup: wire.PermitDenyRightsReply,
  137. RequestID: inFrame.RequestID,
  138. },
  139. Body: wire.SNAC_0x09_0x03_PermitDenyRightsReply{
  140. TLVRestBlock: wire.TLVRestBlock{
  141. TLVList: wire.TLVList{
  142. wire.NewTLVBE(wire.PermitDenyTLVMaxDenies, uint16(100)),
  143. wire.NewTLVBE(wire.PermitDenyTLVMaxPermits, uint16(100)),
  144. wire.NewTLVBE(wire.PermitDenyTLVMaxTempPermits, uint16(100)),
  145. },
  146. },
  147. },
  148. }
  149. }