| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- package server
- import (
- "errors"
- "fmt"
- "github.com/mkaminski/goaim/oscar"
- "io"
- "time"
- )
- const (
- FeedbagErr uint16 = 0x0001
- FeedbagRightsQuery = 0x0002
- FeedbagQuery = 0x0004
- FeedbagQueryIfModified = 0x0005
- FeedbagReply = 0x0006
- FeedbagUse = 0x0007
- FeedbagInsertItem = 0x0008
- FeedbagUpdateItem = 0x0009
- FeedbagDeleteItem = 0x000A
- FeedbagInsertClass = 0x000B
- FeedbagUpdateClass = 0x000C
- FeedbagDeleteClass = 0x000D
- FeedbagStatus = 0x000E
- FeedbagReplyNotModified = 0x000F
- FeedbagDeleteUser = 0x0010
- FeedbagStartCluster = 0x0011
- FeedbagEndCluster = 0x0012
- FeedbagAuthorizeBuddy = 0x0013
- FeedbagPreAuthorizeBuddy = 0x0014
- FeedbagPreAuthorizedBuddy = 0x0015
- FeedbagRemoveMe = 0x0016
- FeedbagRemoveMe2 = 0x0017
- FeedbagRequestAuthorizeToHost = 0x0018
- FeedbagRequestAuthorizeToClient = 0x0019
- FeedbagRespondAuthorizeToHost = 0x001A
- FeedbagRespondAuthorizeToClient = 0x001B
- FeedbagBuddyAdded = 0x001C
- FeedbagRequestAuthorizeToBadog = 0x001D
- FeedbagRespondAuthorizeToBadog = 0x001E
- FeedbagBuddyAddedToBadog = 0x001F
- FeedbagTestSnac = 0x0021
- FeedbagForwardMsg = 0x0022
- FeedbagIsAuthRequiredQuery = 0x0023
- FeedbagIsAuthRequiredReply = 0x0024
- 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
- FeedbagClassIdPermit = 0x0002
- FeedbagClassIdDeny = 0x0003
- FeedbagClassIdPdinfo = 0x0004
- FeedbagClassIdBuddyPrefs = 0x0005
- FeedbagClassIdNonbuddy = 0x0006
- FeedbagClassIdTpaProvider = 0x0007
- FeedbagClassIdTpaSubscription = 0x0008
- FeedbagClassIdClientPrefs = 0x0009
- FeedbagClassIdStock = 0x000A
- FeedbagClassIdWeather = 0x000B
- FeedbagClassIdWatchList = 0x000D
- FeedbagClassIdIgnoreList = 0x000E
- FeedbagClassIdDateTime = 0x000F
- FeedbagClassIdExternalUser = 0x0010
- FeedbagClassIdRootCreator = 0x0011
- FeedbagClassIdFish = 0x0012
- FeedbagClassIdImportTimestamp = 0x0013
- FeedbagClassIdBart = 0x0014
- FeedbagClassIdRbOrder = 0x0015
- FeedbagClassIdPersonality = 0x0016
- FeedbagClassIdAlProf = 0x0017
- FeedbagClassIdAlInfo = 0x0018
- FeedbagClassIdInteraction = 0x0019
- FeedbagClassIdVanityInfo = 0x001D
- FeedbagClassIdFavoriteLocation = 0x001E
- FeedbagClassIdBartPdinfo = 0x001F
- FeedbagClassIdCustomEmoticons = 0x0024
- FeedbagClassIdMaxPredefined = 0x0024
- FeedbagClassIdXIcqStatusNote = 0x015C
- FeedbagClassIdMin = 0x0400
- )
- func routeFeedbag(sm SessionManager, sess *Session, fm *FeedbagStore, snac oscar.SnacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
- switch snac.SubGroup {
- case FeedbagRightsQuery:
- return SendAndReceiveFeedbagRightsQuery(snac, r, w, sequence)
- case FeedbagQuery:
- return ReceiveAndSendFeedbagQuery(sess, fm, snac, w, sequence)
- case FeedbagQueryIfModified:
- return ReceiveAndSendFeedbagQueryIfModified(sess, fm, snac, r, w, sequence)
- case FeedbagUse:
- return ReceiveUse(snac, r, w, sequence)
- case FeedbagInsertItem:
- return ReceiveInsertItem(sm, sess, fm, snac, r, w, sequence)
- case FeedbagUpdateItem:
- return ReceiveUpdateItem(sm, sess, fm, snac, r, w, sequence)
- case FeedbagDeleteItem:
- return ReceiveDeleteItem(sm, sess, fm, snac, r, w, sequence)
- case FeedbagStartCluster:
- return ReceiveFeedbagStartCluster(snac, r, w, sequence)
- case FeedbagEndCluster:
- return ReceiveFeedbagEndCluster(snac, r, w, sequence)
- default:
- return ErrUnsupportedSubGroup
- }
- }
- func SendAndReceiveFeedbagRightsQuery(snac oscar.SnacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
- fmt.Printf("sendAndReceiveFeedbagRightsQuery read SNAC frame: %+v\n", snac)
- snacPayloadIn := oscar.SNAC_0x13_0x02_FeedbagRightsQuery{}
- if err := oscar.Unmarshal(&snacPayloadIn, r); err != nil {
- return err
- }
- fmt.Printf("sendAndReceiveFeedbagRightsQuery read SNAC payload: %+v\n", snacPayloadIn)
- snacFrameOut := oscar.SnacFrame{
- FoodGroup: 0x13,
- SubGroup: 0x03,
- }
- snacPayloadOut := oscar.SNAC_0x13_0x03_FeedbagRightsReply{
- TLVRestBlock: oscar.TLVRestBlock{
- TLVList: oscar.TLVList{
- {
- TType: 0x03,
- Val: uint16(200),
- },
- {
- TType: 0x04,
- Val: []uint16{
- 0x3D,
- 0x3D,
- 0x64,
- 0x64,
- 0x01,
- 0x01,
- 0x32,
- 0x00,
- 0x00,
- 0x03,
- 0x00,
- 0x00,
- 0x00,
- 0x80,
- 0xFF,
- 0x14,
- 0xC8,
- 0x01,
- 0x00,
- 0x01,
- 0x00,
- },
- },
- {
- TType: 0x05,
- Val: uint16(200),
- },
- {
- TType: 0x06,
- Val: uint16(200),
- },
- {
- TType: 0x07,
- Val: uint16(200),
- },
- {
- TType: 0x08,
- Val: uint16(200),
- },
- {
- TType: 0x09,
- Val: uint16(200),
- },
- {
- TType: 0x0A,
- Val: uint16(200),
- },
- {
- TType: 0x0C,
- Val: uint16(200),
- },
- {
- TType: 0x0D,
- Val: uint16(200),
- },
- {
- TType: 0x0E,
- Val: uint16(100),
- },
- },
- },
- }
- return writeOutSNAC(snac, snacFrameOut, snacPayloadOut, sequence, w)
- }
- func ReceiveAndSendFeedbagQuery(sess *Session, fm FeedbagManager, snac oscar.SnacFrame, w io.Writer, sequence *uint32) error {
- fb, err := fm.Retrieve(sess.ScreenName)
- if err != nil {
- return err
- }
- lm := time.UnixMilli(0)
- if len(fb) > 0 {
- lm, err = fm.LastModified(sess.ScreenName)
- if err != nil {
- return err
- }
- }
- snacFrameOut := oscar.SnacFrame{
- FoodGroup: FEEDBAG,
- SubGroup: FeedbagReply,
- }
- snacPayloadOut := oscar.SNAC_0x13_0x06_FeedbagReply{
- Version: 0,
- Items: fb,
- LastUpdate: uint32(lm.Unix()),
- }
- return writeOutSNAC(snac, snacFrameOut, snacPayloadOut, sequence, w)
- }
- func ReceiveAndSendFeedbagQueryIfModified(sess *Session, fm FeedbagManager, snac oscar.SnacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
- snacPayloadIn := oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{}
- if err := oscar.Unmarshal(&snacPayloadIn, r); err != nil {
- return err
- }
- fb, err := fm.Retrieve(sess.ScreenName)
- if err != nil {
- return err
- }
- lm := time.UnixMilli(0)
- if len(fb) > 0 {
- lm, err = fm.LastModified(sess.ScreenName)
- if err != nil {
- return err
- }
- if lm.Before(time.Unix(int64(snacPayloadIn.LastUpdate), 0)) {
- snacFrameOut := oscar.SnacFrame{
- FoodGroup: FEEDBAG,
- SubGroup: FeedbagReplyNotModified,
- }
- snacPayloadOut := oscar.SNAC_0x13_0x05_FeedbagQueryIfModified{
- LastUpdate: uint32(lm.Unix()),
- Count: uint8(len(fb)),
- }
- return writeOutSNAC(snac, snacFrameOut, snacPayloadOut, sequence, w)
- }
- }
- snacFrameOut := oscar.SnacFrame{
- FoodGroup: FEEDBAG,
- SubGroup: FeedbagReply,
- }
- snacPayloadOut := oscar.SNAC_0x13_0x06_FeedbagReply{
- Version: 0,
- Items: fb,
- LastUpdate: uint32(lm.Unix()),
- }
- return writeOutSNAC(snac, snacFrameOut, snacPayloadOut, sequence, w)
- }
- func ReceiveInsertItem(sm SessionManager, sess *Session, fm FeedbagManager, snac oscar.SnacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
- snacPayloadIn := oscar.SNAC_0x13_0x08_FeedbagInsertItem{}
- if err := oscar.Unmarshal(&snacPayloadIn, r); err != nil {
- return err
- }
- for _, item := range snacPayloadIn.Items {
- // don't let users block themselves, it causes the AIM client to go
- // into a weird state.
- if item.ClassID == 3 && item.Name == sess.ScreenName {
- snacFrameOut := oscar.SnacFrame{
- FoodGroup: FEEDBAG,
- SubGroup: FeedbagErr,
- }
- snacPayloadOut := oscar.SnacError{
- Code: ErrorCodeNotSupportedByHost,
- }
- return writeOutSNAC(snac, snacFrameOut, snacPayloadOut, sequence, w)
- }
- }
- if err := fm.Upsert(sess.ScreenName, snacPayloadIn.Items); err != nil {
- return err
- }
- snacFrameOut := oscar.SnacFrame{
- FoodGroup: FEEDBAG,
- SubGroup: FeedbagStatus,
- }
- snacPayloadOut := oscar.SNAC_0x13_0x0E_FeedbagStatus{}
- for range snacPayloadIn.Items {
- snacPayloadOut.Results = append(snacPayloadOut.Results, 0x0000)
- }
- if err := writeOutSNAC(snac, snacFrameOut, snacPayloadOut, sequence, w); err != nil {
- return err
- }
- for _, item := range snacPayloadIn.Items {
- switch item.ClassID {
- case 2:
- // notify that added buddy is online
- if err := NotifyBuddyOnline(w, item.Name, sm, sequence); err != nil {
- return err
- }
- case 3:
- // DENY, block buddy
- if err := blockBuddy(sm, sess, item.Name, sequence, w); err != nil {
- return err
- }
- }
- }
- return nil
- }
- func blockBuddy(sm SessionManager, sess *Session, screenName string, sequence *uint32, w io.Writer) error {
- buddySess, err := sm.RetrieveByScreenName(screenName)
- if err != nil {
- if errors.Is(err, errSessNotFound) {
- // former buddy is offline
- return nil
- }
- return err
- }
- // tell the blocked buddy you've signed off
- sm.SendToScreenName(screenName, XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: BUDDY,
- SubGroup: BuddyDeparted,
- },
- snacOut: oscar.SNAC_0x03_0x0A_BuddyArrived{
- TLVUserInfo: oscar.TLVUserInfo{
- ScreenName: sess.ScreenName,
- WarningLevel: sess.GetWarning(),
- },
- },
- })
- // tell yourself blocked buddy has signed off
- snacFrameOut := oscar.SnacFrame{
- FoodGroup: BUDDY,
- SubGroup: BuddyDeparted,
- }
- snacPayloadOut := oscar.SNAC_0x03_0x0A_BuddyArrived{
- TLVUserInfo: oscar.TLVUserInfo{
- ScreenName: buddySess.ScreenName,
- WarningLevel: buddySess.GetWarning(),
- },
- }
- return writeOutSNAC(oscar.SnacFrame{}, snacFrameOut, snacPayloadOut, sequence, w)
- }
- func ReceiveUpdateItem(sm SessionManager, sess *Session, fm *FeedbagStore, snac oscar.SnacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
- fmt.Printf("ReceiveUpdateItem read SNAC frame: %+v\n", snac)
- snacPayloadIn := oscar.SNAC_0x13_0x09_FeedbagUpdateItem{}
- if err := oscar.Unmarshal(&snacPayloadIn, r); err != nil {
- return err
- }
- if err := fm.Upsert(sess.ScreenName, snacPayloadIn.Items); err != nil {
- return err
- }
- snacPayloadOut := oscar.SNAC_0x13_0x0E_FeedbagStatus{}
- for _, item := range snacPayloadIn.Items {
- snacPayloadOut.Results = append(snacPayloadOut.Results, 0x0000) // success by default
- fmt.Printf("ReceiveUpdateItem read SNAC feedbag item: %+v\n", item)
- }
- snacFrameOut := oscar.SnacFrame{
- FoodGroup: FEEDBAG,
- SubGroup: FeedbagStatus,
- }
- if err := writeOutSNAC(snac, snacFrameOut, snacPayloadOut, sequence, w); err != nil {
- return err
- }
- return GetAllOnlineBuddies(w, sess, sm, fm, sequence)
- }
- func ReceiveDeleteItem(sm SessionManager, sess *Session, fm *FeedbagStore, snac oscar.SnacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
- fmt.Printf("ReceiveUpdateItem read SNAC frame: %+v\n", snac)
- snacPayloadIn := oscar.SNAC_0x13_0x0A_FeedbagDeleteItem{}
- if err := oscar.Unmarshal(&snacPayloadIn, r); err != nil {
- return err
- }
- if err := fm.Delete(sess.ScreenName, snacPayloadIn.Items); err != nil {
- return err
- }
- snacPayloadOut := oscar.SNAC_0x13_0x0E_FeedbagStatus{}
- hasUnblock := false
- for _, item := range snacPayloadIn.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 := oscar.SnacFrame{
- FoodGroup: FEEDBAG,
- SubGroup: FeedbagStatus,
- }
- return writeOutSNAC(snac, snacFrameOut, snacPayloadOut, sequence, w)
- }
- func ReceiveFeedbagStartCluster(snac oscar.SnacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
- fmt.Printf("ReceiveFeedbagStartCluster read SNAC frame: %+v\n", snac)
- tlv := oscar.TLVRestBlock{}
- return tlv.Read(r)
- }
- func ReceiveFeedbagEndCluster(snac oscar.SnacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
- fmt.Printf("receiveFeedbagEndCluster read SNAC frame: %+v\n", snac)
- return nil
- }
- func ReceiveUse(snac oscar.SnacFrame, r io.Reader, w io.Writer, sequence *uint32) error {
- fmt.Printf("ReceiveUse read SNAC frame: %+v\n", snac)
- return nil
- }
|