403Webshell
Server IP : 157.230.181.24  /  Your IP : 216.73.217.11
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux conductive 6.8.0-117-generic #117-Ubuntu SMP PREEMPT_DYNAMIC Tue May 5 19:26:24 UTC 2026 x86_64
User :  ( 1000)
PHP Version : 8.3.31
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/vhosts/ceagon/open-oscar-server/foodgroup/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/vhosts/ceagon/open-oscar-server/foodgroup/locate.go
package foodgroup

import (
	"context"
	"errors"
	"fmt"
	"time"

	"github.com/mk6i/open-oscar-server/state"
	"github.com/mk6i/open-oscar-server/wire"
)

// omitCaps is the map of to filter out of the client's capability list
// because they are not currently supported by the server.
var omitCaps = map[[16]byte]bool{
	wire.CapGames:      true, // games
	wire.CapSupportICQ: true, // ICQ inter-op
	wire.CapVoiceChat:  true, // voice chat
}

// NewLocateService creates a new instance of LocateService.
func NewLocateService(
	bartItemManager BARTItemManager,
	messageRelayer MessageRelayer,
	profileManager ProfileManager,
	relationshipFetcher RelationshipFetcher,
	sessionRetriever SessionRetriever,
	userManager UserManager,
) LocateService {
	return LocateService{
		buddyBroadcaster:    newBuddyNotifier(bartItemManager, relationshipFetcher, messageRelayer, sessionRetriever),
		messageRelayer:      messageRelayer,
		relationshipFetcher: relationshipFetcher,
		profileManager:      profileManager,
		sessionRetriever:    sessionRetriever,
		userManager:         userManager,
	}
}

// LocateService provides functionality for the Locate food group, which is
// responsible for user profiles, user info lookups, directory information, and
// keyword lookups.
type LocateService struct {
	buddyBroadcaster    buddyBroadcaster
	messageRelayer      MessageRelayer
	relationshipFetcher RelationshipFetcher
	profileManager      ProfileManager
	sessionRetriever    SessionRetriever
	userManager         UserManager
}

// RightsQuery returns SNAC wire.LocateRightsReply, which contains Locate food
// group settings for the current user.
func (s LocateService) RightsQuery(_ context.Context, inFrame wire.SNACFrame) wire.SNACMessage {
	return wire.SNACMessage{
		Frame: wire.SNACFrame{
			FoodGroup: wire.Locate,
			SubGroup:  wire.LocateRightsReply,
			RequestID: inFrame.RequestID,
		},
		Body: wire.SNAC_0x02_0x03_LocateRightsReply{
			TLVRestBlock: wire.TLVRestBlock{
				TLVList: wire.TLVList{
					// these are arbitrary values--AIM clients seem to perform
					// OK with them
					wire.NewTLVBE(wire.LocateTLVTagsRightsMaxSigLen, uint16(1000)),
					wire.NewTLVBE(wire.LocateTLVTagsRightsMaxCapabilitiesLen, uint16(1000)),
					wire.NewTLVBE(wire.LocateTLVTagsRightsMaxFindByEmailList, uint16(1000)),
					wire.NewTLVBE(wire.LocateTLVTagsRightsMaxCertsLen, uint16(1000)),
					wire.NewTLVBE(wire.LocateTLVTagsRightsMaxMaxShortCapabilities, uint16(1000)),
				},
			},
		},
	}
}

