Explorar o código

implement blocking / fix tlv read for uint8

Mike %!s(int64=3) %!d(string=hai) anos
pai
achega
c5894b56a6
Modificáronse 4 ficheiros con 204 adicións e 88 borrados
  1. 130 36
      oscar/feedbag.go
  2. 21 39
      oscar/feedbag_store.go
  3. 52 12
      oscar/feedbag_store_test.go
  4. 1 1
      oscar/protocol.go

+ 130 - 36
oscar/feedbag.go

@@ -3,6 +3,7 @@ package oscar
 import (
 	"bytes"
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"io"
 	"reflect"
@@ -45,6 +46,71 @@ const (
 	FeedbagRecentBuddyUpdate               = 0x0025
 )
 
+const (
+	FeedbagAttributesShared                  uint16 = 0x0064
+	FeedbagAttributesInvited                        = 0x0065
+	FeedbagAttributesPending                        = 0x0066
+	FeedbagAttributesTimeT                          = 0x0067
+	FeedbagAttributesDenied                         = 0x0068
+	FeedbagAttributesSwimIndex                      = 0x0069
+	FeedbagAttributesRecentBuddy                    = 0x006A
+	FeedbagAttributesAutoBot                        = 0x006B
+	FeedbagAttributesInteraction                    = 0x006D
+	FeedbagAttributesMegaBot                        = 0x006F
+	FeedbagAttributesOrder                          = 0x00C8
+	FeedbagAttributesBuddyPrefs                     = 0x00C9
+	FeedbagAttributesPdMode                         = 0x00CA
+	FeedbagAttributesPdMask                         = 0x00CB
+	FeedbagAttributesPdFlags                        = 0x00CC
+	FeedbagAttributesClientPrefs                    = 0x00CD
+	FeedbagAttributesLanguage                       = 0x00CE
+	FeedbagAttributesFishUri                        = 0x00CF
+	FeedbagAttributesWirelessPdMode                 = 0x00D0
+	FeedbagAttributesWirelessIgnoreMode             = 0x00D1
+	FeedbagAttributesFishPdMode                     = 0x00D2
+	FeedbagAttributesFishIgnoreMode                 = 0x00D3
+	FeedbagAttributesCreateTime                     = 0x00D4
+	FeedbagAttributesBartInfo                       = 0x00D5
+	FeedbagAttributesBuddyPrefsValid                = 0x00D6
+	FeedbagAttributesBuddyPrefs2                    = 0x00D7
+	FeedbagAttributesBuddyPrefs2Valid               = 0x00D8
+	FeedbagAttributesBartList                       = 0x00D9
+	FeedbagAttributesArriveSound                    = 0x012C
+	FeedbagAttributesLeaveSound                     = 0x012D
+	FeedbagAttributesImage                          = 0x012E
+	FeedbagAttributesColorBg                        = 0x012F
+	FeedbagAttributesColorFg                        = 0x0130
+	FeedbagAttributesAlias                          = 0x0131
+	FeedbagAttributesPassword                       = 0x0132
+	FeedbagAttributesDisabled                       = 0x0133
+	FeedbagAttributesCollapsed                      = 0x0134
+	FeedbagAttributesUrl                            = 0x0135
+	FeedbagAttributesActiveList                     = 0x0136
+	FeedbagAttributesEmailAddr                      = 0x0137
+	FeedbagAttributesPhoneNumber                    = 0x0138
+	FeedbagAttributesCellPhoneNumber                = 0x0139
+	FeedbagAttributesSmsPhoneNumber                 = 0x013A
+	FeedbagAttributesWireless                       = 0x013B
+	FeedbagAttributesNote                           = 0x013C
+	FeedbagAttributesAlertPrefs                     = 0x013D
+	FeedbagAttributesBudalertSound                  = 0x013E
+	FeedbagAttributesStockalertValue                = 0x013F
+	FeedbagAttributesTpalertEditUrl                 = 0x0140
+	FeedbagAttributesTpalertDeleteUrl               = 0x0141
+	FeedbagAttributesTpprovMorealertsUrl            = 0x0142
+	FeedbagAttributesFish                           = 0x0143
+	FeedbagAttributesXunconfirmedxLastAccess        = 0x0145
+	FeedbagAttributesImSent                         = 0x0150
+	FeedbagAttributesOnlineTime                     = 0x0151
+	FeedbagAttributesAwayMsg                        = 0x0152
+	FeedbagAttributesImReceived                     = 0x0153
+	FeedbagAttributesBuddyfeedView                  = 0x0154
+	FeedbagAttributesWorkPhoneNumber                = 0x0158
+	FeedbagAttributesOtherPhoneNumber               = 0x0159
+	FeedbagAttributesWebPdMode                      = 0x015F
+	FeedbagAttributesFirstCreationTimeXc            = 0x0167
+	FeedbagAttributesPdModeXc                       = 0x016E
+)
 const (
 	FeedbagClassIdBuddy            uint16 = 0x0000
 	FeedbagClassIdGroup                   = 0x0001
@@ -95,9 +161,9 @@ func routeFeedbag(sm *SessionManager, sess *Session, fm *FeedbagStore, flap *fla
 	case FeedbagInsertItem:
 		return ReceiveInsertItem(sm, sess, fm, flap, snac, r, w, sequence)
 	case FeedbagUpdateItem:
-		return ReceiveUpdateItem(sess, fm, flap, snac, r, w, sequence)
+		return ReceiveUpdateItem(sm, sess, fm, flap, snac, r, w, sequence)
 	case FeedbagDeleteItem:
-		return ReceiveDeleteItem(sess, fm, flap, snac, r, w, sequence)
+		return ReceiveDeleteItem(sm, sess, fm, flap, snac, r, w, sequence)
 	case FeedbagInsertClass:
 		panic("not implemented")
 	case FeedbagUpdateClass:
@@ -317,37 +383,8 @@ func (f *feedbagItem) read(r io.Reader) error {
 	}
 
 	return f.TLVPayload.read(bytes.NewBuffer(buf), map[uint16]reflect.Kind{
-		0xC8:                           reflect.Slice,
-		FeedbagClassIdBuddy:            reflect.Slice,
-		FeedbagClassIdGroup:            reflect.Slice,
-		FeedbagClassIdPermit:           reflect.Slice,
-		FeedbagClassIdDeny:             reflect.Slice,
-		FeedbagClassIdPdinfo:           reflect.Slice,
-		FeedbagClassIdBuddyPrefs:       reflect.Slice,
-		FeedbagClassIdNonbuddy:         reflect.Slice,
-		FeedbagClassIdTpaProvider:      reflect.Slice,
-		FeedbagClassIdTpaSubscription:  reflect.Slice,
-		FeedbagClassIdClientPrefs:      reflect.Slice,
-		FeedbagClassIdStock:            reflect.Slice,
-		FeedbagClassIdWeather:          reflect.Slice,
-		FeedbagClassIdWatchList:        reflect.Slice,
-		FeedbagClassIdIgnoreList:       reflect.Slice,
-		FeedbagClassIdDateTime:         reflect.Slice,
-		FeedbagClassIdExternalUser:     reflect.Slice,
-		FeedbagClassIdRootCreator:      reflect.Slice,
-		FeedbagClassIdFish:             reflect.Slice,
-		FeedbagClassIdImportTimestamp:  reflect.Slice,
-		FeedbagClassIdBart:             reflect.Slice,
-		FeedbagClassIdRbOrder:          reflect.Slice,
-		FeedbagClassIdPersonality:      reflect.Slice,
-		FeedbagClassIdAlProf:           reflect.Slice,
-		FeedbagClassIdAlInfo:           reflect.Slice,
-		FeedbagClassIdInteraction:      reflect.Slice,
-		FeedbagClassIdVanityInfo:       reflect.Slice,
-		FeedbagClassIdFavoriteLocation: reflect.Slice,
-		FeedbagClassIdBartPdinfo:       reflect.Slice,
-		FeedbagClassIdXIcqStatusNote:   reflect.Slice,
-		FeedbagClassIdMin:              reflect.Slice,
+		FeedbagAttributesOrder:  reflect.Slice,
+		FeedbagAttributesPdMode: reflect.Uint8,
 	})
 }
 
@@ -511,11 +548,53 @@ func ReceiveInsertItem(sm *SessionManager, sess *Session, fm *FeedbagStore, flap
 		return err
 	}
 
+	for _, item := range feedbag {
+		// DENY, block buddy
+		if item.classID == 3 {
+			buddySess, err := sm.RetrieveByScreenName(item.name)
+			if err != nil {
+				if errors.Is(err, errSessNotFound) {
+					// former buddy is offline
+					continue
+				}
+				return err
+			}
+			buddySess.SendMessage(&XMessage{
+				flap: &flapFrame{
+					startMarker: 42,
+					frameType:   2,
+				},
+				snacFrame: snacFrame{
+					foodGroup: BUDDY,
+					subGroup:  BuddyDeparted,
+				},
+				snacOut: &snacBuddyArrived{
+					screenName:   sess.ScreenName,
+					warningLevel: sess.GetWarning(),
+				},
+			})
+			sess.SendMessage(&XMessage{
+				flap: &flapFrame{
+					startMarker: 42,
+					frameType:   2,
+				},
+				snacFrame: snacFrame{
+					foodGroup: BUDDY,
+					subGroup:  BuddyDeparted,
+				},
+				snacOut: &snacBuddyArrived{
+					screenName:   buddySess.ScreenName,
+					warningLevel: buddySess.GetWarning(),
+				},
+			})
+		}
+	}
+
 	// todo: just check online status for buddies that were added
 	return GetOnlineBuddies(w, sess, sm, fm, sequence)
 }
 
-func ReceiveUpdateItem(sess *Session, fm *FeedbagStore, flap *flapFrame, snac *snacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
+func ReceiveUpdateItem(sm *SessionManager, sess *Session, fm *FeedbagStore, flap *flapFrame, snac *snacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
 	fmt.Printf("ReceiveUpdateItem read SNAC frame: %+v\n", snac)
 
 	var items []*feedbagItem
@@ -548,10 +627,14 @@ func ReceiveUpdateItem(sess *Session, fm *FeedbagStore, flap *flapFrame, snac *s
 		subGroup:  FeedbagStatus,
 	}
 
-	return writeOutSNAC(snac, flap, snacFrameOut, snacPayloadOut, sequence, w)
+	if err := writeOutSNAC(snac, flap, snacFrameOut, snacPayloadOut, sequence, w); err != nil {
+		return err
+	}
+
+	return GetOnlineBuddies(w, sess, sm, fm, sequence)
 }
 
-func ReceiveDeleteItem(sess *Session, fm *FeedbagStore, flap *flapFrame, snac *snacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
+func ReceiveDeleteItem(sm *SessionManager, sess *Session, fm *FeedbagStore, flap *flapFrame, snac *snacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
 	fmt.Printf("ReceiveUpdateItem read SNAC frame: %+v\n", snac)
 
 	var items []*feedbagItem
@@ -574,11 +657,22 @@ func ReceiveDeleteItem(sess *Session, fm *FeedbagStore, flap *flapFrame, snac *s
 
 	snacPayloadOut := &snacFeedbagStatusReply{}
 
+	hasUnblock := false
 	for _, item := range items {
+		if item.classID == 3 {
+			hasUnblock = true
+		}
 		snacPayloadOut.results = append(snacPayloadOut.results, 0x0000) // success by default
 		fmt.Printf("ReceiveDeleteItem read SNAC feedbag item: %+v\n", item)
 	}
 
+	if hasUnblock {
+		// notify previously blocked users that user is back online
+		if err := NotifyArrival(sess, sm, fm); err != nil {
+			return err
+		}
+	}
+
 	snacFrameOut := snacFrame{
 		foodGroup: FEEDBAG,
 		subGroup:  FeedbagStatus,

+ 21 - 39
oscar/feedbag_store.go

@@ -100,37 +100,8 @@ func (f *FeedbagStore) Retrieve(screenName string) ([]*feedbagItem, error) {
 			return nil, err
 		}
 		err = item.TLVPayload.read(bytes.NewBuffer(attrs), map[uint16]reflect.Kind{
-			0xC8: reflect.Slice,
-			//FeedbagClassIdBuddy:            reflect.Slice,
-			FeedbagClassIdGroup: reflect.Uint16,
-			//FeedbagClassIdPermit:           reflect.Slice,
-			//FeedbagClassIdDeny:             reflect.Slice,
-			//FeedbagClassIdPdinfo:           reflect.Slice,
-			//FeedbagClassIdBuddyPrefs:       reflect.Slice,
-			//FeedbagClassIdNonbuddy:         reflect.Slice,
-			//FeedbagClassIdTpaProvider:      reflect.Slice,
-			//FeedbagClassIdTpaSubscription:  reflect.Slice,
-			//FeedbagClassIdClientPrefs:      reflect.Slice,
-			//FeedbagClassIdStock:            reflect.Slice,
-			//FeedbagClassIdWeather:          reflect.Slice,
-			//FeedbagClassIdWatchList:        reflect.Slice,
-			//FeedbagClassIdIgnoreList:       reflect.Slice,
-			//FeedbagClassIdDateTime:         reflect.Slice,
-			//FeedbagClassIdExternalUser:     reflect.Slice,
-			//FeedbagClassIdRootCreator:      reflect.Slice,
-			//FeedbagClassIdFish:             reflect.Slice,
-			//FeedbagClassIdImportTimestamp:  reflect.Slice,
-			//FeedbagClassIdBart:             reflect.Slice,
-			FeedbagClassIdRbOrder: reflect.Uint16,
-			//FeedbagClassIdPersonality:      reflect.Slice,
-			//FeedbagClassIdAlProf:           reflect.Slice,
-			//FeedbagClassIdAlInfo:           reflect.Slice,
-			//FeedbagClassIdInteraction:      reflect.Slice,
-			//FeedbagClassIdVanityInfo:       reflect.Slice,
-			//FeedbagClassIdFavoriteLocation: reflect.Slice,
-			//FeedbagClassIdBartPdinfo:       reflect.Slice,
-			//FeedbagClassIdXIcqStatusNote:   reflect.Slice,
-			//FeedbagClassIdMin:              reflect.Slice,
+			FeedbagAttributesOrder:  reflect.Slice,
+			FeedbagAttributesPdMode: reflect.Uint8,
 		})
 		if err != nil {
 			return items, err
@@ -183,14 +154,21 @@ func (f *FeedbagStore) Upsert(screenName string, items []*feedbagItem) error {
 }
 
 // InterestedUsers returns all users who have screenName in their buddy list.
+// Exclude users who are on screenName's block list.
 func (f *FeedbagStore) InterestedUsers(screenName string) ([]string, error) {
 	q := `
-		SELECT ScreenName
-		FROM feedbag
-		WHERE name = ? AND classID = 0
+		SELECT f.ScreenName
+		FROM feedbag f
+		WHERE f.name = ?
+		  AND f.classID = 0
+		  AND NOT EXISTS(SELECT 1
+						 FROM feedbag
+						 WHERE ScreenName = f.ScreenName
+						   AND name = ?
+						   AND classID = 3)
 	`
 
-	rows, err := f.db.Query(q, screenName)
+	rows, err := f.db.Query(q, screenName, screenName)
 	if err != nil {
 		return nil, err
 	}
@@ -210,12 +188,16 @@ func (f *FeedbagStore) InterestedUsers(screenName string) ([]string, error) {
 
 func (f *FeedbagStore) Buddies(screenName string) ([]string, error) {
 	q := `
-		SELECT name
-		FROM feedbag
-		WHERE ScreenName = ? AND classID = 0
+		SELECT f.name
+		FROM feedbag f
+		WHERE f.ScreenName = ? AND f.classID = 0
+		-- Don't include buddy if they blocked screenName
+		AND NOT EXISTS(SELECT 1 FROM feedbag WHERE ScreenName = f.name AND name = ? AND classID = 3)
+		-- Don't include buddy if screen name blocked them
+		AND NOT EXISTS(SELECT 1 FROM feedbag WHERE ScreenName = ? AND name = f.name AND classID = 3)
 	`
 
-	rows, err := f.db.Query(q, screenName)
+	rows, err := f.db.Query(q, screenName, screenName, screenName)
 	if err != nil {
 		return nil, err
 	}

+ 52 - 12
oscar/feedbag_store_test.go

@@ -25,18 +25,11 @@ func TestFeedbagStore(t *testing.T) {
 
 	itemsIn := []*feedbagItem{
 		{
-			groupID: 0,
-			itemID:  1805,
-			classID: 3,
-			name:    "spimmer1234",
-			TLVPayload: TLVPayload{
-				TLVs: []*TLV{
-					{
-						tType: 0x01,
-						val:   uint16(1000),
-					},
-				},
-			},
+			groupID:    0,
+			itemID:     1805,
+			classID:    3,
+			name:       "spimmer1234",
+			TLVPayload: TLVPayload{},
 		},
 		{
 			groupID: 0x0A,
@@ -59,6 +52,53 @@ func TestFeedbagStore(t *testing.T) {
 	}
 }
 
+func TestFeedbagStoreBlockedUser(t *testing.T) {
+
+	const testFile string = "/Users/mike/dev/goaim/aim_test.db"
+	const screenName = "sn2day"
+
+	defer func() {
+		err := os.Remove(testFile)
+		if err != nil {
+			t.Error("unable to clean up test file")
+		}
+	}()
+
+	f, err := NewFeedbagStore(testFile)
+	if err != nil {
+		t.Fatalf("failed to create new feedbag store: %s", err.Error())
+	}
+
+	itemsIn := []*feedbagItem{
+		{
+			groupID:    0,
+			itemID:     1805,
+			classID:    0,
+			name:       "spimmer1234",
+			TLVPayload: TLVPayload{},
+		},
+		{
+			groupID:    0,
+			itemID:     1807,
+			classID:    3,
+			name:       "spimmer1234",
+			TLVPayload: TLVPayload{},
+		},
+	}
+	if err := f.Upsert(screenName, itemsIn); err != nil {
+		t.Fatalf("failed to upsert: %s", err.Error())
+	}
+
+	itemsOut, err := f.Buddies(screenName)
+	if err != nil {
+		t.Fatalf("failed to retrieve: %s", err.Error())
+	}
+
+	if len(itemsOut) != 0 {
+		t.Fatalf("got unexpected blocked buddy %v", itemsOut[0])
+	}
+}
+
 func TestFeedbagDelete(t *testing.T) {
 
 	const testFile string = "/Users/mike/dev/goaim/aim_test.db"

+ 1 - 1
oscar/protocol.go

@@ -273,7 +273,7 @@ func (t *TLV) read(r io.Reader, typeLookup map[uint16]reflect.Kind) error {
 
 	switch kind {
 	case reflect.Uint8:
-		var val uint16
+		var val uint8
 		if err := binary.Read(r, binary.BigEndian, &val); err != nil {
 			return err
 		}