aim-oscar-server/services/0x03_buddy_list_management.go
2022-02-11 13:28:20 -05:00

128 lines
3.2 KiB
Go

package services
import (
"aim-oscar/aimerror"
"aim-oscar/models"
"aim-oscar/oscar"
"aim-oscar/util"
"context"
"database/sql"
"log"
"github.com/pkg/errors"
"github.com/uptrace/bun"
)
type BuddyListManagement struct {
OnlineCh chan *models.User
}
func (b *BuddyListManagement) HandleSNAC(ctx context.Context, db *bun.DB, snac *oscar.SNAC) (context.Context, error) {
session, _ := oscar.SessionFromContext(ctx)
switch snac.Header.Subtype {
// Client wants to know the buddy list params + limitations
case 0x2:
limitSnac := oscar.NewSNAC(3, 3)
limitSnac.Data.WriteBinary(oscar.NewTLV(1, util.Word(500))) // Max buddy list size
limitSnac.Data.WriteBinary(oscar.NewTLV(2, util.Word(750))) // Max list watchers
limitSnac.Data.WriteBinary(oscar.NewTLV(3, util.Word(512))) // Max online notifications ?
limitFlap := oscar.NewFLAP(2)
limitFlap.Data.WriteBinary(limitSnac)
return ctx, session.Send(limitFlap)
// Add buddy
case 0x4:
user := models.UserFromContext(ctx)
if user == nil {
return ctx, aimerror.NoUserInSession
}
for len(snac.Data.Bytes()) > 0 {
buddyScreename, err := snac.Data.ReadLPString()
if err != nil {
return ctx, errors.Wrap(err, "expecting more buddies in list")
}
buddy, err := models.UserByScreenName(ctx, db, buddyScreename)
if err != nil {
return ctx, errors.Wrap(err, "error looking for User")
}
if buddy == nil {
noMatchSnac := oscar.NewSNAC(0x3, 1)
noMatchSnac.Data.WriteUint16(0x14) // error code 0x14: No Match
noMatchFlap := oscar.NewFLAP(2)
noMatchFlap.Data.WriteBinary(noMatchSnac)
session.Send(noMatchFlap)
return ctx, nil
}
rel := &models.Buddy{
SourceUIN: user.UIN,
WithUIN: buddy.UIN,
}
count, err := db.NewSelect().Model((*models.Buddy)(nil)).Where("source_uin = ?", user.UIN).Where("with_uin = ?", buddy.UIN).Count(ctx)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return ctx, err
}
// Already buddies
if count > 0 {
return ctx, nil
}
_, err = db.NewInsert().Model(rel).Exec(ctx)
if err != nil {
return ctx, err
}
b.OnlineCh <- buddy
log.Printf("%s added buddy %s to buddy list", user.ScreenName, buddyScreename)
}
return ctx, nil
// Remove buddies from user list
case 0x5:
user := models.UserFromContext(ctx)
if user == nil {
return ctx, aimerror.NoUserInSession
}
for len(snac.Data.Bytes()) > 0 {
buddyScreename, err := snac.Data.ReadLPString()
if err != nil {
return ctx, errors.Wrap(err, "expecting more buddies in list")
}
buddy, err := models.UserByScreenName(ctx, db, buddyScreename)
if err != nil {
return ctx, errors.Wrap(err, "error looking for User")
}
if buddy == nil {
noMatchSnac := oscar.NewSNAC(0x3, 1)
noMatchSnac.Data.WriteUint16(0x14) // error code 0x14: No Match
noMatchFlap := oscar.NewFLAP(2)
noMatchFlap.Data.WriteBinary(noMatchSnac)
session.Send(noMatchFlap)
return ctx, nil
}
_, err = db.NewDelete().Model((*models.Buddy)(nil)).Where("source_uin = ?", user.UIN).Where("with_uin = ?", buddy.UIN).Exec(ctx)
if err != nil {
return ctx, err
}
log.Printf("%s removed buddy %s from buddy list", user.ScreenName, buddyScreename)
}
return ctx, nil
}
return ctx, nil
}