// SetInfo sets the user's profile, away message or capabilities.
func (s LocateService) SetInfo(ctx context.Context, instance *state.SessionInstance, inBody wire.SNAC_0x02_0x04_LocateSetInfo) error {

	// update profile
	if profileText, hasProfile := inBody.String(wire.LocateTLVTagsInfoSigData); hasProfile {
		mime, _ := inBody.String(wire.LocateTLVTagsInfoSigMime)
		profile := state.UserProfile{
			ProfileText: profileText,
			MIMEType:    mime,
			UpdateTime:  time.Now(),
		}

		// set the server-side profile
		if instance.KerberosAuth() || inBody.HasTag(wire.LocateTLVTagsInfoSupportHostSig) {
			// normally, the SupportHostSig TLV indicates that the profile should
			// be stored server-side. however, some AIM 6 clients expect server-side
			// profiles but do not send this TLV. in order to cover all bases, just
			// save the profile for all kerberos-based clients.
			if err := s.profileManager.SetProfile(ctx, instance.IdentScreenName(), profile); err != nil {
				return err
			}

			for _, _instance := range instance.Session().Instances() {
				if _instance.KerberosAuth() {
					// update all instances that do server-side profile storage
					_instance.SetProfile(profile)
				}
			}

			s.messageRelayer.RelayToOtherInstances(ctx, instance, wire.SNACMessage{
				Frame: wire.SNACFrame{
					FoodGroup: wire.OService,
					SubGroup:  wire.OServiceUserInfoUpdate,
				},
				Body: newOServiceUserInfoUpdate(instance),
			})
		} else {
			// set the client-side profile
			instance.SetProfile(profile)
		}
	}

	// broadcast away message change to buddies
	if awayMsg, hasAwayMsg := inBody.String(wire.LocateTLVTagsInfoUnavailableData); hasAwayMsg {
		if awayMsg != "" {
			instance.SetUserInfoFlag(wire.OServiceUserFlagUnavailable)
		} else {
			instance.ClearUserInfoFlag(wire.OServiceUserFlagUnavailable)
		}
		instance.SetAwayMessage(awayMsg)
		if instance.SignonComplete() {
			if err := s.buddyBroadcaster.BroadcastBuddyArrived(ctx, instance.IdentScreenName(), instance.Session().TLVUserInfo()); err != nil {
				return err
			}
		}
	}

	// update client capabilities (buddy icon, chat, etc...)
	if b, hasCaps := inBody.Bytes(wire.LocateTLVTagsInfoCapabilities); hasCaps {
		if len(b)%16 != 0 {
			return errors.New("capability list must be array of 16-byte values")
		}
		var caps [][16]byte
		for i := 0; i < len(b); i += 16 {
			var c [16]byte
			copy(c[:], b[i:i+16])
			if _, found := omitCaps[c]; found {
				continue
			}
			caps = append(caps, c)
		}
		instance.SetCaps(caps)
		if instance.SignonComplete() {
			if err := s.buddyBroadcaster.BroadcastBuddyArrived(ctx, instance.IdentScreenName(), instance.Session().TLVUserInfo()); err != nil {
				return err
			}
		}
	}

	return nil
}

func newLocateErr(requestID uint32, errCode uint16) wire.SNACMessage {
	return wire.SNACMessage{
		Frame: wire.SNACFrame{
			FoodGroup: wire.Locate,
			SubGroup:  wire.LocateErr,
			RequestID: requestID,
		},
		Body: wire.SNACError{
			Code: errCode,
		},
	}
}

// UserInfoQuery fetches display information about an arbitrary user (not the
// current user). It returns wire.LocateUserInfoReply, which contains the
// profile, if requested, and/or the away message, if requested.
func (s LocateService) UserInfoQuery(ctx context.Context, instance *state.SessionInstance, inFrame wire.SNACFrame, inBody wire.SNAC_0x02_0x05_LocateUserInfoQuery) (wire.SNACMessage, error) {
	lookupSN := state.NewIdentScreenName(inBody.ScreenName)

	var lookupSess *state.Session
	if lookupSN == instance.IdentScreenName() {
		// looking up own profile
		lookupSess = instance.Session()
	} else {
		rel, err := s.relationshipFetcher.Relationship(ctx, instance.IdentScreenName(), lookupSN)
		if err != nil {
			return wire.SNACMessage{}, err
		}

		if rel.YouBlock || rel.BlocksYou {
			return newLocateErr(inFrame.RequestID, wire.ErrorCodeNotLoggedOn), nil
		}

		lookupSess = s.sessionRetriever.RetrieveSession(lookupSN)
		if lookupSess == nil {
			// user is offline
			return newLocateErr(inFrame.RequestID, wire.ErrorCodeNotLoggedOn), nil
		}
	}

	var list wire.TLVList

	if inBody.RequestProfile() {
		prof := lookupSess.Profile()
		// if looking up own profile, return this instance's profile for consistency
		if instance.IdentScreenName() == lookupSN {
			prof = instance.Profile()
		}
		list.AppendList([]wire.TLV{
			wire.NewTLVBE(wire.LocateTLVTagsInfoSigMime, prof.MIMEType),
			wire.NewTLVBE(wire.LocateTLVTagsInfoSigData, prof.ProfileText),
		})
	}

	if inBody.RequestAwayMessage() && lookupSess.Away() {
		list.AppendList([]wire.TLV{
			wire.NewTLVBE(wire.LocateTLVTagsInfoUnavailableMime, `text/aolrtf; charset="us-ascii"`),
			wire.NewTLVBE(wire.LocateTLVTagsInfoUnavailableData, lookupSess.AwayMessage()),
		})
	}

	return wire.SNACMessage{
		Frame: wire.SNACFrame{
			FoodGroup: wire.Locate,
			SubGroup:  wire.LocateUserInfoReply,
			RequestID: inFrame.RequestID,
		},
		Body: wire.SNAC_0x02_0x06_LocateUserInfoReply{
			TLVUserInfo: lookupSess.TLVUserInfo(),
			LocateInfo: wire.TLVRestBlock{
				TLVList: list,
			},
		},
	}, nil
}

// SetDirInfo sets directory information for current user (first name, last
// name, etc).
func (s LocateService) SetDirInfo(ctx context.Context, instance *state.SessionInstance, inFrame wire.SNACFrame, inBody wire.SNAC_0x02_0x09_LocateSetDirInfo) (wire.SNACMessage, error) {
	info := newAIMNameAndAddrFromTLVList(inBody.TLVList)

	if err := s.profileManager.SetDirectoryInfo(ctx, instance.IdentScreenName(), info); err != nil {
		return wire.SNACMessage{}, err
	}

	return wire.SNACMessage{
		Frame: wire.SNACFrame{
			FoodGroup: wire.Locate,
			SubGroup:  wire.LocateSetDirReply,
			RequestID: inFrame.RequestID,
		},
		Body: wire.SNAC_0x02_0x0A_LocateSetDirReply{
			Result: 1,
		},
	}, nil
}

// SetKeywordInfo sets profile keywords and interests. This method does nothing
// and exists to placate the AIM client. It returns wire.LocateSetKeywordReply
// with a canned success message.
func (s LocateService) SetKeywordInfo(ctx context.Context, instance *state.SessionInstance, inFrame wire.SNACFrame, inBody wire.SNAC_0x02_0x0F_LocateSetKeywordInfo) (wire.SNACMessage, error) {
	var keywords [5]string

	i := 0
	for _, tlv := range inBody.TLVList {
		if tlv.Tag != wire.ODirTLVInterest {
			continue
		}
		keywords[i] = string(tlv.Value)
		i++
		if i == len(keywords) {
			break
		}
	}

	if err := s.profileManager.SetKeywords(ctx, instance.IdentScreenName(), keywords); err != nil {
		return wire.SNACMessage{}, fmt.Errorf("SetKeywords: %w", err)
	}

	return wire.SNACMessage{
		Frame: wire.SNACFrame{
			FoodGroup: wire.Locate,
			SubGroup:  wire.LocateSetKeywordReply,
			RequestID: inFrame.RequestID,
		},
		Body: wire.SNAC_0x02_0x10_LocateSetKeywordReply{
			Unknown: 1,
		},
	}, nil
}

// DirInfo returns directory information for a user.
func (s LocateService) DirInfo(ctx context.Context, inFrame wire.SNACFrame, inBody wire.SNAC_0x02_0x0B_LocateGetDirInfo) (wire.SNACMessage, error) {
	reply := wire.SNAC_0x02_0x0C_LocateGetDirReply{
		Status: wire.LocateGetDirReplyOK,
		TLVBlock: wire.TLVBlock{
			TLVList: wire.TLVList{},
		},
	}

	user, err := s.profileManager.User(ctx, state.NewIdentScreenName(inBody.ScreenName))
	if err != nil {
		return wire.SNACMessage{}, fmt.Errorf("User: %w", err)
	}

	if user != nil {
		reply.Append(wire.NewTLVBE(wire.ODirTLVFirstName, user.AIMDirectoryInfo.FirstName))
		reply.Append(wire.NewTLVBE(wire.ODirTLVLastName, user.AIMDirectoryInfo.LastName))
		reply.Append(wire.NewTLVBE(wire.ODirTLVMiddleName, user.AIMDirectoryInfo.MiddleName))
		reply.Append(wire.NewTLVBE(wire.ODirTLVMaidenName, user.AIMDirectoryInfo.MaidenName))
		reply.Append(wire.NewTLVBE(wire.ODirTLVCountry, user.AIMDirectoryInfo.Country))
		reply.Append(wire.NewTLVBE(wire.ODirTLVState, user.AIMDirectoryInfo.State))
		reply.Append(wire.NewTLVBE(wire.ODirTLVCity, user.AIMDirectoryInfo.City))
		reply.Append(wire.NewTLVBE(wire.ODirTLVNickName, user.AIMDirectoryInfo.NickName))
		reply.Append(wire.NewTLVBE(wire.ODirTLVZIP, user.AIMDirectoryInfo.ZIPCode))
		reply.Append(wire.NewTLVBE(wire.ODirTLVAddress, user.AIMDirectoryInfo.Address))
	}

	return wire.SNACMessage{
		Frame: wire.SNACFrame{
			FoodGroup: wire.Locate,
			SubGroup:  wire.LocateGetDirReply,
			RequestID: inFrame.RequestID,
		},
		Body: reply,
	}, nil
}

Youez - 2016 - github.com/yon3zu
LinuXploit